/[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.6 by sysadm, Sat Jun 14 01:40:52 2025 UTC Revision 1.15 by sysadm, Sun Jun 15 02:24:45 2025 UTC
# Line 14  Line 14 
14   *                                                                         *   *                                                                         *
15   ***************************************************************************/   ***************************************************************************/
16    
17    #define _POSIX_C_SOURCE 200809L
18    
19  #include "article_post.h"  #include "article_post.h"
20  #include "article_cache.h"  #include "article_cache.h"
21  #include "editor.h"  #include "editor.h"
22  #include "screen.h"  #include "screen.h"
23    #include "bbs.h"
24  #include "log.h"  #include "log.h"
25  #include "io.h"  #include "io.h"
26  #include "lml.h"  #include "lml.h"
27  #include "database.h"  #include "database.h"
28    #include "user_priv.h"
29  #include <ctype.h>  #include <ctype.h>
30  #include <string.h>  #include <string.h>
31  #include <stdlib.h>  #include <stdlib.h>
32    #include <time.h>
33    
34  #define TITLE_INPUT_MAX_LEN 74  #define TITLE_INPUT_MAX_LEN 74
35  #define ARTICLE_CONTENT_MAX_LEN 1024 * 1024 * 4 // 4MB  #define ARTICLE_CONTENT_MAX_LEN 1024 * 1024 * 4 // 4MB
36  #define ARTICLE_QUOTE_MAX_LINES 20  #define ARTICLE_QUOTE_MAX_LINES 20
37  #define ARTICLE_QUOTE_LINE_MAX_LEN 76  #define ARTICLE_QUOTE_LINE_MAX_LEN 76
38    
39  int article_post(SECTION_LIST *p_section)  #define MODIFY_DT_MAX_LEN 50
40    
41    int article_post(const SECTION_LIST *p_section, ARTICLE *p_article_new)
42  {  {
43            MYSQL *db = NULL;
44            MYSQL_RES *rs = NULL;
45            MYSQL_ROW row;
46            char sql[SQL_BUFFER_LEN];
47            char *sql_content = NULL;
48          EDITOR_DATA *p_editor_data = NULL;          EDITOR_DATA *p_editor_data = NULL;
         char title[BBS_article_title_max_len + 1];  
49          char title_input[TITLE_INPUT_MAX_LEN + 1];          char title_input[TITLE_INPUT_MAX_LEN + 1];
50            char title_f[BBS_article_title_max_len * 2 + 1];
51            char *content = NULL;
52            char *content_f = NULL;
53            long len_content;
54            char nickname_f[BBS_nickname_max_len * 2 + 1];
55          int sign_id = 0;          int sign_id = 0;
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)
# Line 61  int article_post(SECTION_LIST *p_section Line 89  int article_post(SECTION_LIST *p_section
89          {          {
90                  clearscr();                  clearscr();
91                  moveto(21, 1);                  moveto(21, 1);
92                  prints("发表文章于 %s[%s] 讨论区", p_section->stitle, p_section->sname);                  prints("发表文章于 %s[%s] 讨论区,类型: %s", p_section->stitle, p_section->sname, (p_article_new->transship ? "转载" : "原创"));
93                  moveto(22, 1);                  moveto(22, 1);
94                  prints("标题: %s", (title[0] == '\0' ? "[无]" : title));                  prints("标题: %s", (p_article_new->title[0] == '\0' ? "[无]" : p_article_new->title));
95                  moveto(23, 1);                  moveto(23, 1);
96                  prints("使用第 %d 个签名", sign_id);                  prints("使用第 %d 个签名", sign_id);
97    
# Line 72  int article_post(SECTION_LIST *p_section Line 100  int article_post(SECTION_LIST *p_section
100                          prints("    按0~3选签名档(0表示不使用)");                          prints("    按0~3选签名档(0表示不使用)");
101    
102                          moveto(24, 1);                          moveto(24, 1);
103                          prints("T改标题, C取消, Enter继续: ");                          prints("T改标题, C取消, Z设为转载, Y设为原创, Enter继续: ");
104                          iflush();                          iflush();
105                          ch = 0;                          ch = 0;
106                  }                  }
# Line 96  int article_post(SECTION_LIST *p_section Line 124  int article_post(SECTION_LIST *p_section
124                                  len = q - p;                                  len = q - p;
125                                  if (*p != '\0')                                  if (*p != '\0')
126                                  {                                  {
127                                          memcpy(title, p, (size_t)len + 1);                                          memcpy(p_article_new->title, p, (size_t)len + 1);
128                                          memcpy(title_input, title, (size_t)len + 1);                                          memcpy(title_input, p_article_new->title, (size_t)len + 1);
129                                  }                                  }
130                                  ch = 0;                                  ch = 0;
131                                  break;                                  break;
# Line 107  int article_post(SECTION_LIST *p_section Line 135  int article_post(SECTION_LIST *p_section
135                                  prints("取消...");                                  prints("取消...");
136                                  press_any_key();                                  press_any_key();
137                                  goto cleanup;                                  goto cleanup;
138                            case 'Y':
139                                    p_article_new->transship = 0;
140                                    break;
141                            case 'Z':
142                                    p_article_new->transship = 1;
143                                    break;
144                          case '0':                          case '0':
145                          case '1':                          case '1':
146                          case '2':                          case '2':
# Line 120  int article_post(SECTION_LIST *p_section Line 154  int article_post(SECTION_LIST *p_section
154                          break;                          break;
155                  }                  }
156    
157                  if (ch != CR || title[0] == '\0')                  if (ch != CR || p_article_new->title[0] == '\0')
158                  {                  {
159                          continue;                          continue;
160                  }                  }
# Line 166  int article_post(SECTION_LIST *p_section Line 200  int article_post(SECTION_LIST *p_section
200                  }                  }
201          }          }
202    
203          // editor_data_save(p_editor_data, p_data_new, data_new_len);          content = malloc(ARTICLE_CONTENT_MAX_LEN);
204          log_common("Debug: post article\n");          if (content == NULL)
205            {
206                    log_error("malloc(content) error: OOM\n");
207                    ret = -1;
208                    goto cleanup;
209            }
210    
211            len_content = editor_data_save(p_editor_data, content, ARTICLE_CONTENT_MAX_LEN);
212            if (len_content < 0)
213            {
214                    log_error("editor_data_save() error\n");
215                    ret = -2;
216                    goto cleanup;
217            }
218    
219            db = db_open();
220            if (db == NULL)
221            {
222                    log_error("db_open() error: %s\n", mysql_error(db));
223                    ret = -1;
224                    goto cleanup;
225            }
226    
227            if (sign_id > 0)
228            {
229                    snprintf(sql, sizeof(sql),
230                                     "SELECT sign_%d AS sign FROM user_pubinfo WHERE UID = %d",
231                                     sign_id, BBS_priv.uid);
232    
233                    if (mysql_query(db, sql) != 0)
234                    {
235                            log_error("Query sign error: %s\n", mysql_error(db));
236                            ret = -1;
237                            goto cleanup;
238                    }
239                    if ((rs = mysql_use_result(db)) == NULL)
240                    {
241                            log_error("Get sign data failed\n");
242                            ret = -1;
243                            goto cleanup;
244                    }
245    
246                    if ((row = mysql_fetch_row(rs)))
247                    {
248                            len_content += snprintf(content + len_content,
249                                                                            ARTICLE_CONTENT_MAX_LEN - (size_t)len_content,
250                                                                            "\n\n--\n%s\n", row[0]);
251                    }
252                    mysql_free_result(rs);
253                    rs = NULL;
254            }
255    
256            // Begin transaction
257            if (mysql_query(db, "SET autocommit=0") != 0)
258            {
259                    log_error("SET autocommit=0 error: %s\n", mysql_error(db));
260                    ret = -1;
261                    goto cleanup;
262            }
263    
264            if (mysql_query(db, "BEGIN") != 0)
265            {
266                    log_error("Begin transaction error: %s\n", mysql_error(db));
267                    ret = -1;
268                    goto cleanup;
269            }
270    
271            // Secure SQL parameters
272            content_f = malloc((size_t)len_content * 2 + 1);
273            if (content_f == NULL)
274            {
275                    log_error("malloc(content_f) error: OOM\n");
276                    ret = -1;
277                    goto cleanup;
278            }
279    
280            mysql_real_escape_string(db, nickname_f, BBS_nickname, (unsigned long)strnlen(BBS_nickname, sizeof(BBS_nickname)));
281            mysql_real_escape_string(db, title_f, p_article_new->title, strnlen(p_article_new->title, sizeof(p_article_new->title)));
282            mysql_real_escape_string(db, content_f, content, (unsigned long)len_content);
283    
284            free(content);
285            content = NULL;
286    
287            // Add content
288            sql_content = malloc(SQL_BUFFER_LEN + (size_t)len_content * 2 + 1);
289            if (sql_content == NULL)
290            {
291                    log_error("malloc(sql_content) error: OOM\n");
292                    ret = -1;
293                    goto cleanup;
294            }
295    
296            snprintf(sql_content, SQL_BUFFER_LEN + (size_t)len_content * 2 + 1,
297                             "INSERT INTO bbs_content(AID, content) values(0, '%s')",
298                             content_f);
299    
300            free(content_f);
301            content_f = NULL;
302    
303            if (mysql_query(db, sql_content) != 0)
304            {
305                    log_error("Add article content error: %s\n", mysql_error(db));
306                    ret = -1;
307                    goto cleanup;
308            }
309    
310            p_article_new->cid = (int32_t)mysql_insert_id(db);
311    
312            free(sql_content);
313            sql_content = NULL;
314    
315            // Add article
316            snprintf(sql, sizeof(sql),
317                             "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "
318                             "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "
319                             "VALUES(%d, 0, %d, '%s', '%s', '%s', %d, %d, NOW(), '%s', 1, %d, NOW(), 1, %ld)",
320                             p_section->sid, BBS_priv.uid, BBS_username, nickname_f, title_f,
321                             p_article_new->cid, p_article_new->transship, hostaddr_client, BBS_user_exp, len_content);
322    
323            if (mysql_query(db, sql) != 0)
324            {
325                    log_error("Add article error: %s\n", mysql_error(db));
326                    ret = -1;
327                    goto cleanup;
328            }
329    
330            p_article_new->aid = (int32_t)mysql_insert_id(db);
331    
332            // Link content to article
333            snprintf(sql, sizeof(sql),
334                             "UPDATE bbs_content SET AID = %d WHERE CID = %d",
335                             p_article_new->aid, p_article_new->cid);
336    
337            if (mysql_query(db, sql) != 0)
338            {
339                    log_error("Update content error: %s\n", mysql_error(db));
340                    ret = -1;
341                    goto cleanup;
342            }
343    
344            // Add exp
345            if (checkpriv(&BBS_priv, p_section->sid, S_GETEXP)) // Except in test section
346            {
347                    snprintf(sql, sizeof(sql),
348                                     "UPDATE user_pubinfo SET exp = exp + %d WHERE UID = %d",
349                                     (p_article_new->transship ? 5 : 15), BBS_priv.uid);
350    
351                    if (mysql_query(db, sql) != 0)
352                    {
353                            log_error("Update exp error: %s\n", mysql_error(db));
354                            ret = -1;
355                            goto cleanup;
356                    }
357            }
358    
359            // Add log
360            snprintf(sql, sizeof(sql),
361                             "INSERT INTO bbs_article_op(AID, UID, type, op_dt, op_ip)"
362                             "VALUES(%d, %d, 'A', NOW(), '%s')",
363                             p_article_new->aid, BBS_priv.uid, hostaddr_client);
364    
365            if (mysql_query(db, sql) != 0)
366            {
367                    log_error("Add log error: %s\n", mysql_error(db));
368                    ret = -1;
369                    goto cleanup;
370            }
371    
372            // Commit transaction
373            if (mysql_query(db, "COMMIT") != 0)
374            {
375                    log_error("Commit transaction error: %s\n", mysql_error(db));
376                    ret = -1;
377                    goto cleanup;
378            }
379    
380            clearscr();
381            moveto(1, 1);
382            prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval);
383            press_any_key();
384            ret = 1; // Success
385    
386  cleanup:  cleanup:
387            mysql_close(db);
388    
389            // Cleanup buffers
390          editor_data_cleanup(p_editor_data);          editor_data_cleanup(p_editor_data);
391    
392          return 0;          free(sql_content);
393            free(content);
394            free(content_f);
395    
396            return (int)ret;
397  }  }
398    
399  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)
400  {  {
401          MYSQL *db;          MYSQL *db = NULL;
402          MYSQL_RES *rs;          MYSQL_RES *rs = NULL;
403          MYSQL_ROW row;          MYSQL_ROW row;
404          char sql[SQL_BUFFER_LEN];          char sql[SQL_BUFFER_LEN];
405            char *sql_content = NULL;
406            char *content = NULL;
407            char *content_f = NULL;
408            long len_content;
409          int ch;          int ch;
410            long ret = 0;
411            time_t now;
412            struct tm tm_modify_dt;
413            char str_modify_dt[MODIFY_DT_MAX_LEN + 1];
414    
415          EDITOR_DATA *p_editor_data = NULL;          EDITOR_DATA *p_editor_data = NULL;
416    
# Line 190  int article_modify(SECTION_LIST *p_secti Line 419  int article_modify(SECTION_LIST *p_secti
419                  log_error("NULL pointer error\n");                  log_error("NULL pointer error\n");
420          }          }
421    
422            if (p_article->excerption) // Modify is not allowed
423            {
424                    clearscr();
425                    moveto(1, 1);
426                    prints("该文章无法被编辑,请联系版主。");
427                    press_any_key();
428    
429                    return 0;
430            }
431    
432            if (!checkpriv(&BBS_priv, p_section->sid, S_POST))
433            {
434                    clearscr();
435                    moveto(1, 1);
436                    prints("您没有权限在本版块发表文章\n");
437                    press_any_key();
438    
439                    return 0;
440            }
441    
442          db = db_open();          db = db_open();
443          if (db == NULL)          if (db == NULL)
444          {          {
# Line 206  int article_modify(SECTION_LIST *p_secti Line 455  int article_modify(SECTION_LIST *p_secti
455          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
456          {          {
457                  log_error("Query article content error: %s\n", mysql_error(db));                  log_error("Query article content error: %s\n", mysql_error(db));
458                  return -2;                  ret = -2;
459                    goto cleanup;
460          }          }
461          if ((rs = mysql_use_result(db)) == NULL)          if ((rs = mysql_use_result(db)) == NULL)
462          {          {
463                  log_error("Get article content data failed\n");                  log_error("Get article content data failed\n");
464                  return -2;                  ret = -2;
465                    goto cleanup;
466          }          }
467    
468          if ((row = mysql_fetch_row(rs)))          if ((row = mysql_fetch_row(rs)))
469          {          {
470                  p_editor_data = editor_data_load(row[1]);                  content = malloc(ARTICLE_CONTENT_MAX_LEN);
471                    if (content == NULL)
472                    {
473                            log_error("malloc(content) error: OOM\n");
474                            ret = -1;
475                            goto cleanup;
476                    }
477    
478                    strncpy(content, row[1], ARTICLE_CONTENT_MAX_LEN - 1);
479                    content[ARTICLE_CONTENT_MAX_LEN - 1] = '\0';
480    
481                    // Remove control sequence
482                    len_content = ctrl_seq_filter(content);
483    
484                    p_editor_data = editor_data_load(content);
485                  if (p_editor_data == NULL)                  if (p_editor_data == NULL)
486                  {                  {
487                          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]));
488                          mysql_free_result(rs);                          ret = -3;
489                          mysql_close(db);                          goto cleanup;
                         return -3;  
490                  }                  }
491    
492                    free(content);
493                    content = NULL;
494          }          }
495          mysql_free_result(rs);          mysql_free_result(rs);
496            rs = NULL;
497    
498          mysql_close(db);          mysql_close(db);
499            db = NULL;
500    
501          for (ch = 'E'; !SYS_server_exit && toupper(ch) == 'E';)          for (ch = 'E'; !SYS_server_exit && toupper(ch) == 'E';)
502          {          {
# Line 261  int article_modify(SECTION_LIST *p_secti Line 531  int article_modify(SECTION_LIST *p_secti
531                  }                  }
532          }          }
533    
534          // editor_data_save(p_editor_data, p_data_new, data_new_len);          // Allocate buffers in big size
535          log_common("Debug: modify article\n");          content = malloc(ARTICLE_CONTENT_MAX_LEN);
536            if (content == NULL)
537            {
538                    log_error("malloc(content) error: OOM\n");
539                    ret = -1;
540                    goto cleanup;
541            }
542    
543            len_content = editor_data_save(p_editor_data, content, ARTICLE_CONTENT_MAX_LEN - LINE_BUFFER_LEN);
544            if (len_content < 0)
545            {
546                    log_error("editor_data_save() error\n");
547                    ret = -2;
548                    goto cleanup;
549            }
550    
551            time(&now);
552            localtime_r(&now, &tm_modify_dt);
553            strftime(str_modify_dt, sizeof(str_modify_dt), "%Y-%m-%d %H:%M:%S (UTC %z)", &tm_modify_dt);
554    
555            len_content += snprintf(content + len_content, LINE_BUFFER_LEN,
556                                                            "\n--\n※ 作者已于 %s 修改本文※\n",
557                                                            str_modify_dt);
558    
559            db = db_open();
560            if (db == NULL)
561            {
562                    log_error("db_open() error: %s\n", mysql_error(db));
563                    ret = -1;
564                    goto cleanup;
565            }
566    
567            // Begin transaction
568            if (mysql_query(db, "SET autocommit=0") != 0)
569            {
570                    log_error("SET autocommit=0 error: %s\n", mysql_error(db));
571                    ret = -1;
572                    goto cleanup;
573            }
574    
575            if (mysql_query(db, "BEGIN") != 0)
576            {
577                    log_error("Begin transaction error: %s\n", mysql_error(db));
578                    ret = -1;
579                    goto cleanup;
580            }
581    
582            // Secure SQL parameters
583            content_f = malloc((size_t)len_content * 2 + 1);
584            if (content_f == NULL)
585            {
586                    log_error("malloc(content_f) error: OOM\n");
587                    ret = -1;
588                    goto cleanup;
589            }
590    
591            mysql_real_escape_string(db, content_f, content, (unsigned long)len_content);
592    
593            free(content);
594            content = NULL;
595    
596            // Add content
597            sql_content = malloc(SQL_BUFFER_LEN + (size_t)len_content * 2 + 1);
598            if (sql_content == NULL)
599            {
600                    log_error("malloc(sql_content) error: OOM\n");
601                    ret = -1;
602                    goto cleanup;
603            }
604    
605            snprintf(sql_content, SQL_BUFFER_LEN + (size_t)len_content * 2 + 1,
606                             "INSERT INTO bbs_content(AID, content) values(%d, '%s')",
607                             p_article->aid, content_f);
608    
609            free(content_f);
610            content_f = NULL;
611    
612            if (mysql_query(db, sql_content) != 0)
613            {
614                    log_error("Add article content error: %s\n", mysql_error(db));
615                    ret = -1;
616                    goto cleanup;
617            }
618    
619            p_article_new->cid = (int32_t)mysql_insert_id(db);
620    
621            free(sql_content);
622            sql_content = NULL;
623    
624            // Update article
625            snprintf(sql, sizeof(sql),
626                             "UPDATE bbs SET CID = %d, length = %ld, excerption = 0 WHERE AID = %d", // Set excerption = 0 explictly in case of rare condition
627                             p_article_new->cid, len_content, p_article->aid);
628    
629            if (mysql_query(db, sql) != 0)
630            {
631                    log_error("Add article error: %s\n", mysql_error(db));
632                    ret = -1;
633                    goto cleanup;
634            }
635    
636            if (mysql_query(db, sql) != 0)
637            {
638                    log_error("Update content error: %s\n", mysql_error(db));
639                    ret = -1;
640                    goto cleanup;
641            }
642    
643            // Add log
644            snprintf(sql, sizeof(sql),
645                             "INSERT INTO bbs_article_op(AID, UID, type, op_dt, op_ip)"
646                             "VALUES(%d, %d, 'M', NOW(), '%s')",
647                             p_article->aid, BBS_priv.uid, hostaddr_client);
648    
649            if (mysql_query(db, sql) != 0)
650            {
651                    log_error("Add log error: %s\n", mysql_error(db));
652                    ret = -1;
653                    goto cleanup;
654            }
655    
656            // Commit transaction
657            if (mysql_query(db, "COMMIT") != 0)
658            {
659                    log_error("Commit transaction error: %s\n", mysql_error(db));
660                    ret = -1;
661                    goto cleanup;
662            }
663    
664            clearscr();
665            moveto(1, 1);
666            prints("修改完成,新内容通常会在%d秒后可见", BBS_section_list_load_interval);
667            press_any_key();
668            ret = 1; // Success
669    
670  cleanup:  cleanup:
671            mysql_free_result(rs);
672            mysql_close(db);
673    
674            // Cleanup buffers
675          editor_data_cleanup(p_editor_data);          editor_data_cleanup(p_editor_data);
676    
677          return 0;          free(sql_content);
678            free(content);
679            free(content_f);
680    
681            return (int)ret;
682  }  }
683    
684  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)
685  {  {
686          MYSQL *db;          MYSQL *db = NULL;
687          MYSQL_RES *rs;          MYSQL_RES *rs = NULL;
688          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];  
689          long line_offsets[ARTICLE_QUOTE_MAX_LINES + 1];          long line_offsets[ARTICLE_QUOTE_MAX_LINES + 1];
690            char sql[SQL_BUFFER_LEN];
691            char *sql_content = NULL;
692          EDITOR_DATA *p_editor_data = NULL;          EDITOR_DATA *p_editor_data = NULL;
693          char title[BBS_article_title_max_len + 1];          char title_input[BBS_article_title_max_len + sizeof("Re: ")];
694          char title_input[BBS_article_title_max_len + 1 + 4]; // + "Re: "          char title_f[BBS_article_title_max_len * 2 + 1];
695            char *content = NULL;
696            char *content_f = NULL;
697            long len_content;
698            char nickname_f[BBS_nickname_max_len * 2 + 1];
699          int sign_id = 0;          int sign_id = 0;
700          long len;          long len;
701          int ch;          int ch;
# Line 290  int article_reply(SECTION_LIST *p_sectio Line 704  int article_reply(SECTION_LIST *p_sectio
704          int display_len;          int display_len;
705          long quote_content_lines;          long quote_content_lines;
706          long i;          long i;
707            long ret = 0;
708            int topic_locked = 0;
709    
710          if (p_section == NULL || p_article == NULL)          if (p_section == NULL || p_article == NULL)
711          {          {
712                  log_error("NULL pointer error\n");                  log_error("NULL pointer error\n");
713          }          }
714    
715          title[0] = '\0';          if (!checkpriv(&BBS_priv, p_section->sid, S_POST))
716            {
717                    clearscr();
718                    moveto(1, 1);
719                    prints("您没有权限在本版块发表文章\n");
720                    press_any_key();
721    
722                    return 0;
723            }
724    
725            p_article_new->title[0] = '\0';
726          snprintf(title_input, sizeof(title_input), "Re: %s", p_article->title);          snprintf(title_input, sizeof(title_input), "Re: %s", p_article->title);
727          len = split_line(title_input, TITLE_INPUT_MAX_LEN, &eol, &display_len);          len = split_line(title_input, TITLE_INPUT_MAX_LEN, &eol, &display_len);
728          title_input[len] = '\0';          title_input[len] = '\0';
# Line 309  int article_reply(SECTION_LIST *p_sectio Line 735  int article_reply(SECTION_LIST *p_sectio
735          }          }
736    
737          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
738                             "SELECT `lock` FROM bbs WHERE AID = %d",
739                             (p_article->tid == 0 ? p_article->aid : p_article->tid));
740    
741            if (mysql_query(db, sql) != 0)
742            {
743                    log_error("Query article status error: %s\n", mysql_error(db));
744                    return -2;
745            }
746            if ((rs = mysql_store_result(db)) == NULL)
747            {
748                    log_error("Get article status data failed\n");
749                    return -2;
750            }
751    
752            if ((row = mysql_fetch_row(rs)))
753            {
754                    if (atoi(row[0]) != 0)
755                    {
756                            topic_locked = 1;
757                    }
758            }
759            mysql_free_result(rs);
760            rs = NULL;
761    
762            if (topic_locked) // Reply is not allowed
763            {
764                    clearscr();
765                    moveto(1, 1);
766                    prints("该主题谢绝回复");
767                    press_any_key();
768    
769                    goto cleanup;
770            }
771    
772            snprintf(sql, sizeof(sql),
773                           "SELECT bbs_content.CID, bbs_content.content "                           "SELECT bbs_content.CID, bbs_content.content "
774                           "FROM bbs INNER JOIN bbs_content ON bbs.CID = bbs_content.CID "                           "FROM bbs INNER JOIN bbs_content ON bbs.CID = bbs_content.CID "
775                           "WHERE bbs.AID = %d",                           "WHERE bbs.AID = %d",
# Line 327  int article_reply(SECTION_LIST *p_sectio Line 788  int article_reply(SECTION_LIST *p_sectio
788    
789          if ((row = mysql_fetch_row(rs)))          if ((row = mysql_fetch_row(rs)))
790          {          {
791                    content = malloc(ARTICLE_CONTENT_MAX_LEN);
792                    if (content == NULL)
793                    {
794                            log_error("malloc(content) error: OOM\n");
795                            ret = -1;
796                            goto cleanup;
797                    }
798    
799                    content_f = malloc(ARTICLE_CONTENT_MAX_LEN);
800                    if (content_f == NULL)
801                    {
802                            log_error("malloc(content_f) error: OOM\n");
803                            ret = -1;
804                            goto cleanup;
805                    }
806    
807                  // Apply LML render to content body                  // Apply LML render to content body
808                  len = lml_plain(row[1], content_f, ARTICLE_CONTENT_MAX_LEN);                  len = lml_plain(row[1], content_f, ARTICLE_CONTENT_MAX_LEN);
809                  content_f[len] = '\0';                  content_f[len] = '\0';
810    
811                    // Remove control sequence
812                    len = ctrl_seq_filter(content_f);
813    
814                    len = snprintf(content, ARTICLE_CONTENT_MAX_LEN,
815                                               "\n\n【 在 %s (%s) 的大作中提到: 】\n",
816                                               p_article->username, p_article->nickname);
817    
818                  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);
819                  for (i = 0, len = 0; i < quote_content_lines; i++)                  for (i = 0; i < quote_content_lines; i++)
820                  {                  {
821                          memcpy(content + len, ": ", 2); // quote line prefix                          memcpy(content + len, ": ", 2); // quote line prefix
822                          len += 2;                          len += 2;
823                          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]));
824                          len += (line_offsets[i + 1] - line_offsets[i]);                          len += (line_offsets[i + 1] - line_offsets[i]);
825                  }                  }
826                    if (content[len - 1] != '\n') // Appennd \n if not exist
827                    {
828                            content[len] = '\n';
829                            len++;
830                    }
831                  content[len] = '\0';                  content[len] = '\0';
832    
833                    free(content_f);
834                    content_f = NULL;
835    
836                    p_editor_data = editor_data_load(content);
837                    if (p_editor_data == NULL)
838                    {
839                            log_error("editor_data_load(aid=%d, cid=%d) error\n", p_article->aid, atoi(row[0]));
840                            ret = -3;
841                            goto cleanup;
842                    }
843    
844                    free(content);
845                    content = NULL;
846          }          }
847          mysql_free_result(rs);          mysql_free_result(rs);
848          mysql_close(db);          rs = NULL;
849    
850          p_editor_data = editor_data_load(content);          mysql_close(db);
851          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;  
         }  
852    
853          // Set title and sign          // Set title and sign
854          for (ch = 'T'; !SYS_server_exit;)          for (ch = 'T'; !SYS_server_exit;)
# Line 358  int article_reply(SECTION_LIST *p_sectio Line 857  int article_reply(SECTION_LIST *p_sectio
857                  moveto(21, 1);                  moveto(21, 1);
858                  prints("回复文章于 %s[%s] 讨论区", p_section->stitle, p_section->sname);                  prints("回复文章于 %s[%s] 讨论区", p_section->stitle, p_section->sname);
859                  moveto(22, 1);                  moveto(22, 1);
860                  prints("标题: %s", (title[0] == '\0' ? "[无]" : title));                  prints("标题: %s", (p_article_new->title[0] == '\0' ? "[无]" : p_article_new->title));
861                  moveto(23, 1);                  moveto(23, 1);
862                  prints("使用第 %d 个签名", sign_id);                  prints("使用第 %d 个签名", sign_id);
863    
# Line 391  int article_reply(SECTION_LIST *p_sectio Line 890  int article_reply(SECTION_LIST *p_sectio
890                                  len = q - p;                                  len = q - p;
891                                  if (*p != '\0')                                  if (*p != '\0')
892                                  {                                  {
893                                          memcpy(title, p, (size_t)len + 1);                                          memcpy(p_article_new->title, p, (size_t)len + 1);
894                                          memcpy(title_input, title, (size_t)len + 1);                                          memcpy(title_input, p_article_new->title, (size_t)len + 1);
895                                  }                                  }
896                                  ch = 0;                                  ch = 0;
897                                  break;                                  break;
# Line 415  int article_reply(SECTION_LIST *p_sectio Line 914  int article_reply(SECTION_LIST *p_sectio
914                          break;                          break;
915                  }                  }
916    
917                  if (ch != CR || title[0] == '\0')                  if (ch != CR || p_article_new->title[0] == '\0')
918                  {                  {
919                          continue;                          continue;
920                  }                  }
# Line 461  int article_reply(SECTION_LIST *p_sectio Line 960  int article_reply(SECTION_LIST *p_sectio
960                  }                  }
961          }          }
962    
963          // editor_data_save(p_editor_data, p_data_new, data_new_len);          content = malloc(ARTICLE_CONTENT_MAX_LEN);
964          log_common("Debug: reply article\n");          if (content == NULL)
965            {
966                    log_error("malloc(content) error: OOM\n");
967                    ret = -1;
968                    goto cleanup;
969            }
970    
971            len_content = editor_data_save(p_editor_data, content, ARTICLE_CONTENT_MAX_LEN);
972            if (len_content < 0)
973            {
974                    log_error("editor_data_save() error\n");
975                    ret = -2;
976                    goto cleanup;
977            }
978    
979            db = db_open();
980            if (db == NULL)
981            {
982                    log_error("db_open() error: %s\n", mysql_error(db));
983                    ret = -1;
984                    goto cleanup;
985            }
986    
987            if (sign_id > 0)
988            {
989                    snprintf(sql, sizeof(sql),
990                                     "SELECT sign_%d AS sign FROM user_pubinfo WHERE UID = %d",
991                                     sign_id, BBS_priv.uid);
992    
993                    if (mysql_query(db, sql) != 0)
994                    {
995                            log_error("Query sign error: %s\n", mysql_error(db));
996                            ret = -1;
997                            goto cleanup;
998                    }
999                    if ((rs = mysql_use_result(db)) == NULL)
1000                    {
1001                            log_error("Get sign data failed\n");
1002                            ret = -1;
1003                            goto cleanup;
1004                    }
1005    
1006                    if ((row = mysql_fetch_row(rs)))
1007                    {
1008                            len_content += snprintf(content + len_content,
1009                                                                            ARTICLE_CONTENT_MAX_LEN - (size_t)len_content,
1010                                                                            "\n\n--\n%s\n", row[0]);
1011                    }
1012                    mysql_free_result(rs);
1013                    rs = NULL;
1014            }
1015    
1016            // Begin transaction
1017            if (mysql_query(db, "SET autocommit=0") != 0)
1018            {
1019                    log_error("SET autocommit=0 error: %s\n", mysql_error(db));
1020                    ret = -1;
1021                    goto cleanup;
1022            }
1023    
1024            if (mysql_query(db, "BEGIN") != 0)
1025            {
1026                    log_error("Begin transaction error: %s\n", mysql_error(db));
1027                    ret = -1;
1028                    goto cleanup;
1029            }
1030    
1031            // Secure SQL parameters
1032            content_f = malloc((size_t)len_content * 2 + 1);
1033            if (content_f == NULL)
1034            {
1035                    log_error("malloc(content_f) error: OOM\n");
1036                    ret = -1;
1037                    goto cleanup;
1038            }
1039    
1040            mysql_real_escape_string(db, nickname_f, BBS_nickname, (unsigned long)strnlen(BBS_nickname, sizeof(BBS_nickname)));
1041            mysql_real_escape_string(db, title_f, p_article_new->title, strnlen(p_article_new->title, sizeof(p_article_new->title)));
1042            mysql_real_escape_string(db, content_f, content, (unsigned long)len_content);
1043    
1044            free(content);
1045            content = NULL;
1046    
1047            // Add content
1048            sql_content = malloc(SQL_BUFFER_LEN + (size_t)len_content * 2 + 1);
1049            if (sql_content == NULL)
1050            {
1051                    log_error("malloc(sql_content) error: OOM\n");
1052                    ret = -1;
1053                    goto cleanup;
1054            }
1055    
1056            snprintf(sql_content, SQL_BUFFER_LEN + (size_t)len_content * 2 + 1,
1057                             "INSERT INTO bbs_content(AID, content) values(0, '%s')",
1058                             content_f);
1059    
1060            free(content_f);
1061            content_f = NULL;
1062    
1063            if (mysql_query(db, sql_content) != 0)
1064            {
1065                    log_error("Add article content error: %s\n", mysql_error(db));
1066                    ret = -1;
1067                    goto cleanup;
1068            }
1069    
1070            p_article_new->cid = (int32_t)mysql_insert_id(db);
1071    
1072            free(sql_content);
1073            sql_content = NULL;
1074    
1075            // Add article
1076            snprintf(sql, sizeof(sql),
1077                             "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "
1078                             "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "
1079                             "VALUES(%d, %d, %d, '%s', '%s', '%s', %d, 0, NOW(), '%s', 1, %d, NOW(), 1, %ld)",
1080                             p_section->sid, (p_article->tid == 0 ? p_article->aid : p_article->tid),
1081                             BBS_priv.uid, BBS_username, nickname_f, title_f,
1082                             p_article_new->cid, hostaddr_client, BBS_user_exp, len_content);
1083    
1084            if (mysql_query(db, sql) != 0)
1085            {
1086                    log_error("Add article error: %s\n", mysql_error(db));
1087                    ret = -1;
1088                    goto cleanup;
1089            }
1090    
1091            p_article_new->aid = (int32_t)mysql_insert_id(db);
1092    
1093            // Update topic article
1094            snprintf(sql, sizeof(sql),
1095                             "UPDATE bbs SET reply_count = reply_count + 1, "
1096                             "last_reply_dt = NOW(), last_reply_UID=%d, last_reply_username = '%s', "
1097                             "last_reply_nickname = '%s' WHERE AID = %d",
1098                             BBS_priv.uid, BBS_username, nickname_f,
1099                             (p_article->tid == 0 ? p_article->aid : p_article->tid));
1100    
1101            if (mysql_query(db, sql) != 0)
1102            {
1103                    log_error("Update topic article error: %s\n", mysql_error(db));
1104                    ret = -1;
1105                    goto cleanup;
1106            }
1107    
1108            // Link content to article
1109            snprintf(sql, sizeof(sql),
1110                             "UPDATE bbs_content SET AID = %d WHERE CID = %d",
1111                             p_article_new->aid, p_article_new->cid);
1112    
1113            if (mysql_query(db, sql) != 0)
1114            {
1115                    log_error("Update content error: %s\n", mysql_error(db));
1116                    ret = -1;
1117                    goto cleanup;
1118            }
1119    
1120            // Add exp
1121            if (checkpriv(&BBS_priv, p_section->sid, S_GETEXP)) // Except in test section
1122            {
1123                    snprintf(sql, sizeof(sql),
1124                                     "UPDATE user_pubinfo SET exp = exp + %d WHERE UID = %d",
1125                                     3, BBS_priv.uid);
1126    
1127                    if (mysql_query(db, sql) != 0)
1128                    {
1129                            log_error("Update exp error: %s\n", mysql_error(db));
1130                            ret = -1;
1131                            goto cleanup;
1132                    }
1133            }
1134    
1135            // Add log
1136            snprintf(sql, sizeof(sql),
1137                             "INSERT INTO bbs_article_op(AID, UID, type, op_dt, op_ip)"
1138                             "VALUES(%d, %d, 'A', NOW(), '%s')",
1139                             p_article_new->aid, BBS_priv.uid, hostaddr_client);
1140    
1141            if (mysql_query(db, sql) != 0)
1142            {
1143                    log_error("Add log error: %s\n", mysql_error(db));
1144                    ret = -1;
1145                    goto cleanup;
1146            }
1147    
1148            // Commit transaction
1149            if (mysql_query(db, "COMMIT") != 0)
1150            {
1151                    log_error("Commit transaction error: %s\n", mysql_error(db));
1152                    ret = -1;
1153                    goto cleanup;
1154            }
1155    
1156            clearscr();
1157            moveto(1, 1);
1158            prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval);
1159            press_any_key();
1160            ret = 1; // Success
1161    
1162  cleanup:  cleanup:
1163            mysql_free_result(rs);
1164            mysql_close(db);
1165    
1166            // Cleanup buffers
1167          editor_data_cleanup(p_editor_data);          editor_data_cleanup(p_editor_data);
1168    
1169          return 0;          free(sql_content);
1170            free(content);
1171            free(content_f);
1172    
1173            return (int)ret;
1174  }  }


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

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