/[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.18 by sysadm, Sun Jun 15 06:19:21 2025 UTC Revision 1.38 by sysadm, Tue Nov 4 14:58:56 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  #define TITLE_INPUT_MAX_LEN 72
25  #define ARTICLE_CONTENT_MAX_LEN 1024 * 1024 * 4 // 4MB  #define ARTICLE_CONTENT_MAX_LEN 1024 * 1024 * 4 // 4MB
26  #define ARTICLE_QUOTE_MAX_LINES 20  #define ARTICLE_QUOTE_MAX_LINES 20
 #define ARTICLE_QUOTE_LINE_MAX_LEN 76  
27    
28  #define MODIFY_DT_MAX_LEN 50  #define MODIFY_DT_MAX_LEN 50
29    
# Line 46  int article_post(const SECTION_LIST *p_s Line 35  int article_post(const SECTION_LIST *p_s
35          char sql[SQL_BUFFER_LEN];          char sql[SQL_BUFFER_LEN];
36          char *sql_content = NULL;          char *sql_content = NULL;
37          EDITOR_DATA *p_editor_data = NULL;          EDITOR_DATA *p_editor_data = NULL;
38          char title_input[TITLE_INPUT_MAX_LEN + 1];          char title_input[BBS_article_title_max_len + 1];
39          char title_f[BBS_article_title_max_len * 2 + 1];          char title_f[BBS_article_title_max_len * 2 + 1];
40          char *content = NULL;          char *content = NULL;
41          char *content_f = NULL;          char *content_f = NULL;
42          long len_content;          long len_content;
43            int content_display_length;
44          char nickname_f[BBS_nickname_max_len * 2 + 1];          char nickname_f[BBS_nickname_max_len * 2 + 1];
45          int sign_id = 0;          int sign_id = 0;
46            int reply_note = 1;
47          long len;          long len;
48          int ch;          int ch;
49          char *p, *q;          char *p, *q;
# Line 67  int article_post(const SECTION_LIST *p_s Line 58  int article_post(const SECTION_LIST *p_s
58          {          {
59                  clearscr();                  clearscr();
60                  moveto(1, 1);                  moveto(1, 1);
61                  prints("您没有权限在本版块发表文章\n");                  prints("鎮ㄦ病鏈夋潈闄愬湪鏈増鍧楀彂琛ㄦ枃绔燶n");
62                  press_any_key();                  press_any_key();
63    
64                  return 0;                  return 0;
# Line 90  int article_post(const SECTION_LIST *p_s Line 81  int article_post(const SECTION_LIST *p_s
81          {          {
82                  clearscr();                  clearscr();
83                  moveto(21, 1);                  moveto(21, 1);
84                  prints("发表文章于 %s[%s] 讨论区,类型: %s", p_section->stitle, p_section->sname, (p_article_new->transship ? "转载" : "原创"));                  prints("鍙戣〃鏂囩珷浜 %s[%s] 璁ㄨ鍖猴紝绫诲瀷: %s锛屽洖澶嶉氱煡锛%s",
85                               p_section->stitle, p_section->sname,
86                               (p_article_new->transship ? "杞浇" : "鍘熷垱"),
87                               (reply_note ? "寮鍚" : "鍏抽棴"));
88                  moveto(22, 1);                  moveto(22, 1);
89                  prints("标题: %s", (p_article_new->title[0] == '\0' ? "[无]" : p_article_new->title));                  prints("鏍囬: %s", (p_article_new->title[0] == '\0' ? "[鏃燷" : p_article_new->title));
90                  moveto(23, 1);                  moveto(23, 1);
91                  prints("使用第 %d 个签名", sign_id);                  prints("浣跨敤绗 %d 涓鍚", sign_id);
92    
93                  if (toupper(ch) != 'T')                  if (toupper(ch) != 'T')
94                  {                  {
95                          prints("    按0~3选签名档(0表示不使用)");                          prints("    鎸0~3閫夌鍚嶆。(0琛ㄧず涓嶄娇鐢)");
96    
97                          moveto(24, 1);                          moveto(24, 1);
98                          prints("T改标题, C取消, Z设为转载, Y设为原创, Enter继续: ");                          prints("T鏀规爣棰, C鍙栨秷, Z璁句负%s, N%s, Enter缁х画: ",
99                                       (p_article_new->transship ? "鍘熷垱" : "杞浇"),
100                                       (reply_note ? "鍏抽棴鍥炲閫氱煡" : "寮鍚洖澶嶉氱煡"));
101                          iflush();                          iflush();
102                          ch = 0;                          ch = 0;
103                  }                  }
# Line 110  int article_post(const SECTION_LIST *p_s Line 106  int article_post(const SECTION_LIST *p_s
106                  {                  {
107                          switch (toupper(ch))                          switch (toupper(ch))
108                          {                          {
109                            case KEY_NULL:
110                            case KEY_TIMEOUT:
111                                    goto cleanup;
112                          case CR:                          case CR:
                                 igetch_reset();  
113                                  break;                                  break;
114                          case 'T':                          case 'T':
115                                  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);  
116                                  for (p = title_input; *p == ' '; p++)                                  for (p = title_input; *p == ' '; p++)
117                                          ;                                          ;
118                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)
# Line 133  int article_post(const SECTION_LIST *p_s Line 129  int article_post(const SECTION_LIST *p_s
129                          case 'C':                          case 'C':
130                                  clearscr();                                  clearscr();
131                                  moveto(1, 1);                                  moveto(1, 1);
132                                  prints("取消...");                                  prints("鍙栨秷...");
133                                  press_any_key();                                  press_any_key();
134                                  goto cleanup;                                  goto cleanup;
                         case 'Y':  
                                 p_article_new->transship = 0;  
                                 break;  
135                          case 'Z':                          case 'Z':
136                                  p_article_new->transship = 1;                                  p_article_new->transship = (p_article_new->transship ? 0 : 1);
137                                    break;
138                            case 'N':
139                                    reply_note = (reply_note ? 0 : 1);
140                                  break;                                  break;
141                          case '0':                          case '0':
142                          case '1':                          case '1':
# Line 166  int article_post(const SECTION_LIST *p_s Line 162  int article_post(const SECTION_LIST *p_s
162    
163                          clearscr();                          clearscr();
164                          moveto(1, 1);                          moveto(1, 1);
165                          prints("(S)发送, (C)取消, (T)更改标题 or (E)再编辑? [S]: ");                          prints("(S)鍙戦, (C)鍙栨秷, (T)鏇存敼鏍囬 or (E)鍐嶇紪杈? [S]: ");
166                          iflush();                          iflush();
167    
168                          for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))                          for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))
169                          {                          {
170                                  switch (toupper(ch))                                  switch (toupper(ch))
171                                  {                                  {
172                                    case KEY_NULL:
173                                    case KEY_TIMEOUT:
174                                            goto cleanup;
175                                  case CR:                                  case CR:
                                         igetch_reset();  
176                                  case 'S':                                  case 'S':
177                                          break;                                          break;
178                                  case 'C':                                  case 'C':
179                                          clearscr();                                          clearscr();
180                                          moveto(1, 1);                                          moveto(1, 1);
181                                          prints("取消...");                                          prints("鍙栨秷...");
182                                          press_any_key();                                          press_any_key();
183                                          goto cleanup;                                          goto cleanup;
184                                  case 'T':                                  case 'T':
# Line 201  int article_post(const SECTION_LIST *p_s Line 199  int article_post(const SECTION_LIST *p_s
199                  }                  }
200          }          }
201    
202            if (SYS_server_exit) // Do not save data on shutdown
203            {
204                    goto cleanup;
205            }
206    
207          content = malloc(ARTICLE_CONTENT_MAX_LEN);          content = malloc(ARTICLE_CONTENT_MAX_LEN);
208          if (content == NULL)          if (content == NULL)
209          {          {
# Line 254  int article_post(const SECTION_LIST *p_s Line 257  int article_post(const SECTION_LIST *p_s
257                  rs = NULL;                  rs = NULL;
258          }          }
259    
260            // Calculate display length of content
261            content_display_length = str_length(content, 1);
262    
263          // Begin transaction          // Begin transaction
264          if (mysql_query(db, "SET autocommit=0") != 0)          if (mysql_query(db, "SET autocommit=0") != 0)
265          {          {
# Line 317  int article_post(const SECTION_LIST *p_s Line 323  int article_post(const SECTION_LIST *p_s
323          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
324                           "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "                           "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "
325                           "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "                           "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "
326                           "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)",
327                           p_section->sid, BBS_priv.uid, BBS_username, nickname_f, title_f,                           p_section->sid, BBS_priv.uid, BBS_username, nickname_f, title_f,
328                           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,
329                             reply_note, BBS_user_exp, content_display_length);
330    
331          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
332          {          {
# Line 383  int article_post(const SECTION_LIST *p_s Line 390  int article_post(const SECTION_LIST *p_s
390    
391          clearscr();          clearscr();
392          moveto(1, 1);          moveto(1, 1);
393          prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval);          prints("鍙戦佸畬鎴愶紝鏂版枃绔犻氬父浼氬湪%d绉掑悗鍙", BBS_section_list_load_interval);
394          press_any_key();          press_any_key();
395          ret = 1; // Success          ret = 1; // Success
396    
# Line 410  int article_modify(const SECTION_LIST *p Line 417  int article_modify(const SECTION_LIST *p
417          char *content = NULL;          char *content = NULL;
418          char *content_f = NULL;          char *content_f = NULL;
419          long len_content;          long len_content;
420            int content_display_length;
421            int reply_note = 1;
422          int ch;          int ch;
423          long ret = 0;          long ret = 0;
424          time_t now;          time_t now;
# Line 427  int article_modify(const SECTION_LIST *p Line 436  int article_modify(const SECTION_LIST *p
436          {          {
437                  clearscr();                  clearscr();
438                  moveto(1, 1);                  moveto(1, 1);
439                  prints("该文章无法被编辑,请联系版主。");                  prints("璇ユ枃绔犳棤娉曡缂栬緫锛岃鑱旂郴鐗堜富銆");
440                  press_any_key();                  press_any_key();
441    
442                  return 0;                  return 0;
# Line 442  int article_modify(const SECTION_LIST *p Line 451  int article_modify(const SECTION_LIST *p
451          }          }
452    
453          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
454                           "SELECT bbs_content.CID, bbs_content.content "                           "SELECT bbs_content.CID, bbs_content.content, reply_note "
455                           "FROM bbs INNER JOIN bbs_content ON bbs.CID = bbs_content.CID "                           "FROM bbs INNER JOIN bbs_content ON bbs.CID = bbs_content.CID "
456                           "WHERE bbs.AID = %d",                           "WHERE bbs.AID = %d",
457                           p_article->aid);                           p_article->aid);
# Line 474  int article_modify(const SECTION_LIST *p Line 483  int article_modify(const SECTION_LIST *p
483                  content[ARTICLE_CONTENT_MAX_LEN - 1] = '\0';                  content[ARTICLE_CONTENT_MAX_LEN - 1] = '\0';
484    
485                  // Remove control sequence                  // Remove control sequence
486                  len_content = ctrl_seq_filter(content);                  len_content = str_filter(content, 0);
487    
488                  p_editor_data = editor_data_load(content);                  p_editor_data = editor_data_load(content);
489                  if (p_editor_data == NULL)                  if (p_editor_data == NULL)
# Line 486  int article_modify(const SECTION_LIST *p Line 495  int article_modify(const SECTION_LIST *p
495    
496                  free(content);                  free(content);
497                  content = NULL;                  content = NULL;
498    
499                    reply_note = atoi(row[2]);
500          }          }
501          mysql_free_result(rs);          mysql_free_result(rs);
502          rs = NULL;          rs = NULL;
# Line 497  int article_modify(const SECTION_LIST *p Line 508  int article_modify(const SECTION_LIST *p
508          {          {
509                  editor_display(p_editor_data);                  editor_display(p_editor_data);
510    
511                  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))  
512                  {                  {
513                            clearscr();
514                            moveto(1, 1);
515                            prints("(S)淇濆瓨, (C)鍙栨秷, (N)%s鍥炲閫氱煡 or (E)鍐嶇紪杈? [S]: ",
516                                       (reply_note ? "鍏抽棴" : "寮鍚"));
517                            iflush();
518    
519                            ch = igetch_t(MAX_DELAY_TIME);
520                          switch (toupper(ch))                          switch (toupper(ch))
521                          {                          {
522                            case KEY_NULL:
523                            case KEY_TIMEOUT:
524                                    goto cleanup;
525                          case CR:                          case CR:
                                 igetch_reset();  
526                          case 'S':                          case 'S':
527                                  break;                                  break;
528                          case 'C':                          case 'C':
529                                  clearscr();                                  clearscr();
530                                  moveto(1, 1);                                  moveto(1, 1);
531                                  prints("取消...");                                  prints("鍙栨秷...");
532                                  press_any_key();                                  press_any_key();
533                                  goto cleanup;                                  goto cleanup;
534                            case 'N':
535                                    reply_note = (reply_note ? 0 : 1);
536                                    continue;
537                          case 'E':                          case 'E':
538                                  break;                                  break;
539                          default: // Invalid selection                          default: // Invalid selection
# Line 526  int article_modify(const SECTION_LIST *p Line 544  int article_modify(const SECTION_LIST *p
544                  }                  }
545          }          }
546    
547            if (SYS_server_exit) // Do not save data on shutdown
548            {
549                    goto cleanup;
550            }
551    
552          // Allocate buffers in big size          // Allocate buffers in big size
553          content = malloc(ARTICLE_CONTENT_MAX_LEN);          content = malloc(ARTICLE_CONTENT_MAX_LEN);
554          if (content == NULL)          if (content == NULL)
# Line 548  int article_modify(const SECTION_LIST *p Line 571  int article_modify(const SECTION_LIST *p
571          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);
572    
573          len_content += snprintf(content + len_content, LINE_BUFFER_LEN,          len_content += snprintf(content + len_content, LINE_BUFFER_LEN,
574                                                          "\n--\n※ 作者已于 %s 修改本文※\n",                                                          "\n--\n鈥 浣滆呭凡浜 %s 淇敼鏈枃鈥籠n",
575                                                          str_modify_dt);                                                          str_modify_dt);
576    
577            // Calculate display length of content
578            content_display_length = str_length(content, 1);
579    
580          db = db_open();          db = db_open();
581          if (db == NULL)          if (db == NULL)
582          {          {
# Line 618  int article_modify(const SECTION_LIST *p Line 644  int article_modify(const SECTION_LIST *p
644    
645          // Update article          // Update article
646          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
647                           "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
648                           p_article_new->cid, len_content, p_article->aid);                           p_article_new->cid, content_display_length, reply_note, p_article->aid);
649    
650          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
651          {          {
# Line 661  int article_modify(const SECTION_LIST *p Line 687  int article_modify(const SECTION_LIST *p
687    
688          clearscr();          clearscr();
689          moveto(1, 1);          moveto(1, 1);
690          prints("修改完成,新内容通常会在%d秒后可见", BBS_section_list_load_interval);          prints("淇敼瀹屾垚锛屾柊鍐呭閫氬父浼氬湪%d绉掑悗鍙", BBS_section_list_load_interval);
691          press_any_key();          press_any_key();
692          ret = 1; // Success          ret = 1; // Success
693    
# Line 693  int article_reply(const SECTION_LIST *p_ Line 719  int article_reply(const SECTION_LIST *p_
719          char *content = NULL;          char *content = NULL;
720          char *content_f = NULL;          char *content_f = NULL;
721          long len_content;          long len_content;
722            int content_display_length;
723          char nickname_f[BBS_nickname_max_len * 2 + 1];          char nickname_f[BBS_nickname_max_len * 2 + 1];
724          int sign_id = 0;          int sign_id = 0;
725            int reply_note = 0;
726          long len;          long len;
727          int ch;          int ch;
728          char *p, *q;          char *p, *q;
# Line 704  int article_reply(const SECTION_LIST *p_ Line 732  int article_reply(const SECTION_LIST *p_
732          long i;          long i;
733          long ret = 0;          long ret = 0;
734          int topic_locked = 0;          int topic_locked = 0;
735            char msg[BBS_msg_max_len];
736            char msg_f[BBS_msg_max_len * 2 + 1];
737            int len_msg;
738    
739          if (p_section == NULL || p_article == NULL)          if (p_section == NULL || p_article == NULL)
740          {          {
# Line 714  int article_reply(const SECTION_LIST *p_ Line 745  int article_reply(const SECTION_LIST *p_
745          {          {
746                  clearscr();                  clearscr();
747                  moveto(1, 1);                  moveto(1, 1);
748                  prints("您没有权限在本版块发表文章\n");                  prints("鎮ㄦ病鏈夋潈闄愬湪鏈増鍧楀彂琛ㄦ枃绔燶n");
749                  press_any_key();                  press_any_key();
750    
751                  return 0;                  return 0;
# Line 722  int article_reply(const SECTION_LIST *p_ Line 753  int article_reply(const SECTION_LIST *p_
753    
754          p_article_new->title[0] = '\0';          p_article_new->title[0] = '\0';
755          snprintf(title_input, sizeof(title_input), "Re: %s", p_article->title);          snprintf(title_input, sizeof(title_input), "Re: %s", p_article->title);
756          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);
757          title_input[len] = '\0';          title_input[len] = '\0';
758    
759          db = db_open();          db = db_open();
# Line 767  int article_reply(const SECTION_LIST *p_ Line 798  int article_reply(const SECTION_LIST *p_
798    
799                  clearscr();                  clearscr();
800                  moveto(1, 1);                  moveto(1, 1);
801                  prints("该主题谢绝回复");                  prints("璇ヤ富棰樿阿缁濆洖澶");
802                  press_any_key();                  press_any_key();
803    
804                  goto cleanup;                  goto cleanup;
# Line 811  int article_reply(const SECTION_LIST *p_ Line 842  int article_reply(const SECTION_LIST *p_
842                  }                  }
843    
844                  // Apply LML render to content body                  // Apply LML render to content body
845                  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);
846                  content_f[len] = '\0';                  content_f[len] = '\0';
847    
848                  // Remove control sequence                  // Remove control sequence
849                  len = ctrl_seq_filter(content_f);                  len = str_filter(content_f, 0);
850    
851                  len = snprintf(content, ARTICLE_CONTENT_MAX_LEN,                  len = snprintf(content, ARTICLE_CONTENT_MAX_LEN,
852                                             "\n\n【 在 %s (%s) 的大作中提到: 】\n",                                             "\n\n銆 鍦 %s (%s) 鐨勫ぇ浣滀腑鎻愬埌: 銆慭n",
853                                             p_article->username, p_article->nickname);                                             p_article->username, p_article->nickname);
854    
855                  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);
856                  for (i = 0; i < quote_content_lines; i++)                  for (i = 0; i < quote_content_lines; i++)
857                  {                  {
858                          memcpy(content + len, ": ", 2); // quote line prefix                          memcpy(content + len, ": ", 2); // quote line prefix
# Line 866  int article_reply(const SECTION_LIST *p_ Line 897  int article_reply(const SECTION_LIST *p_
897          {          {
898                  clearscr();                  clearscr();
899                  moveto(21, 1);                  moveto(21, 1);
900                  prints("回复文章于 %s[%s] 讨论区", p_section->stitle, p_section->sname);                  prints("鍥炲鏂囩珷浜 %s[%s] 璁ㄨ鍖猴紝鍥炲閫氱煡锛%s", p_section->stitle, p_section->sname, (reply_note ? "寮鍚" : "鍏抽棴"));
901                  moveto(22, 1);                  moveto(22, 1);
902                  prints("标题: %s", (p_article_new->title[0] == '\0' ? "[无]" : p_article_new->title));                  prints("鏍囬: %s", (p_article_new->title[0] == '\0' ? "[鏃燷" : p_article_new->title));
903                  moveto(23, 1);                  moveto(23, 1);
904                  prints("使用第 %d 个签名", sign_id);                  prints("浣跨敤绗 %d 涓鍚", sign_id);
905    
906                  if (toupper(ch) != 'T')                  if (toupper(ch) != 'T')
907                  {                  {
908                          prints("    按0~3选签名档(0表示不使用)");                          prints("    鎸0~3閫夌鍚嶆。(0琛ㄧず涓嶄娇鐢)");
909    
910                          moveto(24, 1);                          moveto(24, 1);
911                          prints("T改标题, C取消, Enter继续: ");                          prints("T鏀规爣棰, C鍙栨秷, N%s, Enter缁х画: ",
912                                       (reply_note ? "鍏抽棴鍥炲閫氱煡" : "寮鍚洖澶嶉氱煡"));
913                          iflush();                          iflush();
914                          ch = 0;                          ch = 0;
915                  }                  }
# Line 886  int article_reply(const SECTION_LIST *p_ Line 918  int article_reply(const SECTION_LIST *p_
918                  {                  {
919                          switch (toupper(ch))                          switch (toupper(ch))
920                          {                          {
921                            case KEY_NULL:
922                            case KEY_TIMEOUT:
923                                    goto cleanup;
924                          case CR:                          case CR:
                                 igetch_reset();  
925                                  break;                                  break;
926                          case 'T':                          case 'T':
927                                  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);  
928                                  for (p = title_input; *p == ' '; p++)                                  for (p = title_input; *p == ' '; p++)
929                                          ;                                          ;
930                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)
# Line 909  int article_reply(const SECTION_LIST *p_ Line 941  int article_reply(const SECTION_LIST *p_
941                          case 'C':                          case 'C':
942                                  clearscr();                                  clearscr();
943                                  moveto(1, 1);                                  moveto(1, 1);
944                                  prints("取消...");                                  prints("鍙栨秷...");
945                                  press_any_key();                                  press_any_key();
946                                  goto cleanup;                                  goto cleanup;
947                            case 'N':
948                                    reply_note = (reply_note ? 0 : 1);
949                                    break;
950                          case '0':                          case '0':
951                          case '1':                          case '1':
952                          case '2':                          case '2':
# Line 936  int article_reply(const SECTION_LIST *p_ Line 971  int article_reply(const SECTION_LIST *p_
971    
972                          clearscr();                          clearscr();
973                          moveto(1, 1);                          moveto(1, 1);
974                          prints("(S)发送, (C)取消, (T)更改标题 or (E)再编辑? [S]: ");                          prints("(S)鍙戦, (C)鍙栨秷, (T)鏇存敼鏍囬 or (E)鍐嶇紪杈? [S]: ");
975                          iflush();                          iflush();
976    
977                          for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))                          for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))
978                          {                          {
979                                  switch (toupper(ch))                                  switch (toupper(ch))
980                                  {                                  {
981                                    case KEY_NULL:
982                                    case KEY_TIMEOUT:
983                                            goto cleanup;
984                                  case CR:                                  case CR:
                                         igetch_reset();  
985                                  case 'S':                                  case 'S':
986                                          break;                                          break;
987                                  case 'C':                                  case 'C':
988                                          clearscr();                                          clearscr();
989                                          moveto(1, 1);                                          moveto(1, 1);
990                                          prints("取消...");                                          prints("鍙栨秷...");
991                                          press_any_key();                                          press_any_key();
992                                          goto cleanup;                                          goto cleanup;
993                                  case 'T':                                  case 'T':
# Line 971  int article_reply(const SECTION_LIST *p_ Line 1008  int article_reply(const SECTION_LIST *p_
1008                  }                  }
1009          }          }
1010    
1011            if (SYS_server_exit) // Do not save data on shutdown
1012            {
1013                    goto cleanup;
1014            }
1015    
1016          content = malloc(ARTICLE_CONTENT_MAX_LEN);          content = malloc(ARTICLE_CONTENT_MAX_LEN);
1017          if (content == NULL)          if (content == NULL)
1018          {          {
# Line 1024  int article_reply(const SECTION_LIST *p_ Line 1066  int article_reply(const SECTION_LIST *p_
1066                  rs = NULL;                  rs = NULL;
1067          }          }
1068    
1069            // Calculate display length of content
1070            content_display_length = str_length(content, 1);
1071    
1072          // Begin transaction          // Begin transaction
1073          if (mysql_query(db, "SET autocommit=0") != 0)          if (mysql_query(db, "SET autocommit=0") != 0)
1074          {          {
# Line 1087  int article_reply(const SECTION_LIST *p_ Line 1132  int article_reply(const SECTION_LIST *p_
1132          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
1133                           "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "                           "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "
1134                           "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "                           "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "
1135                           "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)",
1136                           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),
1137                           BBS_priv.uid, BBS_username, nickname_f, title_f,                           BBS_priv.uid, BBS_username, nickname_f, title_f,
1138                           p_article_new->cid, hostaddr_client, BBS_user_exp, len_content);                           p_article_new->cid, hostaddr_client,
1139                             reply_note, BBS_user_exp, content_display_length);
1140    
1141          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
1142          {          {
# Line 1128  int article_reply(const SECTION_LIST *p_ Line 1174  int article_reply(const SECTION_LIST *p_
1174                  goto cleanup;                  goto cleanup;
1175          }          }
1176    
1177            // Notify the authors of the topic / article which is replyed.
1178            snprintf(sql, sizeof(sql),
1179                             "SELECT DISTINCT UID FROM bbs WHERE (AID = %d OR AID = %d) "
1180                             "AND visible AND reply_note AND UID <> %d",
1181                             p_article->tid, p_article->aid, BBS_priv.uid);
1182    
1183            if (mysql_query(db, sql) != 0)
1184            {
1185                    log_error("Read reply info error: %s\n", mysql_error(db));
1186                    ret = -1;
1187                    goto cleanup;
1188            }
1189            if ((rs = mysql_store_result(db)) == NULL)
1190            {
1191                    log_error("Get reply info failed\n");
1192                    ret = -1;
1193                    goto cleanup;
1194            }
1195    
1196            while ((row = mysql_fetch_row(rs)))
1197            {
1198                    // Send notification message
1199                    len_msg = snprintf(msg, BBS_msg_max_len,
1200                                                       "鏈変汉鍥炲浜嗘偍鎵鍙戣〃/鍥炲鐨勬枃绔狅紝蹇潵"
1201                                                       "[article %d]鐪嬬湅[/article]銆%s銆嬪惂锛乗n",
1202                                                       p_article_new->aid, title_f);
1203    
1204                    mysql_real_escape_string(db, msg_f, msg, (unsigned long)len_msg);
1205    
1206                    snprintf(sql, sizeof(sql),
1207                                     "INSERT INTO bbs_msg(fromUID, toUID, content, send_dt, send_ip) "
1208                                     "VALUES(%d, %d, '%s', NOW(), '%s')",
1209                                     BBS_sys_id, atoi(row[0]), msg_f, hostaddr_client);
1210    
1211                    if (mysql_query(db, sql) != 0)
1212                    {
1213                            log_error("Insert msg error: %s\n", mysql_error(db));
1214                            ret = -1;
1215                            goto cleanup;
1216                    }
1217            }
1218            mysql_free_result(rs);
1219            rs = NULL;
1220    
1221          // Add exp          // Add exp
1222          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
1223          {          {
# Line 1169  int article_reply(const SECTION_LIST *p_ Line 1259  int article_reply(const SECTION_LIST *p_
1259    
1260          clearscr();          clearscr();
1261          moveto(1, 1);          moveto(1, 1);
1262          prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval);          prints("鍙戦佸畬鎴愶紝鏂版枃绔犻氬父浼氬湪%d绉掑悗鍙", BBS_section_list_load_interval);
1263          press_any_key();          press_any_key();
1264          ret = 1; // Success          ret = 1; // Success
1265    


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

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