/[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.2 by sysadm, Thu Jun 12 12:53:49 2025 UTC Revision 1.7 by sysadm, Sat Jun 14 02:58:11 2025 UTC
# Line 19  Line 19 
19  #include "editor.h"  #include "editor.h"
20  #include "screen.h"  #include "screen.h"
21  #include "log.h"  #include "log.h"
22    #include "io.h"
23    #include "lml.h"
24    #include "database.h"
25    #include <ctype.h>
26    #include <string.h>
27    #include <stdlib.h>
28    
29  int article_post(SECTION_LIST *p_section, ARTICLE *p_article, ARTICLE_POST_TYPE type)  #define TITLE_INPUT_MAX_LEN 74
30    #define ARTICLE_CONTENT_MAX_LEN 1024 * 1024 * 4 // 4MB
31    #define ARTICLE_QUOTE_MAX_LINES 20
32    #define ARTICLE_QUOTE_LINE_MAX_LEN 76
33    
34    int article_post(SECTION_LIST *p_section)
35  {  {
36          ARTICLE_CACHE cache;          EDITOR_DATA *p_editor_data = NULL;
37          EDITOR_DATA *p_editor_data;          char title[BBS_article_title_max_len + 1];
38            char title_input[TITLE_INPUT_MAX_LEN + 1];
39            int sign_id = 0;
40            long len;
41            int ch;
42            char *p, *q;
43    
44            if (p_section == NULL)
45            {
46                    log_error("NULL pointer error\n");
47            }
48    
49          log_common("Debug: sid=%d aid=%d type=%d\n",          title[0] = '\0';
50                             p_section->sid, (p_article == NULL ? 0 : p_article->aid), type);          title_input[0] = '\0';
51    
52          switch (type)          p_editor_data = editor_data_load("");
53            if (p_editor_data == NULL)
54          {          {
55          case ARTICLE_POST_NEW:                  log_error("editor_data_load() error\n");
56                  p_editor_data = editor_data_load("");                  return -2;
57                  if (p_editor_data == NULL)          }
58    
59            // Set title and sign
60            for (ch = 'T'; !SYS_server_exit;)
61            {
62                    clearscr();
63                    moveto(21, 1);
64                    prints("发表文章于 %s[%s] 讨论区", p_section->stitle, p_section->sname);
65                    moveto(22, 1);
66                    prints("标题: %s", (title[0] == '\0' ? "[无]" : title));
67                    moveto(23, 1);
68                    prints("使用第 %d 个签名", sign_id);
69    
70                    if (toupper(ch) != 'T')
71                    {
72                            prints("    按0~3选签名档(0表示不使用)");
73    
74                            moveto(24, 1);
75                            prints("T改标题, C取消, Enter继续: ");
76                            iflush();
77                            ch = 0;
78                    }
79    
80                    for (; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))
81                    {
82                            switch (toupper(ch))
83                            {
84                            case CR:
85                                    igetch_reset();
86                                    break;
87                            case 'T':
88                                    moveto(24, 1);
89                                    clrtoeol();
90                                    len = get_data(24, 1, "标题: ", title_input, TITLE_INPUT_MAX_LEN, 1);
91                                    for (p = title_input; *p == ' '; p++)
92                                            ;
93                                    for (q = title_input + len; q > p && *(q - 1) == ' '; q--)
94                                            ;
95                                    *q = '\0';
96                                    len = q - p;
97                                    if (*p != '\0')
98                                    {
99                                            memcpy(title, p, (size_t)len + 1);
100                                            memcpy(title_input, title, (size_t)len + 1);
101                                    }
102                                    ch = 0;
103                                    break;
104                            case 'C':
105                                    clearscr();
106                                    moveto(1, 1);
107                                    prints("取消...");
108                                    press_any_key();
109                                    goto cleanup;
110                            case '0':
111                            case '1':
112                            case '2':
113                            case '3':
114                                    sign_id = ch - '0';
115                                    break;
116                            default: // Invalid selection
117                                    continue;
118                            }
119    
120                            break;
121                    }
122    
123                    if (ch != CR || title[0] == '\0')
124                  {                  {
125                          log_error("editor_data_load() error\n");                          continue;
126                          return -2;                  }
127    
128                    for (ch = 'E'; !SYS_server_exit && toupper(ch) == 'E';)
129                    {
130                            editor_display(p_editor_data);
131    
132                            clearscr();
133                            moveto(1, 1);
134                            prints("(S)发送, (C)取消, (T)更改标题 or (E)再编辑? [S]: ");
135                            iflush();
136    
137                            for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))
138                            {
139                                    switch (toupper(ch))
140                                    {
141                                    case CR:
142                                            igetch_reset();
143                                    case 'S':
144                                            break;
145                                    case 'C':
146                                            clearscr();
147                                            moveto(1, 1);
148                                            prints("取消...");
149                                            press_any_key();
150                                            goto cleanup;
151                                    case 'T':
152                                            break;
153                                    case 'E':
154                                            break;
155                                    default: // Invalid selection
156                                            continue;
157                                    }
158    
159                                    break;
160                            }
161                  }                  }
162                  break;  
163          case ARTICLE_POST_EDIT:                  if (toupper(ch) != 'T')
         case ARTICLE_POST_REPLY:  
                 if (article_cache_load(&cache, VAR_ARTICLE_CACHE_DIR, p_article) < 0)  
164                  {                  {
165                          log_error("article_cache_load(aid=%d, cid=%d) error\n", p_article->aid, p_article->cid);                          break;
                         return -2;  
166                  }                  }
167                  p_editor_data = editor_data_load(cache.p_data);          }
168    
169            // editor_data_save(p_editor_data, p_data_new, data_new_len);
170            log_common("Debug: post article\n");
171    
172    cleanup:
173            editor_data_cleanup(p_editor_data);
174    
175            return 0;
176    }
177    
178    int article_modify(SECTION_LIST *p_section, ARTICLE *p_article)
179    {
180            MYSQL *db;
181            MYSQL_RES *rs;
182            MYSQL_ROW row;
183            char sql[SQL_BUFFER_LEN];
184            int ch;
185    
186            EDITOR_DATA *p_editor_data = NULL;
187    
188            if (p_section == NULL || p_article == NULL)
189            {
190                    log_error("NULL pointer error\n");
191            }
192    
193            db = db_open();
194            if (db == NULL)
195            {
196                    log_error("db_open() error: %s\n", mysql_error(db));
197                    return -1;
198            }
199    
200            snprintf(sql, sizeof(sql),
201                             "SELECT bbs_content.CID, bbs_content.content "
202                             "FROM bbs INNER JOIN bbs_content ON bbs.CID = bbs_content.CID "
203                             "WHERE bbs.AID = %d",
204                             p_article->aid);
205    
206            if (mysql_query(db, sql) != 0)
207            {
208                    log_error("Query article content error: %s\n", mysql_error(db));
209                    return -2;
210            }
211            if ((rs = mysql_use_result(db)) == NULL)
212            {
213                    log_error("Get article content data failed\n");
214                    return -2;
215            }
216    
217            if ((row = mysql_fetch_row(rs)))
218            {
219                    p_editor_data = editor_data_load(row[1]);
220                  if (p_editor_data == NULL)                  if (p_editor_data == NULL)
221                  {                  {
222                          log_error("editor_data_load(aid=%d, cid=%d) error\n", p_article->aid, p_article->cid);                          log_error("editor_data_load(aid=%d, cid=%d) error\n", p_article->aid, atoi(row[0]));
223                          return -2;                          mysql_free_result(rs);
224                            mysql_close(db);
225                            return -3;
226                  }                  }
227                  if (article_cache_unload(&cache) < 0)          }
228            mysql_free_result(rs);
229            mysql_close(db);
230    
231            for (ch = 'E'; !SYS_server_exit && toupper(ch) == 'E';)
232            {
233                    editor_display(p_editor_data);
234    
235                    clearscr();
236                    moveto(1, 1);
237                    prints("(S)保存, (C)取消 or (E)再编辑? [S]: ");
238                    iflush();
239    
240                    for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))
241                  {                  {
242                          log_error("article_cache_unload(aid=%d, cid=%d) error\n", p_article->aid, p_article->cid);                          switch (toupper(ch))
243                          return -2;                          {
244                            case CR:
245                                    igetch_reset();
246                            case 'S':
247                                    break;
248                            case 'C':
249                                    clearscr();
250                                    moveto(1, 1);
251                                    prints("取消...");
252                                    press_any_key();
253                                    goto cleanup;
254                            case 'E':
255                                    break;
256                            default: // Invalid selection
257                                    continue;
258                            }
259    
260                            break;
261                  }                  }
262                  break;          }
263          default:  
264                  log_error("Unsupported type=%d\n", type);          // editor_data_save(p_editor_data, p_data_new, data_new_len);
265            log_common("Debug: modify article\n");
266    
267    cleanup:
268            editor_data_cleanup(p_editor_data);
269    
270            return 0;
271    }
272    
273    int article_reply(SECTION_LIST *p_section, ARTICLE *p_article)
274    {
275            MYSQL *db;
276            MYSQL_RES *rs;
277            MYSQL_ROW row;
278            char sql[SQL_BUFFER_LEN];
279            char content[LINE_BUFFER_LEN * ARTICLE_QUOTE_MAX_LINES + 1];
280            char content_f[ARTICLE_CONTENT_MAX_LEN];
281            long line_offsets[ARTICLE_QUOTE_MAX_LINES + 1];
282            EDITOR_DATA *p_editor_data = NULL;
283            char title[BBS_article_title_max_len + 1];
284            char title_input[BBS_article_title_max_len + 1 + 4]; // + "Re: "
285            int sign_id = 0;
286            long len;
287            int ch;
288            char *p, *q;
289            int eol;
290            int display_len;
291            long quote_content_lines;
292            long i;
293    
294            if (p_section == NULL || p_article == NULL)
295            {
296                    log_error("NULL pointer error\n");
297            }
298    
299            title[0] = '\0';
300            snprintf(title_input, sizeof(title_input), "Re: %s", p_article->title);
301            len = split_line(title_input, TITLE_INPUT_MAX_LEN, &eol, &display_len);
302            title_input[len] = '\0';
303    
304            db = db_open();
305            if (db == NULL)
306            {
307                    log_error("db_open() error: %s\n", mysql_error(db));
308                  return -1;                  return -1;
309          }          }
310    
311          editor_display(p_editor_data);          snprintf(sql, sizeof(sql),
312                             "SELECT bbs_content.CID, bbs_content.content "
313                             "FROM bbs INNER JOIN bbs_content ON bbs.CID = bbs_content.CID "
314                             "WHERE bbs.AID = %d",
315                             p_article->aid);
316    
317            if (mysql_query(db, sql) != 0)
318            {
319                    log_error("Query article content error: %s\n", mysql_error(db));
320                    return -2;
321            }
322            if ((rs = mysql_use_result(db)) == NULL)
323            {
324                    log_error("Get article content data failed\n");
325                    return -2;
326            }
327    
328            if ((row = mysql_fetch_row(rs)))
329            {
330                    // Apply LML render to content body
331                    len = lml_plain(row[1], content_f, ARTICLE_CONTENT_MAX_LEN);
332                    content_f[len] = '\0';
333    
334                    // Remove control sequence
335                    len = ctrl_seq_filter(content_f);
336    
337                    len = snprintf(content, sizeof(content), "\n\n【 在 %s (%s) 的大作中提到: 】\n", p_article->username, p_article->nickname);
338    
339                    quote_content_lines = split_data_lines(content_f, ARTICLE_QUOTE_LINE_MAX_LEN, line_offsets, ARTICLE_QUOTE_MAX_LINES + 1);
340                    for (i = 0; i < quote_content_lines; i++)
341                    {
342                            memcpy(content + len, ": ", 2); // quote line prefix
343                            len += 2;
344                            memcpy(content + len, content_f + line_offsets[i], (size_t)(line_offsets[i + 1] - line_offsets[i]));
345                            len += (line_offsets[i + 1] - line_offsets[i]);
346                    }
347                    content[len] = '\0';
348            }
349            mysql_free_result(rs);
350            mysql_close(db);
351    
352            p_editor_data = editor_data_load(content);
353            if (p_editor_data == NULL)
354            {
355                    log_error("editor_data_load(aid=%d, cid=%d) error\n", p_article->aid, atoi(row[0]));
356                    return -3;
357            }
358    
359            // Set title and sign
360            for (ch = 'T'; !SYS_server_exit;)
361            {
362                    clearscr();
363                    moveto(21, 1);
364                    prints("回复文章于 %s[%s] 讨论区", p_section->stitle, p_section->sname);
365                    moveto(22, 1);
366                    prints("标题: %s", (title[0] == '\0' ? "[无]" : title));
367                    moveto(23, 1);
368                    prints("使用第 %d 个签名", sign_id);
369    
370                    if (toupper(ch) != 'T')
371                    {
372                            prints("    按0~3选签名档(0表示不使用)");
373    
374                            moveto(24, 1);
375                            prints("T改标题, C取消, Enter继续: ");
376                            iflush();
377                            ch = 0;
378                    }
379    
380                    for (; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))
381                    {
382                            switch (toupper(ch))
383                            {
384                            case CR:
385                                    igetch_reset();
386                                    break;
387                            case 'T':
388                                    moveto(24, 1);
389                                    clrtoeol();
390                                    len = get_data(24, 1, "标题: ", title_input, TITLE_INPUT_MAX_LEN, 1);
391                                    for (p = title_input; *p == ' '; p++)
392                                            ;
393                                    for (q = title_input + len; q > p && *(q - 1) == ' '; q--)
394                                            ;
395                                    *q = '\0';
396                                    len = q - p;
397                                    if (*p != '\0')
398                                    {
399                                            memcpy(title, p, (size_t)len + 1);
400                                            memcpy(title_input, title, (size_t)len + 1);
401                                    }
402                                    ch = 0;
403                                    break;
404                            case 'C':
405                                    clearscr();
406                                    moveto(1, 1);
407                                    prints("取消...");
408                                    press_any_key();
409                                    goto cleanup;
410                            case '0':
411                            case '1':
412                            case '2':
413                            case '3':
414                                    sign_id = ch - '0';
415                                    break;
416                            default: // Invalid selection
417                                    continue;
418                            }
419    
420                            break;
421                    }
422    
423                    if (ch != CR || title[0] == '\0')
424                    {
425                            continue;
426                    }
427    
428                    for (ch = 'E'; !SYS_server_exit && toupper(ch) == 'E';)
429                    {
430                            editor_display(p_editor_data);
431    
432                            clearscr();
433                            moveto(1, 1);
434                            prints("(S)发送, (C)取消, (T)更改标题 or (E)再编辑? [S]: ");
435                            iflush();
436    
437                            for (ch = 0; !SYS_server_exit; ch = igetch_t(MAX_DELAY_TIME))
438                            {
439                                    switch (toupper(ch))
440                                    {
441                                    case CR:
442                                            igetch_reset();
443                                    case 'S':
444                                            break;
445                                    case 'C':
446                                            clearscr();
447                                            moveto(1, 1);
448                                            prints("取消...");
449                                            press_any_key();
450                                            goto cleanup;
451                                    case 'T':
452                                            break;
453                                    case 'E':
454                                            break;
455                                    default: // Invalid selection
456                                            continue;
457                                    }
458    
459                                    break;
460                            }
461                    }
462    
463                    if (toupper(ch) != 'T')
464                    {
465                            break;
466                    }
467            }
468    
469          // editor_data_save(p_editor_data, p_data_new, data_new_len);          // editor_data_save(p_editor_data, p_data_new, data_new_len);
470            log_common("Debug: reply article\n");
471    
472    cleanup:
473          editor_data_cleanup(p_editor_data);          editor_data_cleanup(p_editor_data);
474    
475          return 0;          return 0;


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

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