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


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

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