/[LeafOK_CVS]/lbbs/src/article_post.c
ViewVC logotype

Diff of /lbbs/src/article_post.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 1.20 by sysadm, Mon Jun 16 01:36:56 2025 UTC Revision 1.25 by sysadm, Tue Sep 30 03:02:06 2025 UTC
# Line 14  Line 14 
14   *                                                                         *   *                                                                         *
15   ***************************************************************************/   ***************************************************************************/
16    
 #define _POSIX_C_SOURCE 200809L  
   
 #include "article_post.h"  
17  #include "article_cache.h"  #include "article_cache.h"
18  #include "editor.h"  #include "article_post.h"
 #include "screen.h"  
19  #include "bbs.h"  #include "bbs.h"
20  #include "log.h"  #include "database.h"
21    #include "editor.h"
22  #include "io.h"  #include "io.h"
23    #include "log.h"
24  #include "lml.h"  #include "lml.h"
25  #include "database.h"  #include "screen.h"
26  #include "user_priv.h"  #include "user_priv.h"
27  #include <ctype.h>  #include <ctype.h>
28  #include <string.h>  #include <string.h>
29  #include <stdlib.h>  #include <stdlib.h>
30  #include <time.h>  #include <time.h>
31    
32  #define TITLE_INPUT_MAX_LEN 74  #define TITLE_INPUT_MAX_LEN 72
33  #define ARTICLE_CONTENT_MAX_LEN 1024 * 1024 * 4 // 4MB  #define ARTICLE_CONTENT_MAX_LEN 1024 * 1024 * 4 // 4MB
34  #define ARTICLE_QUOTE_MAX_LINES 20  #define ARTICLE_QUOTE_MAX_LINES 20
35  #define ARTICLE_QUOTE_LINE_MAX_LEN 76  #define ARTICLE_QUOTE_LINE_MAX_LEN 76
# Line 46  int article_post(const SECTION_LIST *p_s Line 44  int article_post(const SECTION_LIST *p_s
44          char sql[SQL_BUFFER_LEN];          char sql[SQL_BUFFER_LEN];
45          char *sql_content = NULL;          char *sql_content = NULL;
46          EDITOR_DATA *p_editor_data = NULL;          EDITOR_DATA *p_editor_data = NULL;
47          char title_input[TITLE_INPUT_MAX_LEN + 1];          char title_input[BBS_article_title_max_len + 1];
48          char title_f[BBS_article_title_max_len * 2 + 1];          char title_f[BBS_article_title_max_len * 2 + 1];
49          char *content = NULL;          char *content = NULL;
50          char *content_f = NULL;          char *content_f = NULL;
51          long len_content;          long len_content;
52            int content_display_length;
53          char nickname_f[BBS_nickname_max_len * 2 + 1];          char nickname_f[BBS_nickname_max_len * 2 + 1];
54          int sign_id = 0;          int sign_id = 0;
55          long len;          long len;
# Line 67  int article_post(const SECTION_LIST *p_s Line 66  int article_post(const SECTION_LIST *p_s
66          {          {
67                  clearscr();                  clearscr();
68                  moveto(1, 1);                  moveto(1, 1);
69                  prints("您没有权限在本版块发表文章\n");                  prints("鎮ㄦ病鏈夋潈闄愬湪鏈増鍧楀彂琛ㄦ枃绔燶n");
70                  press_any_key();                  press_any_key();
71    
72                  return 0;                  return 0;
# Line 90  int article_post(const SECTION_LIST *p_s Line 89  int article_post(const SECTION_LIST *p_s
89          {          {
90                  clearscr();                  clearscr();
91                  moveto(21, 1);                  moveto(21, 1);
92                  prints("发表文章于 %s[%s] 讨论区,类型: %s", p_section->stitle, p_section->sname, (p_article_new->transship ? "转载" : "原创"));                  prints("鍙戣〃鏂囩珷浜 %s[%s] 璁ㄨ鍖猴紝绫诲瀷: %s", p_section->stitle, p_section->sname, (p_article_new->transship ? "杞浇" : "鍘熷垱"));
93                  moveto(22, 1);                  moveto(22, 1);
94                  prints("标题: %s", (p_article_new->title[0] == '\0' ? "[无]" : p_article_new->title));                  prints("鏍囬: %s", (p_article_new->title[0] == '\0' ? "[鏃燷" : p_article_new->title));
95                  moveto(23, 1);                  moveto(23, 1);
96                  prints("使用第 %d 个签名", sign_id);                  prints("浣跨敤绗 %d 涓鍚", sign_id);
97    
98                  if (toupper(ch) != 'T')                  if (toupper(ch) != 'T')
99                  {                  {
100                          prints("    按0~3选签名档(0表示不使用)");                          prints("    鎸0~3閫夌鍚嶆。(0琛ㄧず涓嶄娇鐢)");
101    
102                          moveto(24, 1);                          moveto(24, 1);
103                          prints("T改标题, C取消, Z设为转载, Y设为原创, Enter继续: ");                          prints("T鏀规爣棰, C鍙栨秷, Z璁句负杞浇, Y璁句负鍘熷垱, Enter缁х画: ");
104                          iflush();                          iflush();
105                          ch = 0;                          ch = 0;
106                  }                  }
# Line 119  int article_post(const SECTION_LIST *p_s Line 118  int article_post(const SECTION_LIST *p_s
118                          case 'T':                          case 'T':
119                                  moveto(24, 1);                                  moveto(24, 1);
120                                  clrtoeol();                                  clrtoeol();
121                                  len = get_data(24, 1, "标题: ", title_input, TITLE_INPUT_MAX_LEN, 1);                                  len = get_data(24, 1, "鏍囬: ", title_input, sizeof(title_input), TITLE_INPUT_MAX_LEN, DOECHO);
122                                  for (p = title_input; *p == ' '; p++)                                  for (p = title_input; *p == ' '; p++)
123                                          ;                                          ;
124                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)
# Line 136  int article_post(const SECTION_LIST *p_s Line 135  int article_post(const SECTION_LIST *p_s
135                          case 'C':                          case 'C':
136                                  clearscr();                                  clearscr();
137                                  moveto(1, 1);                                  moveto(1, 1);
138                                  prints("取消...");                                  prints("鍙栨秷...");
139                                  press_any_key();                                  press_any_key();
140                                  goto cleanup;                                  goto cleanup;
141                          case 'Y':                          case 'Y':
# Line 169  int article_post(const SECTION_LIST *p_s Line 168  int article_post(const SECTION_LIST *p_s
168    
169                          clearscr();                          clearscr();
170                          moveto(1, 1);                          moveto(1, 1);
171                          prints("(S)发送, (C)取消, (T)更改标题 or (E)再编辑? [S]: ");                          prints("(S)鍙戦, (C)鍙栨秷, (T)鏇存敼鏍囬 or (E)鍐嶇紪杈? [S]: ");
172                          iflush();                          iflush();
173    
174                          for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))                          for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))
# Line 186  int article_post(const SECTION_LIST *p_s Line 185  int article_post(const SECTION_LIST *p_s
185                                  case 'C':                                  case 'C':
186                                          clearscr();                                          clearscr();
187                                          moveto(1, 1);                                          moveto(1, 1);
188                                          prints("取消...");                                          prints("鍙栨秷...");
189                                          press_any_key();                                          press_any_key();
190                                          goto cleanup;                                          goto cleanup;
191                                  case 'T':                                  case 'T':
# Line 265  int article_post(const SECTION_LIST *p_s Line 264  int article_post(const SECTION_LIST *p_s
264                  rs = NULL;                  rs = NULL;
265          }          }
266    
267            // Calculate display length of content
268            content_display_length = str_length(content, 1);
269    
270          // Begin transaction          // Begin transaction
271          if (mysql_query(db, "SET autocommit=0") != 0)          if (mysql_query(db, "SET autocommit=0") != 0)
272          {          {
# Line 328  int article_post(const SECTION_LIST *p_s Line 330  int article_post(const SECTION_LIST *p_s
330          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
331                           "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "                           "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "
332                           "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "                           "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "
333                           "VALUES(%d, 0, %d, '%s', '%s', '%s', %d, %d, NOW(), '%s', 1, %d, NOW(), 1, %ld)",                           "VALUES(%d, 0, %d, '%s', '%s', '%s', %d, %d, NOW(), '%s', 1, %d, NOW(), 1, %d)",
334                           p_section->sid, BBS_priv.uid, BBS_username, nickname_f, title_f,                           p_section->sid, BBS_priv.uid, BBS_username, nickname_f, title_f,
335                           p_article_new->cid, p_article_new->transship, hostaddr_client, BBS_user_exp, len_content);                           p_article_new->cid, p_article_new->transship, hostaddr_client, BBS_user_exp, content_display_length);
336    
337          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
338          {          {
# Line 394  int article_post(const SECTION_LIST *p_s Line 396  int article_post(const SECTION_LIST *p_s
396    
397          clearscr();          clearscr();
398          moveto(1, 1);          moveto(1, 1);
399          prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval);          prints("鍙戦佸畬鎴愶紝鏂版枃绔犻氬父浼氬湪%d绉掑悗鍙", BBS_section_list_load_interval);
400          press_any_key();          press_any_key();
401          ret = 1; // Success          ret = 1; // Success
402    
# Line 421  int article_modify(const SECTION_LIST *p Line 423  int article_modify(const SECTION_LIST *p
423          char *content = NULL;          char *content = NULL;
424          char *content_f = NULL;          char *content_f = NULL;
425          long len_content;          long len_content;
426            int content_display_length;
427          int ch;          int ch;
428          long ret = 0;          long ret = 0;
429          time_t now;          time_t now;
# Line 438  int article_modify(const SECTION_LIST *p Line 441  int article_modify(const SECTION_LIST *p
441          {          {
442                  clearscr();                  clearscr();
443                  moveto(1, 1);                  moveto(1, 1);
444                  prints("该文章无法被编辑,请联系版主。");                  prints("璇ユ枃绔犳棤娉曡缂栬緫锛岃鑱旂郴鐗堜富銆");
445                  press_any_key();                  press_any_key();
446    
447                  return 0;                  return 0;
# Line 510  int article_modify(const SECTION_LIST *p Line 513  int article_modify(const SECTION_LIST *p
513    
514                  clearscr();                  clearscr();
515                  moveto(1, 1);                  moveto(1, 1);
516                  prints("(S)保存, (C)取消 or (E)再编辑? [S]: ");                  prints("(S)淇濆瓨, (C)鍙栨秷 or (E)鍐嶇紪杈? [S]: ");
517                  iflush();                  iflush();
518    
519                  for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))                  for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))
# Line 527  int article_modify(const SECTION_LIST *p Line 530  int article_modify(const SECTION_LIST *p
530                          case 'C':                          case 'C':
531                                  clearscr();                                  clearscr();
532                                  moveto(1, 1);                                  moveto(1, 1);
533                                  prints("取消...");                                  prints("鍙栨秷...");
534                                  press_any_key();                                  press_any_key();
535                                  goto cleanup;                                  goto cleanup;
536                          case 'E':                          case 'E':
# Line 567  int article_modify(const SECTION_LIST *p Line 570  int article_modify(const SECTION_LIST *p
570          strftime(str_modify_dt, sizeof(str_modify_dt), "%Y-%m-%d %H:%M:%S (UTC %z)", &tm_modify_dt);          strftime(str_modify_dt, sizeof(str_modify_dt), "%Y-%m-%d %H:%M:%S (UTC %z)", &tm_modify_dt);
571    
572          len_content += snprintf(content + len_content, LINE_BUFFER_LEN,          len_content += snprintf(content + len_content, LINE_BUFFER_LEN,
573                                                          "\n--\n※ 作者已于 %s 修改本文※\n",                                                          "\n--\n鈥 浣滆呭凡浜 %s 淇敼鏈枃鈥籠n",
574                                                          str_modify_dt);                                                          str_modify_dt);
575    
576            // Calculate display length of content
577            content_display_length = str_length(content, 1);
578    
579          db = db_open();          db = db_open();
580          if (db == NULL)          if (db == NULL)
581          {          {
# Line 637  int article_modify(const SECTION_LIST *p Line 643  int article_modify(const SECTION_LIST *p
643    
644          // Update article          // Update article
645          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
646                           "UPDATE bbs SET CID = %d, length = %ld, excerption = 0 WHERE AID = %d", // Set excerption = 0 explictly in case of rare condition                           "UPDATE bbs SET CID = %d, length = %d, excerption = 0 WHERE AID = %d", // Set excerption = 0 explictly in case of rare condition
647                           p_article_new->cid, len_content, p_article->aid);                           p_article_new->cid, content_display_length, p_article->aid);
648    
649          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
650          {          {
# Line 680  int article_modify(const SECTION_LIST *p Line 686  int article_modify(const SECTION_LIST *p
686    
687          clearscr();          clearscr();
688          moveto(1, 1);          moveto(1, 1);
689          prints("修改完成,新内容通常会在%d秒后可见", BBS_section_list_load_interval);          prints("淇敼瀹屾垚锛屾柊鍐呭閫氬父浼氬湪%d绉掑悗鍙", BBS_section_list_load_interval);
690          press_any_key();          press_any_key();
691          ret = 1; // Success          ret = 1; // Success
692    
# Line 712  int article_reply(const SECTION_LIST *p_ Line 718  int article_reply(const SECTION_LIST *p_
718          char *content = NULL;          char *content = NULL;
719          char *content_f = NULL;          char *content_f = NULL;
720          long len_content;          long len_content;
721            int content_display_length;
722          char nickname_f[BBS_nickname_max_len * 2 + 1];          char nickname_f[BBS_nickname_max_len * 2 + 1];
723          int sign_id = 0;          int sign_id = 0;
724          long len;          long len;
# Line 733  int article_reply(const SECTION_LIST *p_ Line 740  int article_reply(const SECTION_LIST *p_
740          {          {
741                  clearscr();                  clearscr();
742                  moveto(1, 1);                  moveto(1, 1);
743                  prints("您没有权限在本版块发表文章\n");                  prints("鎮ㄦ病鏈夋潈闄愬湪鏈増鍧楀彂琛ㄦ枃绔燶n");
744                  press_any_key();                  press_any_key();
745    
746                  return 0;                  return 0;
# Line 786  int article_reply(const SECTION_LIST *p_ Line 793  int article_reply(const SECTION_LIST *p_
793    
794                  clearscr();                  clearscr();
795                  moveto(1, 1);                  moveto(1, 1);
796                  prints("该主题谢绝回复");                  prints("璇ヤ富棰樿阿缁濆洖澶");
797                  press_any_key();                  press_any_key();
798    
799                  goto cleanup;                  goto cleanup;
# Line 830  int article_reply(const SECTION_LIST *p_ Line 837  int article_reply(const SECTION_LIST *p_
837                  }                  }
838    
839                  // Apply LML render to content body                  // Apply LML render to content body
840                  len = lml_plain(row[1], content_f, ARTICLE_CONTENT_MAX_LEN);                  len = lml_plain(row[1], content_f, ARTICLE_CONTENT_MAX_LEN, 0);
841                  content_f[len] = '\0';                  content_f[len] = '\0';
842    
843                  // Remove control sequence                  // Remove control sequence
844                  len = str_filter(content_f, 0);                  len = str_filter(content_f, 0);
845    
846                  len = snprintf(content, ARTICLE_CONTENT_MAX_LEN,                  len = snprintf(content, ARTICLE_CONTENT_MAX_LEN,
847                                             "\n\n【 在 %s (%s) 的大作中提到: 】\n",                                             "\n\n銆 鍦 %s (%s) 鐨勫ぇ浣滀腑鎻愬埌: 銆慭n",
848                                             p_article->username, p_article->nickname);                                             p_article->username, p_article->nickname);
849    
850                  quote_content_lines = split_data_lines(content_f, ARTICLE_QUOTE_LINE_MAX_LEN, line_offsets, ARTICLE_QUOTE_MAX_LINES + 1, 0);                  quote_content_lines = split_data_lines(content_f, ARTICLE_QUOTE_LINE_MAX_LEN, line_offsets, ARTICLE_QUOTE_MAX_LINES + 1, 0, NULL);
851                  for (i = 0; i < quote_content_lines; i++)                  for (i = 0; i < quote_content_lines; i++)
852                  {                  {
853                          memcpy(content + len, ": ", 2); // quote line prefix                          memcpy(content + len, ": ", 2); // quote line prefix
# Line 885  int article_reply(const SECTION_LIST *p_ Line 892  int article_reply(const SECTION_LIST *p_
892          {          {
893                  clearscr();                  clearscr();
894                  moveto(21, 1);                  moveto(21, 1);
895                  prints("回复文章于 %s[%s] 讨论区", p_section->stitle, p_section->sname);                  prints("鍥炲鏂囩珷浜 %s[%s] 璁ㄨ鍖", p_section->stitle, p_section->sname);
896                  moveto(22, 1);                  moveto(22, 1);
897                  prints("标题: %s", (p_article_new->title[0] == '\0' ? "[无]" : p_article_new->title));                  prints("鏍囬: %s", (p_article_new->title[0] == '\0' ? "[鏃燷" : p_article_new->title));
898                  moveto(23, 1);                  moveto(23, 1);
899                  prints("使用第 %d 个签名", sign_id);                  prints("浣跨敤绗 %d 涓鍚", sign_id);
900    
901                  if (toupper(ch) != 'T')                  if (toupper(ch) != 'T')
902                  {                  {
903                          prints("    按0~3选签名档(0表示不使用)");                          prints("    鎸0~3閫夌鍚嶆。(0琛ㄧず涓嶄娇鐢)");
904    
905                          moveto(24, 1);                          moveto(24, 1);
906                          prints("T改标题, C取消, Enter继续: ");                          prints("T鏀规爣棰, C鍙栨秷, Enter缁х画: ");
907                          iflush();                          iflush();
908                          ch = 0;                          ch = 0;
909                  }                  }
# Line 914  int article_reply(const SECTION_LIST *p_ Line 921  int article_reply(const SECTION_LIST *p_
921                          case 'T':                          case 'T':
922                                  moveto(24, 1);                                  moveto(24, 1);
923                                  clrtoeol();                                  clrtoeol();
924                                  len = get_data(24, 1, "标题: ", title_input, TITLE_INPUT_MAX_LEN, 1);                                  len = get_data(24, 1, "鏍囬: ", title_input, sizeof(title_input), TITLE_INPUT_MAX_LEN, DOECHO);
925                                  for (p = title_input; *p == ' '; p++)                                  for (p = title_input; *p == ' '; p++)
926                                          ;                                          ;
927                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)
# Line 931  int article_reply(const SECTION_LIST *p_ Line 938  int article_reply(const SECTION_LIST *p_
938                          case 'C':                          case 'C':
939                                  clearscr();                                  clearscr();
940                                  moveto(1, 1);                                  moveto(1, 1);
941                                  prints("取消...");                                  prints("鍙栨秷...");
942                                  press_any_key();                                  press_any_key();
943                                  goto cleanup;                                  goto cleanup;
944                          case '0':                          case '0':
# Line 958  int article_reply(const SECTION_LIST *p_ Line 965  int article_reply(const SECTION_LIST *p_
965    
966                          clearscr();                          clearscr();
967                          moveto(1, 1);                          moveto(1, 1);
968                          prints("(S)发送, (C)取消, (T)更改标题 or (E)再编辑? [S]: ");                          prints("(S)鍙戦, (C)鍙栨秷, (T)鏇存敼鏍囬 or (E)鍐嶇紪杈? [S]: ");
969                          iflush();                          iflush();
970    
971                          for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))                          for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))
# Line 975  int article_reply(const SECTION_LIST *p_ Line 982  int article_reply(const SECTION_LIST *p_
982                                  case 'C':                                  case 'C':
983                                          clearscr();                                          clearscr();
984                                          moveto(1, 1);                                          moveto(1, 1);
985                                          prints("取消...");                                          prints("鍙栨秷...");
986                                          press_any_key();                                          press_any_key();
987                                          goto cleanup;                                          goto cleanup;
988                                  case 'T':                                  case 'T':
# Line 1054  int article_reply(const SECTION_LIST *p_ Line 1061  int article_reply(const SECTION_LIST *p_
1061                  rs = NULL;                  rs = NULL;
1062          }          }
1063    
1064            // Calculate display length of content
1065            content_display_length = str_length(content, 1);
1066    
1067          // Begin transaction          // Begin transaction
1068          if (mysql_query(db, "SET autocommit=0") != 0)          if (mysql_query(db, "SET autocommit=0") != 0)
1069          {          {
# Line 1117  int article_reply(const SECTION_LIST *p_ Line 1127  int article_reply(const SECTION_LIST *p_
1127          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
1128                           "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "                           "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "
1129                           "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "                           "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "
1130                           "VALUES(%d, %d, %d, '%s', '%s', '%s', %d, 0, NOW(), '%s', 1, %d, NOW(), 1, %ld)",                           "VALUES(%d, %d, %d, '%s', '%s', '%s', %d, 0, NOW(), '%s', 1, %d, NOW(), 1, %d)",
1131                           p_section->sid, (p_article->tid == 0 ? p_article->aid : p_article->tid),                           p_section->sid, (p_article->tid == 0 ? p_article->aid : p_article->tid),
1132                           BBS_priv.uid, BBS_username, nickname_f, title_f,                           BBS_priv.uid, BBS_username, nickname_f, title_f,
1133                           p_article_new->cid, hostaddr_client, BBS_user_exp, len_content);                           p_article_new->cid, hostaddr_client, BBS_user_exp, content_display_length);
1134    
1135          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
1136          {          {
# Line 1199  int article_reply(const SECTION_LIST *p_ Line 1209  int article_reply(const SECTION_LIST *p_
1209    
1210          clearscr();          clearscr();
1211          moveto(1, 1);          moveto(1, 1);
1212          prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval);          prints("鍙戦佸畬鎴愶紝鏂版枃绔犻氬父浼氬湪%d绉掑悗鍙", BBS_section_list_load_interval);
1213          press_any_key();          press_any_key();
1214          ret = 1; // Success          ret = 1; // Success
1215    


Legend:
Removed lines/characters  
Changed lines/characters
  Added lines/characters

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1