/[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.19 by sysadm, Sun Jun 15 13:42:38 2025 UTC Revision 1.41 by sysadm, Fri Nov 7 06:41:43 2025 UTC
# Line 1  Line 1 
1  /***************************************************************************  /* SPDX-License-Identifier: GPL-3.0-or-later */
2                                                  article_post.c  -  description  /*
3                                                           -------------------   * article_post
4          copyright            : (C) 2004-2025 by Leaflet   *   - user interactive feature to post / modify / reply article
5          email                : leaflet@leafok.com   *
6   ***************************************************************************/   * Copyright (C) 2004-2025  Leaflet <leaflet@leafok.com>
7     */
 /***************************************************************************  
  *                                                                         *  
  *   This program is free software; you can redistribute it and/or modify  *  
  *   it under the terms of the GNU General Public License as published by  *  
  *   the Free Software Foundation; either version 3 of the License, or     *  
  *   (at your option) any later version.                                   *  
  *                                                                         *  
  ***************************************************************************/  
8    
 #define _POSIX_C_SOURCE 200809L  
   
 #include "article_post.h"  
9  #include "article_cache.h"  #include "article_cache.h"
10  #include "editor.h"  #include "article_post.h"
 #include "screen.h"  
11  #include "bbs.h"  #include "bbs.h"
12  #include "log.h"  #include "bwf.h"
13    #include "database.h"
14    #include "editor.h"
15  #include "io.h"  #include "io.h"
16    #include "log.h"
17  #include "lml.h"  #include "lml.h"
18  #include "database.h"  #include "screen.h"
19  #include "user_priv.h"  #include "user_priv.h"
20  #include <ctype.h>  #include <ctype.h>
21  #include <string.h>  #include <string.h>
22  #include <stdlib.h>  #include <stdlib.h>
23  #include <time.h>  #include <time.h>
24    
25  #define TITLE_INPUT_MAX_LEN 74  enum _article_post_constant_t
26  #define ARTICLE_CONTENT_MAX_LEN 1024 * 1024 * 4 // 4MB  {
27  #define ARTICLE_QUOTE_MAX_LINES 20          TITLE_INPUT_MAX_LEN = 72,
28  #define ARTICLE_QUOTE_LINE_MAX_LEN 76          ARTICLE_QUOTE_MAX_LINES = 20,
29            MODIFY_DT_MAX_LEN = 50,
30  #define MODIFY_DT_MAX_LEN 50  };
31    
32  int article_post(const SECTION_LIST *p_section, ARTICLE *p_article_new)  int article_post(const SECTION_LIST *p_section, ARTICLE *p_article_new)
33  {  {
# Line 46  int article_post(const SECTION_LIST *p_s Line 37  int article_post(const SECTION_LIST *p_s
37          char sql[SQL_BUFFER_LEN];          char sql[SQL_BUFFER_LEN];
38          char *sql_content = NULL;          char *sql_content = NULL;
39          EDITOR_DATA *p_editor_data = NULL;          EDITOR_DATA *p_editor_data = NULL;
40          char title_input[TITLE_INPUT_MAX_LEN + 1];          char title_input[BBS_article_title_max_len + 1];
41          char title_f[BBS_article_title_max_len * 2 + 1];          char title_f[BBS_article_title_max_len * 2 + 1];
42          char *content = NULL;          char *content = NULL;
43          char *content_f = NULL;          char *content_f = NULL;
44          long len_content;          long len_content;
45            int content_display_length;
46          char nickname_f[BBS_nickname_max_len * 2 + 1];          char nickname_f[BBS_nickname_max_len * 2 + 1];
47          int sign_id = 0;          int sign_id = 0;
48            int reply_note = 1;
49          long len;          long len;
50          int ch;          int ch;
51          char *p, *q;          char *p, *q;
# Line 67  int article_post(const SECTION_LIST *p_s Line 60  int article_post(const SECTION_LIST *p_s
60          {          {
61                  clearscr();                  clearscr();
62                  moveto(1, 1);                  moveto(1, 1);
63                  prints("您没有权限在本版块发表文章\n");                  prints("鎮ㄦ病鏈夋潈闄愬湪鏈増鍧楀彂琛ㄦ枃绔燶n");
64                  press_any_key();                  press_any_key();
65    
66                  return 0;                  return 0;
# Line 90  int article_post(const SECTION_LIST *p_s Line 83  int article_post(const SECTION_LIST *p_s
83          {          {
84                  clearscr();                  clearscr();
85                  moveto(21, 1);                  moveto(21, 1);
86                  prints("发表文章于 %s[%s] 讨论区,类型: %s", p_section->stitle, p_section->sname, (p_article_new->transship ? "转载" : "原创"));                  prints("鍙戣〃鏂囩珷浜 %s[%s] 璁ㄨ鍖猴紝绫诲瀷: %s锛屽洖澶嶉氱煡锛%s",
87                               p_section->stitle, p_section->sname,
88                               (p_article_new->transship ? "杞浇" : "鍘熷垱"),
89                               (reply_note ? "寮鍚" : "鍏抽棴"));
90                  moveto(22, 1);                  moveto(22, 1);
91                  prints("标题: %s", (p_article_new->title[0] == '\0' ? "[无]" : p_article_new->title));                  prints("鏍囬: %s", (p_article_new->title[0] == '\0' ? "[鏃燷" : p_article_new->title));
92                  moveto(23, 1);                  moveto(23, 1);
93                  prints("使用第 %d 个签名", sign_id);                  prints("浣跨敤绗 %d 涓鍚", sign_id);
94    
95                  if (toupper(ch) != 'T')                  if (toupper(ch) != 'T')
96                  {                  {
97                          prints("    按0~3选签名档(0表示不使用)");                          prints("    鎸0~3閫夌鍚嶆。(0琛ㄧず涓嶄娇鐢)");
98    
99                          moveto(24, 1);                          moveto(24, 1);
100                          prints("T改标题, C取消, Z设为转载, Y设为原创, Enter继续: ");                          prints("T鏀规爣棰, C鍙栨秷, Z璁句负%s, N%s, Enter缁х画: ",
101                                       (p_article_new->transship ? "鍘熷垱" : "杞浇"),
102                                       (reply_note ? "鍏抽棴鍥炲閫氱煡" : "寮鍚洖澶嶉氱煡"));
103                          iflush();                          iflush();
104                          ch = 0;                          ch = 0;
105                  }                  }
106    
107                  for (; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))                  while (!SYS_server_exit)
108                  {                  {
109                          switch (toupper(ch))                          switch (toupper(ch))
110                          {                          {
# Line 114  int article_post(const SECTION_LIST *p_s Line 112  int article_post(const SECTION_LIST *p_s
112                          case KEY_TIMEOUT:                          case KEY_TIMEOUT:
113                                  goto cleanup;                                  goto cleanup;
114                          case CR:                          case CR:
                                 igetch_reset();  
115                                  break;                                  break;
116                          case 'T':                          case 'T':
117                                  moveto(24, 1);                                  len = get_data(24, 1, "鏍囬: ", title_input, sizeof(title_input), TITLE_INPUT_MAX_LEN);
                                 clrtoeol();  
                                 len = get_data(24, 1, "标题: ", title_input, TITLE_INPUT_MAX_LEN, 1);  
118                                  for (p = title_input; *p == ' '; p++)                                  for (p = title_input; *p == ' '; p++)
119                                          ;                                          ;
120                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)
# Line 128  int article_post(const SECTION_LIST *p_s Line 123  int article_post(const SECTION_LIST *p_s
123                                  len = q - p;                                  len = q - p;
124                                  if (*p != '\0')                                  if (*p != '\0')
125                                  {                                  {
126                                            if ((ret = check_badwords(p, '*')) < 0)
127                                            {
128                                                    log_error("check_badwords(title) error\n");
129                                            }
130                                            else if (ret > 0)
131                                            {
132                                                    memcpy(title_input, p, (size_t)len + 1);
133                                                    continue;
134                                            }
135                                          memcpy(p_article_new->title, p, (size_t)len + 1);                                          memcpy(p_article_new->title, p, (size_t)len + 1);
136                                          memcpy(title_input, p_article_new->title, (size_t)len + 1);                                          memcpy(title_input, p_article_new->title, (size_t)len + 1);
137                                  }                                  }
# Line 136  int article_post(const SECTION_LIST *p_s Line 140  int article_post(const SECTION_LIST *p_s
140                          case 'C':                          case 'C':
141                                  clearscr();                                  clearscr();
142                                  moveto(1, 1);                                  moveto(1, 1);
143                                  prints("取消...");                                  prints("鍙栨秷...");
144                                  press_any_key();                                  press_any_key();
145                                  goto cleanup;                                  goto cleanup;
                         case 'Y':  
                                 p_article_new->transship = 0;  
                                 break;  
146                          case 'Z':                          case 'Z':
147                                  p_article_new->transship = 1;                                  p_article_new->transship = (p_article_new->transship ? 0 : 1);
148                                    break;
149                            case 'N':
150                                    reply_note = (reply_note ? 0 : 1);
151                                  break;                                  break;
152                          case '0':                          case '0':
153                          case '1':                          case '1':
# Line 152  int article_post(const SECTION_LIST *p_s Line 156  int article_post(const SECTION_LIST *p_s
156                                  sign_id = ch - '0';                                  sign_id = ch - '0';
157                                  break;                                  break;
158                          default: // Invalid selection                          default: // Invalid selection
159                                    ch = igetch_t(BBS_max_user_idle_time);
160                                  continue;                                  continue;
161                          }                          }
162    
# Line 169  int article_post(const SECTION_LIST *p_s Line 174  int article_post(const SECTION_LIST *p_s
174    
175                          clearscr();                          clearscr();
176                          moveto(1, 1);                          moveto(1, 1);
177                          prints("(S)发送, (C)取消, (T)更改标题 or (E)再编辑? [S]: ");                          prints("(S)鍙戦, (C)鍙栨秷, (T)鏇存敼鏍囬 or (E)鍐嶇紪杈? [S]: ");
178                          iflush();                          iflush();
179    
180                          for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))                          for (ch = 0; !SYS_server_exit; ch = igetch_t(BBS_max_user_idle_time))
181                          {                          {
182                                  switch (toupper(ch))                                  switch (toupper(ch))
183                                  {                                  {
# Line 180  int article_post(const SECTION_LIST *p_s Line 185  int article_post(const SECTION_LIST *p_s
185                                  case KEY_TIMEOUT:                                  case KEY_TIMEOUT:
186                                          goto cleanup;                                          goto cleanup;
187                                  case CR:                                  case CR:
                                         igetch_reset();  
188                                  case 'S':                                  case 'S':
189                                          break;                                          break;
190                                  case 'C':                                  case 'C':
191                                          clearscr();                                          clearscr();
192                                          moveto(1, 1);                                          moveto(1, 1);
193                                          prints("取消...");                                          prints("鍙栨秷...");
194                                          press_any_key();                                          press_any_key();
195                                          goto cleanup;                                          goto cleanup;
196                                  case 'T':                                  case 'T':
# Line 228  int article_post(const SECTION_LIST *p_s Line 232  int article_post(const SECTION_LIST *p_s
232                  goto cleanup;                  goto cleanup;
233          }          }
234    
235            if (check_badwords(content, '*') < 0)
236            {
237                    log_error("check_badwords(content) error\n");
238                    ret = -1;
239                    goto cleanup;
240            }
241    
242          db = db_open();          db = db_open();
243          if (db == NULL)          if (db == NULL)
244          {          {
# Line 265  int article_post(const SECTION_LIST *p_s Line 276  int article_post(const SECTION_LIST *p_s
276                  rs = NULL;                  rs = NULL;
277          }          }
278    
279            // Calculate display length of content
280            content_display_length = str_length(content, 1);
281    
282          // Begin transaction          // Begin transaction
283          if (mysql_query(db, "SET autocommit=0") != 0)          if (mysql_query(db, "SET autocommit=0") != 0)
284          {          {
# Line 328  int article_post(const SECTION_LIST *p_s Line 342  int article_post(const SECTION_LIST *p_s
342          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
343                           "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "                           "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "
344                           "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "                           "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "
345                           "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', %d, %d, NOW(), 1, %d)",
346                           p_section->sid, BBS_priv.uid, BBS_username, nickname_f, title_f,                           p_section->sid, BBS_priv.uid, BBS_username, nickname_f, title_f,
347                           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,
348                             reply_note, BBS_user_exp, content_display_length);
349    
350          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
351          {          {
# Line 394  int article_post(const SECTION_LIST *p_s Line 409  int article_post(const SECTION_LIST *p_s
409    
410          clearscr();          clearscr();
411          moveto(1, 1);          moveto(1, 1);
412          prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval);          prints("鍙戦佸畬鎴愶紝鏂版枃绔犻氬父浼氬湪%d绉掑悗鍙", BBS_section_list_load_interval);
413          press_any_key();          press_any_key();
414          ret = 1; // Success          ret = 1; // Success
415    
# Line 421  int article_modify(const SECTION_LIST *p Line 436  int article_modify(const SECTION_LIST *p
436          char *content = NULL;          char *content = NULL;
437          char *content_f = NULL;          char *content_f = NULL;
438          long len_content;          long len_content;
439            int content_display_length;
440            int reply_note = 1;
441          int ch;          int ch;
442          long ret = 0;          long ret = 0;
443          time_t now;          time_t now;
# Line 438  int article_modify(const SECTION_LIST *p Line 455  int article_modify(const SECTION_LIST *p
455          {          {
456                  clearscr();                  clearscr();
457                  moveto(1, 1);                  moveto(1, 1);
458                  prints("该文章无法被编辑,请联系版主。");                  prints("璇ユ枃绔犳棤娉曡缂栬緫锛岃鑱旂郴鐗堜富銆");
459                  press_any_key();                  press_any_key();
460    
461                  return 0;                  return 0;
# Line 453  int article_modify(const SECTION_LIST *p Line 470  int article_modify(const SECTION_LIST *p
470          }          }
471    
472          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
473                           "SELECT bbs_content.CID, bbs_content.content "                           "SELECT bbs_content.CID, bbs_content.content, reply_note "
474                           "FROM bbs INNER JOIN bbs_content ON bbs.CID = bbs_content.CID "                           "FROM bbs INNER JOIN bbs_content ON bbs.CID = bbs_content.CID "
475                           "WHERE bbs.AID = %d",                           "WHERE bbs.AID = %d",
476                           p_article->aid);                           p_article->aid);
# Line 485  int article_modify(const SECTION_LIST *p Line 502  int article_modify(const SECTION_LIST *p
502                  content[ARTICLE_CONTENT_MAX_LEN - 1] = '\0';                  content[ARTICLE_CONTENT_MAX_LEN - 1] = '\0';
503    
504                  // Remove control sequence                  // Remove control sequence
505                  len_content = ctrl_seq_filter(content);                  len_content = str_filter(content, 0);
506    
507                  p_editor_data = editor_data_load(content);                  p_editor_data = editor_data_load(content);
508                  if (p_editor_data == NULL)                  if (p_editor_data == NULL)
# Line 497  int article_modify(const SECTION_LIST *p Line 514  int article_modify(const SECTION_LIST *p
514    
515                  free(content);                  free(content);
516                  content = NULL;                  content = NULL;
517    
518                    reply_note = atoi(row[2]);
519          }          }
520          mysql_free_result(rs);          mysql_free_result(rs);
521          rs = NULL;          rs = NULL;
# Line 508  int article_modify(const SECTION_LIST *p Line 527  int article_modify(const SECTION_LIST *p
527          {          {
528                  editor_display(p_editor_data);                  editor_display(p_editor_data);
529    
530                  clearscr();                  while (!SYS_server_exit)
                 moveto(1, 1);  
                 prints("(S)保存, (C)取消 or (E)再编辑? [S]: ");  
                 iflush();  
   
                 for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))  
531                  {                  {
532                            clearscr();
533                            moveto(1, 1);
534                            prints("(S)淇濆瓨, (C)鍙栨秷, (N)%s鍥炲閫氱煡 or (E)鍐嶇紪杈? [S]: ",
535                                       (reply_note ? "鍏抽棴" : "寮鍚"));
536                            iflush();
537    
538                            ch = igetch_t(BBS_max_user_idle_time);
539                          switch (toupper(ch))                          switch (toupper(ch))
540                          {                          {
541                          case KEY_NULL:                          case KEY_NULL:
542                          case KEY_TIMEOUT:                          case KEY_TIMEOUT:
543                                  goto cleanup;                                  goto cleanup;
544                          case CR:                          case CR:
                                 igetch_reset();  
545                          case 'S':                          case 'S':
546                                  break;                                  break;
547                          case 'C':                          case 'C':
548                                  clearscr();                                  clearscr();
549                                  moveto(1, 1);                                  moveto(1, 1);
550                                  prints("取消...");                                  prints("鍙栨秷...");
551                                  press_any_key();                                  press_any_key();
552                                  goto cleanup;                                  goto cleanup;
553                            case 'N':
554                                    reply_note = (reply_note ? 0 : 1);
555                                    continue;
556                          case 'E':                          case 'E':
557                                  break;                                  break;
558                          default: // Invalid selection                          default: // Invalid selection
# Line 562  int article_modify(const SECTION_LIST *p Line 585  int article_modify(const SECTION_LIST *p
585                  goto cleanup;                  goto cleanup;
586          }          }
587    
588            if (check_badwords(content, '*') < 0)
589            {
590                    log_error("check_badwords(content) error\n");
591                    ret = -1;
592                    goto cleanup;
593            }
594    
595          time(&now);          time(&now);
596          localtime_r(&now, &tm_modify_dt);          localtime_r(&now, &tm_modify_dt);
597          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);
598    
599          len_content += snprintf(content + len_content, LINE_BUFFER_LEN,          len_content += snprintf(content + len_content, LINE_BUFFER_LEN,
600                                                          "\n--\n※ 作者已于 %s 修改本文※\n",                                                          "\n--\n鈥 浣滆呭凡浜 %s 淇敼鏈枃鈥籠n",
601                                                          str_modify_dt);                                                          str_modify_dt);
602    
603            // Calculate display length of content
604            content_display_length = str_length(content, 1);
605    
606          db = db_open();          db = db_open();
607          if (db == NULL)          if (db == NULL)
608          {          {
# Line 637  int article_modify(const SECTION_LIST *p Line 670  int article_modify(const SECTION_LIST *p
670    
671          // Update article          // Update article
672          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
673                           "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, reply_note = %d, excerption = 0 WHERE AID = %d", // Set excerption = 0 explictly in case of rare condition
674                           p_article_new->cid, len_content, p_article->aid);                           p_article_new->cid, content_display_length, reply_note, p_article->aid);
675    
676          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
677          {          {
# Line 680  int article_modify(const SECTION_LIST *p Line 713  int article_modify(const SECTION_LIST *p
713    
714          clearscr();          clearscr();
715          moveto(1, 1);          moveto(1, 1);
716          prints("修改完成,新内容通常会在%d秒后可见", BBS_section_list_load_interval);          prints("淇敼瀹屾垚锛屾柊鍐呭閫氬父浼氬湪%d绉掑悗鍙", BBS_section_list_load_interval);
717          press_any_key();          press_any_key();
718          ret = 1; // Success          ret = 1; // Success
719    
# Line 712  int article_reply(const SECTION_LIST *p_ Line 745  int article_reply(const SECTION_LIST *p_
745          char *content = NULL;          char *content = NULL;
746          char *content_f = NULL;          char *content_f = NULL;
747          long len_content;          long len_content;
748            int content_display_length;
749          char nickname_f[BBS_nickname_max_len * 2 + 1];          char nickname_f[BBS_nickname_max_len * 2 + 1];
750          int sign_id = 0;          int sign_id = 0;
751            int reply_note = 0;
752          long len;          long len;
753          int ch;          int ch;
754          char *p, *q;          char *p, *q;
# Line 723  int article_reply(const SECTION_LIST *p_ Line 758  int article_reply(const SECTION_LIST *p_
758          long i;          long i;
759          long ret = 0;          long ret = 0;
760          int topic_locked = 0;          int topic_locked = 0;
761            char msg[BBS_msg_max_len];
762            char msg_f[BBS_msg_max_len * 2 + 1];
763            int len_msg;
764    
765          if (p_section == NULL || p_article == NULL)          if (p_section == NULL || p_article == NULL)
766          {          {
# Line 733  int article_reply(const SECTION_LIST *p_ Line 771  int article_reply(const SECTION_LIST *p_
771          {          {
772                  clearscr();                  clearscr();
773                  moveto(1, 1);                  moveto(1, 1);
774                  prints("您没有权限在本版块发表文章\n");                  prints("鎮ㄦ病鏈夋潈闄愬湪鏈増鍧楀彂琛ㄦ枃绔燶n");
775                  press_any_key();                  press_any_key();
776    
777                  return 0;                  return 0;
# Line 741  int article_reply(const SECTION_LIST *p_ Line 779  int article_reply(const SECTION_LIST *p_
779    
780          p_article_new->title[0] = '\0';          p_article_new->title[0] = '\0';
781          snprintf(title_input, sizeof(title_input), "Re: %s", p_article->title);          snprintf(title_input, sizeof(title_input), "Re: %s", p_article->title);
782          len = split_line(title_input, TITLE_INPUT_MAX_LEN, &eol, &display_len);          len = split_line(title_input, TITLE_INPUT_MAX_LEN, &eol, &display_len, 0);
783          title_input[len] = '\0';          title_input[len] = '\0';
784    
785          db = db_open();          db = db_open();
# Line 786  int article_reply(const SECTION_LIST *p_ Line 824  int article_reply(const SECTION_LIST *p_
824    
825                  clearscr();                  clearscr();
826                  moveto(1, 1);                  moveto(1, 1);
827                  prints("该主题谢绝回复");                  prints("璇ヤ富棰樿阿缁濆洖澶");
828                  press_any_key();                  press_any_key();
829    
830                  goto cleanup;                  goto cleanup;
# Line 830  int article_reply(const SECTION_LIST *p_ Line 868  int article_reply(const SECTION_LIST *p_
868                  }                  }
869    
870                  // Apply LML render to content body                  // Apply LML render to content body
871                  len = lml_plain(row[1], content_f, ARTICLE_CONTENT_MAX_LEN);                  len = lml_render(row[1], content_f, ARTICLE_CONTENT_MAX_LEN, MAX_EDITOR_DATA_LINE_LENGTH - 3, 1);
872                  content_f[len] = '\0';                  content_f[len] = '\0';
873    
874                  // Remove control sequence                  // Remove control sequence
875                  len = ctrl_seq_filter(content_f);                  len = str_filter(content_f, 0);
876    
877                  len = snprintf(content, ARTICLE_CONTENT_MAX_LEN,                  len = snprintf(content, ARTICLE_CONTENT_MAX_LEN,
878                                             "\n\n【 在 %s (%s) 的大作中提到: 】\n",                                             "\n\n銆 鍦 %s (%s) 鐨勫ぇ浣滀腑鎻愬埌: 銆慭n",
879                                             p_article->username, p_article->nickname);                                             p_article->username, p_article->nickname);
880    
881                  quote_content_lines = split_data_lines(content_f, ARTICLE_QUOTE_LINE_MAX_LEN, line_offsets, ARTICLE_QUOTE_MAX_LINES + 1);                  quote_content_lines = split_data_lines(content_f, MAX_EDITOR_DATA_LINE_LENGTH - 2, line_offsets, ARTICLE_QUOTE_MAX_LINES + 1, 0, NULL);
882                  for (i = 0; i < quote_content_lines; i++)                  for (i = 0; i < quote_content_lines; i++)
883                  {                  {
884                          memcpy(content + len, ": ", 2); // quote line prefix                          memcpy(content + len, ": ", 2); // quote line prefix
# Line 885  int article_reply(const SECTION_LIST *p_ Line 923  int article_reply(const SECTION_LIST *p_
923          {          {
924                  clearscr();                  clearscr();
925                  moveto(21, 1);                  moveto(21, 1);
926                  prints("回复文章于 %s[%s] 讨论区", p_section->stitle, p_section->sname);                  prints("鍥炲鏂囩珷浜 %s[%s] 璁ㄨ鍖猴紝鍥炲閫氱煡锛%s", p_section->stitle, p_section->sname, (reply_note ? "寮鍚" : "鍏抽棴"));
927                  moveto(22, 1);                  moveto(22, 1);
928                  prints("标题: %s", (p_article_new->title[0] == '\0' ? "[无]" : p_article_new->title));                  prints("鏍囬: %s", (p_article_new->title[0] == '\0' ? "[鏃燷" : p_article_new->title));
929                  moveto(23, 1);                  moveto(23, 1);
930                  prints("使用第 %d 个签名", sign_id);                  prints("浣跨敤绗 %d 涓鍚", sign_id);
931    
932                  if (toupper(ch) != 'T')                  if (toupper(ch) != 'T')
933                  {                  {
934                          prints("    按0~3选签名档(0表示不使用)");                          prints("    鎸0~3閫夌鍚嶆。(0琛ㄧず涓嶄娇鐢)");
935    
936                          moveto(24, 1);                          moveto(24, 1);
937                          prints("T改标题, C取消, Enter继续: ");                          prints("T鏀规爣棰, C鍙栨秷, N%s, Enter缁х画: ",
938                                       (reply_note ? "鍏抽棴鍥炲閫氱煡" : "寮鍚洖澶嶉氱煡"));
939                          iflush();                          iflush();
940                          ch = 0;                          ch = 0;
941                  }                  }
942    
943                  for (; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))                  while (!SYS_server_exit)
944                  {                  {
945                          switch (toupper(ch))                          switch (toupper(ch))
946                          {                          {
# Line 909  int article_reply(const SECTION_LIST *p_ Line 948  int article_reply(const SECTION_LIST *p_
948                          case KEY_TIMEOUT:                          case KEY_TIMEOUT:
949                                  goto cleanup;                                  goto cleanup;
950                          case CR:                          case CR:
                                 igetch_reset();  
951                                  break;                                  break;
952                          case 'T':                          case 'T':
953                                  moveto(24, 1);                                  len = get_data(24, 1, "鏍囬: ", title_input, sizeof(title_input), TITLE_INPUT_MAX_LEN);
                                 clrtoeol();  
                                 len = get_data(24, 1, "标题: ", title_input, TITLE_INPUT_MAX_LEN, 1);  
954                                  for (p = title_input; *p == ' '; p++)                                  for (p = title_input; *p == ' '; p++)
955                                          ;                                          ;
956                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)
# Line 923  int article_reply(const SECTION_LIST *p_ Line 959  int article_reply(const SECTION_LIST *p_
959                                  len = q - p;                                  len = q - p;
960                                  if (*p != '\0')                                  if (*p != '\0')
961                                  {                                  {
962                                            if ((ret = check_badwords(p, '*')) < 0)
963                                            {
964                                                    log_error("check_badwords(title) error\n");
965                                            }
966                                            else if (ret > 0)
967                                            {
968                                                    memcpy(title_input, p, (size_t)len + 1);
969                                                    continue;
970                                            }
971                                          memcpy(p_article_new->title, p, (size_t)len + 1);                                          memcpy(p_article_new->title, p, (size_t)len + 1);
972                                          memcpy(title_input, p_article_new->title, (size_t)len + 1);                                          memcpy(title_input, p_article_new->title, (size_t)len + 1);
973                                  }                                  }
# Line 931  int article_reply(const SECTION_LIST *p_ Line 976  int article_reply(const SECTION_LIST *p_
976                          case 'C':                          case 'C':
977                                  clearscr();                                  clearscr();
978                                  moveto(1, 1);                                  moveto(1, 1);
979                                  prints("取消...");                                  prints("鍙栨秷...");
980                                  press_any_key();                                  press_any_key();
981                                  goto cleanup;                                  goto cleanup;
982                            case 'N':
983                                    reply_note = (reply_note ? 0 : 1);
984                                    break;
985                          case '0':                          case '0':
986                          case '1':                          case '1':
987                          case '2':                          case '2':
# Line 941  int article_reply(const SECTION_LIST *p_ Line 989  int article_reply(const SECTION_LIST *p_
989                                  sign_id = ch - '0';                                  sign_id = ch - '0';
990                                  break;                                  break;
991                          default: // Invalid selection                          default: // Invalid selection
992                                    ch = igetch_t(BBS_max_user_idle_time);
993                                  continue;                                  continue;
994                          }                          }
995    
# Line 958  int article_reply(const SECTION_LIST *p_ Line 1007  int article_reply(const SECTION_LIST *p_
1007    
1008                          clearscr();                          clearscr();
1009                          moveto(1, 1);                          moveto(1, 1);
1010                          prints("(S)发送, (C)取消, (T)更改标题 or (E)再编辑? [S]: ");                          prints("(S)鍙戦, (C)鍙栨秷, (T)鏇存敼鏍囬 or (E)鍐嶇紪杈? [S]: ");
1011                          iflush();                          iflush();
1012    
1013                          for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))                          for (ch = 0; !SYS_server_exit; ch = igetch_t(BBS_max_user_idle_time))
1014                          {                          {
1015                                  switch (toupper(ch))                                  switch (toupper(ch))
1016                                  {                                  {
# Line 969  int article_reply(const SECTION_LIST *p_ Line 1018  int article_reply(const SECTION_LIST *p_
1018                                  case KEY_TIMEOUT:                                  case KEY_TIMEOUT:
1019                                          goto cleanup;                                          goto cleanup;
1020                                  case CR:                                  case CR:
                                         igetch_reset();  
1021                                  case 'S':                                  case 'S':
1022                                          break;                                          break;
1023                                  case 'C':                                  case 'C':
1024                                          clearscr();                                          clearscr();
1025                                          moveto(1, 1);                                          moveto(1, 1);
1026                                          prints("取消...");                                          prints("鍙栨秷...");
1027                                          press_any_key();                                          press_any_key();
1028                                          goto cleanup;                                          goto cleanup;
1029                                  case 'T':                                  case 'T':
# Line 1017  int article_reply(const SECTION_LIST *p_ Line 1065  int article_reply(const SECTION_LIST *p_
1065                  goto cleanup;                  goto cleanup;
1066          }          }
1067    
1068            if (check_badwords(content, '*') < 0)
1069            {
1070                    log_error("check_badwords(content) error\n");
1071                    ret = -1;
1072                    goto cleanup;
1073            }
1074    
1075          db = db_open();          db = db_open();
1076          if (db == NULL)          if (db == NULL)
1077          {          {
# Line 1054  int article_reply(const SECTION_LIST *p_ Line 1109  int article_reply(const SECTION_LIST *p_
1109                  rs = NULL;                  rs = NULL;
1110          }          }
1111    
1112            // Calculate display length of content
1113            content_display_length = str_length(content, 1);
1114    
1115          // Begin transaction          // Begin transaction
1116          if (mysql_query(db, "SET autocommit=0") != 0)          if (mysql_query(db, "SET autocommit=0") != 0)
1117          {          {
# Line 1117  int article_reply(const SECTION_LIST *p_ Line 1175  int article_reply(const SECTION_LIST *p_
1175          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
1176                           "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "                           "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "
1177                           "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "                           "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "
1178                           "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', %d, %d, NOW(), 1, %d)",
1179                           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),
1180                           BBS_priv.uid, BBS_username, nickname_f, title_f,                           BBS_priv.uid, BBS_username, nickname_f, title_f,
1181                           p_article_new->cid, hostaddr_client, BBS_user_exp, len_content);                           p_article_new->cid, hostaddr_client,
1182                             reply_note, BBS_user_exp, content_display_length);
1183    
1184          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
1185          {          {
# Line 1158  int article_reply(const SECTION_LIST *p_ Line 1217  int article_reply(const SECTION_LIST *p_
1217                  goto cleanup;                  goto cleanup;
1218          }          }
1219    
1220            // Notify the authors of the topic / article which is replyed.
1221            snprintf(sql, sizeof(sql),
1222                             "SELECT DISTINCT UID FROM bbs WHERE (AID = %d OR AID = %d) "
1223                             "AND visible AND reply_note AND UID <> %d",
1224                             p_article->tid, p_article->aid, BBS_priv.uid);
1225    
1226            if (mysql_query(db, sql) != 0)
1227            {
1228                    log_error("Read reply info error: %s\n", mysql_error(db));
1229                    ret = -1;
1230                    goto cleanup;
1231            }
1232            if ((rs = mysql_store_result(db)) == NULL)
1233            {
1234                    log_error("Get reply info failed\n");
1235                    ret = -1;
1236                    goto cleanup;
1237            }
1238    
1239            while ((row = mysql_fetch_row(rs)))
1240            {
1241                    // Send notification message
1242                    len_msg = snprintf(msg, BBS_msg_max_len,
1243                                                       "鏈変汉鍥炲浜嗘偍鎵鍙戣〃/鍥炲鐨勬枃绔狅紝蹇潵"
1244                                                       "[article %d]鐪嬬湅[/article]銆%s銆嬪惂锛乗n",
1245                                                       p_article_new->aid, title_f);
1246    
1247                    mysql_real_escape_string(db, msg_f, msg, (unsigned long)len_msg);
1248    
1249                    snprintf(sql, sizeof(sql),
1250                                     "INSERT INTO bbs_msg(fromUID, toUID, content, send_dt, send_ip) "
1251                                     "VALUES(%d, %d, '%s', NOW(), '%s')",
1252                                     BBS_sys_id, atoi(row[0]), msg_f, hostaddr_client);
1253    
1254                    if (mysql_query(db, sql) != 0)
1255                    {
1256                            log_error("Insert msg error: %s\n", mysql_error(db));
1257                            ret = -1;
1258                            goto cleanup;
1259                    }
1260            }
1261            mysql_free_result(rs);
1262            rs = NULL;
1263    
1264          // Add exp          // Add exp
1265          if (checkpriv(&BBS_priv, p_section->sid, S_GETEXP)) // Except in test section          if (checkpriv(&BBS_priv, p_section->sid, S_GETEXP)) // Except in test section
1266          {          {
# Line 1199  int article_reply(const SECTION_LIST *p_ Line 1302  int article_reply(const SECTION_LIST *p_
1302    
1303          clearscr();          clearscr();
1304          moveto(1, 1);          moveto(1, 1);
1305          prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval);          prints("鍙戦佸畬鎴愶紝鏂版枃绔犻氬父浼氬湪%d绉掑悗鍙", BBS_section_list_load_interval);
1306          press_any_key();          press_any_key();
1307          ret = 1; // Success          ret = 1; // Success
1308    


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

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