/[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.7 by sysadm, Sat Jun 14 02:58:11 2025 UTC Revision 1.33 by sysadm, Fri Oct 17 01:25:08 2025 UTC
# Line 14  Line 14 
14   *                                                                         *   *                                                                         *
15   ***************************************************************************/   ***************************************************************************/
16    
 #include "article_post.h"  
17  #include "article_cache.h"  #include "article_cache.h"
18    #include "article_post.h"
19    #include "bbs.h"
20    #include "database.h"
21  #include "editor.h"  #include "editor.h"
 #include "screen.h"  
 #include "log.h"  
22  #include "io.h"  #include "io.h"
23    #include "log.h"
24  #include "lml.h"  #include "lml.h"
25  #include "database.h"  #include "screen.h"
26    #include "user_priv.h"
27  #include <ctype.h>  #include <ctype.h>
28  #include <string.h>  #include <string.h>
29  #include <stdlib.h>  #include <stdlib.h>
30    #include <time.h>
31    
32  #define TITLE_INPUT_MAX_LEN 74  #define TITLE_INPUT_MAX_LEN 72
33  #define ARTICLE_CONTENT_MAX_LEN 1024 * 1024 * 4 // 4MB  #define ARTICLE_CONTENT_MAX_LEN 1024 * 1024 * 4 // 4MB
34  #define ARTICLE_QUOTE_MAX_LINES 20  #define ARTICLE_QUOTE_MAX_LINES 20
35  #define ARTICLE_QUOTE_LINE_MAX_LEN 76  #define ARTICLE_QUOTE_LINE_MAX_LEN 76
36    
37  int article_post(SECTION_LIST *p_section)  #define MODIFY_DT_MAX_LEN 50
38    
39    int article_post(const SECTION_LIST *p_section, ARTICLE *p_article_new)
40  {  {
41            MYSQL *db = NULL;
42            MYSQL_RES *rs = NULL;
43            MYSQL_ROW row;
44            char sql[SQL_BUFFER_LEN];
45            char *sql_content = NULL;
46          EDITOR_DATA *p_editor_data = NULL;          EDITOR_DATA *p_editor_data = NULL;
47          char title[BBS_article_title_max_len + 1];          char title_input[BBS_article_title_max_len + 1];
48          char title_input[TITLE_INPUT_MAX_LEN + 1];          char title_f[BBS_article_title_max_len * 2 + 1];
49            char *content = NULL;
50            char *content_f = NULL;
51            long len_content;
52            int content_display_length;
53            char nickname_f[BBS_nickname_max_len * 2 + 1];
54          int sign_id = 0;          int sign_id = 0;
55            int reply_note = 1;
56          long len;          long len;
57          int ch;          int ch;
58          char *p, *q;          char *p, *q;
59            long ret = 0;
60    
61          if (p_section == NULL)          if (p_section == NULL || p_article_new == NULL)
62          {          {
63                  log_error("NULL pointer error\n");                  log_error("NULL pointer error\n");
64          }          }
65    
66          title[0] = '\0';          if (!checkpriv(&BBS_priv, p_section->sid, S_POST))
67            {
68                    clearscr();
69                    moveto(1, 1);
70                    prints("您没有权限在本版块发表文章\n");
71                    press_any_key();
72    
73                    return 0;
74            }
75    
76            p_article_new->title[0] = '\0';
77          title_input[0] = '\0';          title_input[0] = '\0';
78            p_article_new->transship = 0;
79    
80          p_editor_data = editor_data_load("");          p_editor_data = editor_data_load("");
81          if (p_editor_data == NULL)          if (p_editor_data == NULL)
82          {          {
83                  log_error("editor_data_load() error\n");                  log_error("editor_data_load() error\n");
84                  return -2;                  ret = -1;
85                    goto cleanup;
86          }          }
87    
88          // Set title and sign          // Set title and sign
# Line 61  int article_post(SECTION_LIST *p_section Line 90  int article_post(SECTION_LIST *p_section
90          {          {
91                  clearscr();                  clearscr();
92                  moveto(21, 1);                  moveto(21, 1);
93                  prints(" %s[%s] ", p_section->stitle, p_section->sname);                  prints("发表文章于 %s[%s] 讨论区,类型: %s,回复通知:%s",
94                               p_section->stitle, p_section->sname,
95                               (p_article_new->transship ? "转载" : "原创"),
96                               (reply_note ? "开启" : "关闭"));
97                  moveto(22, 1);                  moveto(22, 1);
98                  prints(": %s", (title[0] == '\0' ? "[]" : title));                  prints("标题: %s", (p_article_new->title[0] == '\0' ? "[无]" : p_article_new->title));
99                  moveto(23, 1);                  moveto(23, 1);
100                  prints("ʹõ %d ǩ", sign_id);                  prints("使用第 %d 个签名", sign_id);
101    
102                  if (toupper(ch) != 'T')                  if (toupper(ch) != 'T')
103                  {                  {
104                          prints("    0~3ѡǩ(0ʾʹ)");                          prints("    按0~3选签名档(0表示不使用)");
105    
106                          moveto(24, 1);                          moveto(24, 1);
107                          prints("Tı, Cȡ, Enter: ");                          prints("T改标题, C取消, Z设为%s, N%s, Enter继续: ",
108                                       (p_article_new->transship ? "原创" : "转载"),
109                                       (reply_note ? "关闭回复通知" : "开启回复通知"));
110                          iflush();                          iflush();
111                          ch = 0;                          ch = 0;
112                  }                  }
# Line 81  int article_post(SECTION_LIST *p_section Line 115  int article_post(SECTION_LIST *p_section
115                  {                  {
116                          switch (toupper(ch))                          switch (toupper(ch))
117                          {                          {
118                            case KEY_NULL:
119                            case KEY_TIMEOUT:
120                                    goto cleanup;
121                          case CR:                          case CR:
                                 igetch_reset();  
122                                  break;                                  break;
123                          case 'T':                          case 'T':
124                                  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);  
125                                  for (p = title_input; *p == ' '; p++)                                  for (p = title_input; *p == ' '; p++)
126                                          ;                                          ;
127                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)
# Line 96  int article_post(SECTION_LIST *p_section Line 130  int article_post(SECTION_LIST *p_section
130                                  len = q - p;                                  len = q - p;
131                                  if (*p != '\0')                                  if (*p != '\0')
132                                  {                                  {
133                                          memcpy(title, p, (size_t)len + 1);                                          memcpy(p_article_new->title, p, (size_t)len + 1);
134                                          memcpy(title_input, title, (size_t)len + 1);                                          memcpy(title_input, p_article_new->title, (size_t)len + 1);
135                                  }                                  }
136                                  ch = 0;                                  ch = 0;
137                                  break;                                  break;
138                          case 'C':                          case 'C':
139                                  clearscr();                                  clearscr();
140                                  moveto(1, 1);                                  moveto(1, 1);
141                                  prints("ȡ...");                                  prints("取消...");
142                                  press_any_key();                                  press_any_key();
143                                  goto cleanup;                                  goto cleanup;
144                            case 'Z':
145                                    p_article_new->transship = (p_article_new->transship ? 0 : 1);
146                                    break;
147                            case 'N':
148                                    reply_note = (reply_note ? 0 : 1);
149                                    break;
150                          case '0':                          case '0':
151                          case '1':                          case '1':
152                          case '2':                          case '2':
# Line 120  int article_post(SECTION_LIST *p_section Line 160  int article_post(SECTION_LIST *p_section
160                          break;                          break;
161                  }                  }
162    
163                  if (ch != CR || title[0] == '\0')                  if (ch != CR || p_article_new->title[0] == '\0')
164                  {                  {
165                          continue;                          continue;
166                  }                  }
# Line 131  int article_post(SECTION_LIST *p_section Line 171  int article_post(SECTION_LIST *p_section
171    
172                          clearscr();                          clearscr();
173                          moveto(1, 1);                          moveto(1, 1);
174                          prints("(S), (C)ȡ, (T)ı or (E)ٱ༭? [S]: ");                          prints("(S)发送, (C)取消, (T)更改标题 or (E)再编辑? [S]: ");
175                          iflush();                          iflush();
176    
177                          for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))                          for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))
178                          {                          {
179                                  switch (toupper(ch))                                  switch (toupper(ch))
180                                  {                                  {
181                                    case KEY_NULL:
182                                    case KEY_TIMEOUT:
183                                            goto cleanup;
184                                  case CR:                                  case CR:
                                         igetch_reset();  
185                                  case 'S':                                  case 'S':
186                                          break;                                          break;
187                                  case 'C':                                  case 'C':
188                                          clearscr();                                          clearscr();
189                                          moveto(1, 1);                                          moveto(1, 1);
190                                          prints("ȡ...");                                          prints("取消...");
191                                          press_any_key();                                          press_any_key();
192                                          goto cleanup;                                          goto cleanup;
193                                  case 'T':                                  case 'T':
# Line 166  int article_post(SECTION_LIST *p_section Line 208  int article_post(SECTION_LIST *p_section
208                  }                  }
209          }          }
210    
211          // editor_data_save(p_editor_data, p_data_new, data_new_len);          if (SYS_server_exit) // Do not save data on shutdown
212          log_common("Debug: post article\n");          {
213                    goto cleanup;
214            }
215    
216            content = malloc(ARTICLE_CONTENT_MAX_LEN);
217            if (content == NULL)
218            {
219                    log_error("malloc(content) error: OOM\n");
220                    ret = -1;
221                    goto cleanup;
222            }
223    
224            len_content = editor_data_save(p_editor_data, content, ARTICLE_CONTENT_MAX_LEN);
225            if (len_content < 0)
226            {
227                    log_error("editor_data_save() error\n");
228                    ret = -1;
229                    goto cleanup;
230            }
231    
232            db = db_open();
233            if (db == NULL)
234            {
235                    log_error("db_open() error: %s\n", mysql_error(db));
236                    ret = -1;
237                    goto cleanup;
238            }
239    
240            if (sign_id > 0)
241            {
242                    snprintf(sql, sizeof(sql),
243                                     "SELECT sign_%d AS sign FROM user_pubinfo WHERE UID = %d",
244                                     sign_id, BBS_priv.uid);
245    
246                    if (mysql_query(db, sql) != 0)
247                    {
248                            log_error("Query sign error: %s\n", mysql_error(db));
249                            ret = -1;
250                            goto cleanup;
251                    }
252                    if ((rs = mysql_use_result(db)) == NULL)
253                    {
254                            log_error("Get sign data failed\n");
255                            ret = -1;
256                            goto cleanup;
257                    }
258    
259                    if ((row = mysql_fetch_row(rs)))
260                    {
261                            len_content += snprintf(content + len_content,
262                                                                            ARTICLE_CONTENT_MAX_LEN - (size_t)len_content,
263                                                                            "\n\n--\n%s\n", row[0]);
264                    }
265                    mysql_free_result(rs);
266                    rs = NULL;
267            }
268    
269            // Calculate display length of content
270            content_display_length = str_length(content, 1);
271    
272            // Begin transaction
273            if (mysql_query(db, "SET autocommit=0") != 0)
274            {
275                    log_error("SET autocommit=0 error: %s\n", mysql_error(db));
276                    ret = -1;
277                    goto cleanup;
278            }
279    
280            if (mysql_query(db, "BEGIN") != 0)
281            {
282                    log_error("Begin transaction error: %s\n", mysql_error(db));
283                    ret = -1;
284                    goto cleanup;
285            }
286    
287            // Secure SQL parameters
288            content_f = malloc((size_t)len_content * 2 + 1);
289            if (content_f == NULL)
290            {
291                    log_error("malloc(content_f) error: OOM\n");
292                    ret = -1;
293                    goto cleanup;
294            }
295    
296            mysql_real_escape_string(db, nickname_f, BBS_nickname, (unsigned long)strnlen(BBS_nickname, sizeof(BBS_nickname)));
297            mysql_real_escape_string(db, title_f, p_article_new->title, strnlen(p_article_new->title, sizeof(p_article_new->title)));
298            mysql_real_escape_string(db, content_f, content, (unsigned long)len_content);
299    
300            free(content);
301            content = NULL;
302    
303            // Add content
304            sql_content = malloc(SQL_BUFFER_LEN + (size_t)len_content * 2 + 1);
305            if (sql_content == NULL)
306            {
307                    log_error("malloc(sql_content) error: OOM\n");
308                    ret = -1;
309                    goto cleanup;
310            }
311    
312            snprintf(sql_content, SQL_BUFFER_LEN + (size_t)len_content * 2 + 1,
313                             "INSERT INTO bbs_content(AID, content) values(0, '%s')",
314                             content_f);
315    
316            free(content_f);
317            content_f = NULL;
318    
319            if (mysql_query(db, sql_content) != 0)
320            {
321                    log_error("Add article content error: %s\n", mysql_error(db));
322                    ret = -1;
323                    goto cleanup;
324            }
325    
326            p_article_new->cid = (int32_t)mysql_insert_id(db);
327    
328            free(sql_content);
329            sql_content = NULL;
330    
331            // Add article
332            snprintf(sql, sizeof(sql),
333                             "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "
334                             "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "
335                             "VALUES(%d, 0, %d, '%s', '%s', '%s', %d, %d, NOW(), '%s', %d, %d, NOW(), 1, %d)",
336                             p_section->sid, BBS_priv.uid, BBS_username, nickname_f, title_f,
337                             p_article_new->cid, p_article_new->transship, hostaddr_client,
338                             reply_note, BBS_user_exp, content_display_length);
339    
340            if (mysql_query(db, sql) != 0)
341            {
342                    log_error("Add article error: %s\n", mysql_error(db));
343                    ret = -1;
344                    goto cleanup;
345            }
346    
347            p_article_new->aid = (int32_t)mysql_insert_id(db);
348    
349            // Link content to article
350            snprintf(sql, sizeof(sql),
351                             "UPDATE bbs_content SET AID = %d WHERE CID = %d",
352                             p_article_new->aid, p_article_new->cid);
353    
354            if (mysql_query(db, sql) != 0)
355            {
356                    log_error("Update content error: %s\n", mysql_error(db));
357                    ret = -1;
358                    goto cleanup;
359            }
360    
361            // Add exp
362            if (checkpriv(&BBS_priv, p_section->sid, S_GETEXP)) // Except in test section
363            {
364                    snprintf(sql, sizeof(sql),
365                                     "UPDATE user_pubinfo SET exp = exp + %d WHERE UID = %d",
366                                     (p_article_new->transship ? 5 : 15), BBS_priv.uid);
367    
368                    if (mysql_query(db, sql) != 0)
369                    {
370                            log_error("Update exp error: %s\n", mysql_error(db));
371                            ret = -1;
372                            goto cleanup;
373                    }
374            }
375    
376            // Add log
377            snprintf(sql, sizeof(sql),
378                             "INSERT INTO bbs_article_op(AID, UID, type, op_dt, op_ip)"
379                             "VALUES(%d, %d, 'A', NOW(), '%s')",
380                             p_article_new->aid, BBS_priv.uid, hostaddr_client);
381    
382            if (mysql_query(db, sql) != 0)
383            {
384                    log_error("Add log error: %s\n", mysql_error(db));
385                    ret = -1;
386                    goto cleanup;
387            }
388    
389            // Commit transaction
390            if (mysql_query(db, "COMMIT") != 0)
391            {
392                    log_error("Commit transaction error: %s\n", mysql_error(db));
393                    ret = -1;
394                    goto cleanup;
395            }
396    
397            mysql_close(db);
398            db = NULL;
399    
400            clearscr();
401            moveto(1, 1);
402            prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval);
403            press_any_key();
404            ret = 1; // Success
405    
406  cleanup:  cleanup:
407            mysql_close(db);
408    
409            // Cleanup buffers
410          editor_data_cleanup(p_editor_data);          editor_data_cleanup(p_editor_data);
411    
412          return 0;          free(sql_content);
413            free(content);
414            free(content_f);
415    
416            return (int)ret;
417  }  }
418    
419  int article_modify(SECTION_LIST *p_section, ARTICLE *p_article)  int article_modify(const SECTION_LIST *p_section, const ARTICLE *p_article, ARTICLE *p_article_new)
420  {  {
421          MYSQL *db;          MYSQL *db = NULL;
422          MYSQL_RES *rs;          MYSQL_RES *rs = NULL;
423          MYSQL_ROW row;          MYSQL_ROW row;
424          char sql[SQL_BUFFER_LEN];          char sql[SQL_BUFFER_LEN];
425            char *sql_content = NULL;
426            char *content = NULL;
427            char *content_f = NULL;
428            long len_content;
429            int content_display_length;
430            int reply_note = 1;
431          int ch;          int ch;
432            long ret = 0;
433            time_t now;
434            struct tm tm_modify_dt;
435            char str_modify_dt[MODIFY_DT_MAX_LEN + 1];
436    
437          EDITOR_DATA *p_editor_data = NULL;          EDITOR_DATA *p_editor_data = NULL;
438    
# Line 190  int article_modify(SECTION_LIST *p_secti Line 441  int article_modify(SECTION_LIST *p_secti
441                  log_error("NULL pointer error\n");                  log_error("NULL pointer error\n");
442          }          }
443    
444            if (p_article->excerption) // Modify is not allowed
445            {
446                    clearscr();
447                    moveto(1, 1);
448                    prints("该文章无法被编辑,请联系版主。");
449                    press_any_key();
450    
451                    return 0;
452            }
453    
454          db = db_open();          db = db_open();
455          if (db == NULL)          if (db == NULL)
456          {          {
457                  log_error("db_open() error: %s\n", mysql_error(db));                  log_error("db_open() error: %s\n", mysql_error(db));
458                  return -1;                  ret = -1;
459                    goto cleanup;
460          }          }
461    
462          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
463                           "SELECT bbs_content.CID, bbs_content.content "                           "SELECT bbs_content.CID, bbs_content.content, reply_note "
464                           "FROM bbs INNER JOIN bbs_content ON bbs.CID = bbs_content.CID "                           "FROM bbs INNER JOIN bbs_content ON bbs.CID = bbs_content.CID "
465                           "WHERE bbs.AID = %d",                           "WHERE bbs.AID = %d",
466                           p_article->aid);                           p_article->aid);
# Line 206  int article_modify(SECTION_LIST *p_secti Line 468  int article_modify(SECTION_LIST *p_secti
468          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
469          {          {
470                  log_error("Query article content error: %s\n", mysql_error(db));                  log_error("Query article content error: %s\n", mysql_error(db));
471                  return -2;                  ret = -1;
472                    goto cleanup;
473          }          }
474          if ((rs = mysql_use_result(db)) == NULL)          if ((rs = mysql_use_result(db)) == NULL)
475          {          {
476                  log_error("Get article content data failed\n");                  log_error("Get article content data failed\n");
477                  return -2;                  ret = -1;
478                    goto cleanup;
479          }          }
480    
481          if ((row = mysql_fetch_row(rs)))          if ((row = mysql_fetch_row(rs)))
482          {          {
483                  p_editor_data = editor_data_load(row[1]);                  content = malloc(ARTICLE_CONTENT_MAX_LEN);
484                    if (content == NULL)
485                    {
486                            log_error("malloc(content) error: OOM\n");
487                            ret = -1;
488                            goto cleanup;
489                    }
490    
491                    strncpy(content, row[1], ARTICLE_CONTENT_MAX_LEN - 1);
492                    content[ARTICLE_CONTENT_MAX_LEN - 1] = '\0';
493    
494                    // Remove control sequence
495                    len_content = str_filter(content, 0);
496    
497                    p_editor_data = editor_data_load(content);
498                  if (p_editor_data == NULL)                  if (p_editor_data == NULL)
499                  {                  {
500                          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]));
501                          mysql_free_result(rs);                          ret = -1;
502                          mysql_close(db);                          goto cleanup;
                         return -3;  
503                  }                  }
504    
505                    free(content);
506                    content = NULL;
507    
508                    reply_note = atoi(row[2]);
509          }          }
510          mysql_free_result(rs);          mysql_free_result(rs);
511            rs = NULL;
512    
513          mysql_close(db);          mysql_close(db);
514            db = NULL;
515    
516          for (ch = 'E'; !SYS_server_exit && toupper(ch) == 'E';)          for (ch = 'E'; !SYS_server_exit && toupper(ch) == 'E';)
517          {          {
518                  editor_display(p_editor_data);                  editor_display(p_editor_data);
519    
520                  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))  
521                  {                  {
522                            clearscr();
523                            moveto(1, 1);
524                            prints("(S)保存, (C)取消, (N)%s回复通知 or (E)再编辑? [S]: ",
525                                       (reply_note ? "关闭" : "开启"));
526                            iflush();
527    
528                            ch = igetch_t(MAX_DELAY_TIME);
529                          switch (toupper(ch))                          switch (toupper(ch))
530                          {                          {
531                            case KEY_NULL:
532                            case KEY_TIMEOUT:
533                                    goto cleanup;
534                          case CR:                          case CR:
                                 igetch_reset();  
535                          case 'S':                          case 'S':
536                                  break;                                  break;
537                          case 'C':                          case 'C':
538                                  clearscr();                                  clearscr();
539                                  moveto(1, 1);                                  moveto(1, 1);
540                                  prints("ȡ...");                                  prints("取消...");
541                                  press_any_key();                                  press_any_key();
542                                  goto cleanup;                                  goto cleanup;
543                            case 'N':
544                                    reply_note = (reply_note ? 0 : 1);
545                                    continue;
546                          case 'E':                          case 'E':
547                                  break;                                  break;
548                          default: // Invalid selection                          default: // Invalid selection
# Line 261  int article_modify(SECTION_LIST *p_secti Line 553  int article_modify(SECTION_LIST *p_secti
553                  }                  }
554          }          }
555    
556          // editor_data_save(p_editor_data, p_data_new, data_new_len);          if (SYS_server_exit) // Do not save data on shutdown
557          log_common("Debug: modify article\n");          {
558                    goto cleanup;
559            }
560    
561            // Allocate buffers in big size
562            content = malloc(ARTICLE_CONTENT_MAX_LEN);
563            if (content == NULL)
564            {
565                    log_error("malloc(content) error: OOM\n");
566                    ret = -1;
567                    goto cleanup;
568            }
569    
570            len_content = editor_data_save(p_editor_data, content, ARTICLE_CONTENT_MAX_LEN - LINE_BUFFER_LEN);
571            if (len_content < 0)
572            {
573                    log_error("editor_data_save() error\n");
574                    ret = -1;
575                    goto cleanup;
576            }
577    
578            time(&now);
579            localtime_r(&now, &tm_modify_dt);
580            strftime(str_modify_dt, sizeof(str_modify_dt), "%Y-%m-%d %H:%M:%S (UTC %z)", &tm_modify_dt);
581    
582            len_content += snprintf(content + len_content, LINE_BUFFER_LEN,
583                                                            "\n--\n※ 作者已于 %s 修改本文※\n",
584                                                            str_modify_dt);
585    
586            // Calculate display length of content
587            content_display_length = str_length(content, 1);
588    
589            db = db_open();
590            if (db == NULL)
591            {
592                    log_error("db_open() error: %s\n", mysql_error(db));
593                    ret = -1;
594                    goto cleanup;
595            }
596    
597            // Begin transaction
598            if (mysql_query(db, "SET autocommit=0") != 0)
599            {
600                    log_error("SET autocommit=0 error: %s\n", mysql_error(db));
601                    ret = -1;
602                    goto cleanup;
603            }
604    
605            if (mysql_query(db, "BEGIN") != 0)
606            {
607                    log_error("Begin transaction error: %s\n", mysql_error(db));
608                    ret = -1;
609                    goto cleanup;
610            }
611    
612            // Secure SQL parameters
613            content_f = malloc((size_t)len_content * 2 + 1);
614            if (content_f == NULL)
615            {
616                    log_error("malloc(content_f) error: OOM\n");
617                    ret = -1;
618                    goto cleanup;
619            }
620    
621            mysql_real_escape_string(db, content_f, content, (unsigned long)len_content);
622    
623            free(content);
624            content = NULL;
625    
626            // Add content
627            sql_content = malloc(SQL_BUFFER_LEN + (size_t)len_content * 2 + 1);
628            if (sql_content == NULL)
629            {
630                    log_error("malloc(sql_content) error: OOM\n");
631                    ret = -1;
632                    goto cleanup;
633            }
634    
635            snprintf(sql_content, SQL_BUFFER_LEN + (size_t)len_content * 2 + 1,
636                             "INSERT INTO bbs_content(AID, content) values(%d, '%s')",
637                             p_article->aid, content_f);
638    
639            free(content_f);
640            content_f = NULL;
641    
642            if (mysql_query(db, sql_content) != 0)
643            {
644                    log_error("Add article content error: %s\n", mysql_error(db));
645                    ret = -1;
646                    goto cleanup;
647            }
648    
649            p_article_new->cid = (int32_t)mysql_insert_id(db);
650    
651            free(sql_content);
652            sql_content = NULL;
653    
654            // Update article
655            snprintf(sql, sizeof(sql),
656                             "UPDATE bbs SET CID = %d, length = %d, reply_note = %d, excerption = 0 WHERE AID = %d", // Set excerption = 0 explictly in case of rare condition
657                             p_article_new->cid, content_display_length, reply_note, p_article->aid);
658    
659            if (mysql_query(db, sql) != 0)
660            {
661                    log_error("Add article error: %s\n", mysql_error(db));
662                    ret = -1;
663                    goto cleanup;
664            }
665    
666            if (mysql_query(db, sql) != 0)
667            {
668                    log_error("Update content error: %s\n", mysql_error(db));
669                    ret = -1;
670                    goto cleanup;
671            }
672    
673            // Add log
674            snprintf(sql, sizeof(sql),
675                             "INSERT INTO bbs_article_op(AID, UID, type, op_dt, op_ip)"
676                             "VALUES(%d, %d, 'M', NOW(), '%s')",
677                             p_article->aid, BBS_priv.uid, hostaddr_client);
678    
679            if (mysql_query(db, sql) != 0)
680            {
681                    log_error("Add log error: %s\n", mysql_error(db));
682                    ret = -1;
683                    goto cleanup;
684            }
685    
686            // Commit transaction
687            if (mysql_query(db, "COMMIT") != 0)
688            {
689                    log_error("Commit transaction error: %s\n", mysql_error(db));
690                    ret = -1;
691                    goto cleanup;
692            }
693    
694            mysql_close(db);
695            db = NULL;
696    
697            clearscr();
698            moveto(1, 1);
699            prints("修改完成,新内容通常会在%d秒后可见", BBS_section_list_load_interval);
700            press_any_key();
701            ret = 1; // Success
702    
703  cleanup:  cleanup:
704            mysql_free_result(rs);
705            mysql_close(db);
706    
707            // Cleanup buffers
708          editor_data_cleanup(p_editor_data);          editor_data_cleanup(p_editor_data);
709    
710          return 0;          free(sql_content);
711            free(content);
712            free(content_f);
713    
714            return (int)ret;
715  }  }
716    
717  int article_reply(SECTION_LIST *p_section, ARTICLE *p_article)  int article_reply(const SECTION_LIST *p_section, const ARTICLE *p_article, ARTICLE *p_article_new)
718  {  {
719          MYSQL *db;          MYSQL *db = NULL;
720          MYSQL_RES *rs;          MYSQL_RES *rs = NULL;
721          MYSQL_ROW row;          MYSQL_ROW row;
         char sql[SQL_BUFFER_LEN];  
         char content[LINE_BUFFER_LEN * ARTICLE_QUOTE_MAX_LINES + 1];  
         char content_f[ARTICLE_CONTENT_MAX_LEN];  
722          long line_offsets[ARTICLE_QUOTE_MAX_LINES + 1];          long line_offsets[ARTICLE_QUOTE_MAX_LINES + 1];
723            char sql[SQL_BUFFER_LEN];
724            char *sql_content = NULL;
725          EDITOR_DATA *p_editor_data = NULL;          EDITOR_DATA *p_editor_data = NULL;
726          char title[BBS_article_title_max_len + 1];          char title_input[BBS_article_title_max_len + sizeof("Re: ")];
727          char title_input[BBS_article_title_max_len + 1 + 4]; // + "Re: "          char title_f[BBS_article_title_max_len * 2 + 1];
728            char *content = NULL;
729            char *content_f = NULL;
730            long len_content;
731            int content_display_length;
732            char nickname_f[BBS_nickname_max_len * 2 + 1];
733          int sign_id = 0;          int sign_id = 0;
734            int reply_note = 0;
735          long len;          long len;
736          int ch;          int ch;
737          char *p, *q;          char *p, *q;
# Line 290  int article_reply(SECTION_LIST *p_sectio Line 739  int article_reply(SECTION_LIST *p_sectio
739          int display_len;          int display_len;
740          long quote_content_lines;          long quote_content_lines;
741          long i;          long i;
742            long ret = 0;
743            int topic_locked = 0;
744            char msg[BBS_msg_max_len];
745            char msg_f[BBS_msg_max_len * 2 + 1];
746            int len_msg;
747    
748          if (p_section == NULL || p_article == NULL)          if (p_section == NULL || p_article == NULL)
749          {          {
750                  log_error("NULL pointer error\n");                  log_error("NULL pointer error\n");
751          }          }
752    
753          title[0] = '\0';          if (!checkpriv(&BBS_priv, p_section->sid, S_POST))
754            {
755                    clearscr();
756                    moveto(1, 1);
757                    prints("您没有权限在本版块发表文章\n");
758                    press_any_key();
759    
760                    return 0;
761            }
762    
763            p_article_new->title[0] = '\0';
764          snprintf(title_input, sizeof(title_input), "Re: %s", p_article->title);          snprintf(title_input, sizeof(title_input), "Re: %s", p_article->title);
765          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);
766          title_input[len] = '\0';          title_input[len] = '\0';
767    
768          db = db_open();          db = db_open();
769          if (db == NULL)          if (db == NULL)
770          {          {
771                  log_error("db_open() error: %s\n", mysql_error(db));                  log_error("db_open() error: %s\n", mysql_error(db));
772                  return -1;                  ret = -1;
773                    goto cleanup;
774            }
775    
776            snprintf(sql, sizeof(sql),
777                             "SELECT `lock` FROM bbs WHERE AID = %d",
778                             (p_article->tid == 0 ? p_article->aid : p_article->tid));
779    
780            if (mysql_query(db, sql) != 0)
781            {
782                    log_error("Query article status error: %s\n", mysql_error(db));
783                    ret = -1;
784                    goto cleanup;
785            }
786            if ((rs = mysql_store_result(db)) == NULL)
787            {
788                    log_error("Get article status data failed\n");
789                    ret = -1;
790                    goto cleanup;
791            }
792    
793            if ((row = mysql_fetch_row(rs)))
794            {
795                    if (atoi(row[0]) != 0)
796                    {
797                            topic_locked = 1;
798                    }
799            }
800            mysql_free_result(rs);
801            rs = NULL;
802    
803            if (topic_locked) // Reply is not allowed
804            {
805                    mysql_close(db);
806                    db = NULL;
807    
808                    clearscr();
809                    moveto(1, 1);
810                    prints("该主题谢绝回复");
811                    press_any_key();
812    
813                    goto cleanup;
814          }          }
815    
816          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
# Line 317  int article_reply(SECTION_LIST *p_sectio Line 822  int article_reply(SECTION_LIST *p_sectio
822          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
823          {          {
824                  log_error("Query article content error: %s\n", mysql_error(db));                  log_error("Query article content error: %s\n", mysql_error(db));
825                  return -2;                  ret = -1;
826                    goto cleanup;
827          }          }
828          if ((rs = mysql_use_result(db)) == NULL)          if ((rs = mysql_use_result(db)) == NULL)
829          {          {
830                  log_error("Get article content data failed\n");                  log_error("Get article content data failed\n");
831                  return -2;                  ret = -1;
832                    goto cleanup;
833          }          }
834    
835          if ((row = mysql_fetch_row(rs)))          if ((row = mysql_fetch_row(rs)))
836          {          {
837                    content = malloc(ARTICLE_CONTENT_MAX_LEN);
838                    if (content == NULL)
839                    {
840                            log_error("malloc(content) error: OOM\n");
841                            ret = -1;
842                            goto cleanup;
843                    }
844    
845                    content_f = malloc(ARTICLE_CONTENT_MAX_LEN);
846                    if (content_f == NULL)
847                    {
848                            log_error("malloc(content_f) error: OOM\n");
849                            ret = -1;
850                            goto cleanup;
851                    }
852    
853                  // Apply LML render to content body                  // Apply LML render to content body
854                  len = lml_plain(row[1], content_f, ARTICLE_CONTENT_MAX_LEN);                  len = lml_render(row[1], content_f, ARTICLE_CONTENT_MAX_LEN, 0);
855                  content_f[len] = '\0';                  content_f[len] = '\0';
856    
857                  // Remove control sequence                  // Remove control sequence
858                  len = ctrl_seq_filter(content_f);                  len = str_filter(content_f, 0);
859    
860                  len = snprintf(content, sizeof(content), "\n\n %s (%s) Ĵᵽ: \n", p_article->username, p_article->nickname);                  len = snprintf(content, ARTICLE_CONTENT_MAX_LEN,
861                                               "\n\n【 在 %s (%s) 的大作中提到: 】\n",
862                                               p_article->username, p_article->nickname);
863    
864                  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, ARTICLE_QUOTE_LINE_MAX_LEN, line_offsets, ARTICLE_QUOTE_MAX_LINES + 1, 0, NULL);
865                  for (i = 0; i < quote_content_lines; i++)                  for (i = 0; i < quote_content_lines; i++)
866                  {                  {
867                          memcpy(content + len, ": ", 2); // quote line prefix                          memcpy(content + len, ": ", 2); // quote line prefix
868                          len += 2;                          len += 2;
869                          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]));
870                          len += (line_offsets[i + 1] - line_offsets[i]);                          len += (line_offsets[i + 1] - line_offsets[i]);
871                            if (content[len - 1] != '\n') // Appennd \n if not exist
872                            {
873                                    content[len] = '\n';
874                                    len++;
875                            }
876                    }
877                    if (content[len - 1] != '\n') // Appennd \n if not exist
878                    {
879                            content[len] = '\n';
880                            len++;
881                  }                  }
882                  content[len] = '\0';                  content[len] = '\0';
883    
884                    free(content_f);
885                    content_f = NULL;
886    
887                    p_editor_data = editor_data_load(content);
888                    if (p_editor_data == NULL)
889                    {
890                            log_error("editor_data_load(aid=%d, cid=%d) error\n", p_article->aid, atoi(row[0]));
891                            ret = -1;
892                            goto cleanup;
893                    }
894    
895                    free(content);
896                    content = NULL;
897          }          }
898          mysql_free_result(rs);          mysql_free_result(rs);
899          mysql_close(db);          rs = NULL;
900    
901          p_editor_data = editor_data_load(content);          mysql_close(db);
902          if (p_editor_data == NULL)          db = NULL;
         {  
                 log_error("editor_data_load(aid=%d, cid=%d) error\n", p_article->aid, atoi(row[0]));  
                 return -3;  
         }  
903    
904          // Set title and sign          // Set title and sign
905          for (ch = 'T'; !SYS_server_exit;)          for (ch = 'T'; !SYS_server_exit;)
906          {          {
907                  clearscr();                  clearscr();
908                  moveto(21, 1);                  moveto(21, 1);
909                  prints("ظ %s[%s] ", p_section->stitle, p_section->sname);                  prints("回复文章于 %s[%s] 讨论区,回复通知:%s", p_section->stitle, p_section->sname, (reply_note ? "开启" : "关闭"));
910                  moveto(22, 1);                  moveto(22, 1);
911                  prints(": %s", (title[0] == '\0' ? "[]" : title));                  prints("标题: %s", (p_article_new->title[0] == '\0' ? "[无]" : p_article_new->title));
912                  moveto(23, 1);                  moveto(23, 1);
913                  prints("ʹõ %d ǩ", sign_id);                  prints("使用第 %d 个签名", sign_id);
914    
915                  if (toupper(ch) != 'T')                  if (toupper(ch) != 'T')
916                  {                  {
917                          prints("    0~3ѡǩ(0ʾʹ)");                          prints("    按0~3选签名档(0表示不使用)");
918    
919                          moveto(24, 1);                          moveto(24, 1);
920                          prints("Tı, Cȡ, Enter: ");                          prints("T改标题, C取消, N%s, Enter继续: ",
921                                       (reply_note ? "关闭回复通知" : "开启回复通知"));
922                          iflush();                          iflush();
923                          ch = 0;                          ch = 0;
924                  }                  }
# Line 381  int article_reply(SECTION_LIST *p_sectio Line 927  int article_reply(SECTION_LIST *p_sectio
927                  {                  {
928                          switch (toupper(ch))                          switch (toupper(ch))
929                          {                          {
930                            case KEY_NULL:
931                            case KEY_TIMEOUT:
932                                    goto cleanup;
933                          case CR:                          case CR:
                                 igetch_reset();  
934                                  break;                                  break;
935                          case 'T':                          case 'T':
936                                  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);  
937                                  for (p = title_input; *p == ' '; p++)                                  for (p = title_input; *p == ' '; p++)
938                                          ;                                          ;
939                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)                                  for (q = title_input + len; q > p && *(q - 1) == ' '; q--)
# Line 396  int article_reply(SECTION_LIST *p_sectio Line 942  int article_reply(SECTION_LIST *p_sectio
942                                  len = q - p;                                  len = q - p;
943                                  if (*p != '\0')                                  if (*p != '\0')
944                                  {                                  {
945                                          memcpy(title, p, (size_t)len + 1);                                          memcpy(p_article_new->title, p, (size_t)len + 1);
946                                          memcpy(title_input, title, (size_t)len + 1);                                          memcpy(title_input, p_article_new->title, (size_t)len + 1);
947                                  }                                  }
948                                  ch = 0;                                  ch = 0;
949                                  break;                                  break;
950                          case 'C':                          case 'C':
951                                  clearscr();                                  clearscr();
952                                  moveto(1, 1);                                  moveto(1, 1);
953                                  prints("ȡ...");                                  prints("取消...");
954                                  press_any_key();                                  press_any_key();
955                                  goto cleanup;                                  goto cleanup;
956                            case 'N':
957                                    reply_note = (reply_note ? 0 : 1);
958                                    break;
959                          case '0':                          case '0':
960                          case '1':                          case '1':
961                          case '2':                          case '2':
# Line 420  int article_reply(SECTION_LIST *p_sectio Line 969  int article_reply(SECTION_LIST *p_sectio
969                          break;                          break;
970                  }                  }
971    
972                  if (ch != CR || title[0] == '\0')                  if (ch != CR || p_article_new->title[0] == '\0')
973                  {                  {
974                          continue;                          continue;
975                  }                  }
# Line 431  int article_reply(SECTION_LIST *p_sectio Line 980  int article_reply(SECTION_LIST *p_sectio
980    
981                          clearscr();                          clearscr();
982                          moveto(1, 1);                          moveto(1, 1);
983                          prints("(S), (C)ȡ, (T)ı or (E)ٱ༭? [S]: ");                          prints("(S)发送, (C)取消, (T)更改标题 or (E)再编辑? [S]: ");
984                          iflush();                          iflush();
985    
986                          for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))                          for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))
987                          {                          {
988                                  switch (toupper(ch))                                  switch (toupper(ch))
989                                  {                                  {
990                                    case KEY_NULL:
991                                    case KEY_TIMEOUT:
992                                            goto cleanup;
993                                  case CR:                                  case CR:
                                         igetch_reset();  
994                                  case 'S':                                  case 'S':
995                                          break;                                          break;
996                                  case 'C':                                  case 'C':
997                                          clearscr();                                          clearscr();
998                                          moveto(1, 1);                                          moveto(1, 1);
999                                          prints("ȡ...");                                          prints("取消...");
1000                                          press_any_key();                                          press_any_key();
1001                                          goto cleanup;                                          goto cleanup;
1002                                  case 'T':                                  case 'T':
# Line 466  int article_reply(SECTION_LIST *p_sectio Line 1017  int article_reply(SECTION_LIST *p_sectio
1017                  }                  }
1018          }          }
1019    
1020          // editor_data_save(p_editor_data, p_data_new, data_new_len);          if (SYS_server_exit) // Do not save data on shutdown
1021          log_common("Debug: reply article\n");          {
1022                    goto cleanup;
1023            }
1024    
1025            content = malloc(ARTICLE_CONTENT_MAX_LEN);
1026            if (content == NULL)
1027            {
1028                    log_error("malloc(content) error: OOM\n");
1029                    ret = -1;
1030                    goto cleanup;
1031            }
1032    
1033            len_content = editor_data_save(p_editor_data, content, ARTICLE_CONTENT_MAX_LEN);
1034            if (len_content < 0)
1035            {
1036                    log_error("editor_data_save() error\n");
1037                    ret = -1;
1038                    goto cleanup;
1039            }
1040    
1041            db = db_open();
1042            if (db == NULL)
1043            {
1044                    log_error("db_open() error: %s\n", mysql_error(db));
1045                    ret = -1;
1046                    goto cleanup;
1047            }
1048    
1049            if (sign_id > 0)
1050            {
1051                    snprintf(sql, sizeof(sql),
1052                                     "SELECT sign_%d AS sign FROM user_pubinfo WHERE UID = %d",
1053                                     sign_id, BBS_priv.uid);
1054    
1055                    if (mysql_query(db, sql) != 0)
1056                    {
1057                            log_error("Query sign error: %s\n", mysql_error(db));
1058                            ret = -1;
1059                            goto cleanup;
1060                    }
1061                    if ((rs = mysql_use_result(db)) == NULL)
1062                    {
1063                            log_error("Get sign data failed\n");
1064                            ret = -1;
1065                            goto cleanup;
1066                    }
1067    
1068                    if ((row = mysql_fetch_row(rs)))
1069                    {
1070                            len_content += snprintf(content + len_content,
1071                                                                            ARTICLE_CONTENT_MAX_LEN - (size_t)len_content,
1072                                                                            "\n\n--\n%s\n", row[0]);
1073                    }
1074                    mysql_free_result(rs);
1075                    rs = NULL;
1076            }
1077    
1078            // Calculate display length of content
1079            content_display_length = str_length(content, 1);
1080    
1081            // Begin transaction
1082            if (mysql_query(db, "SET autocommit=0") != 0)
1083            {
1084                    log_error("SET autocommit=0 error: %s\n", mysql_error(db));
1085                    ret = -1;
1086                    goto cleanup;
1087            }
1088    
1089            if (mysql_query(db, "BEGIN") != 0)
1090            {
1091                    log_error("Begin transaction error: %s\n", mysql_error(db));
1092                    ret = -1;
1093                    goto cleanup;
1094            }
1095    
1096            // Secure SQL parameters
1097            content_f = malloc((size_t)len_content * 2 + 1);
1098            if (content_f == NULL)
1099            {
1100                    log_error("malloc(content_f) error: OOM\n");
1101                    ret = -1;
1102                    goto cleanup;
1103            }
1104    
1105            mysql_real_escape_string(db, nickname_f, BBS_nickname, (unsigned long)strnlen(BBS_nickname, sizeof(BBS_nickname)));
1106            mysql_real_escape_string(db, title_f, p_article_new->title, strnlen(p_article_new->title, sizeof(p_article_new->title)));
1107            mysql_real_escape_string(db, content_f, content, (unsigned long)len_content);
1108    
1109            free(content);
1110            content = NULL;
1111    
1112            // Add content
1113            sql_content = malloc(SQL_BUFFER_LEN + (size_t)len_content * 2 + 1);
1114            if (sql_content == NULL)
1115            {
1116                    log_error("malloc(sql_content) error: OOM\n");
1117                    ret = -1;
1118                    goto cleanup;
1119            }
1120    
1121            snprintf(sql_content, SQL_BUFFER_LEN + (size_t)len_content * 2 + 1,
1122                             "INSERT INTO bbs_content(AID, content) values(0, '%s')",
1123                             content_f);
1124    
1125            free(content_f);
1126            content_f = NULL;
1127    
1128            if (mysql_query(db, sql_content) != 0)
1129            {
1130                    log_error("Add article content error: %s\n", mysql_error(db));
1131                    ret = -1;
1132                    goto cleanup;
1133            }
1134    
1135            p_article_new->cid = (int32_t)mysql_insert_id(db);
1136    
1137            free(sql_content);
1138            sql_content = NULL;
1139    
1140            // Add article
1141            snprintf(sql, sizeof(sql),
1142                             "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "
1143                             "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "
1144                             "VALUES(%d, %d, %d, '%s', '%s', '%s', %d, 0, NOW(), '%s', %d, %d, NOW(), 1, %d)",
1145                             p_section->sid, (p_article->tid == 0 ? p_article->aid : p_article->tid),
1146                             BBS_priv.uid, BBS_username, nickname_f, title_f,
1147                             p_article_new->cid, hostaddr_client,
1148                             reply_note, BBS_user_exp, content_display_length);
1149    
1150            if (mysql_query(db, sql) != 0)
1151            {
1152                    log_error("Add article error: %s\n", mysql_error(db));
1153                    ret = -1;
1154                    goto cleanup;
1155            }
1156    
1157            p_article_new->aid = (int32_t)mysql_insert_id(db);
1158    
1159            // Update topic article
1160            snprintf(sql, sizeof(sql),
1161                             "UPDATE bbs SET reply_count = reply_count + 1, "
1162                             "last_reply_dt = NOW(), last_reply_UID=%d, last_reply_username = '%s', "
1163                             "last_reply_nickname = '%s' WHERE AID = %d",
1164                             BBS_priv.uid, BBS_username, nickname_f,
1165                             (p_article->tid == 0 ? p_article->aid : p_article->tid));
1166    
1167            if (mysql_query(db, sql) != 0)
1168            {
1169                    log_error("Update topic article error: %s\n", mysql_error(db));
1170                    ret = -1;
1171                    goto cleanup;
1172            }
1173    
1174            // Link content to article
1175            snprintf(sql, sizeof(sql),
1176                             "UPDATE bbs_content SET AID = %d WHERE CID = %d",
1177                             p_article_new->aid, p_article_new->cid);
1178    
1179            if (mysql_query(db, sql) != 0)
1180            {
1181                    log_error("Update content error: %s\n", mysql_error(db));
1182                    ret = -1;
1183                    goto cleanup;
1184            }
1185    
1186            // Notify the authors of the topic / article which is replyed.
1187            snprintf(sql, sizeof(sql),
1188                             "SELECT DISTINCT UID FROM bbs WHERE (AID = %d OR AID = %d) "
1189                             "AND visible AND reply_note AND UID <> %d",
1190                             p_article->tid, p_article->aid, BBS_priv.uid);
1191    
1192            if (mysql_query(db, sql) != 0)
1193            {
1194                    log_error("Read reply info error: %s\n", mysql_error(db));
1195                    ret = -1;
1196                    goto cleanup;
1197            }
1198            if ((rs = mysql_store_result(db)) == NULL)
1199            {
1200                    log_error("Get reply info failed\n");
1201                    ret = -1;
1202                    goto cleanup;
1203            }
1204    
1205            while ((row = mysql_fetch_row(rs)))
1206            {
1207                    // Send notification message
1208                    len_msg = snprintf(msg, BBS_msg_max_len,
1209                                                       "有人回复了您所发表/回复的文章,快来"
1210                                                       "[article %d]看看[/article]《%s》吧!\n",
1211                                                       p_article_new->aid, title_f);
1212    
1213                    mysql_real_escape_string(db, msg_f, msg, (unsigned long)len_msg);
1214    
1215                    snprintf(sql, sizeof(sql),
1216                                     "INSERT INTO bbs_msg(fromUID, toUID, content, send_dt, send_ip) "
1217                                     "VALUES(%d, %d, '%s', NOW(), '%s')",
1218                                     BBS_sys_id, atoi(row[0]), msg_f, hostaddr_client);
1219    
1220                    if (mysql_query(db, sql) != 0)
1221                    {
1222                            log_error("Insert msg error: %s\n", mysql_error(db));
1223                            ret = -1;
1224                            goto cleanup;
1225                    }
1226            }
1227            mysql_free_result(rs);
1228            rs = NULL;
1229    
1230            // Add exp
1231            if (checkpriv(&BBS_priv, p_section->sid, S_GETEXP)) // Except in test section
1232            {
1233                    snprintf(sql, sizeof(sql),
1234                                     "UPDATE user_pubinfo SET exp = exp + %d WHERE UID = %d",
1235                                     3, BBS_priv.uid);
1236    
1237                    if (mysql_query(db, sql) != 0)
1238                    {
1239                            log_error("Update exp error: %s\n", mysql_error(db));
1240                            ret = -1;
1241                            goto cleanup;
1242                    }
1243            }
1244    
1245            // Add log
1246            snprintf(sql, sizeof(sql),
1247                             "INSERT INTO bbs_article_op(AID, UID, type, op_dt, op_ip)"
1248                             "VALUES(%d, %d, 'A', NOW(), '%s')",
1249                             p_article_new->aid, BBS_priv.uid, hostaddr_client);
1250    
1251            if (mysql_query(db, sql) != 0)
1252            {
1253                    log_error("Add log error: %s\n", mysql_error(db));
1254                    ret = -1;
1255                    goto cleanup;
1256            }
1257    
1258            // Commit transaction
1259            if (mysql_query(db, "COMMIT") != 0)
1260            {
1261                    log_error("Commit transaction error: %s\n", mysql_error(db));
1262                    ret = -1;
1263                    goto cleanup;
1264            }
1265    
1266            mysql_close(db);
1267            db = NULL;
1268    
1269            clearscr();
1270            moveto(1, 1);
1271            prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval);
1272            press_any_key();
1273            ret = 1; // Success
1274    
1275  cleanup:  cleanup:
1276            mysql_free_result(rs);
1277            mysql_close(db);
1278    
1279            // Cleanup buffers
1280          editor_data_cleanup(p_editor_data);          editor_data_cleanup(p_editor_data);
1281    
1282          return 0;          free(sql_content);
1283            free(content);
1284            free(content_f);
1285    
1286            return (int)ret;
1287  }  }


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

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