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


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

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