/[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.9 by sysadm, Sat Jun 14 11:15:46 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';          p_article_new->title[0] = '\0';
67          title_input[0] = '\0';          title_input[0] = '\0';
68            p_article_new->transship = 0;
69    
70          p_editor_data = editor_data_load("");          p_editor_data = editor_data_load("");
71          if (p_editor_data == NULL)          if (p_editor_data == NULL)
# Line 61  int article_post(SECTION_LIST *p_section Line 79  int article_post(SECTION_LIST *p_section
79          {          {
80                  clearscr();                  clearscr();
81                  moveto(21, 1);                  moveto(21, 1);
82                  prints("发表文章于 %s[%s] 讨论区", p_section->stitle, p_section->sname);                  prints("发表文章于 %s[%s] 讨论区,类型: %s", p_section->stitle, p_section->sname, (p_article_new->transship ? "转载" : "原创"));
83                  moveto(22, 1);                  moveto(22, 1);
84                  prints("标题: %s", (title[0] == '\0' ? "[无]" : title));                  prints("标题: %s", (p_article_new->title[0] == '\0' ? "[无]" : p_article_new->title));
85                  moveto(23, 1);                  moveto(23, 1);
86                  prints("使用第 %d 个签名", sign_id);                  prints("使用第 %d 个签名", sign_id);
87    
# Line 72  int article_post(SECTION_LIST *p_section Line 90  int article_post(SECTION_LIST *p_section
90                          prints("    按0~3选签名档(0表示不使用)");                          prints("    按0~3选签名档(0表示不使用)");
91    
92                          moveto(24, 1);                          moveto(24, 1);
93                          prints("T改标题, C取消, Enter继续: ");                          prints("T改标题, C取消, Z设为转载, Y设为原创, Enter继续: ");
94                          iflush();                          iflush();
95                          ch = 0;                          ch = 0;
96                  }                  }
# Line 96  int article_post(SECTION_LIST *p_section Line 114  int article_post(SECTION_LIST *p_section
114                                  len = q - p;                                  len = q - p;
115                                  if (*p != '\0')                                  if (*p != '\0')
116                                  {                                  {
117                                          memcpy(title, p, (size_t)len + 1);                                          memcpy(p_article_new->title, p, (size_t)len + 1);
118                                          memcpy(title_input, title, (size_t)len + 1);                                          memcpy(title_input, p_article_new->title, (size_t)len + 1);
119                                  }                                  }
120                                  ch = 0;                                  ch = 0;
121                                  break;                                  break;
# Line 107  int article_post(SECTION_LIST *p_section Line 125  int article_post(SECTION_LIST *p_section
125                                  prints("取消...");                                  prints("取消...");
126                                  press_any_key();                                  press_any_key();
127                                  goto cleanup;                                  goto cleanup;
128                            case 'Y':
129                                    p_article_new->transship = 0;
130                                    break;
131                            case 'Z':
132                                    p_article_new->transship = 1;
133                                    break;
134                          case '0':                          case '0':
135                          case '1':                          case '1':
136                          case '2':                          case '2':
# Line 120  int article_post(SECTION_LIST *p_section Line 144  int article_post(SECTION_LIST *p_section
144                          break;                          break;
145                  }                  }
146    
147                  if (ch != CR || title[0] == '\0')                  if (ch != CR || p_article_new->title[0] == '\0')
148                  {                  {
149                          continue;                          continue;
150                  }                  }
# Line 166  int article_post(SECTION_LIST *p_section Line 190  int article_post(SECTION_LIST *p_section
190                  }                  }
191          }          }
192    
193          // editor_data_save(p_editor_data, p_data_new, data_new_len);          content = malloc(ARTICLE_CONTENT_MAX_LEN);
194          log_common("Debug: post article\n");          if (content == NULL)
195            {
196                    log_error("malloc(content) error: OOM\n");
197                    ret = -1;
198                    goto cleanup;
199            }
200    
201            len_content = editor_data_save(p_editor_data, content, ARTICLE_CONTENT_MAX_LEN);
202            if (len_content < 0)
203            {
204                    log_error("editor_data_save() error\n");
205                    ret = -2;
206                    goto cleanup;
207            }
208    
209            db = db_open();
210            if (db == NULL)
211            {
212                    log_error("db_open() error: %s\n", mysql_error(db));
213                    ret = -1;
214                    goto cleanup;
215            }
216    
217            if (sign_id > 0)
218            {
219                    snprintf(sql, sizeof(sql),
220                                     "SELECT sign_%d AS sign FROM user_pubinfo WHERE UID = %d",
221                                     sign_id, BBS_priv.uid);
222    
223                    if (mysql_query(db, sql) != 0)
224                    {
225                            log_error("Query sign error: %s\n", mysql_error(db));
226                            ret = -1;
227                            goto cleanup;
228                    }
229                    if ((rs = mysql_use_result(db)) == NULL)
230                    {
231                            log_error("Get sign data failed\n");
232                            ret = -1;
233                            goto cleanup;
234                    }
235    
236                    if ((row = mysql_fetch_row(rs)))
237                    {
238                            len_content += snprintf(content + len_content,
239                                                                            ARTICLE_CONTENT_MAX_LEN - (size_t)len_content,
240                                                                            "\n\n--\n%s\n", row[0]);
241                    }
242                    mysql_free_result(rs);
243                    rs = NULL;
244            }
245    
246            content_f = malloc((size_t)len_content * 2 + 1);
247            if (content_f == NULL)
248            {
249                    log_error("malloc(content_f) error: OOM\n");
250                    ret = -1;
251                    goto cleanup;
252            }
253    
254            sql_content = malloc(SQL_BUFFER_LEN + (size_t)len_content * 2 + 1);
255            if (sql_content == NULL)
256            {
257                    log_error("malloc(sql_content) error: OOM\n");
258                    ret = -1;
259                    goto cleanup;
260            }
261    
262            // Begin transaction
263            if (mysql_query(db, "SET autocommit=0") != 0)
264            {
265                    log_error("SET autocommit=0 error: %s\n", mysql_error(db));
266                    ret = -1;
267                    goto cleanup;
268            }
269    
270            if (mysql_query(db, "BEGIN") != 0)
271            {
272                    log_error("Begin transaction error: %s\n", mysql_error(db));
273                    ret = -1;
274                    goto cleanup;
275            }
276    
277            // Secure SQL parameters
278            mysql_real_escape_string(db, nickname_f, BBS_nickname, (unsigned long)strnlen(BBS_nickname, sizeof(BBS_nickname)));
279            mysql_real_escape_string(db, title_f, p_article_new->title, strnlen(p_article_new->title, sizeof(p_article_new->title)));
280            mysql_real_escape_string(db, content_f, content, (unsigned long)len_content);
281    
282            // Add content
283            snprintf(sql, SQL_BUFFER_LEN + (size_t)len_content * 2 + 1,
284                             "INSERT INTO bbs_content(AID, content) values(0, '%s')",
285                             content_f);
286    
287            if (mysql_query(db, sql) != 0)
288            {
289                    log_error("Add article content error: %s\n", mysql_error(db));
290                    ret = -1;
291                    goto cleanup;
292            }
293    
294            p_article_new->cid = (int32_t)mysql_insert_id(db);
295    
296            // Add article
297            snprintf(sql, sizeof(sql),
298                             "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "
299                             "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "
300                             "VALUES(%d, 0, %d, '%s', '%s', '%s', %d, %d, NOW(), '%s', 1, %d, NOW(), 1, %ld)",
301                             p_section->sid, BBS_priv.uid, BBS_username, nickname_f, title_f,
302                             p_article_new->cid, p_article_new->transship, hostaddr_client, BBS_user_exp, len_content);
303    
304            if (mysql_query(db, sql) != 0)
305            {
306                    log_error("Add article error: %s\n", mysql_error(db));
307                    ret = -1;
308                    goto cleanup;
309            }
310    
311            p_article_new->aid = (int32_t)mysql_insert_id(db);
312    
313            // Link content to article
314            snprintf(sql, sizeof(sql),
315                             "UPDATE bbs_content SET AID = %d WHERE CID = %d",
316                             p_article_new->aid, p_article_new->cid);
317    
318            if (mysql_query(db, sql) != 0)
319            {
320                    log_error("Update content error: %s\n", mysql_error(db));
321                    ret = -1;
322                    goto cleanup;
323            }
324    
325            // Add exp
326            if (checkpriv(&BBS_priv, p_section->sid, S_GETEXP)) // Except in test section
327            {
328                    snprintf(sql, sizeof(sql),
329                                     "UPDATE user_pubinfo SET exp = exp + %d WHERE UID = %d",
330                                     (p_article_new->transship ? 5 : 15), BBS_priv.uid);
331    
332                    if (mysql_query(db, sql) != 0)
333                    {
334                            log_error("Update exp error: %s\n", mysql_error(db));
335                            ret = -1;
336                            goto cleanup;
337                    }
338            }
339    
340            // Add log
341            snprintf(sql, sizeof(sql),
342                             "INSERT INTO bbs_article_op(AID, UID, type, op_dt, op_ip)"
343                             "VALUES(%d, %d, 'A', NOW(), '%s')",
344                             p_article_new->aid, BBS_priv.uid, hostaddr_client);
345    
346            if (mysql_query(db, sql) != 0)
347            {
348                    log_error("Add log error: %s\n", mysql_error(db));
349                    ret = -1;
350                    goto cleanup;
351            }
352    
353            // Commit transaction
354            if (mysql_query(db, "COMMIT") != 0)
355            {
356                    log_error("Commit transaction error: %s\n", mysql_error(db));
357                    ret = -1;
358                    goto cleanup;
359            }
360    
361            clearscr();
362            moveto(1, 1);
363            prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval);
364            press_any_key();
365            ret = 1; // Success
366    
367  cleanup:  cleanup:
368            mysql_close(db);
369    
370            // Cleanup buffers
371          editor_data_cleanup(p_editor_data);          editor_data_cleanup(p_editor_data);
372    
373          return 0;          free(sql_content);
374            free(content);
375            free(content_f);
376    
377            return (int)ret;
378  }  }
379    
380  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)
381  {  {
382          MYSQL *db;          MYSQL *db = NULL;
383          MYSQL_RES *rs;          MYSQL_RES *rs = NULL;
384          MYSQL_ROW row;          MYSQL_ROW row;
385          char sql[SQL_BUFFER_LEN];          char sql[SQL_BUFFER_LEN];
386            char *sql_content = NULL;
387            char *content = NULL;
388            char *content_f = NULL;
389            long len_content;
390          int ch;          int ch;
391            long ret = 0;
392            time_t now;
393            struct tm tm_modify_dt;
394            char str_modify_dt[MODIFY_DT_MAX_LEN + 1];
395    
396          EDITOR_DATA *p_editor_data = NULL;          EDITOR_DATA *p_editor_data = NULL;
397    
# Line 190  int article_modify(SECTION_LIST *p_secti Line 400  int article_modify(SECTION_LIST *p_secti
400                  log_error("NULL pointer error\n");                  log_error("NULL pointer error\n");
401          }          }
402    
403            if (p_article->excerption) // Modify is not allowed
404            {
405                    clearscr();
406                    moveto(1, 1);
407                    prints("该文章无法被编辑,请联系版主。");
408                    press_any_key();
409    
410                    return 0;
411            }
412    
413          db = db_open();          db = db_open();
414          if (db == NULL)          if (db == NULL)
415          {          {
# Line 206  int article_modify(SECTION_LIST *p_secti Line 426  int article_modify(SECTION_LIST *p_secti
426          if (mysql_query(db, sql) != 0)          if (mysql_query(db, sql) != 0)
427          {          {
428                  log_error("Query article content error: %s\n", mysql_error(db));                  log_error("Query article content error: %s\n", mysql_error(db));
429                  return -2;                  ret = -2;
430                    goto cleanup;
431          }          }
432          if ((rs = mysql_use_result(db)) == NULL)          if ((rs = mysql_use_result(db)) == NULL)
433          {          {
434                  log_error("Get article content data failed\n");                  log_error("Get article content data failed\n");
435                  return -2;                  ret = -2;
436                    goto cleanup;
437          }          }
438    
439          if ((row = mysql_fetch_row(rs)))          if ((row = mysql_fetch_row(rs)))
# Line 220  int article_modify(SECTION_LIST *p_secti Line 442  int article_modify(SECTION_LIST *p_secti
442                  if (p_editor_data == NULL)                  if (p_editor_data == NULL)
443                  {                  {
444                          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]));
445                          mysql_free_result(rs);                          ret = -3;
446                          mysql_close(db);                          goto cleanup;
                         return -3;  
447                  }                  }
448          }          }
449          mysql_free_result(rs);          mysql_free_result(rs);
450            rs = NULL;
451    
452          mysql_close(db);          mysql_close(db);
453            db = NULL;
454    
455          for (ch = 'E'; !SYS_server_exit && toupper(ch) == 'E';)          for (ch = 'E'; !SYS_server_exit && toupper(ch) == 'E';)
456          {          {
# Line 261  int article_modify(SECTION_LIST *p_secti Line 485  int article_modify(SECTION_LIST *p_secti
485                  }                  }
486          }          }
487    
488          // editor_data_save(p_editor_data, p_data_new, data_new_len);          // Allocate buffers in big size
489          log_common("Debug: modify article\n");          content = malloc(ARTICLE_CONTENT_MAX_LEN);
490            if (content == NULL)
491            {
492                    log_error("malloc(content) error: OOM\n");
493                    ret = -1;
494                    goto cleanup;
495            }
496    
497            len_content = editor_data_save(p_editor_data, content, ARTICLE_CONTENT_MAX_LEN - LINE_BUFFER_LEN);
498            if (len_content < 0)
499            {
500                    log_error("editor_data_save() error\n");
501                    ret = -2;
502                    goto cleanup;
503            }
504    
505            time(&now);
506            localtime_r(&now, &tm_modify_dt);
507            strftime(str_modify_dt, sizeof(str_modify_dt), "%Y-%m-%d %H:%M:%S (UTC %z)", &tm_modify_dt);
508    
509            len_content += snprintf(content + len_content, LINE_BUFFER_LEN,
510                                                            "\n--\n※ 作者已于 %s 修改本文※\n",
511                                                            str_modify_dt);
512    
513            content_f = malloc((size_t)len_content * 2 + 1);
514            if (content_f == NULL)
515            {
516                    log_error("malloc(content_f) error: OOM\n");
517                    ret = -1;
518                    goto cleanup;
519            }
520    
521            sql_content = malloc(SQL_BUFFER_LEN + (size_t)len_content * 2 + 1);
522            if (sql_content == NULL)
523            {
524                    log_error("malloc(sql_content) error: OOM\n");
525                    ret = -1;
526                    goto cleanup;
527            }
528    
529            db = db_open();
530            if (db == NULL)
531            {
532                    log_error("db_open() error: %s\n", mysql_error(db));
533                    ret = -1;
534                    goto cleanup;
535            }
536    
537            // Begin transaction
538            if (mysql_query(db, "SET autocommit=0") != 0)
539            {
540                    log_error("SET autocommit=0 error: %s\n", mysql_error(db));
541                    ret = -1;
542                    goto cleanup;
543            }
544    
545            if (mysql_query(db, "BEGIN") != 0)
546            {
547                    log_error("Begin transaction error: %s\n", mysql_error(db));
548                    ret = -1;
549                    goto cleanup;
550            }
551    
552            // Secure SQL parameters
553            mysql_real_escape_string(db, content_f, content, (unsigned long)len_content);
554    
555            // Add content
556            snprintf(sql, SQL_BUFFER_LEN + (size_t)len_content * 2 + 1,
557                             "INSERT INTO bbs_content(AID, content) values(%d, '%s')",
558                             p_article->aid, content_f);
559    
560            if (mysql_query(db, sql) != 0)
561            {
562                    log_error("Add article content error: %s\n", mysql_error(db));
563                    ret = -1;
564                    goto cleanup;
565            }
566    
567            p_article_new->cid = (int32_t)mysql_insert_id(db);
568    
569            // Update article
570            snprintf(sql, sizeof(sql),
571                             "UPDATE bbs SET CID = %d, length = %ld WHERE AID = %d",
572                             p_article_new->cid, len_content, p_article->aid);
573    
574            if (mysql_query(db, sql) != 0)
575            {
576                    log_error("Add article error: %s\n", mysql_error(db));
577                    ret = -1;
578                    goto cleanup;
579            }
580    
581            if (mysql_query(db, sql) != 0)
582            {
583                    log_error("Update content error: %s\n", mysql_error(db));
584                    ret = -1;
585                    goto cleanup;
586            }
587    
588            // Add log
589            snprintf(sql, sizeof(sql),
590                             "INSERT INTO bbs_article_op(AID, UID, type, op_dt, op_ip)"
591                             "VALUES(%d, %d, 'M', NOW(), '%s')",
592                             p_article->aid, BBS_priv.uid, hostaddr_client);
593    
594            if (mysql_query(db, sql) != 0)
595            {
596                    log_error("Add log error: %s\n", mysql_error(db));
597                    ret = -1;
598                    goto cleanup;
599            }
600    
601            // Commit transaction
602            if (mysql_query(db, "COMMIT") != 0)
603            {
604                    log_error("Commit transaction error: %s\n", mysql_error(db));
605                    ret = -1;
606                    goto cleanup;
607            }
608    
609            clearscr();
610            moveto(1, 1);
611            prints("修改完成,新内容通常会在%d秒后可见", BBS_section_list_load_interval);
612            press_any_key();
613            ret = 1; // Success
614    
615  cleanup:  cleanup:
616            mysql_close(db);
617    
618            // Cleanup buffers
619          editor_data_cleanup(p_editor_data);          editor_data_cleanup(p_editor_data);
620    
621          return 0;          free(sql_content);
622            free(content);
623            free(content_f);
624    
625            return (int)ret;
626  }  }
627    
628  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)
629  {  {
630          MYSQL *db;          MYSQL *db = NULL;
631          MYSQL_RES *rs;          MYSQL_RES *rs = NULL;
632          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];  
633          long line_offsets[ARTICLE_QUOTE_MAX_LINES + 1];          long line_offsets[ARTICLE_QUOTE_MAX_LINES + 1];
634            char sql[SQL_BUFFER_LEN];
635            char *sql_content = NULL;
636          EDITOR_DATA *p_editor_data = NULL;          EDITOR_DATA *p_editor_data = NULL;
637          char title[BBS_article_title_max_len + 1];          char title_input[BBS_article_title_max_len + sizeof("Re: ")];
638          char title_input[BBS_article_title_max_len + 1 + 4]; // + "Re: "          char title_f[BBS_article_title_max_len * 2 + 1];
639            char *content = NULL;
640            char *content_f = NULL;
641            long len_content;
642            char nickname_f[BBS_nickname_max_len * 2 + 1];
643          int sign_id = 0;          int sign_id = 0;
644          long len;          long len;
645          int ch;          int ch;
# Line 290  int article_reply(SECTION_LIST *p_sectio Line 648  int article_reply(SECTION_LIST *p_sectio
648          int display_len;          int display_len;
649          long quote_content_lines;          long quote_content_lines;
650          long i;          long i;
651            long ret = 0;
652    
653          if (p_section == NULL || p_article == NULL)          if (p_section == NULL || p_article == NULL)
654          {          {
655                  log_error("NULL pointer error\n");                  log_error("NULL pointer error\n");
656          }          }
657    
658          title[0] = '\0';          if (p_article->lock) // Reply is not allowed
659            {
660                    clearscr();
661                    moveto(1, 1);
662                    prints("该文章谢绝回复");
663                    press_any_key();
664    
665                    return 0;
666            }
667    
668            p_article_new->title[0] = '\0';
669          snprintf(title_input, sizeof(title_input), "Re: %s", p_article->title);          snprintf(title_input, sizeof(title_input), "Re: %s", p_article->title);
670          len = split_line(title_input, TITLE_INPUT_MAX_LEN, &eol, &display_len);          len = split_line(title_input, TITLE_INPUT_MAX_LEN, &eol, &display_len);
671          title_input[len] = '\0';          title_input[len] = '\0';
# Line 327  int article_reply(SECTION_LIST *p_sectio Line 696  int article_reply(SECTION_LIST *p_sectio
696    
697          if ((row = mysql_fetch_row(rs)))          if ((row = mysql_fetch_row(rs)))
698          {          {
699                    content = malloc(ARTICLE_CONTENT_MAX_LEN);
700                    if (content == NULL)
701                    {
702                            log_error("malloc(content) error: OOM\n");
703                            ret = -1;
704                            goto cleanup;
705                    }
706    
707                    content_f = malloc(ARTICLE_CONTENT_MAX_LEN);
708                    if (content_f == NULL)
709                    {
710                            log_error("malloc(content_f) error: OOM\n");
711                            ret = -1;
712                            goto cleanup;
713                    }
714    
715                  // Apply LML render to content body                  // Apply LML render to content body
716                  len = lml_plain(row[1], content_f, ARTICLE_CONTENT_MAX_LEN);                  len = lml_plain(row[1], content_f, ARTICLE_CONTENT_MAX_LEN);
717                  content_f[len] = '\0';                  content_f[len] = '\0';
718    
719                    // Remove control sequence
720                    len = ctrl_seq_filter(content_f);
721    
722                    len = snprintf(content, ARTICLE_CONTENT_MAX_LEN,
723                                               "\n\n【 在 %s (%s) 的大作中提到: 】\n",
724                                               p_article->username, p_article->nickname);
725    
726                  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);
727                  for (i = 0, len = 0; i < quote_content_lines; i++)                  for (i = 0; i < quote_content_lines; i++)
728                  {                  {
729                          memcpy(content + len, ": ", 2); // quote line prefix                          memcpy(content + len, ": ", 2); // quote line prefix
730                          len += 2;                          len += 2;
731                          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]));
732                          len += (line_offsets[i + 1] - line_offsets[i]);                          len += (line_offsets[i + 1] - line_offsets[i]);
733                  }                  }
734                    if (content[len - 1] != '\n') // Appennd \n if not exist
735                    {
736                            content[len] = '\n';
737                            len++;
738                    }
739                  content[len] = '\0';                  content[len] = '\0';
740    
741                    free(content_f);
742                    content_f = NULL;
743    
744                    p_editor_data = editor_data_load(content);
745                    if (p_editor_data == NULL)
746                    {
747                            log_error("editor_data_load(aid=%d, cid=%d) error\n", p_article->aid, atoi(row[0]));
748                            ret = -3;
749                            goto cleanup;
750                    }
751    
752                    free(content);
753                    content = NULL;
754          }          }
755          mysql_free_result(rs);          mysql_free_result(rs);
756          mysql_close(db);          rs = NULL;
757    
758          p_editor_data = editor_data_load(content);          mysql_close(db);
759          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;  
         }  
760    
761          // Set title and sign          // Set title and sign
762          for (ch = 'T'; !SYS_server_exit;)          for (ch = 'T'; !SYS_server_exit;)
# Line 358  int article_reply(SECTION_LIST *p_sectio Line 765  int article_reply(SECTION_LIST *p_sectio
765                  moveto(21, 1);                  moveto(21, 1);
766                  prints("回复文章于 %s[%s] 讨论区", p_section->stitle, p_section->sname);                  prints("回复文章于 %s[%s] 讨论区", p_section->stitle, p_section->sname);
767                  moveto(22, 1);                  moveto(22, 1);
768                  prints("标题: %s", (title[0] == '\0' ? "[无]" : title));                  prints("标题: %s", (p_article_new->title[0] == '\0' ? "[无]" : p_article_new->title));
769                  moveto(23, 1);                  moveto(23, 1);
770                  prints("使用第 %d 个签名", sign_id);                  prints("使用第 %d 个签名", sign_id);
771    
# Line 391  int article_reply(SECTION_LIST *p_sectio Line 798  int article_reply(SECTION_LIST *p_sectio
798                                  len = q - p;                                  len = q - p;
799                                  if (*p != '\0')                                  if (*p != '\0')
800                                  {                                  {
801                                          memcpy(title, p, (size_t)len + 1);                                          memcpy(p_article_new->title, p, (size_t)len + 1);
802                                          memcpy(title_input, title, (size_t)len + 1);                                          memcpy(title_input, p_article_new->title, (size_t)len + 1);
803                                  }                                  }
804                                  ch = 0;                                  ch = 0;
805                                  break;                                  break;
# Line 415  int article_reply(SECTION_LIST *p_sectio Line 822  int article_reply(SECTION_LIST *p_sectio
822                          break;                          break;
823                  }                  }
824    
825                  if (ch != CR || title[0] == '\0')                  if (ch != CR || p_article_new->title[0] == '\0')
826                  {                  {
827                          continue;                          continue;
828                  }                  }
# Line 461  int article_reply(SECTION_LIST *p_sectio Line 868  int article_reply(SECTION_LIST *p_sectio
868                  }                  }
869          }          }
870    
871          // editor_data_save(p_editor_data, p_data_new, data_new_len);          content = malloc(ARTICLE_CONTENT_MAX_LEN);
872          log_common("Debug: reply article\n");          if (content == NULL)
873            {
874                    log_error("malloc(content) error: OOM\n");
875                    ret = -1;
876                    goto cleanup;
877            }
878    
879            len_content = editor_data_save(p_editor_data, content, ARTICLE_CONTENT_MAX_LEN);
880            if (len_content < 0)
881            {
882                    log_error("editor_data_save() error\n");
883                    ret = -2;
884                    goto cleanup;
885            }
886    
887            db = db_open();
888            if (db == NULL)
889            {
890                    log_error("db_open() error: %s\n", mysql_error(db));
891                    ret = -1;
892                    goto cleanup;
893            }
894    
895            if (sign_id > 0)
896            {
897                    snprintf(sql, sizeof(sql),
898                                     "SELECT sign_%d AS sign FROM user_pubinfo WHERE UID = %d",
899                                     sign_id, BBS_priv.uid);
900    
901                    if (mysql_query(db, sql) != 0)
902                    {
903                            log_error("Query sign error: %s\n", mysql_error(db));
904                            ret = -1;
905                            goto cleanup;
906                    }
907                    if ((rs = mysql_use_result(db)) == NULL)
908                    {
909                            log_error("Get sign data failed\n");
910                            ret = -1;
911                            goto cleanup;
912                    }
913    
914                    if ((row = mysql_fetch_row(rs)))
915                    {
916                            len_content += snprintf(content + len_content,
917                                                                            ARTICLE_CONTENT_MAX_LEN - (size_t)len_content,
918                                                                            "\n\n--\n%s\n", row[0]);
919                    }
920                    mysql_free_result(rs);
921                    rs = NULL;
922            }
923    
924            content_f = malloc((size_t)len_content * 2 + 1);
925            if (content_f == NULL)
926            {
927                    log_error("malloc(content_f) error: OOM\n");
928                    ret = -1;
929                    goto cleanup;
930            }
931    
932            sql_content = malloc(SQL_BUFFER_LEN + (size_t)len_content * 2 + 1);
933            if (sql_content == NULL)
934            {
935                    log_error("malloc(sql_content) error: OOM\n");
936                    ret = -1;
937                    goto cleanup;
938            }
939    
940            // Begin transaction
941            if (mysql_query(db, "SET autocommit=0") != 0)
942            {
943                    log_error("SET autocommit=0 error: %s\n", mysql_error(db));
944                    ret = -1;
945                    goto cleanup;
946            }
947    
948            if (mysql_query(db, "BEGIN") != 0)
949            {
950                    log_error("Begin transaction error: %s\n", mysql_error(db));
951                    ret = -1;
952                    goto cleanup;
953            }
954    
955            // Secure SQL parameters
956            mysql_real_escape_string(db, nickname_f, BBS_nickname, (unsigned long)strnlen(BBS_nickname, sizeof(BBS_nickname)));
957            mysql_real_escape_string(db, title_f, p_article_new->title, strnlen(p_article_new->title, sizeof(p_article_new->title)));
958            mysql_real_escape_string(db, content_f, content, (unsigned long)len_content);
959    
960            // Add content
961            snprintf(sql, SQL_BUFFER_LEN + (size_t)len_content * 2 + 1,
962                             "INSERT INTO bbs_content(AID, content) values(0, '%s')",
963                             content_f);
964    
965            if (mysql_query(db, sql) != 0)
966            {
967                    log_error("Add article content error: %s\n", mysql_error(db));
968                    ret = -1;
969                    goto cleanup;
970            }
971    
972            p_article_new->cid = (int32_t)mysql_insert_id(db);
973    
974            // Add article
975            snprintf(sql, sizeof(sql),
976                             "INSERT INTO bbs(SID, TID, UID, username, nickname, title, CID, transship, "
977                             "sub_dt, sub_ip, reply_note, exp, last_reply_dt, icon, length) "
978                             "VALUES(%d, 0, %d, '%s', '%s', '%s', %d, 0, NOW(), '%s', 1, %d, NOW(), 1, %ld)",
979                             p_section->sid, BBS_priv.uid, BBS_username, nickname_f, title_f,
980                             p_article_new->cid, hostaddr_client, BBS_user_exp, len_content);
981    
982            if (mysql_query(db, sql) != 0)
983            {
984                    log_error("Add article error: %s\n", mysql_error(db));
985                    ret = -1;
986                    goto cleanup;
987            }
988    
989            p_article_new->aid = (int32_t)mysql_insert_id(db);
990    
991            // Update topic article
992            snprintf(sql, sizeof(sql),
993                             "UPDATE bbs SET reply_count = reply_count + 1, "
994                             "last_reply_dt = NOW(), last_reply_UID=%d, last_reply_username = '%s', "
995                             "last_reply_nickname = '%s' WHERE Aid = %d",
996                             BBS_priv.uid, BBS_username, nickname_f, p_article->aid);
997    
998            // Link content to article
999            snprintf(sql, sizeof(sql),
1000                             "UPDATE bbs_content SET AID = %d WHERE CID = %d",
1001                             p_article_new->aid, p_article_new->cid);
1002    
1003            if (mysql_query(db, sql) != 0)
1004            {
1005                    log_error("Update content error: %s\n", mysql_error(db));
1006                    ret = -1;
1007                    goto cleanup;
1008            }
1009    
1010            // Add exp
1011            if (checkpriv(&BBS_priv, p_section->sid, S_GETEXP)) // Except in test section
1012            {
1013                    snprintf(sql, sizeof(sql),
1014                                     "UPDATE user_pubinfo SET exp = exp + %d WHERE UID = %d",
1015                                     3, BBS_priv.uid);
1016    
1017                    if (mysql_query(db, sql) != 0)
1018                    {
1019                            log_error("Update exp error: %s\n", mysql_error(db));
1020                            ret = -1;
1021                            goto cleanup;
1022                    }
1023            }
1024    
1025            // Add log
1026            snprintf(sql, sizeof(sql),
1027                             "INSERT INTO bbs_article_op(AID, UID, type, op_dt, op_ip)"
1028                             "VALUES(%d, %d, 'A', NOW(), '%s')",
1029                             p_article_new->aid, BBS_priv.uid, hostaddr_client);
1030    
1031            if (mysql_query(db, sql) != 0)
1032            {
1033                    log_error("Add log error: %s\n", mysql_error(db));
1034                    ret = -1;
1035                    goto cleanup;
1036            }
1037    
1038            // Commit transaction
1039            if (mysql_query(db, "COMMIT") != 0)
1040            {
1041                    log_error("Commit transaction error: %s\n", mysql_error(db));
1042                    ret = -1;
1043                    goto cleanup;
1044            }
1045    
1046            clearscr();
1047            moveto(1, 1);
1048            prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval);
1049            press_any_key();
1050            ret = 1; // Success
1051    
1052  cleanup:  cleanup:
1053            mysql_free_result(rs);
1054            mysql_close(db);
1055    
1056            // Cleanup buffers
1057          editor_data_cleanup(p_editor_data);          editor_data_cleanup(p_editor_data);
1058    
1059          return 0;          free(sql_content);
1060            free(content);
1061            free(content_f);
1062    
1063            return (int)ret;
1064  }  }


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

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