/[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.12 by sysadm, Sat Jun 14 12:30:15 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            content_f = malloc((size_t)len_content * 2 + 1);
257            if (content_f == NULL)
258            {
259                    log_error("malloc(content_f) error: OOM\n");
260                    ret = -1;
261                    goto cleanup;
262            }
263    
264            sql_content = malloc(SQL_BUFFER_LEN + (size_t)len_content * 2 + 1);
265            if (sql_content == NULL)
266            {
267                    log_error("malloc(sql_content) error: OOM\n");
268                    ret = -1;
269                    goto cleanup;
270            }
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            mysql_real_escape_string(db, nickname_f, BBS_nickname, (unsigned long)strnlen(BBS_nickname, sizeof(BBS_nickname)));
289            mysql_real_escape_string(db, title_f, p_article_new->title, strnlen(p_article_new->title, sizeof(p_article_new->title)));
290            mysql_real_escape_string(db, content_f, content, (unsigned long)len_content);
291    
292            // Add content
293            snprintf(sql, SQL_BUFFER_LEN + (size_t)len_content * 2 + 1,
294                             "INSERT INTO bbs_content(AID, content) values(0, '%s')",
295                             content_f);
296    
297            if (mysql_query(db, sql) != 0)
298            {
299                    log_error("Add article content error: %s\n", mysql_error(db));
300                    ret = -1;
301                    goto cleanup;
302            }
303    
304            p_article_new->cid = (int32_t)mysql_insert_id(db);
305    
306            // Add article
307            snprintf(sql, sizeof(sql),
308                             "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "
309                             "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "
310                             "VALUES(%d, 0, %d, '%s', '%s', '%s', %d, %d, NOW(), '%s', 1, %d, NOW(), 1, %ld)",
311                             p_section->sid, BBS_priv.uid, BBS_username, nickname_f, title_f,
312                             p_article_new->cid, p_article_new->transship, hostaddr_client, BBS_user_exp, len_content);
313    
314            if (mysql_query(db, sql) != 0)
315            {
316                    log_error("Add article error: %s\n", mysql_error(db));
317                    ret = -1;
318                    goto cleanup;
319            }
320    
321            p_article_new->aid = (int32_t)mysql_insert_id(db);
322    
323            // Link content to article
324            snprintf(sql, sizeof(sql),
325                             "UPDATE bbs_content SET AID = %d WHERE CID = %d",
326                             p_article_new->aid, p_article_new->cid);
327    
328            if (mysql_query(db, sql) != 0)
329            {
330                    log_error("Update content error: %s\n", mysql_error(db));
331                    ret = -1;
332                    goto cleanup;
333            }
334    
335            // Add exp
336            if (checkpriv(&BBS_priv, p_section->sid, S_GETEXP)) // Except in test section
337            {
338                    snprintf(sql, sizeof(sql),
339                                     "UPDATE user_pubinfo SET exp = exp + %d WHERE UID = %d",
340                                     (p_article_new->transship ? 5 : 15), BBS_priv.uid);
341    
342                    if (mysql_query(db, sql) != 0)
343                    {
344                            log_error("Update exp error: %s\n", mysql_error(db));
345                            ret = -1;
346                            goto cleanup;
347                    }
348            }
349    
350            // Add log
351            snprintf(sql, sizeof(sql),
352                             "INSERT INTO bbs_article_op(AID, UID, type, op_dt, op_ip)"
353                             "VALUES(%d, %d, 'A', NOW(), '%s')",
354                             p_article_new->aid, BBS_priv.uid, hostaddr_client);
355    
356            if (mysql_query(db, sql) != 0)
357            {
358                    log_error("Add log error: %s\n", mysql_error(db));
359                    ret = -1;
360                    goto cleanup;
361            }
362    
363            // Commit transaction
364            if (mysql_query(db, "COMMIT") != 0)
365            {
366                    log_error("Commit transaction error: %s\n", mysql_error(db));
367                    ret = -1;
368                    goto cleanup;
369            }
370    
371            clearscr();
372            moveto(1, 1);
373            prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval);
374            press_any_key();
375            ret = 1; // Success
376    
377  cleanup:  cleanup:
378            mysql_close(db);
379    
380            // Cleanup buffers
381          editor_data_cleanup(p_editor_data);          editor_data_cleanup(p_editor_data);
382    
383          return 0;          free(sql_content);
384            free(content);
385            free(content_f);
386    
387            return (int)ret;
388  }  }
389    
390  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)
391  {  {
392          MYSQL *db;          MYSQL *db = NULL;
393          MYSQL_RES *rs;          MYSQL_RES *rs = NULL;
394          MYSQL_ROW row;          MYSQL_ROW row;
395          char sql[SQL_BUFFER_LEN];          char sql[SQL_BUFFER_LEN];
396            char *sql_content = NULL;
397            char *content = NULL;
398            char *content_f = NULL;
399            long len_content;
400          int ch;          int ch;
401            long ret = 0;
402            time_t now;
403            struct tm tm_modify_dt;
404            char str_modify_dt[MODIFY_DT_MAX_LEN + 1];
405    
406          EDITOR_DATA *p_editor_data = NULL;          EDITOR_DATA *p_editor_data = NULL;
407    
# Line 190  int article_modify(SECTION_LIST *p_secti Line 410  int article_modify(SECTION_LIST *p_secti
410                  log_error("NULL pointer error\n");                  log_error("NULL pointer error\n");
411          }          }
412    
413            if (p_article->excerption) // Modify is not allowed
414            {
415                    clearscr();
416                    moveto(1, 1);
417                    prints("该文章无法被编辑,请联系版主。");
418                    press_any_key();
419    
420                    return 0;
421            }
422    
423            if (!checkpriv(&BBS_priv, p_section->sid, S_POST))
424            {
425                    clearscr();
426                    moveto(1, 1);
427                    prints("您没有权限在本版块发表文章\n");
428                    press_any_key();
429    
430                    return 0;
431            }
432    
433          db = db_open();          db = db_open();
434          if (db == NULL)          if (db == NULL)
435          {          {
# Line 206  int article_modify(SECTION_LIST *p_secti Line 446  int article_modify(SECTION_LIST *p_secti
446          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
447          {          {
448                  log_error("Query article content error: %s\n", mysql_error(db));                  log_error("Query article content error: %s\n", mysql_error(db));
449                  return -2;                  ret = -2;
450                    goto cleanup;
451          }          }
452          if ((rs = mysql_use_result(db)) == NULL)          if ((rs = mysql_use_result(db)) == NULL)
453          {          {
454                  log_error("Get article content data failed\n");                  log_error("Get article content data failed\n");
455                  return -2;                  ret = -2;
456                    goto cleanup;
457          }          }
458    
459          if ((row = mysql_fetch_row(rs)))          if ((row = mysql_fetch_row(rs)))
# Line 220  int article_modify(SECTION_LIST *p_secti Line 462  int article_modify(SECTION_LIST *p_secti
462                  if (p_editor_data == NULL)                  if (p_editor_data == NULL)
463                  {                  {
464                          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]));
465                          mysql_free_result(rs);                          ret = -3;
466                          mysql_close(db);                          goto cleanup;
                         return -3;  
467                  }                  }
468          }          }
469          mysql_free_result(rs);          mysql_free_result(rs);
470            rs = NULL;
471    
472          mysql_close(db);          mysql_close(db);
473            db = NULL;
474    
475          for (ch = 'E'; !SYS_server_exit && toupper(ch) == 'E';)          for (ch = 'E'; !SYS_server_exit && toupper(ch) == 'E';)
476          {          {
# Line 261  int article_modify(SECTION_LIST *p_secti Line 505  int article_modify(SECTION_LIST *p_secti
505                  }                  }
506          }          }
507    
508          // editor_data_save(p_editor_data, p_data_new, data_new_len);          // Allocate buffers in big size
509          log_common("Debug: modify article\n");          content = malloc(ARTICLE_CONTENT_MAX_LEN);
510            if (content == NULL)
511            {
512                    log_error("malloc(content) error: OOM\n");
513                    ret = -1;
514                    goto cleanup;
515            }
516    
517            len_content = editor_data_save(p_editor_data, content, ARTICLE_CONTENT_MAX_LEN - LINE_BUFFER_LEN);
518            if (len_content < 0)
519            {
520                    log_error("editor_data_save() error\n");
521                    ret = -2;
522                    goto cleanup;
523            }
524    
525            time(&now);
526            localtime_r(&now, &tm_modify_dt);
527            strftime(str_modify_dt, sizeof(str_modify_dt), "%Y-%m-%d %H:%M:%S (UTC %z)", &tm_modify_dt);
528    
529            len_content += snprintf(content + len_content, LINE_BUFFER_LEN,
530                                                            "\n--\n※ 作者已于 %s 修改本文※\n",
531                                                            str_modify_dt);
532    
533            content_f = malloc((size_t)len_content * 2 + 1);
534            if (content_f == NULL)
535            {
536                    log_error("malloc(content_f) error: OOM\n");
537                    ret = -1;
538                    goto cleanup;
539            }
540    
541            sql_content = malloc(SQL_BUFFER_LEN + (size_t)len_content * 2 + 1);
542            if (sql_content == NULL)
543            {
544                    log_error("malloc(sql_content) error: OOM\n");
545                    ret = -1;
546                    goto cleanup;
547            }
548    
549            db = db_open();
550            if (db == NULL)
551            {
552                    log_error("db_open() error: %s\n", mysql_error(db));
553                    ret = -1;
554                    goto cleanup;
555            }
556    
557            // Begin transaction
558            if (mysql_query(db, "SET autocommit=0") != 0)
559            {
560                    log_error("SET autocommit=0 error: %s\n", mysql_error(db));
561                    ret = -1;
562                    goto cleanup;
563            }
564    
565            if (mysql_query(db, "BEGIN") != 0)
566            {
567                    log_error("Begin transaction error: %s\n", mysql_error(db));
568                    ret = -1;
569                    goto cleanup;
570            }
571    
572            // Secure SQL parameters
573            mysql_real_escape_string(db, content_f, content, (unsigned long)len_content);
574    
575            // Add content
576            snprintf(sql, SQL_BUFFER_LEN + (size_t)len_content * 2 + 1,
577                             "INSERT INTO bbs_content(AID, content) values(%d, '%s')",
578                             p_article->aid, content_f);
579    
580            if (mysql_query(db, sql) != 0)
581            {
582                    log_error("Add article content error: %s\n", mysql_error(db));
583                    ret = -1;
584                    goto cleanup;
585            }
586    
587            p_article_new->cid = (int32_t)mysql_insert_id(db);
588    
589            // Update article
590            snprintf(sql, sizeof(sql),
591                             "UPDATE bbs SET CID = %d, length = %ld WHERE AID = %d",
592                             p_article_new->cid, len_content, p_article->aid);
593    
594            if (mysql_query(db, sql) != 0)
595            {
596                    log_error("Add article error: %s\n", mysql_error(db));
597                    ret = -1;
598                    goto cleanup;
599            }
600    
601            if (mysql_query(db, sql) != 0)
602            {
603                    log_error("Update content error: %s\n", mysql_error(db));
604                    ret = -1;
605                    goto cleanup;
606            }
607    
608            // Add log
609            snprintf(sql, sizeof(sql),
610                             "INSERT INTO bbs_article_op(AID, UID, type, op_dt, op_ip)"
611                             "VALUES(%d, %d, 'M', NOW(), '%s')",
612                             p_article->aid, BBS_priv.uid, hostaddr_client);
613    
614            if (mysql_query(db, sql) != 0)
615            {
616                    log_error("Add log error: %s\n", mysql_error(db));
617                    ret = -1;
618                    goto cleanup;
619            }
620    
621            // Commit transaction
622            if (mysql_query(db, "COMMIT") != 0)
623            {
624                    log_error("Commit transaction error: %s\n", mysql_error(db));
625                    ret = -1;
626                    goto cleanup;
627            }
628    
629            clearscr();
630            moveto(1, 1);
631            prints("修改完成,新内容通常会在%d秒后可见", BBS_section_list_load_interval);
632            press_any_key();
633            ret = 1; // Success
634    
635  cleanup:  cleanup:
636            mysql_close(db);
637    
638            // Cleanup buffers
639          editor_data_cleanup(p_editor_data);          editor_data_cleanup(p_editor_data);
640    
641          return 0;          free(sql_content);
642            free(content);
643            free(content_f);
644    
645            return (int)ret;
646  }  }
647    
648  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)
649  {  {
650          MYSQL *db;          MYSQL *db = NULL;
651          MYSQL_RES *rs;          MYSQL_RES *rs = NULL;
652          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];  
653          long line_offsets[ARTICLE_QUOTE_MAX_LINES + 1];          long line_offsets[ARTICLE_QUOTE_MAX_LINES + 1];
654            char sql[SQL_BUFFER_LEN];
655            char *sql_content = NULL;
656          EDITOR_DATA *p_editor_data = NULL;          EDITOR_DATA *p_editor_data = NULL;
657          char title[BBS_article_title_max_len + 1];          char title_input[BBS_article_title_max_len + sizeof("Re: ")];
658          char title_input[BBS_article_title_max_len + 1 + 4]; // + "Re: "          char title_f[BBS_article_title_max_len * 2 + 1];
659            char *content = NULL;
660            char *content_f = NULL;
661            long len_content;
662            char nickname_f[BBS_nickname_max_len * 2 + 1];
663          int sign_id = 0;          int sign_id = 0;
664          long len;          long len;
665          int ch;          int ch;
# Line 290  int article_reply(SECTION_LIST *p_sectio Line 668  int article_reply(SECTION_LIST *p_sectio
668          int display_len;          int display_len;
669          long quote_content_lines;          long quote_content_lines;
670          long i;          long i;
671            long ret = 0;
672    
673          if (p_section == NULL || p_article == NULL)          if (p_section == NULL || p_article == NULL)
674          {          {
675                  log_error("NULL pointer error\n");                  log_error("NULL pointer error\n");
676          }          }
677    
678          title[0] = '\0';          if (!checkpriv(&BBS_priv, p_section->sid, S_POST))
679            {
680                    clearscr();
681                    moveto(1, 1);
682                    prints("您没有权限在本版块发表文章\n");
683                    press_any_key();
684    
685                    return 0;
686            }
687    
688            if (p_article->lock) // Reply is not allowed
689            {
690                    clearscr();
691                    moveto(1, 1);
692                    prints("该文章谢绝回复");
693                    press_any_key();
694    
695                    return 0;
696            }
697    
698            p_article_new->title[0] = '\0';
699          snprintf(title_input, sizeof(title_input), "Re: %s", p_article->title);          snprintf(title_input, sizeof(title_input), "Re: %s", p_article->title);
700          len = split_line(title_input, TITLE_INPUT_MAX_LEN, &eol, &display_len);          len = split_line(title_input, TITLE_INPUT_MAX_LEN, &eol, &display_len);
701          title_input[len] = '\0';          title_input[len] = '\0';
# Line 327  int article_reply(SECTION_LIST *p_sectio Line 726  int article_reply(SECTION_LIST *p_sectio
726    
727          if ((row = mysql_fetch_row(rs)))          if ((row = mysql_fetch_row(rs)))
728          {          {
729                    content = malloc(ARTICLE_CONTENT_MAX_LEN);
730                    if (content == NULL)
731                    {
732                            log_error("malloc(content) error: OOM\n");
733                            ret = -1;
734                            goto cleanup;
735                    }
736    
737                    content_f = malloc(ARTICLE_CONTENT_MAX_LEN);
738                    if (content_f == NULL)
739                    {
740                            log_error("malloc(content_f) error: OOM\n");
741                            ret = -1;
742                            goto cleanup;
743                    }
744    
745                  // Apply LML render to content body                  // Apply LML render to content body
746                  len = lml_plain(row[1], content_f, ARTICLE_CONTENT_MAX_LEN);                  len = lml_plain(row[1], content_f, ARTICLE_CONTENT_MAX_LEN);
747                  content_f[len] = '\0';                  content_f[len] = '\0';
748    
749                    // Remove control sequence
750                    len = ctrl_seq_filter(content_f);
751    
752                    len = snprintf(content, ARTICLE_CONTENT_MAX_LEN,
753                                               "\n\n【 在 %s (%s) 的大作中提到: 】\n",
754                                               p_article->username, p_article->nickname);
755    
756                  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);
757                  for (i = 0, len = 0; i < quote_content_lines; i++)                  for (i = 0; i < quote_content_lines; i++)
758                  {                  {
759                          memcpy(content + len, ": ", 2); // quote line prefix                          memcpy(content + len, ": ", 2); // quote line prefix
760                          len += 2;                          len += 2;
761                          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]));
762                          len += (line_offsets[i + 1] - line_offsets[i]);                          len += (line_offsets[i + 1] - line_offsets[i]);
763                  }                  }
764                    if (content[len - 1] != '\n') // Appennd \n if not exist
765                    {
766                            content[len] = '\n';
767                            len++;
768                    }
769                  content[len] = '\0';                  content[len] = '\0';
770    
771                    free(content_f);
772                    content_f = NULL;
773    
774                    p_editor_data = editor_data_load(content);
775                    if (p_editor_data == NULL)
776                    {
777                            log_error("editor_data_load(aid=%d, cid=%d) error\n", p_article->aid, atoi(row[0]));
778                            ret = -3;
779                            goto cleanup;
780                    }
781    
782                    free(content);
783                    content = NULL;
784          }          }
785          mysql_free_result(rs);          mysql_free_result(rs);
786          mysql_close(db);          rs = NULL;
787    
788          p_editor_data = editor_data_load(content);          mysql_close(db);
789          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;  
         }  
790    
791          // Set title and sign          // Set title and sign
792          for (ch = 'T'; !SYS_server_exit;)          for (ch = 'T'; !SYS_server_exit;)
# Line 358  int article_reply(SECTION_LIST *p_sectio Line 795  int article_reply(SECTION_LIST *p_sectio
795                  moveto(21, 1);                  moveto(21, 1);
796                  prints("回复文章于 %s[%s] 讨论区", p_section->stitle, p_section->sname);                  prints("回复文章于 %s[%s] 讨论区", p_section->stitle, p_section->sname);
797                  moveto(22, 1);                  moveto(22, 1);
798                  prints("标题: %s", (title[0] == '\0' ? "[无]" : title));                  prints("标题: %s", (p_article_new->title[0] == '\0' ? "[无]" : p_article_new->title));
799                  moveto(23, 1);                  moveto(23, 1);
800                  prints("使用第 %d 个签名", sign_id);                  prints("使用第 %d 个签名", sign_id);
801    
# Line 391  int article_reply(SECTION_LIST *p_sectio Line 828  int article_reply(SECTION_LIST *p_sectio
828                                  len = q - p;                                  len = q - p;
829                                  if (*p != '\0')                                  if (*p != '\0')
830                                  {                                  {
831                                          memcpy(title, p, (size_t)len + 1);                                          memcpy(p_article_new->title, p, (size_t)len + 1);
832                                          memcpy(title_input, title, (size_t)len + 1);                                          memcpy(title_input, p_article_new->title, (size_t)len + 1);
833                                  }                                  }
834                                  ch = 0;                                  ch = 0;
835                                  break;                                  break;
# Line 415  int article_reply(SECTION_LIST *p_sectio Line 852  int article_reply(SECTION_LIST *p_sectio
852                          break;                          break;
853                  }                  }
854    
855                  if (ch != CR || title[0] == '\0')                  if (ch != CR || p_article_new->title[0] == '\0')
856                  {                  {
857                          continue;                          continue;
858                  }                  }
# Line 461  int article_reply(SECTION_LIST *p_sectio Line 898  int article_reply(SECTION_LIST *p_sectio
898                  }                  }
899          }          }
900    
901          // editor_data_save(p_editor_data, p_data_new, data_new_len);          content = malloc(ARTICLE_CONTENT_MAX_LEN);
902          log_common("Debug: reply article\n");          if (content == NULL)
903            {
904                    log_error("malloc(content) error: OOM\n");
905                    ret = -1;
906                    goto cleanup;
907            }
908    
909            len_content = editor_data_save(p_editor_data, content, ARTICLE_CONTENT_MAX_LEN);
910            if (len_content < 0)
911            {
912                    log_error("editor_data_save() error\n");
913                    ret = -2;
914                    goto cleanup;
915            }
916    
917            db = db_open();
918            if (db == NULL)
919            {
920                    log_error("db_open() error: %s\n", mysql_error(db));
921                    ret = -1;
922                    goto cleanup;
923            }
924    
925            if (sign_id > 0)
926            {
927                    snprintf(sql, sizeof(sql),
928                                     "SELECT sign_%d AS sign FROM user_pubinfo WHERE UID = %d",
929                                     sign_id, BBS_priv.uid);
930    
931                    if (mysql_query(db, sql) != 0)
932                    {
933                            log_error("Query sign error: %s\n", mysql_error(db));
934                            ret = -1;
935                            goto cleanup;
936                    }
937                    if ((rs = mysql_use_result(db)) == NULL)
938                    {
939                            log_error("Get sign data failed\n");
940                            ret = -1;
941                            goto cleanup;
942                    }
943    
944                    if ((row = mysql_fetch_row(rs)))
945                    {
946                            len_content += snprintf(content + len_content,
947                                                                            ARTICLE_CONTENT_MAX_LEN - (size_t)len_content,
948                                                                            "\n\n--\n%s\n", row[0]);
949                    }
950                    mysql_free_result(rs);
951                    rs = NULL;
952            }
953    
954            content_f = malloc((size_t)len_content * 2 + 1);
955            if (content_f == NULL)
956            {
957                    log_error("malloc(content_f) error: OOM\n");
958                    ret = -1;
959                    goto cleanup;
960            }
961    
962            sql_content = malloc(SQL_BUFFER_LEN + (size_t)len_content * 2 + 1);
963            if (sql_content == NULL)
964            {
965                    log_error("malloc(sql_content) error: OOM\n");
966                    ret = -1;
967                    goto cleanup;
968            }
969    
970            // Begin transaction
971            if (mysql_query(db, "SET autocommit=0") != 0)
972            {
973                    log_error("SET autocommit=0 error: %s\n", mysql_error(db));
974                    ret = -1;
975                    goto cleanup;
976            }
977    
978            if (mysql_query(db, "BEGIN") != 0)
979            {
980                    log_error("Begin transaction error: %s\n", mysql_error(db));
981                    ret = -1;
982                    goto cleanup;
983            }
984    
985            // Secure SQL parameters
986            mysql_real_escape_string(db, nickname_f, BBS_nickname, (unsigned long)strnlen(BBS_nickname, sizeof(BBS_nickname)));
987            mysql_real_escape_string(db, title_f, p_article_new->title, strnlen(p_article_new->title, sizeof(p_article_new->title)));
988            mysql_real_escape_string(db, content_f, content, (unsigned long)len_content);
989    
990            // Add content
991            snprintf(sql, SQL_BUFFER_LEN + (size_t)len_content * 2 + 1,
992                             "INSERT INTO bbs_content(AID, content) values(0, '%s')",
993                             content_f);
994    
995            if (mysql_query(db, sql) != 0)
996            {
997                    log_error("Add article content error: %s\n", mysql_error(db));
998                    ret = -1;
999                    goto cleanup;
1000            }
1001    
1002            p_article_new->cid = (int32_t)mysql_insert_id(db);
1003    
1004            // Add article
1005            snprintf(sql, sizeof(sql),
1006                             "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "
1007                             "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "
1008                             "VALUES(%d, %d, %d, '%s', '%s', '%s', %d, 0, NOW(), '%s', 1, %d, NOW(), 1, %ld)",
1009                             p_section->sid, (p_article->tid == 0 ? p_article->aid : p_article->tid),
1010                             BBS_priv.uid, BBS_username, nickname_f, title_f,
1011                             p_article_new->cid, hostaddr_client, BBS_user_exp, len_content);
1012    
1013            if (mysql_query(db, sql) != 0)
1014            {
1015                    log_error("Add article error: %s\n", mysql_error(db));
1016                    ret = -1;
1017                    goto cleanup;
1018            }
1019    
1020            p_article_new->aid = (int32_t)mysql_insert_id(db);
1021    
1022            // Update topic article
1023            snprintf(sql, sizeof(sql),
1024                             "UPDATE bbs SET reply_count = reply_count + 1, "
1025                             "last_reply_dt = NOW(), last_reply_UID=%d, last_reply_username = '%s', "
1026                             "last_reply_nickname = '%s' WHERE AID = %d",
1027                             BBS_priv.uid, BBS_username, nickname_f,
1028                             (p_article->tid == 0 ? p_article->aid : p_article->tid));
1029    
1030            if (mysql_query(db, sql) != 0)
1031            {
1032                    log_error("Update topic article error: %s\n", mysql_error(db));
1033                    ret = -1;
1034                    goto cleanup;
1035            }
1036    
1037            // Link content to article
1038            snprintf(sql, sizeof(sql),
1039                             "UPDATE bbs_content SET AID = %d WHERE CID = %d",
1040                             p_article_new->aid, p_article_new->cid);
1041    
1042            if (mysql_query(db, sql) != 0)
1043            {
1044                    log_error("Update content error: %s\n", mysql_error(db));
1045                    ret = -1;
1046                    goto cleanup;
1047            }
1048    
1049            // Add exp
1050            if (checkpriv(&BBS_priv, p_section->sid, S_GETEXP)) // Except in test section
1051            {
1052                    snprintf(sql, sizeof(sql),
1053                                     "UPDATE user_pubinfo SET exp = exp + %d WHERE UID = %d",
1054                                     3, BBS_priv.uid);
1055    
1056                    if (mysql_query(db, sql) != 0)
1057                    {
1058                            log_error("Update exp error: %s\n", mysql_error(db));
1059                            ret = -1;
1060                            goto cleanup;
1061                    }
1062            }
1063    
1064            // Add log
1065            snprintf(sql, sizeof(sql),
1066                             "INSERT INTO bbs_article_op(AID, UID, type, op_dt, op_ip)"
1067                             "VALUES(%d, %d, 'A', NOW(), '%s')",
1068                             p_article_new->aid, BBS_priv.uid, hostaddr_client);
1069    
1070            if (mysql_query(db, sql) != 0)
1071            {
1072                    log_error("Add log error: %s\n", mysql_error(db));
1073                    ret = -1;
1074                    goto cleanup;
1075            }
1076    
1077            // Commit transaction
1078            if (mysql_query(db, "COMMIT") != 0)
1079            {
1080                    log_error("Commit transaction error: %s\n", mysql_error(db));
1081                    ret = -1;
1082                    goto cleanup;
1083            }
1084    
1085            clearscr();
1086            moveto(1, 1);
1087            prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval);
1088            press_any_key();
1089            ret = 1; // Success
1090    
1091  cleanup:  cleanup:
1092            mysql_free_result(rs);
1093            mysql_close(db);
1094    
1095            // Cleanup buffers
1096          editor_data_cleanup(p_editor_data);          editor_data_cleanup(p_editor_data);
1097    
1098          return 0;          free(sql_content);
1099            free(content);
1100            free(content_f);
1101    
1102            return (int)ret;
1103  }  }


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

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