/[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.15 by sysadm, Sun Jun 15 02:24:45 2025 UTC Revision 1.40 by sysadm, Wed Nov 5 03:17:12 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 "database.h"
13    #include "editor.h"
14  #include "io.h"  #include "io.h"
15    #include "log.h"
16  #include "lml.h"  #include "lml.h"
17  #include "database.h"  #include "screen.h"
18  #include "user_priv.h"  #include "user_priv.h"
19  #include <ctype.h>  #include <ctype.h>
20  #include <string.h>  #include <string.h>
21  #include <stdlib.h>  #include <stdlib.h>
22  #include <time.h>  #include <time.h>
23    
24  #define TITLE_INPUT_MAX_LEN 74  enum _article_post_constant_t
25  #define ARTICLE_CONTENT_MAX_LEN 1024 * 1024 * 4 // 4MB  {
26  #define ARTICLE_QUOTE_MAX_LINES 20          TITLE_INPUT_MAX_LEN = 72,
27  #define ARTICLE_QUOTE_LINE_MAX_LEN 76          ARTICLE_QUOTE_MAX_LINES = 20,
28            MODIFY_DT_MAX_LEN = 50,
29  #define MODIFY_DT_MAX_LEN 50  };
30    
31  int article_post(const SECTION_LIST *p_section, ARTICLE *p_article_new)  int article_post(const SECTION_LIST *p_section, ARTICLE *p_article_new)
32  {  {
# Line 46  int article_post(const SECTION_LIST *p_s Line 36  int article_post(const SECTION_LIST *p_s
36          char sql[SQL_BUFFER_LEN];          char sql[SQL_BUFFER_LEN];
37          char *sql_content = NULL;          char *sql_content = NULL;
38          EDITOR_DATA *p_editor_data = NULL;          EDITOR_DATA *p_editor_data = NULL;
39          char title_input[TITLE_INPUT_MAX_LEN + 1];          char title_input[BBS_article_title_max_len + 1];
40          char title_f[BBS_article_title_max_len * 2 + 1];          char title_f[BBS_article_title_max_len * 2 + 1];
41          char *content = NULL;          char *content = NULL;
42          char *content_f = NULL;          char *content_f = NULL;
43          long len_content;          long len_content;
44            int content_display_length;
45          char nickname_f[BBS_nickname_max_len * 2 + 1];          char nickname_f[BBS_nickname_max_len * 2 + 1];
46          int sign_id = 0;          int sign_id = 0;
47            int reply_note = 1;
48          long len;          long len;
49          int ch;          int ch;
50          char *p, *q;          char *p, *q;
# Line 67  int article_post(const SECTION_LIST *p_s Line 59  int article_post(const SECTION_LIST *p_s
59          {          {
60                  clearscr();                  clearscr();
61                  moveto(1, 1);                  moveto(1, 1);
62                  prints("您没有权限在本版块发表文章\n");                  prints("鎮ㄦ病鏈夋潈闄愬湪鏈増鍧楀彂琛ㄦ枃绔燶n");
63                  press_any_key();                  press_any_key();
64    
65                  return 0;                  return 0;
# Line 81  int article_post(const SECTION_LIST *p_s Line 73  int article_post(const SECTION_LIST *p_s
73          if (p_editor_data == NULL)          if (p_editor_data == NULL)
74          {          {
75                  log_error("editor_data_load() error\n");                  log_error("editor_data_load() error\n");
76                  return -2;                  ret = -1;
77                    goto cleanup;
78          }          }
79    
80          // Set title and sign          // Set title and sign
# Line 89  int article_post(const SECTION_LIST *p_s Line 82  int article_post(const SECTION_LIST *p_s
82          {          {
83                  clearscr();                  clearscr();
84                  moveto(21, 1);                  moveto(21, 1);
85                  prints("发表文章于 %s[%s] 讨论区,类型: %s", p_section->stitle, p_section->sname, (p_article_new->transship ? "转载" : "原创"));                  prints("鍙戣〃鏂囩珷浜 %s[%s] 璁ㄨ鍖猴紝绫诲瀷: %s锛屽洖澶嶉氱煡锛%s",
86                               p_section->stitle, p_section->sname,
87                               (p_article_new->transship ? "杞浇" : "鍘熷垱"),
88                               (reply_note ? "寮鍚" : "鍏抽棴"));
89                  moveto(22, 1);                  moveto(22, 1);
90                  prints("标题: %s", (p_article_new->title[0] == '\0' ? "[无]" : p_article_new->title));                  prints("鏍囬: %s", (p_article_new->title[0] == '\0' ? "[鏃燷" : p_article_new->title));
91                  moveto(23, 1);                  moveto(23, 1);
92                  prints("使用第 %d 个签名", sign_id);                  prints("浣跨敤绗 %d 涓鍚", sign_id);
93    
94                  if (toupper(ch) != 'T')                  if (toupper(ch) != 'T')
95                  {                  {
96                          prints("    按0~3选签名档(0表示不使用)");                          prints("    鎸0~3閫夌鍚嶆。(0琛ㄧず涓嶄娇鐢)");
97    
98                          moveto(24, 1);                          moveto(24, 1);
99                          prints("T改标题, C取消, Z设为转载, Y设为原创, Enter继续: ");                          prints("T鏀规爣棰, C鍙栨秷, Z璁句负%s, N%s, Enter缁х画: ",
100                                       (p_article_new->transship ? "鍘熷垱" : "杞浇"),
101                                       (reply_note ? "鍏抽棴鍥炲閫氱煡" : "寮鍚洖澶嶉氱煡"));
102                          iflush();                          iflush();
103                          ch = 0;                          ch = 0;
104                  }                  }
105    
106                  for (; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))                  for (; !SYS_server_exit; ch = igetch_t(BBS_max_user_idle_time))
107                  {                  {
108                          switch (toupper(ch))                          switch (toupper(ch))
109                          {                          {
110                            case KEY_NULL:
111                            case KEY_TIMEOUT:
112                                    goto cleanup;
113                          case CR:                          case CR:
                                 igetch_reset();  
114                                  break;                                  break;
115                          case 'T':                          case 'T':
116                                  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);  
117                                  for (p = title_input; *p == ' '; p++)                                  for (p = title_input; *p == ' '; p++)
118                                          ;                                          ;
119                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)
# Line 132  int article_post(const SECTION_LIST *p_s Line 130  int article_post(const SECTION_LIST *p_s
130                          case 'C':                          case 'C':
131                                  clearscr();                                  clearscr();
132                                  moveto(1, 1);                                  moveto(1, 1);
133                                  prints("取消...");                                  prints("鍙栨秷...");
134                                  press_any_key();                                  press_any_key();
135                                  goto cleanup;                                  goto cleanup;
                         case 'Y':  
                                 p_article_new->transship = 0;  
                                 break;  
136                          case 'Z':                          case 'Z':
137                                  p_article_new->transship = 1;                                  p_article_new->transship = (p_article_new->transship ? 0 : 1);
138                                    break;
139                            case 'N':
140                                    reply_note = (reply_note ? 0 : 1);
141                                  break;                                  break;
142                          case '0':                          case '0':
143                          case '1':                          case '1':
# Line 165  int article_post(const SECTION_LIST *p_s Line 163  int article_post(const SECTION_LIST *p_s
163    
164                          clearscr();                          clearscr();
165                          moveto(1, 1);                          moveto(1, 1);
166                          prints("(S)发送, (C)取消, (T)更改标题 or (E)再编辑? [S]: ");                          prints("(S)鍙戦, (C)鍙栨秷, (T)鏇存敼鏍囬 or (E)鍐嶇紪杈? [S]: ");
167                          iflush();                          iflush();
168    
169                          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))
170                          {                          {
171                                  switch (toupper(ch))                                  switch (toupper(ch))
172                                  {                                  {
173                                    case KEY_NULL:
174                                    case KEY_TIMEOUT:
175                                            goto cleanup;
176                                  case CR:                                  case CR:
                                         igetch_reset();  
177                                  case 'S':                                  case 'S':
178                                          break;                                          break;
179                                  case 'C':                                  case 'C':
180                                          clearscr();                                          clearscr();
181                                          moveto(1, 1);                                          moveto(1, 1);
182                                          prints("取消...");                                          prints("鍙栨秷...");
183                                          press_any_key();                                          press_any_key();
184                                          goto cleanup;                                          goto cleanup;
185                                  case 'T':                                  case 'T':
# Line 200  int article_post(const SECTION_LIST *p_s Line 200  int article_post(const SECTION_LIST *p_s
200                  }                  }
201          }          }
202    
203            if (SYS_server_exit) // Do not save data on shutdown
204            {
205                    goto cleanup;
206            }
207    
208          content = malloc(ARTICLE_CONTENT_MAX_LEN);          content = malloc(ARTICLE_CONTENT_MAX_LEN);
209          if (content == NULL)          if (content == NULL)
210          {          {
# Line 212  int article_post(const SECTION_LIST *p_s Line 217  int article_post(const SECTION_LIST *p_s
217          if (len_content < 0)          if (len_content < 0)
218          {          {
219                  log_error("editor_data_save() error\n");                  log_error("editor_data_save() error\n");
220                  ret = -2;                  ret = -1;
221                  goto cleanup;                  goto cleanup;
222          }          }
223    
# Line 253  int article_post(const SECTION_LIST *p_s Line 258  int article_post(const SECTION_LIST *p_s
258                  rs = NULL;                  rs = NULL;
259          }          }
260    
261            // Calculate display length of content
262            content_display_length = str_length(content, 1);
263    
264          // Begin transaction          // Begin transaction
265          if (mysql_query(db, "SET autocommit=0") != 0)          if (mysql_query(db, "SET autocommit=0") != 0)
266          {          {
# Line 316  int article_post(const SECTION_LIST *p_s Line 324  int article_post(const SECTION_LIST *p_s
324          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
325                           "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "                           "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "
326                           "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "                           "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "
327                           "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)",
328                           p_section->sid, BBS_priv.uid, BBS_username, nickname_f, title_f,                           p_section->sid, BBS_priv.uid, BBS_username, nickname_f, title_f,
329                           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,
330                             reply_note, BBS_user_exp, content_display_length);
331    
332          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
333          {          {
# Line 377  int article_post(const SECTION_LIST *p_s Line 386  int article_post(const SECTION_LIST *p_s
386                  goto cleanup;                  goto cleanup;
387          }          }
388    
389            mysql_close(db);
390            db = NULL;
391    
392          clearscr();          clearscr();
393          moveto(1, 1);          moveto(1, 1);
394          prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval);          prints("鍙戦佸畬鎴愶紝鏂版枃绔犻氬父浼氬湪%d绉掑悗鍙", BBS_section_list_load_interval);
395          press_any_key();          press_any_key();
396          ret = 1; // Success          ret = 1; // Success
397    
# Line 406  int article_modify(const SECTION_LIST *p Line 418  int article_modify(const SECTION_LIST *p
418          char *content = NULL;          char *content = NULL;
419          char *content_f = NULL;          char *content_f = NULL;
420          long len_content;          long len_content;
421            int content_display_length;
422            int reply_note = 1;
423          int ch;          int ch;
424          long ret = 0;          long ret = 0;
425          time_t now;          time_t now;
# Line 423  int article_modify(const SECTION_LIST *p Line 437  int article_modify(const SECTION_LIST *p
437          {          {
438                  clearscr();                  clearscr();
439                  moveto(1, 1);                  moveto(1, 1);
440                  prints("该文章无法被编辑,请联系版主。");                  prints("璇ユ枃绔犳棤娉曡缂栬緫锛岃鑱旂郴鐗堜富銆");
                 press_any_key();  
   
                 return 0;  
         }  
   
         if (!checkpriv(&BBS_priv, p_section->sid, S_POST))  
         {  
                 clearscr();  
                 moveto(1, 1);  
                 prints("您没有权限在本版块发表文章\n");  
441                  press_any_key();                  press_any_key();
442    
443                  return 0;                  return 0;
# Line 443  int article_modify(const SECTION_LIST *p Line 447  int article_modify(const SECTION_LIST *p
447          if (db == NULL)          if (db == NULL)
448          {          {
449                  log_error("db_open() error: %s\n", mysql_error(db));                  log_error("db_open() error: %s\n", mysql_error(db));
450                  return -1;                  ret = -1;
451                    goto cleanup;
452          }          }
453    
454          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
455                           "SELECT bbs_content.CID, bbs_content.content "                           "SELECT bbs_content.CID, bbs_content.content, reply_note "
456                           "FROM bbs INNER JOIN bbs_content ON bbs.CID = bbs_content.CID "                           "FROM bbs INNER JOIN bbs_content ON bbs.CID = bbs_content.CID "
457                           "WHERE bbs.AID = %d",                           "WHERE bbs.AID = %d",
458                           p_article->aid);                           p_article->aid);
# Line 455  int article_modify(const SECTION_LIST *p Line 460  int article_modify(const SECTION_LIST *p
460          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
461          {          {
462                  log_error("Query article content error: %s\n", mysql_error(db));                  log_error("Query article content error: %s\n", mysql_error(db));
463                  ret = -2;                  ret = -1;
464                  goto cleanup;                  goto cleanup;
465          }          }
466          if ((rs = mysql_use_result(db)) == NULL)          if ((rs = mysql_use_result(db)) == NULL)
467          {          {
468                  log_error("Get article content data failed\n");                  log_error("Get article content data failed\n");
469                  ret = -2;                  ret = -1;
470                  goto cleanup;                  goto cleanup;
471          }          }
472    
# Line 479  int article_modify(const SECTION_LIST *p Line 484  int article_modify(const SECTION_LIST *p
484                  content[ARTICLE_CONTENT_MAX_LEN - 1] = '\0';                  content[ARTICLE_CONTENT_MAX_LEN - 1] = '\0';
485    
486                  // Remove control sequence                  // Remove control sequence
487                  len_content = ctrl_seq_filter(content);                  len_content = str_filter(content, 0);
488    
489                  p_editor_data = editor_data_load(content);                  p_editor_data = editor_data_load(content);
490                  if (p_editor_data == NULL)                  if (p_editor_data == NULL)
491                  {                  {
492                          log_error("editor_data_load(aid=%d, cid=%d) error\n", p_article->aid, atoi(row[0]));                          log_error("editor_data_load(aid=%d, cid=%d) error\n", p_article->aid, atoi(row[0]));
493                          ret = -3;                          ret = -1;
494                          goto cleanup;                          goto cleanup;
495                  }                  }
496    
497                  free(content);                  free(content);
498                  content = NULL;                  content = NULL;
499    
500                    reply_note = atoi(row[2]);
501          }          }
502          mysql_free_result(rs);          mysql_free_result(rs);
503          rs = NULL;          rs = NULL;
# Line 502  int article_modify(const SECTION_LIST *p Line 509  int article_modify(const SECTION_LIST *p
509          {          {
510                  editor_display(p_editor_data);                  editor_display(p_editor_data);
511    
512                  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))  
513                  {                  {
514                            clearscr();
515                            moveto(1, 1);
516                            prints("(S)淇濆瓨, (C)鍙栨秷, (N)%s鍥炲閫氱煡 or (E)鍐嶇紪杈? [S]: ",
517                                       (reply_note ? "鍏抽棴" : "寮鍚"));
518                            iflush();
519    
520                            ch = igetch_t(BBS_max_user_idle_time);
521                          switch (toupper(ch))                          switch (toupper(ch))
522                          {                          {
523                            case KEY_NULL:
524                            case KEY_TIMEOUT:
525                                    goto cleanup;
526                          case CR:                          case CR:
                                 igetch_reset();  
527                          case 'S':                          case 'S':
528                                  break;                                  break;
529                          case 'C':                          case 'C':
530                                  clearscr();                                  clearscr();
531                                  moveto(1, 1);                                  moveto(1, 1);
532                                  prints("取消...");                                  prints("鍙栨秷...");
533                                  press_any_key();                                  press_any_key();
534                                  goto cleanup;                                  goto cleanup;
535                            case 'N':
536                                    reply_note = (reply_note ? 0 : 1);
537                                    continue;
538                          case 'E':                          case 'E':
539                                  break;                                  break;
540                          default: // Invalid selection                          default: // Invalid selection
# Line 531  int article_modify(const SECTION_LIST *p Line 545  int article_modify(const SECTION_LIST *p
545                  }                  }
546          }          }
547    
548            if (SYS_server_exit) // Do not save data on shutdown
549            {
550                    goto cleanup;
551            }
552    
553          // Allocate buffers in big size          // Allocate buffers in big size
554          content = malloc(ARTICLE_CONTENT_MAX_LEN);          content = malloc(ARTICLE_CONTENT_MAX_LEN);
555          if (content == NULL)          if (content == NULL)
# Line 544  int article_modify(const SECTION_LIST *p Line 563  int article_modify(const SECTION_LIST *p
563          if (len_content < 0)          if (len_content < 0)
564          {          {
565                  log_error("editor_data_save() error\n");                  log_error("editor_data_save() error\n");
566                  ret = -2;                  ret = -1;
567                  goto cleanup;                  goto cleanup;
568          }          }
569    
# Line 553  int article_modify(const SECTION_LIST *p Line 572  int article_modify(const SECTION_LIST *p
572          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);
573    
574          len_content += snprintf(content + len_content, LINE_BUFFER_LEN,          len_content += snprintf(content + len_content, LINE_BUFFER_LEN,
575                                                          "\n--\n※ 作者已于 %s 修改本文※\n",                                                          "\n--\n鈥 浣滆呭凡浜 %s 淇敼鏈枃鈥籠n",
576                                                          str_modify_dt);                                                          str_modify_dt);
577    
578            // Calculate display length of content
579            content_display_length = str_length(content, 1);
580    
581          db = db_open();          db = db_open();
582          if (db == NULL)          if (db == NULL)
583          {          {
# Line 623  int article_modify(const SECTION_LIST *p Line 645  int article_modify(const SECTION_LIST *p
645    
646          // Update article          // Update article
647          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
648                           "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
649                           p_article_new->cid, len_content, p_article->aid);                           p_article_new->cid, content_display_length, reply_note, p_article->aid);
650    
651          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
652          {          {
# Line 661  int article_modify(const SECTION_LIST *p Line 683  int article_modify(const SECTION_LIST *p
683                  goto cleanup;                  goto cleanup;
684          }          }
685    
686            mysql_close(db);
687            db = NULL;
688    
689          clearscr();          clearscr();
690          moveto(1, 1);          moveto(1, 1);
691          prints("修改完成,新内容通常会在%d秒后可见", BBS_section_list_load_interval);          prints("淇敼瀹屾垚锛屾柊鍐呭閫氬父浼氬湪%d绉掑悗鍙", BBS_section_list_load_interval);
692          press_any_key();          press_any_key();
693          ret = 1; // Success          ret = 1; // Success
694    
# Line 695  int article_reply(const SECTION_LIST *p_ Line 720  int article_reply(const SECTION_LIST *p_
720          char *content = NULL;          char *content = NULL;
721          char *content_f = NULL;          char *content_f = NULL;
722          long len_content;          long len_content;
723            int content_display_length;
724          char nickname_f[BBS_nickname_max_len * 2 + 1];          char nickname_f[BBS_nickname_max_len * 2 + 1];
725          int sign_id = 0;          int sign_id = 0;
726            int reply_note = 0;
727          long len;          long len;
728          int ch;          int ch;
729          char *p, *q;          char *p, *q;
# Line 706  int article_reply(const SECTION_LIST *p_ Line 733  int article_reply(const SECTION_LIST *p_
733          long i;          long i;
734          long ret = 0;          long ret = 0;
735          int topic_locked = 0;          int topic_locked = 0;
736            char msg[BBS_msg_max_len];
737            char msg_f[BBS_msg_max_len * 2 + 1];
738            int len_msg;
739    
740          if (p_section == NULL || p_article == NULL)          if (p_section == NULL || p_article == NULL)
741          {          {
# Line 716  int article_reply(const SECTION_LIST *p_ Line 746  int article_reply(const SECTION_LIST *p_
746          {          {
747                  clearscr();                  clearscr();
748                  moveto(1, 1);                  moveto(1, 1);
749                  prints("您没有权限在本版块发表文章\n");                  prints("鎮ㄦ病鏈夋潈闄愬湪鏈増鍧楀彂琛ㄦ枃绔燶n");
750                  press_any_key();                  press_any_key();
751    
752                  return 0;                  return 0;
# Line 724  int article_reply(const SECTION_LIST *p_ Line 754  int article_reply(const SECTION_LIST *p_
754    
755          p_article_new->title[0] = '\0';          p_article_new->title[0] = '\0';
756          snprintf(title_input, sizeof(title_input), "Re: %s", p_article->title);          snprintf(title_input, sizeof(title_input), "Re: %s", p_article->title);
757          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);
758          title_input[len] = '\0';          title_input[len] = '\0';
759    
760          db = db_open();          db = db_open();
761          if (db == NULL)          if (db == NULL)
762          {          {
763                  log_error("db_open() error: %s\n", mysql_error(db));                  log_error("db_open() error: %s\n", mysql_error(db));
764                  return -1;                  ret = -1;
765                    goto cleanup;
766          }          }
767    
768          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
# Line 741  int article_reply(const SECTION_LIST *p_ Line 772  int article_reply(const SECTION_LIST *p_
772          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
773          {          {
774                  log_error("Query article status error: %s\n", mysql_error(db));                  log_error("Query article status error: %s\n", mysql_error(db));
775                  return -2;                  ret = -1;
776                    goto cleanup;
777          }          }
778          if ((rs = mysql_store_result(db)) == NULL)          if ((rs = mysql_store_result(db)) == NULL)
779          {          {
780                  log_error("Get article status data failed\n");                  log_error("Get article status data failed\n");
781                  return -2;                  ret = -1;
782                    goto cleanup;
783          }          }
784    
785          if ((row = mysql_fetch_row(rs)))          if ((row = mysql_fetch_row(rs)))
# Line 761  int article_reply(const SECTION_LIST *p_ Line 794  int article_reply(const SECTION_LIST *p_
794    
795          if (topic_locked) // Reply is not allowed          if (topic_locked) // Reply is not allowed
796          {          {
797                    mysql_close(db);
798                    db = NULL;
799    
800                  clearscr();                  clearscr();
801                  moveto(1, 1);                  moveto(1, 1);
802                  prints("该主题谢绝回复");                  prints("璇ヤ富棰樿阿缁濆洖澶");
803                  press_any_key();                  press_any_key();
804    
805                  goto cleanup;                  goto cleanup;
# Line 778  int article_reply(const SECTION_LIST *p_ Line 814  int article_reply(const SECTION_LIST *p_
814          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
815          {          {
816                  log_error("Query article content error: %s\n", mysql_error(db));                  log_error("Query article content error: %s\n", mysql_error(db));
817                  return -2;                  ret = -1;
818                    goto cleanup;
819          }          }
820          if ((rs = mysql_use_result(db)) == NULL)          if ((rs = mysql_use_result(db)) == NULL)
821          {          {
822                  log_error("Get article content data failed\n");                  log_error("Get article content data failed\n");
823                  return -2;                  ret = -1;
824                    goto cleanup;
825          }          }
826    
827          if ((row = mysql_fetch_row(rs)))          if ((row = mysql_fetch_row(rs)))
# Line 805  int article_reply(const SECTION_LIST *p_ Line 843  int article_reply(const SECTION_LIST *p_
843                  }                  }
844    
845                  // Apply LML render to content body                  // Apply LML render to content body
846                  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);
847                  content_f[len] = '\0';                  content_f[len] = '\0';
848    
849                  // Remove control sequence                  // Remove control sequence
850                  len = ctrl_seq_filter(content_f);                  len = str_filter(content_f, 0);
851    
852                  len = snprintf(content, ARTICLE_CONTENT_MAX_LEN,                  len = snprintf(content, ARTICLE_CONTENT_MAX_LEN,
853                                             "\n\n【 在 %s (%s) 的大作中提到: 】\n",                                             "\n\n銆 鍦 %s (%s) 鐨勫ぇ浣滀腑鎻愬埌: 銆慭n",
854                                             p_article->username, p_article->nickname);                                             p_article->username, p_article->nickname);
855    
856                  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);
857                  for (i = 0; i < quote_content_lines; i++)                  for (i = 0; i < quote_content_lines; i++)
858                  {                  {
859                          memcpy(content + len, ": ", 2); // quote line prefix                          memcpy(content + len, ": ", 2); // quote line prefix
860                          len += 2;                          len += 2;
861                          memcpy(content + len, content_f + line_offsets[i], (size_t)(line_offsets[i + 1] - line_offsets[i]));                          memcpy(content + len, content_f + line_offsets[i], (size_t)(line_offsets[i + 1] - line_offsets[i]));
862                          len += (line_offsets[i + 1] - line_offsets[i]);                          len += (line_offsets[i + 1] - line_offsets[i]);
863                            if (content[len - 1] != '\n') // Appennd \n if not exist
864                            {
865                                    content[len] = '\n';
866                                    len++;
867                            }
868                  }                  }
869                  if (content[len - 1] != '\n') // Appennd \n if not exist                  if (content[len - 1] != '\n') // Appennd \n if not exist
870                  {                  {
# Line 837  int article_reply(const SECTION_LIST *p_ Line 880  int article_reply(const SECTION_LIST *p_
880                  if (p_editor_data == NULL)                  if (p_editor_data == NULL)
881                  {                  {
882                          log_error("editor_data_load(aid=%d, cid=%d) error\n", p_article->aid, atoi(row[0]));                          log_error("editor_data_load(aid=%d, cid=%d) error\n", p_article->aid, atoi(row[0]));
883                          ret = -3;                          ret = -1;
884                          goto cleanup;                          goto cleanup;
885                  }                  }
886    
# Line 855  int article_reply(const SECTION_LIST *p_ Line 898  int article_reply(const SECTION_LIST *p_
898          {          {
899                  clearscr();                  clearscr();
900                  moveto(21, 1);                  moveto(21, 1);
901                  prints("回复文章于 %s[%s] 讨论区", p_section->stitle, p_section->sname);                  prints("鍥炲鏂囩珷浜 %s[%s] 璁ㄨ鍖猴紝鍥炲閫氱煡锛%s", p_section->stitle, p_section->sname, (reply_note ? "寮鍚" : "鍏抽棴"));
902                  moveto(22, 1);                  moveto(22, 1);
903                  prints("标题: %s", (p_article_new->title[0] == '\0' ? "[无]" : p_article_new->title));                  prints("鏍囬: %s", (p_article_new->title[0] == '\0' ? "[鏃燷" : p_article_new->title));
904                  moveto(23, 1);                  moveto(23, 1);
905                  prints("使用第 %d 个签名", sign_id);                  prints("浣跨敤绗 %d 涓鍚", sign_id);
906    
907                  if (toupper(ch) != 'T')                  if (toupper(ch) != 'T')
908                  {                  {
909                          prints("    按0~3选签名档(0表示不使用)");                          prints("    鎸0~3閫夌鍚嶆。(0琛ㄧず涓嶄娇鐢)");
910    
911                          moveto(24, 1);                          moveto(24, 1);
912                          prints("T改标题, C取消, Enter继续: ");                          prints("T鏀规爣棰, C鍙栨秷, N%s, Enter缁х画: ",
913                                       (reply_note ? "鍏抽棴鍥炲閫氱煡" : "寮鍚洖澶嶉氱煡"));
914                          iflush();                          iflush();
915                          ch = 0;                          ch = 0;
916                  }                  }
917    
918                  for (; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))                  for (; !SYS_server_exit; ch = igetch_t(BBS_max_user_idle_time))
919                  {                  {
920                          switch (toupper(ch))                          switch (toupper(ch))
921                          {                          {
922                            case KEY_NULL:
923                            case KEY_TIMEOUT:
924                                    goto cleanup;
925                          case CR:                          case CR:
                                 igetch_reset();  
926                                  break;                                  break;
927                          case 'T':                          case 'T':
928                                  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);  
929                                  for (p = title_input; *p == ' '; p++)                                  for (p = title_input; *p == ' '; p++)
930                                          ;                                          ;
931                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)
# Line 898  int article_reply(const SECTION_LIST *p_ Line 942  int article_reply(const SECTION_LIST *p_
942                          case 'C':                          case 'C':
943                                  clearscr();                                  clearscr();
944                                  moveto(1, 1);                                  moveto(1, 1);
945                                  prints("取消...");                                  prints("鍙栨秷...");
946                                  press_any_key();                                  press_any_key();
947                                  goto cleanup;                                  goto cleanup;
948                            case 'N':
949                                    reply_note = (reply_note ? 0 : 1);
950                                    break;
951                          case '0':                          case '0':
952                          case '1':                          case '1':
953                          case '2':                          case '2':
# Line 925  int article_reply(const SECTION_LIST *p_ Line 972  int article_reply(const SECTION_LIST *p_
972    
973                          clearscr();                          clearscr();
974                          moveto(1, 1);                          moveto(1, 1);
975                          prints("(S)发送, (C)取消, (T)更改标题 or (E)再编辑? [S]: ");                          prints("(S)鍙戦, (C)鍙栨秷, (T)鏇存敼鏍囬 or (E)鍐嶇紪杈? [S]: ");
976                          iflush();                          iflush();
977    
978                          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))
979                          {                          {
980                                  switch (toupper(ch))                                  switch (toupper(ch))
981                                  {                                  {
982                                    case KEY_NULL:
983                                    case KEY_TIMEOUT:
984                                            goto cleanup;
985                                  case CR:                                  case CR:
                                         igetch_reset();  
986                                  case 'S':                                  case 'S':
987                                          break;                                          break;
988                                  case 'C':                                  case 'C':
989                                          clearscr();                                          clearscr();
990                                          moveto(1, 1);                                          moveto(1, 1);
991                                          prints("取消...");                                          prints("鍙栨秷...");
992                                          press_any_key();                                          press_any_key();
993                                          goto cleanup;                                          goto cleanup;
994                                  case 'T':                                  case 'T':
# Line 960  int article_reply(const SECTION_LIST *p_ Line 1009  int article_reply(const SECTION_LIST *p_
1009                  }                  }
1010          }          }
1011    
1012            if (SYS_server_exit) // Do not save data on shutdown
1013            {
1014                    goto cleanup;
1015            }
1016    
1017          content = malloc(ARTICLE_CONTENT_MAX_LEN);          content = malloc(ARTICLE_CONTENT_MAX_LEN);
1018          if (content == NULL)          if (content == NULL)
1019          {          {
# Line 972  int article_reply(const SECTION_LIST *p_ Line 1026  int article_reply(const SECTION_LIST *p_
1026          if (len_content < 0)          if (len_content < 0)
1027          {          {
1028                  log_error("editor_data_save() error\n");                  log_error("editor_data_save() error\n");
1029                  ret = -2;                  ret = -1;
1030                  goto cleanup;                  goto cleanup;
1031          }          }
1032    
# Line 1013  int article_reply(const SECTION_LIST *p_ Line 1067  int article_reply(const SECTION_LIST *p_
1067                  rs = NULL;                  rs = NULL;
1068          }          }
1069    
1070            // Calculate display length of content
1071            content_display_length = str_length(content, 1);
1072    
1073          // Begin transaction          // Begin transaction
1074          if (mysql_query(db, "SET autocommit=0") != 0)          if (mysql_query(db, "SET autocommit=0") != 0)
1075          {          {
# Line 1076  int article_reply(const SECTION_LIST *p_ Line 1133  int article_reply(const SECTION_LIST *p_
1133          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
1134                           "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "                           "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "
1135                           "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "                           "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "
1136                           "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)",
1137                           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),
1138                           BBS_priv.uid, BBS_username, nickname_f, title_f,                           BBS_priv.uid, BBS_username, nickname_f, title_f,
1139                           p_article_new->cid, hostaddr_client, BBS_user_exp, len_content);                           p_article_new->cid, hostaddr_client,
1140                             reply_note, BBS_user_exp, content_display_length);
1141    
1142          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
1143          {          {
# Line 1117  int article_reply(const SECTION_LIST *p_ Line 1175  int article_reply(const SECTION_LIST *p_
1175                  goto cleanup;                  goto cleanup;
1176          }          }
1177    
1178            // Notify the authors of the topic / article which is replyed.
1179            snprintf(sql, sizeof(sql),
1180                             "SELECT DISTINCT UID FROM bbs WHERE (AID = %d OR AID = %d) "
1181                             "AND visible AND reply_note AND UID <> %d",
1182                             p_article->tid, p_article->aid, BBS_priv.uid);
1183    
1184            if (mysql_query(db, sql) != 0)
1185            {
1186                    log_error("Read reply info error: %s\n", mysql_error(db));
1187                    ret = -1;
1188                    goto cleanup;
1189            }
1190            if ((rs = mysql_store_result(db)) == NULL)
1191            {
1192                    log_error("Get reply info failed\n");
1193                    ret = -1;
1194                    goto cleanup;
1195            }
1196    
1197            while ((row = mysql_fetch_row(rs)))
1198            {
1199                    // Send notification message
1200                    len_msg = snprintf(msg, BBS_msg_max_len,
1201                                                       "鏈変汉鍥炲浜嗘偍鎵鍙戣〃/鍥炲鐨勬枃绔狅紝蹇潵"
1202                                                       "[article %d]鐪嬬湅[/article]銆%s銆嬪惂锛乗n",
1203                                                       p_article_new->aid, title_f);
1204    
1205                    mysql_real_escape_string(db, msg_f, msg, (unsigned long)len_msg);
1206    
1207                    snprintf(sql, sizeof(sql),
1208                                     "INSERT INTO bbs_msg(fromUID, toUID, content, send_dt, send_ip) "
1209                                     "VALUES(%d, %d, '%s', NOW(), '%s')",
1210                                     BBS_sys_id, atoi(row[0]), msg_f, hostaddr_client);
1211    
1212                    if (mysql_query(db, sql) != 0)
1213                    {
1214                            log_error("Insert msg error: %s\n", mysql_error(db));
1215                            ret = -1;
1216                            goto cleanup;
1217                    }
1218            }
1219            mysql_free_result(rs);
1220            rs = NULL;
1221    
1222          // Add exp          // Add exp
1223          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
1224          {          {
# Line 1153  int article_reply(const SECTION_LIST *p_ Line 1255  int article_reply(const SECTION_LIST *p_
1255                  goto cleanup;                  goto cleanup;
1256          }          }
1257    
1258            mysql_close(db);
1259            db = NULL;
1260    
1261          clearscr();          clearscr();
1262          moveto(1, 1);          moveto(1, 1);
1263          prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval);          prints("鍙戦佸畬鎴愶紝鏂版枃绔犻氬父浼氬湪%d绉掑悗鍙", BBS_section_list_load_interval);
1264          press_any_key();          press_any_key();
1265          ret = 1; // Success          ret = 1; // Success
1266    


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

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