/[LeafOK_CVS]/lbbs/src/article_post.c
ViewVC logotype

Annotation of /lbbs/src/article_post.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.44 - (hide annotations)
Fri Dec 19 06:16:26 2025 UTC (2 months, 3 weeks ago) by sysadm
Branch: MAIN
Changes since 1.43: +68 -68 lines
Content type: text/x-csrc
Append \n to the end of logging message by log_...()
Remove ending \n from each logging message

1 sysadm 1.37 /* SPDX-License-Identifier: GPL-3.0-or-later */
2     /*
3     * article_post
4     * - user interactive feature to post / modify / reply article
5     *
6 sysadm 1.38 * Copyright (C) 2004-2025 Leaflet <leaflet@leafok.com>
7 sysadm 1.37 */
8 sysadm 1.1
9 sysadm 1.43 #ifdef HAVE_CONFIG_H
10     #include "config.h"
11     #endif
12    
13 sysadm 1.22 #include "article_cache.h"
14 sysadm 1.1 #include "article_post.h"
15 sysadm 1.22 #include "bbs.h"
16 sysadm 1.41 #include "bwf.h"
17 sysadm 1.22 #include "database.h"
18 sysadm 1.1 #include "editor.h"
19 sysadm 1.22 #include "io.h"
20 sysadm 1.1 #include "log.h"
21 sysadm 1.6 #include "lml.h"
22 sysadm 1.22 #include "screen.h"
23 sysadm 1.8 #include "user_priv.h"
24 sysadm 1.3 #include <ctype.h>
25     #include <string.h>
26 sysadm 1.6 #include <stdlib.h>
27 sysadm 1.8 #include <time.h>
28 sysadm 1.1
29 sysadm 1.40 enum _article_post_constant_t
30     {
31     TITLE_INPUT_MAX_LEN = 72,
32 sysadm 1.42 ARTICLE_QUOTE_DEFAULT_LINES = 20,
33 sysadm 1.40 MODIFY_DT_MAX_LEN = 50,
34     };
35 sysadm 1.8
36     int article_post(const SECTION_LIST *p_section, ARTICLE *p_article_new)
37 sysadm 1.1 {
38 sysadm 1.8 MYSQL *db = NULL;
39     MYSQL_RES *rs = NULL;
40     MYSQL_ROW row;
41     char sql[SQL_BUFFER_LEN];
42     char *sql_content = NULL;
43 sysadm 1.6 EDITOR_DATA *p_editor_data = NULL;
44 sysadm 1.24 char title_input[BBS_article_title_max_len + 1];
45 sysadm 1.8 char title_f[BBS_article_title_max_len * 2 + 1];
46     char *content = NULL;
47     char *content_f = NULL;
48     long len_content;
49 sysadm 1.24 int content_display_length;
50 sysadm 1.8 char nickname_f[BBS_nickname_max_len * 2 + 1];
51 sysadm 1.3 int sign_id = 0;
52 sysadm 1.29 int reply_note = 1;
53 sysadm 1.3 long len;
54     int ch;
55     char *p, *q;
56 sysadm 1.8 long ret = 0;
57 sysadm 1.3
58 sysadm 1.8 if (p_section == NULL || p_article_new == NULL)
59 sysadm 1.3 {
60 sysadm 1.44 log_error("NULL pointer error");
61 sysadm 1.3 }
62 sysadm 1.2
63 sysadm 1.12 if (!checkpriv(&BBS_priv, p_section->sid, S_POST))
64     {
65     clearscr();
66     moveto(1, 1);
67 sysadm 1.24 prints("您没有权限在本版块发表文章\n");
68 sysadm 1.12 press_any_key();
69    
70     return 0;
71     }
72    
73 sysadm 1.8 p_article_new->title[0] = '\0';
74 sysadm 1.6 title_input[0] = '\0';
75 sysadm 1.8 p_article_new->transship = 0;
76 sysadm 1.6
77 sysadm 1.3 p_editor_data = editor_data_load("");
78     if (p_editor_data == NULL)
79     {
80 sysadm 1.44 log_error("editor_data_load() error");
81 sysadm 1.16 ret = -1;
82     goto cleanup;
83 sysadm 1.3 }
84 sysadm 1.1
85 sysadm 1.3 // Set title and sign
86     for (ch = 'T'; !SYS_server_exit;)
87 sysadm 1.2 {
88 sysadm 1.3 clearscr();
89     moveto(21, 1);
90 sysadm 1.42 prints("发表文章于 %s[%s] 讨论区,类型: %s,回复通知: %s",
91 sysadm 1.29 p_section->stitle, p_section->sname,
92     (p_article_new->transship ? "转载" : "原创"),
93     (reply_note ? "开启" : "关闭"));
94 sysadm 1.3 moveto(22, 1);
95 sysadm 1.24 prints("标题: %s", (p_article_new->title[0] == '\0' ? "[无]" : p_article_new->title));
96 sysadm 1.3 moveto(23, 1);
97 sysadm 1.24 prints("使用第 %d 个签名", sign_id);
98 sysadm 1.3
99     if (toupper(ch) != 'T')
100 sysadm 1.2 {
101 sysadm 1.24 prints(" 按0~3选签名档(0表示不使用)");
102 sysadm 1.3
103     moveto(24, 1);
104 sysadm 1.29 prints("T改标题, C取消, Z设为%s, N%s, Enter继续: ",
105     (p_article_new->transship ? "原创" : "转载"),
106 sysadm 1.32 (reply_note ? "关闭回复通知" : "开启回复通知"));
107 sysadm 1.3 iflush();
108     ch = 0;
109 sysadm 1.2 }
110 sysadm 1.3
111 sysadm 1.41 while (!SYS_server_exit)
112 sysadm 1.2 {
113 sysadm 1.3 switch (toupper(ch))
114     {
115 sysadm 1.19 case KEY_NULL:
116     case KEY_TIMEOUT:
117     goto cleanup;
118 sysadm 1.3 case CR:
119     break;
120     case 'T':
121 sysadm 1.27 len = get_data(24, 1, "标题: ", title_input, sizeof(title_input), TITLE_INPUT_MAX_LEN);
122 sysadm 1.3 for (p = title_input; *p == ' '; p++)
123     ;
124     for (q = title_input + len; q > p && *(q - 1) == ' '; q--)
125     ;
126     *q = '\0';
127     len = q - p;
128     if (*p != '\0')
129     {
130 sysadm 1.41 if ((ret = check_badwords(p, '*')) < 0)
131     {
132 sysadm 1.44 log_error("check_badwords(title) error");
133 sysadm 1.41 }
134     else if (ret > 0)
135     {
136     memcpy(title_input, p, (size_t)len + 1);
137     continue;
138     }
139 sysadm 1.8 memcpy(p_article_new->title, p, (size_t)len + 1);
140     memcpy(title_input, p_article_new->title, (size_t)len + 1);
141 sysadm 1.3 }
142 sysadm 1.4 ch = 0;
143 sysadm 1.3 break;
144     case 'C':
145     clearscr();
146     moveto(1, 1);
147 sysadm 1.24 prints("取消...");
148 sysadm 1.3 press_any_key();
149     goto cleanup;
150 sysadm 1.29 case 'Z':
151     p_article_new->transship = (p_article_new->transship ? 0 : 1);
152 sysadm 1.8 break;
153 sysadm 1.29 case 'N':
154     reply_note = (reply_note ? 0 : 1);
155 sysadm 1.8 break;
156 sysadm 1.3 case '0':
157     case '1':
158     case '2':
159     case '3':
160     sign_id = ch - '0';
161     break;
162     default: // Invalid selection
163 sysadm 1.41 ch = igetch_t(BBS_max_user_idle_time);
164 sysadm 1.3 continue;
165     }
166    
167     break;
168 sysadm 1.2 }
169 sysadm 1.3
170 sysadm 1.8 if (ch != CR || p_article_new->title[0] == '\0')
171 sysadm 1.2 {
172 sysadm 1.3 continue;
173 sysadm 1.2 }
174 sysadm 1.3
175     for (ch = 'E'; !SYS_server_exit && toupper(ch) == 'E';)
176 sysadm 1.2 {
177 sysadm 1.3 editor_display(p_editor_data);
178    
179     clearscr();
180     moveto(1, 1);
181 sysadm 1.24 prints("(S)发送, (C)取消, (T)更改标题 or (E)再编辑? [S]: ");
182 sysadm 1.3 iflush();
183    
184 sysadm 1.39 for (ch = 0; !SYS_server_exit; ch = igetch_t(BBS_max_user_idle_time))
185 sysadm 1.3 {
186     switch (toupper(ch))
187     {
188 sysadm 1.19 case KEY_NULL:
189     case KEY_TIMEOUT:
190     goto cleanup;
191 sysadm 1.3 case CR:
192     case 'S':
193     break;
194     case 'C':
195     clearscr();
196     moveto(1, 1);
197 sysadm 1.24 prints("取消...");
198 sysadm 1.3 press_any_key();
199     goto cleanup;
200     case 'T':
201     break;
202     case 'E':
203     break;
204     default: // Invalid selection
205     continue;
206     }
207    
208     break;
209     }
210 sysadm 1.2 }
211 sysadm 1.5
212     if (toupper(ch) != 'T')
213     {
214     break;
215     }
216 sysadm 1.3 }
217    
218 sysadm 1.19 if (SYS_server_exit) // Do not save data on shutdown
219     {
220     goto cleanup;
221     }
222    
223 sysadm 1.8 content = malloc(ARTICLE_CONTENT_MAX_LEN);
224     if (content == NULL)
225     {
226 sysadm 1.44 log_error("malloc(content) error: OOM");
227 sysadm 1.8 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 sysadm 1.44 log_error("editor_data_save() error");
235 sysadm 1.16 ret = -1;
236 sysadm 1.8 goto cleanup;
237     }
238    
239 sysadm 1.41 if (check_badwords(content, '*') < 0)
240     {
241 sysadm 1.44 log_error("check_badwords(content) error");
242 sysadm 1.41 ret = -1;
243     goto cleanup;
244     }
245    
246 sysadm 1.8 db = db_open();
247     if (db == NULL)
248     {
249 sysadm 1.44 log_error("db_open() error: %s", mysql_error(db));
250 sysadm 1.8 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 sysadm 1.44 log_error("Query sign error: %s", mysql_error(db));
263 sysadm 1.8 ret = -1;
264     goto cleanup;
265     }
266     if ((rs = mysql_use_result(db)) == NULL)
267     {
268 sysadm 1.44 log_error("Get sign data failed");
269 sysadm 1.8 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 sysadm 1.24 // Calculate display length of content
284     content_display_length = str_length(content, 1);
285    
286 sysadm 1.8 // Begin transaction
287     if (mysql_query(db, "SET autocommit=0") != 0)
288     {
289 sysadm 1.44 log_error("SET autocommit=0 error: %s", mysql_error(db));
290 sysadm 1.8 ret = -1;
291     goto cleanup;
292     }
293    
294     if (mysql_query(db, "BEGIN") != 0)
295     {
296 sysadm 1.44 log_error("Begin transaction error: %s", mysql_error(db));
297 sysadm 1.8 ret = -1;
298     goto cleanup;
299     }
300    
301     // Secure SQL parameters
302 sysadm 1.13 content_f = malloc((size_t)len_content * 2 + 1);
303     if (content_f == NULL)
304     {
305 sysadm 1.44 log_error("malloc(content_f) error: OOM");
306 sysadm 1.13 ret = -1;
307     goto cleanup;
308     }
309    
310 sysadm 1.8 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 sysadm 1.13 free(content);
315     content = NULL;
316    
317 sysadm 1.8 // Add content
318 sysadm 1.13 sql_content = malloc(SQL_BUFFER_LEN + (size_t)len_content * 2 + 1);
319     if (sql_content == NULL)
320     {
321 sysadm 1.44 log_error("malloc(sql_content) error: OOM");
322 sysadm 1.13 ret = -1;
323     goto cleanup;
324     }
325    
326     snprintf(sql_content, SQL_BUFFER_LEN + (size_t)len_content * 2 + 1,
327 sysadm 1.8 "INSERT INTO bbs_content(AID, content) values(0, '%s')",
328     content_f);
329    
330 sysadm 1.13 free(content_f);
331     content_f = NULL;
332    
333     if (mysql_query(db, sql_content) != 0)
334 sysadm 1.8 {
335 sysadm 1.44 log_error("Add article content error: %s", mysql_error(db));
336 sysadm 1.8 ret = -1;
337     goto cleanup;
338     }
339    
340     p_article_new->cid = (int32_t)mysql_insert_id(db);
341    
342 sysadm 1.13 free(sql_content);
343     sql_content = NULL;
344    
345 sysadm 1.8 // 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 sysadm 1.29 "VALUES(%d, 0, %d, '%s', '%s', '%s', %d, %d, NOW(), '%s', %d, %d, NOW(), 1, %d)",
350 sysadm 1.8 p_section->sid, BBS_priv.uid, BBS_username, nickname_f, title_f,
351 sysadm 1.29 p_article_new->cid, p_article_new->transship, hostaddr_client,
352     reply_note, BBS_user_exp, content_display_length);
353 sysadm 1.8
354     if (mysql_query(db, sql) != 0)
355     {
356 sysadm 1.44 log_error("Add article error: %s", mysql_error(db));
357 sysadm 1.8 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 sysadm 1.44 log_error("Update content error: %s", mysql_error(db));
371 sysadm 1.8 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 sysadm 1.44 log_error("Update exp error: %s", mysql_error(db));
385 sysadm 1.8 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 sysadm 1.44 log_error("Add log error: %s", mysql_error(db));
399 sysadm 1.8 ret = -1;
400     goto cleanup;
401     }
402    
403     // Commit transaction
404     if (mysql_query(db, "COMMIT") != 0)
405     {
406 sysadm 1.44 log_error("Commit transaction error: %s", mysql_error(db));
407 sysadm 1.8 ret = -1;
408     goto cleanup;
409     }
410    
411 sysadm 1.17 mysql_close(db);
412     db = NULL;
413    
414 sysadm 1.8 clearscr();
415     moveto(1, 1);
416 sysadm 1.24 prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval);
417 sysadm 1.8 press_any_key();
418     ret = 1; // Success
419 sysadm 1.3
420     cleanup:
421 sysadm 1.8 mysql_close(db);
422    
423     // Cleanup buffers
424 sysadm 1.3 editor_data_cleanup(p_editor_data);
425    
426 sysadm 1.8 free(sql_content);
427     free(content);
428     free(content_f);
429    
430     return (int)ret;
431 sysadm 1.3 }
432    
433 sysadm 1.8 int article_modify(const SECTION_LIST *p_section, const ARTICLE *p_article, ARTICLE *p_article_new)
434 sysadm 1.3 {
435 sysadm 1.8 MYSQL *db = NULL;
436     MYSQL_RES *rs = NULL;
437 sysadm 1.6 MYSQL_ROW row;
438     char sql[SQL_BUFFER_LEN];
439 sysadm 1.8 char *sql_content = NULL;
440     char *content = NULL;
441     char *content_f = NULL;
442     long len_content;
443 sysadm 1.24 int content_display_length;
444 sysadm 1.29 int reply_note = 1;
445 sysadm 1.6 int ch;
446 sysadm 1.8 long ret = 0;
447     time_t now;
448     struct tm tm_modify_dt;
449     char str_modify_dt[MODIFY_DT_MAX_LEN + 1];
450 sysadm 1.6
451     EDITOR_DATA *p_editor_data = NULL;
452 sysadm 1.3
453     if (p_section == NULL || p_article == NULL)
454     {
455 sysadm 1.44 log_error("NULL pointer error");
456 sysadm 1.3 }
457    
458 sysadm 1.8 if (p_article->excerption) // Modify is not allowed
459     {
460     clearscr();
461     moveto(1, 1);
462 sysadm 1.24 prints("该文章无法被编辑,请联系版主。");
463 sysadm 1.8 press_any_key();
464    
465     return 0;
466     }
467    
468 sysadm 1.6 db = db_open();
469     if (db == NULL)
470 sysadm 1.3 {
471 sysadm 1.44 log_error("db_open() error: %s", mysql_error(db));
472 sysadm 1.16 ret = -1;
473     goto cleanup;
474 sysadm 1.6 }
475    
476     snprintf(sql, sizeof(sql),
477 sysadm 1.29 "SELECT bbs_content.CID, bbs_content.content, reply_note "
478 sysadm 1.6 "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 sysadm 1.44 log_error("Query article content error: %s", mysql_error(db));
485 sysadm 1.16 ret = -1;
486 sysadm 1.8 goto cleanup;
487 sysadm 1.3 }
488 sysadm 1.6 if ((rs = mysql_use_result(db)) == NULL)
489 sysadm 1.3 {
490 sysadm 1.44 log_error("Get article content data failed");
491 sysadm 1.16 ret = -1;
492 sysadm 1.8 goto cleanup;
493 sysadm 1.3 }
494 sysadm 1.5
495 sysadm 1.6 if ((row = mysql_fetch_row(rs)))
496 sysadm 1.3 {
497 sysadm 1.13 content = malloc(ARTICLE_CONTENT_MAX_LEN);
498     if (content == NULL)
499     {
500 sysadm 1.44 log_error("malloc(content) error: OOM");
501 sysadm 1.13 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 sysadm 1.20 len_content = str_filter(content, 0);
510 sysadm 1.13
511     p_editor_data = editor_data_load(content);
512 sysadm 1.6 if (p_editor_data == NULL)
513     {
514 sysadm 1.44 log_error("editor_data_load(aid=%d, cid=%d) error", p_article->aid, atoi(row[0]));
515 sysadm 1.16 ret = -1;
516 sysadm 1.8 goto cleanup;
517 sysadm 1.6 }
518 sysadm 1.13
519     free(content);
520     content = NULL;
521 sysadm 1.29
522     reply_note = atoi(row[2]);
523 sysadm 1.3 }
524 sysadm 1.6 mysql_free_result(rs);
525 sysadm 1.8 rs = NULL;
526    
527 sysadm 1.6 mysql_close(db);
528 sysadm 1.8 db = NULL;
529 sysadm 1.3
530 sysadm 1.6 for (ch = 'E'; !SYS_server_exit && toupper(ch) == 'E';)
531     {
532     editor_display(p_editor_data);
533    
534 sysadm 1.29 while (!SYS_server_exit)
535     {
536     clearscr();
537     moveto(1, 1);
538 sysadm 1.32 prints("(S)保存, (C)取消, (N)%s回复通知 or (E)再编辑? [S]: ",
539 sysadm 1.29 (reply_note ? "关闭" : "开启"));
540     iflush();
541 sysadm 1.6
542 sysadm 1.39 ch = igetch_t(BBS_max_user_idle_time);
543 sysadm 1.6 switch (toupper(ch))
544     {
545 sysadm 1.19 case KEY_NULL:
546     case KEY_TIMEOUT:
547     goto cleanup;
548 sysadm 1.6 case CR:
549     case 'S':
550     break;
551     case 'C':
552     clearscr();
553     moveto(1, 1);
554 sysadm 1.24 prints("取消...");
555 sysadm 1.6 press_any_key();
556     goto cleanup;
557 sysadm 1.29 case 'N':
558     reply_note = (reply_note ? 0 : 1);
559     continue;
560 sysadm 1.6 case 'E':
561     break;
562     default: // Invalid selection
563     continue;
564     }
565    
566     break;
567     }
568     }
569 sysadm 1.3
570 sysadm 1.19 if (SYS_server_exit) // Do not save data on shutdown
571     {
572     goto cleanup;
573     }
574    
575 sysadm 1.8 // Allocate buffers in big size
576     content = malloc(ARTICLE_CONTENT_MAX_LEN);
577     if (content == NULL)
578     {
579 sysadm 1.44 log_error("malloc(content) error: OOM");
580 sysadm 1.8 ret = -1;
581     goto cleanup;
582     }
583    
584     len_content = editor_data_save(p_editor_data, content, ARTICLE_CONTENT_MAX_LEN - LINE_BUFFER_LEN);
585     if (len_content < 0)
586     {
587 sysadm 1.44 log_error("editor_data_save() error");
588 sysadm 1.16 ret = -1;
589 sysadm 1.8 goto cleanup;
590     }
591    
592 sysadm 1.41 if (check_badwords(content, '*') < 0)
593     {
594 sysadm 1.44 log_error("check_badwords(content) error");
595 sysadm 1.41 ret = -1;
596     goto cleanup;
597     }
598    
599 sysadm 1.8 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 sysadm 1.24 "\n--\n※ 作者已于 %s 修改本文※\n",
605 sysadm 1.8 str_modify_dt);
606    
607 sysadm 1.24 // Calculate display length of content
608     content_display_length = str_length(content, 1);
609    
610 sysadm 1.8 db = db_open();
611     if (db == NULL)
612     {
613 sysadm 1.44 log_error("db_open() error: %s", mysql_error(db));
614 sysadm 1.8 ret = -1;
615     goto cleanup;
616     }
617    
618     // Begin transaction
619     if (mysql_query(db, "SET autocommit=0") != 0)
620     {
621 sysadm 1.44 log_error("SET autocommit=0 error: %s", mysql_error(db));
622 sysadm 1.8 ret = -1;
623     goto cleanup;
624     }
625    
626     if (mysql_query(db, "BEGIN") != 0)
627     {
628 sysadm 1.44 log_error("Begin transaction error: %s", mysql_error(db));
629 sysadm 1.8 ret = -1;
630     goto cleanup;
631     }
632    
633     // Secure SQL parameters
634 sysadm 1.13 content_f = malloc((size_t)len_content * 2 + 1);
635     if (content_f == NULL)
636     {
637 sysadm 1.44 log_error("malloc(content_f) error: OOM");
638 sysadm 1.13 ret = -1;
639     goto cleanup;
640     }
641    
642 sysadm 1.8 mysql_real_escape_string(db, content_f, content, (unsigned long)len_content);
643    
644 sysadm 1.13 free(content);
645     content = NULL;
646    
647 sysadm 1.8 // Add content
648 sysadm 1.13 sql_content = malloc(SQL_BUFFER_LEN + (size_t)len_content * 2 + 1);
649     if (sql_content == NULL)
650     {
651 sysadm 1.44 log_error("malloc(sql_content) error: OOM");
652 sysadm 1.13 ret = -1;
653     goto cleanup;
654     }
655    
656     snprintf(sql_content, SQL_BUFFER_LEN + (size_t)len_content * 2 + 1,
657 sysadm 1.8 "INSERT INTO bbs_content(AID, content) values(%d, '%s')",
658     p_article->aid, content_f);
659    
660 sysadm 1.13 free(content_f);
661     content_f = NULL;
662    
663     if (mysql_query(db, sql_content) != 0)
664 sysadm 1.8 {
665 sysadm 1.44 log_error("Add article content error: %s", mysql_error(db));
666 sysadm 1.8 ret = -1;
667     goto cleanup;
668     }
669    
670     p_article_new->cid = (int32_t)mysql_insert_id(db);
671    
672 sysadm 1.13 free(sql_content);
673     sql_content = NULL;
674    
675 sysadm 1.8 // Update article
676     snprintf(sql, sizeof(sql),
677 sysadm 1.29 "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 sysadm 1.8
680     if (mysql_query(db, sql) != 0)
681     {
682 sysadm 1.44 log_error("Add article error: %s", mysql_error(db));
683 sysadm 1.8 ret = -1;
684     goto cleanup;
685     }
686    
687     if (mysql_query(db, sql) != 0)
688     {
689 sysadm 1.44 log_error("Update content error: %s", mysql_error(db));
690 sysadm 1.8 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 sysadm 1.44 log_error("Add log error: %s", mysql_error(db));
703 sysadm 1.8 ret = -1;
704     goto cleanup;
705     }
706    
707     // Commit transaction
708     if (mysql_query(db, "COMMIT") != 0)
709     {
710 sysadm 1.44 log_error("Commit transaction error: %s", mysql_error(db));
711 sysadm 1.8 ret = -1;
712     goto cleanup;
713     }
714    
715 sysadm 1.17 mysql_close(db);
716     db = NULL;
717    
718 sysadm 1.8 clearscr();
719     moveto(1, 1);
720 sysadm 1.24 prints("修改完成,新内容通常会在%d秒后可见", BBS_section_list_load_interval);
721 sysadm 1.8 press_any_key();
722     ret = 1; // Success
723 sysadm 1.3
724 sysadm 1.6 cleanup:
725 sysadm 1.13 mysql_free_result(rs);
726 sysadm 1.8 mysql_close(db);
727    
728     // Cleanup buffers
729 sysadm 1.3 editor_data_cleanup(p_editor_data);
730    
731 sysadm 1.8 free(sql_content);
732     free(content);
733     free(content_f);
734    
735     return (int)ret;
736 sysadm 1.3 }
737    
738 sysadm 1.8 int article_reply(const SECTION_LIST *p_section, const ARTICLE *p_article, ARTICLE *p_article_new)
739 sysadm 1.3 {
740 sysadm 1.8 MYSQL *db = NULL;
741     MYSQL_RES *rs = NULL;
742 sysadm 1.6 MYSQL_ROW row;
743 sysadm 1.42 long line_offsets[MAX_EDITOR_DATA_LINES + 1];
744 sysadm 1.6 char sql[SQL_BUFFER_LEN];
745 sysadm 1.8 char *sql_content = NULL;
746 sysadm 1.6 EDITOR_DATA *p_editor_data = NULL;
747 sysadm 1.8 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 sysadm 1.24 int content_display_length;
753 sysadm 1.8 char nickname_f[BBS_nickname_max_len * 2 + 1];
754 sysadm 1.6 int sign_id = 0;
755 sysadm 1.30 int reply_note = 0;
756 sysadm 1.42 int full_quote = 0;
757 sysadm 1.6 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 sysadm 1.8 long ret = 0;
765 sysadm 1.14 int topic_locked = 0;
766 sysadm 1.28 char msg[BBS_msg_max_len];
767     char msg_f[BBS_msg_max_len * 2 + 1];
768     int len_msg;
769 sysadm 1.3
770     if (p_section == NULL || p_article == NULL)
771     {
772 sysadm 1.44 log_error("NULL pointer error");
773 sysadm 1.3 }
774    
775 sysadm 1.12 if (!checkpriv(&BBS_priv, p_section->sid, S_POST))
776     {
777     clearscr();
778     moveto(1, 1);
779 sysadm 1.24 prints("您没有权限在本版块发表文章\n");
780 sysadm 1.12 press_any_key();
781    
782     return 0;
783     }
784    
785 sysadm 1.8 p_article_new->title[0] = '\0';
786 sysadm 1.6 snprintf(title_input, sizeof(title_input), "Re: %s", p_article->title);
787 sysadm 1.20 len = split_line(title_input, TITLE_INPUT_MAX_LEN, &eol, &display_len, 0);
788 sysadm 1.6 title_input[len] = '\0';
789    
790     db = db_open();
791     if (db == NULL)
792     {
793 sysadm 1.44 log_error("db_open() error: %s", mysql_error(db));
794 sysadm 1.16 ret = -1;
795     goto cleanup;
796 sysadm 1.6 }
797    
798     snprintf(sql, sizeof(sql),
799 sysadm 1.14 "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 sysadm 1.44 log_error("Query article status error: %s", mysql_error(db));
805 sysadm 1.16 ret = -1;
806     goto cleanup;
807 sysadm 1.14 }
808     if ((rs = mysql_store_result(db)) == NULL)
809     {
810 sysadm 1.44 log_error("Get article status data failed");
811 sysadm 1.16 ret = -1;
812     goto cleanup;
813 sysadm 1.14 }
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 sysadm 1.17 mysql_close(db);
828     db = NULL;
829 sysadm 1.18
830 sysadm 1.14 clearscr();
831     moveto(1, 1);
832 sysadm 1.24 prints("该主题谢绝回复");
833 sysadm 1.14 press_any_key();
834    
835     goto cleanup;
836     }
837    
838     snprintf(sql, sizeof(sql),
839 sysadm 1.6 "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 sysadm 1.3 {
846 sysadm 1.44 log_error("Query article content error: %s", mysql_error(db));
847 sysadm 1.16 ret = -1;
848     goto cleanup;
849 sysadm 1.6 }
850     if ((rs = mysql_use_result(db)) == NULL)
851     {
852 sysadm 1.44 log_error("Get article content data failed");
853 sysadm 1.16 ret = -1;
854     goto cleanup;
855 sysadm 1.3 }
856 sysadm 1.5
857 sysadm 1.6 if ((row = mysql_fetch_row(rs)))
858     {
859 sysadm 1.8 content = malloc(ARTICLE_CONTENT_MAX_LEN);
860     if (content == NULL)
861     {
862 sysadm 1.44 log_error("malloc(content) error: OOM");
863 sysadm 1.8 ret = -1;
864     goto cleanup;
865     }
866    
867     content_f = malloc(ARTICLE_CONTENT_MAX_LEN);
868     if (content_f == NULL)
869     {
870 sysadm 1.44 log_error("malloc(content_f) error: OOM");
871 sysadm 1.8 ret = -1;
872     goto cleanup;
873     }
874    
875 sysadm 1.6 // Apply LML render to content body
876 sysadm 1.36 len = lml_render(row[1], content_f, ARTICLE_CONTENT_MAX_LEN, MAX_EDITOR_DATA_LINE_LENGTH - 3, 1);
877 sysadm 1.6 content_f[len] = '\0';
878    
879 sysadm 1.7 // Remove control sequence
880 sysadm 1.20 len = str_filter(content_f, 0);
881 sysadm 1.6 }
882     mysql_free_result(rs);
883 sysadm 1.8 rs = NULL;
884    
885 sysadm 1.6 mysql_close(db);
886 sysadm 1.8 db = NULL;
887 sysadm 1.5
888 sysadm 1.6 // Set title and sign
889     for (ch = 'T'; !SYS_server_exit;)
890 sysadm 1.3 {
891 sysadm 1.6 clearscr();
892     moveto(21, 1);
893 sysadm 1.42 prints("回复文章于 %s[%s] 讨论区, 回复通知: %s, 引用模式: %s",
894     p_section->stitle, p_section->sname,
895     (reply_note ? "开启" : "关闭"),
896     (full_quote ? "完整" : "精简"));
897 sysadm 1.6 moveto(22, 1);
898 sysadm 1.24 prints("标题: %s", (p_article_new->title[0] == '\0' ? "[无]" : p_article_new->title));
899 sysadm 1.6 moveto(23, 1);
900 sysadm 1.24 prints("使用第 %d 个签名", sign_id);
901 sysadm 1.6
902     if (toupper(ch) != 'T')
903     {
904 sysadm 1.24 prints(" 按0~3选签名档(0表示不使用)");
905 sysadm 1.6
906     moveto(24, 1);
907 sysadm 1.42 prints("T改标题, C取消, N%s, Q%s, Enter继续: ",
908     (reply_note ? "关闭回复通知" : "开启回复通知"), (full_quote ? "精简引用" : "完整引用"));
909 sysadm 1.6 iflush();
910     ch = 0;
911     }
912    
913 sysadm 1.41 while (!SYS_server_exit)
914 sysadm 1.6 {
915     switch (toupper(ch))
916     {
917 sysadm 1.19 case KEY_NULL:
918     case KEY_TIMEOUT:
919     goto cleanup;
920 sysadm 1.6 case CR:
921     break;
922     case 'T':
923 sysadm 1.27 len = get_data(24, 1, "标题: ", title_input, sizeof(title_input), TITLE_INPUT_MAX_LEN);
924 sysadm 1.6 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 sysadm 1.41 if ((ret = check_badwords(p, '*')) < 0)
933     {
934 sysadm 1.44 log_error("check_badwords(title) error");
935 sysadm 1.41 }
936     else if (ret > 0)
937     {
938     memcpy(title_input, p, (size_t)len + 1);
939     continue;
940     }
941 sysadm 1.8 memcpy(p_article_new->title, p, (size_t)len + 1);
942     memcpy(title_input, p_article_new->title, (size_t)len + 1);
943 sysadm 1.6 }
944     ch = 0;
945     break;
946     case 'C':
947     clearscr();
948     moveto(1, 1);
949 sysadm 1.24 prints("取消...");
950 sysadm 1.6 press_any_key();
951     goto cleanup;
952 sysadm 1.29 case 'N':
953     reply_note = (reply_note ? 0 : 1);
954     break;
955 sysadm 1.42 case 'Q':
956     full_quote = (full_quote ? 0 : 1);
957     break;
958 sysadm 1.6 case '0':
959     case '1':
960     case '2':
961     case '3':
962     sign_id = ch - '0';
963     break;
964     default: // Invalid selection
965 sysadm 1.41 ch = igetch_t(BBS_max_user_idle_time);
966 sysadm 1.6 continue;
967     }
968    
969     break;
970     }
971    
972 sysadm 1.8 if (ch != CR || p_article_new->title[0] == '\0')
973 sysadm 1.6 {
974     continue;
975     }
976    
977 sysadm 1.42 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 sysadm 1.44 log_error("editor_data_load(aid=%d, cid=%d) error", p_article->aid, atoi(row[0]));
1011 sysadm 1.42 ret = -1;
1012     goto cleanup;
1013     }
1014    
1015     free(content);
1016     content = NULL;
1017    
1018 sysadm 1.6 for (ch = 'E'; !SYS_server_exit && toupper(ch) == 'E';)
1019     {
1020     editor_display(p_editor_data);
1021    
1022     clearscr();
1023     moveto(1, 1);
1024 sysadm 1.24 prints("(S)发送, (C)取消, (T)更改标题 or (E)再编辑? [S]: ");
1025 sysadm 1.6 iflush();
1026    
1027 sysadm 1.39 for (ch = 0; !SYS_server_exit; ch = igetch_t(BBS_max_user_idle_time))
1028 sysadm 1.6 {
1029     switch (toupper(ch))
1030     {
1031 sysadm 1.19 case KEY_NULL:
1032     case KEY_TIMEOUT:
1033     goto cleanup;
1034 sysadm 1.6 case CR:
1035     case 'S':
1036     break;
1037     case 'C':
1038     clearscr();
1039     moveto(1, 1);
1040 sysadm 1.24 prints("取消...");
1041 sysadm 1.6 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 sysadm 1.2 }
1060    
1061 sysadm 1.19 if (SYS_server_exit) // Do not save data on shutdown
1062     {
1063     goto cleanup;
1064     }
1065    
1066 sysadm 1.8 content = malloc(ARTICLE_CONTENT_MAX_LEN);
1067     if (content == NULL)
1068     {
1069 sysadm 1.44 log_error("malloc(content) error: OOM");
1070 sysadm 1.8 ret = -1;
1071     goto cleanup;
1072     }
1073    
1074     len_content = editor_data_save(p_editor_data, content, ARTICLE_CONTENT_MAX_LEN);
1075     if (len_content < 0)
1076     {
1077 sysadm 1.44 log_error("editor_data_save() error");
1078 sysadm 1.16 ret = -1;
1079 sysadm 1.8 goto cleanup;
1080     }
1081    
1082 sysadm 1.41 if (check_badwords(content, '*') < 0)
1083     {
1084 sysadm 1.44 log_error("check_badwords(content) error");
1085 sysadm 1.41 ret = -1;
1086     goto cleanup;
1087     }
1088    
1089 sysadm 1.8 db = db_open();
1090     if (db == NULL)
1091     {
1092 sysadm 1.44 log_error("db_open() error: %s", mysql_error(db));
1093 sysadm 1.8 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     if (mysql_query(db, sql) != 0)
1104     {
1105 sysadm 1.44 log_error("Query sign error: %s", mysql_error(db));
1106 sysadm 1.8 ret = -1;
1107     goto cleanup;
1108     }
1109     if ((rs = mysql_use_result(db)) == NULL)
1110     {
1111 sysadm 1.44 log_error("Get sign data failed");
1112 sysadm 1.8 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 sysadm 1.24 // Calculate display length of content
1127     content_display_length = str_length(content, 1);
1128    
1129 sysadm 1.8 // Begin transaction
1130     if (mysql_query(db, "SET autocommit=0") != 0)
1131     {
1132 sysadm 1.44 log_error("SET autocommit=0 error: %s", mysql_error(db));
1133 sysadm 1.8 ret = -1;
1134     goto cleanup;
1135     }
1136    
1137     if (mysql_query(db, "BEGIN") != 0)
1138     {
1139 sysadm 1.44 log_error("Begin transaction error: %s", mysql_error(db));
1140 sysadm 1.8 ret = -1;
1141     goto cleanup;
1142     }
1143    
1144     // Secure SQL parameters
1145 sysadm 1.13 content_f = malloc((size_t)len_content * 2 + 1);
1146     if (content_f == NULL)
1147     {
1148 sysadm 1.44 log_error("malloc(content_f) error: OOM");
1149 sysadm 1.13 ret = -1;
1150     goto cleanup;
1151     }
1152    
1153 sysadm 1.8 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 sysadm 1.13 free(content);
1158     content = NULL;
1159    
1160 sysadm 1.8 // Add content
1161 sysadm 1.13 sql_content = malloc(SQL_BUFFER_LEN + (size_t)len_content * 2 + 1);
1162     if (sql_content == NULL)
1163     {
1164 sysadm 1.44 log_error("malloc(sql_content) error: OOM");
1165 sysadm 1.13 ret = -1;
1166     goto cleanup;
1167     }
1168    
1169     snprintf(sql_content, SQL_BUFFER_LEN + (size_t)len_content * 2 + 1,
1170 sysadm 1.8 "INSERT INTO bbs_content(AID, content) values(0, '%s')",
1171     content_f);
1172    
1173 sysadm 1.13 free(content_f);
1174     content_f = NULL;
1175    
1176     if (mysql_query(db, sql_content) != 0)
1177 sysadm 1.8 {
1178 sysadm 1.44 log_error("Add article content error: %s", mysql_error(db));
1179 sysadm 1.8 ret = -1;
1180     goto cleanup;
1181     }
1182    
1183     p_article_new->cid = (int32_t)mysql_insert_id(db);
1184    
1185 sysadm 1.13 free(sql_content);
1186     sql_content = NULL;
1187    
1188 sysadm 1.8 // 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 sysadm 1.29 "VALUES(%d, %d, %d, '%s', '%s', '%s', %d, 0, NOW(), '%s', %d, %d, NOW(), 1, %d)",
1193 sysadm 1.11 p_section->sid, (p_article->tid == 0 ? p_article->aid : p_article->tid),
1194     BBS_priv.uid, BBS_username, nickname_f, title_f,
1195 sysadm 1.29 p_article_new->cid, hostaddr_client,
1196     reply_note, BBS_user_exp, content_display_length);
1197 sysadm 1.8
1198     if (mysql_query(db, sql) != 0)
1199     {
1200 sysadm 1.44 log_error("Add article error: %s", mysql_error(db));
1201 sysadm 1.8 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 sysadm 1.12 "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 sysadm 1.44 log_error("Update topic article error: %s", mysql_error(db));
1218 sysadm 1.12 ret = -1;
1219     goto cleanup;
1220     }
1221 sysadm 1.8
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 sysadm 1.44 log_error("Update content error: %s", mysql_error(db));
1230 sysadm 1.8 ret = -1;
1231     goto cleanup;
1232     }
1233    
1234 sysadm 1.28 // 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 sysadm 1.44 log_error("Read reply info error: %s", mysql_error(db));
1243 sysadm 1.28 ret = -1;
1244     goto cleanup;
1245     }
1246     if ((rs = mysql_store_result(db)) == NULL)
1247     {
1248 sysadm 1.44 log_error("Get reply info failed");
1249 sysadm 1.28 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 sysadm 1.31 "有人回复了您所发表/回复的文章,快来"
1258 sysadm 1.28 "[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 sysadm 1.44 log_error("Insert msg error: %s", mysql_error(db));
1271 sysadm 1.28 ret = -1;
1272     goto cleanup;
1273     }
1274     }
1275     mysql_free_result(rs);
1276     rs = NULL;
1277    
1278 sysadm 1.8 // 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 sysadm 1.44 log_error("Update exp error: %s", mysql_error(db));
1288 sysadm 1.8 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 sysadm 1.44 log_error("Add log error: %s", mysql_error(db));
1302 sysadm 1.8 ret = -1;
1303     goto cleanup;
1304     }
1305    
1306     // Commit transaction
1307     if (mysql_query(db, "COMMIT") != 0)
1308     {
1309 sysadm 1.44 log_error("Commit transaction error: %s", mysql_error(db));
1310 sysadm 1.8 ret = -1;
1311     goto cleanup;
1312     }
1313    
1314 sysadm 1.17 mysql_close(db);
1315     db = NULL;
1316    
1317 sysadm 1.8 clearscr();
1318     moveto(1, 1);
1319 sysadm 1.24 prints("发送完成,新文章通常会在%d秒后可见", BBS_section_list_load_interval);
1320 sysadm 1.8 press_any_key();
1321     ret = 1; // Success
1322 sysadm 1.2
1323 sysadm 1.6 cleanup:
1324 sysadm 1.8 mysql_free_result(rs);
1325     mysql_close(db);
1326    
1327     // Cleanup buffers
1328 sysadm 1.2 editor_data_cleanup(p_editor_data);
1329    
1330 sysadm 1.8 free(sql_content);
1331     free(content);
1332     free(content_f);
1333    
1334     return (int)ret;
1335 sysadm 1.1 }

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