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

Contents of /lbbs/src/section_list_display.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.67 - (show annotations)
Mon Nov 3 15:06:46 2025 UTC (4 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.66: +38 -11 lines
Content type: text/x-csrc
query_section_articles after article reply / delete / edit

1 /***************************************************************************
2 section_list_display.c - description
3 -------------------
4 Copyright : (C) 2004-2025 by Leaflet
5 Email : leaflet@leafok.com
6 ***************************************************************************/
7
8 /***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 3 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16
17 #include "article_cache.h"
18 #include "article_favor.h"
19 #include "article_op.h"
20 #include "article_post.h"
21 #include "article_view_log.h"
22 #include "article_del.h"
23 #include "common.h"
24 #include "io.h"
25 #include "log.h"
26 #include "login.h"
27 #include "menu.h"
28 #include "menu_proc.h"
29 #include "section_list_display.h"
30 #include "section_list_loader.h"
31 #include "screen.h"
32 #include "str_process.h"
33 #include "user_info_display.h"
34 #include "user_list_display.h"
35 #include "user_priv.h"
36 #include <ctype.h>
37 #include <errno.h>
38 #include <string.h>
39 #include <time.h>
40 #include <sys/param.h>
41
42 #define TITLE_SEARCH_MAX_LEN 60
43
44 static int32_t section_aid_locations[BBS_max_section] = {0};
45 static int section_topic_view_mode = 0;
46 static int section_topic_view_tid = -1;
47
48 enum select_cmd_t
49 {
50 EXIT_SECTION = 0,
51 VIEW_ARTICLE,
52 CHANGE_PAGE,
53 SHOW_HELP,
54 CHANGE_NAME_DISPLAY,
55 POST_ARTICLE,
56 EDIT_ARTICLE,
57 DELETE_ARTICLE,
58 QUERY_ARTICLE,
59 QUERY_USER,
60 SET_FAVOR_ARTICLE,
61 UNSET_FAVOR_ARTICLE,
62 FIRST_TOPIC_ARTICLE,
63 LAST_TOPIC_ARTICLE,
64 SCAN_NEW_ARTICLE,
65 SCAN_ARTICLE_BACKWARD_BY_USER,
66 SCAN_ARTICLE_FORWARD_BY_USER,
67 SCAN_ARTICLE_BACKWARD_BY_TITLE,
68 SCAN_ARTICLE_FORWARD_BY_TITLE,
69 VIEW_EX_DIR,
70 SHOW_TOP10,
71 SEARCH_USER,
72 };
73
74 static int section_list_draw_items(int page_id, ARTICLE *p_articles[], int article_count, int display_nickname, int ontop_start_offset)
75 {
76 char str_time[LINE_BUFFER_LEN];
77 struct tm tm_sub;
78 char title_f[BBS_article_title_max_len + 1];
79 int title_f_len;
80 int eol;
81 int len;
82 int i;
83 size_t j;
84 char article_flag;
85 int is_viewed;
86 int is_favor;
87 time_t tm_now;
88
89 time(&tm_now);
90
91 clrline(4, 23);
92
93 for (i = 0; i < article_count; i++)
94 {
95 if (p_articles[i]->uid == BBS_priv.uid)
96 {
97 is_viewed = 1;
98 }
99 else
100 {
101 is_viewed = article_view_log_is_viewed(p_articles[i]->aid, &BBS_article_view_log);
102 if (is_viewed < 0)
103 {
104 log_error("article_view_log_is_viewed(aid=%d) error\n", p_articles[i]->aid);
105 is_viewed = 0;
106 }
107 }
108
109 if (p_articles[i]->tid == 0)
110 {
111 is_favor = article_favor_check(p_articles[i]->aid, &BBS_article_favor);
112 if (is_favor < 0)
113 {
114 log_error("article_favor_check(aid=%d) error\n", p_articles[i]->aid);
115 is_favor = 0;
116 }
117 }
118 else
119 {
120 is_favor = 0;
121 }
122
123 if (p_articles[i]->excerption)
124 {
125 article_flag = (is_viewed ? 'm' : 'M');
126 }
127 else if (p_articles[i]->lock && is_viewed)
128 {
129 article_flag = 'x';
130 }
131 else
132 {
133 article_flag = (is_viewed ? ' ' : 'N');
134 }
135
136 localtime_r(&p_articles[i]->sub_dt, &tm_sub);
137 if (tm_now - p_articles[i]->sub_dt < 3600 * 24 * 365)
138 {
139 strftime(str_time, sizeof(str_time), "%b %e ", &tm_sub);
140 }
141 else
142 {
143 strftime(str_time, sizeof(str_time), "%m/%Y", &tm_sub);
144 }
145
146 strncpy(title_f, (p_articles[i]->tid == 0 ? "● " : ""), sizeof(title_f) - 1);
147 title_f[sizeof(title_f) - 1] = '\0';
148 strncat(title_f, (p_articles[i]->transship ? "[转载]" : ""), sizeof(title_f) - 1 - strnlen(title_f, sizeof(title_f)));
149
150 // Rewrite title with "Re: Re: " prefix into "Re: ... "
151 j = 0;
152 if (p_articles[i]->tid != 0)
153 {
154 while (strncmp(p_articles[i]->title + j, "Re: ", strlen("Re: ")) == 0)
155 {
156 j += strlen("Re: ");
157 }
158 if (j >= strlen("Re: Re: "))
159 {
160 strncat(title_f, "Re: ... ", sizeof(title_f) - 1 - strnlen(title_f, sizeof(title_f)));
161 }
162 else
163 {
164 j = 0;
165 }
166 }
167 strncat(title_f, p_articles[i]->title + j, sizeof(title_f) - 1 - strnlen(title_f, sizeof(title_f)));
168
169 len = split_line(title_f, 59 - (display_nickname ? BBS_nickname_max_len / 2 : BBS_username_max_len), &eol, &title_f_len, 1);
170 if (title_f[len] != '\0')
171 {
172 title_f[len] = '\0';
173 }
174
175 moveto(4 + i, 1);
176 if (i >= ontop_start_offset)
177 {
178 prints(" \033[1;33m[提示]\033[m%c%c %s%*s %s %s%s\033[m",
179 (is_favor ? '@' : ' '),
180 article_flag,
181 (display_nickname ? p_articles[i]->nickname : p_articles[i]->username),
182 (display_nickname ? BBS_nickname_max_len / 2 - str_length(p_articles[i]->nickname, 1)
183 : BBS_username_max_len - str_length(p_articles[i]->username, 1)),
184 "",
185 str_time,
186 (p_articles[i]->aid == section_topic_view_tid
187 ? "\033[1;33m"
188 : (p_articles[i]->tid == section_topic_view_tid
189 ? "\033[1;36m"
190 : "")),
191 title_f);
192 }
193 else
194 {
195 prints(" %s%7d\033[m%c%c %s%*s %s %s%s\033[m",
196 (p_articles[i]->aid == section_topic_view_tid
197 ? "\033[1;33m"
198 : (p_articles[i]->tid == section_topic_view_tid
199 ? "\033[1;36m"
200 : "")),
201 p_articles[i]->aid,
202 (is_favor ? '@' : ' '),
203 article_flag,
204 (display_nickname ? p_articles[i]->nickname : p_articles[i]->username),
205 (display_nickname ? BBS_nickname_max_len / 2 - str_length(p_articles[i]->nickname, 1)
206 : BBS_username_max_len - str_length(p_articles[i]->username, 1)),
207 "",
208 str_time,
209 (p_articles[i]->aid == section_topic_view_tid
210 ? "\033[1;33m"
211 : (p_articles[i]->tid == section_topic_view_tid
212 ? "\033[1;36m"
213 : "")),
214 title_f);
215 }
216 }
217
218 return 0;
219 }
220
221 static int section_list_draw_screen(const char *sname, const char *stitle, const char *master_list, int display_nickname)
222 {
223 char str_section_master[LINE_BUFFER_LEN] = "诚征版主中";
224 char str_section_name[LINE_BUFFER_LEN];
225
226 if (master_list[0] != '\0')
227 {
228 snprintf(str_section_master, sizeof(str_section_master), "版主:%s", master_list);
229 }
230 snprintf(str_section_name, sizeof(str_section_name), "讨论区 [%s]", sname);
231
232 clearscr();
233 show_top(str_section_master, stitle, str_section_name);
234 moveto(2, 0);
235 prints("返回[\033[1;32m←\033[0;37m,\033[1;32mESC\033[0;37m] 选择[\033[1;32m↑\033[0;37m,\033[1;32m↓\033[0;37m] "
236 "阅读[\033[1;32m→\033[0;37m,\033[1;32mENTER\033[0;37m] 发表[\033[1;32mCtrl-P\033[0;37m] "
237 "%s[\033[1;32mn\033[0;37m] 精华区[\033[1;32mx\033[0;37m] 帮助[\033[1;32mh\033[0;37m]\033[m",
238 (display_nickname ? "用户名" : "昵称"));
239 moveto(3, 0);
240 if (display_nickname)
241 {
242 prints("\033[44;37m \033[1;37m 编 号 发布者昵称 日 期 文章标题 \033[m");
243 }
244 else
245 {
246 prints("\033[44;37m \033[1;37m 编 号 发 布 者 日 期 文章标题 \033[m");
247 }
248
249 return 0;
250 }
251
252 static enum select_cmd_t section_list_select(int total_page, int item_count, int *p_page_id, int *p_selected_index)
253 {
254 int old_page_id = *p_page_id;
255 int old_selected_index = *p_selected_index;
256 int ch;
257 time_t last_refresh_tm = time(NULL);
258
259 if (item_count > 0 && *p_selected_index >= 0)
260 {
261 moveto(4 + *p_selected_index, 1);
262 outc('>');
263 iflush();
264 }
265
266 while (!SYS_server_exit)
267 {
268 ch = igetch(100);
269
270 if (ch != KEY_NULL && ch != KEY_TIMEOUT)
271 {
272 BBS_last_access_tm = time(NULL);
273 }
274
275 switch (ch)
276 {
277 case KEY_NULL: // broken pipe
278 log_error("KEY_NULL\n");
279 return EXIT_SECTION;
280 case KEY_TIMEOUT:
281 if (time(NULL) - BBS_last_access_tm >= MAX_DELAY_TIME)
282 {
283 log_error("User input timeout\n");
284 return EXIT_SECTION;
285 }
286 continue;
287 case KEY_ESC:
288 case KEY_LEFT:
289 return EXIT_SECTION;
290 case 'n':
291 return CHANGE_NAME_DISPLAY;
292 case CR:
293 case 'r':
294 case KEY_RIGHT:
295 if (item_count > 0)
296 {
297 return VIEW_ARTICLE;
298 }
299 break;
300 case Ctrl('P'):
301 return POST_ARTICLE;
302 case 'E':
303 if (item_count > 0)
304 {
305 return EDIT_ARTICLE;
306 }
307 break;
308 case 'd':
309 if (item_count > 0)
310 {
311 return DELETE_ARTICLE;
312 }
313 break;
314 case Ctrl('Q'):
315 if (item_count > 0)
316 {
317 return QUERY_ARTICLE;
318 }
319 break;
320 case Ctrl('A'):
321 if (item_count > 0)
322 {
323 return QUERY_USER;
324 }
325 break;
326 case 'F':
327 if (item_count > 0)
328 {
329 return SET_FAVOR_ARTICLE;
330 }
331 break;
332 case '-':
333 if (item_count > 0)
334 {
335 return UNSET_FAVOR_ARTICLE;
336 }
337 break;
338 case KEY_HOME:
339 *p_page_id = 0;
340 case 'P':
341 case KEY_PGUP:
342 *p_selected_index = 0;
343 case 'k':
344 case KEY_UP:
345 if (*p_selected_index <= 0)
346 {
347 if (*p_page_id > 0)
348 {
349 (*p_page_id)--;
350 *p_selected_index = BBS_article_limit_per_page - 1;
351 }
352 else if (ch == KEY_UP || ch == 'k') // Rotate to the tail of section list
353 {
354 if (total_page > 0)
355 {
356 *p_page_id = total_page - 1;
357 }
358 if (item_count > 0)
359 {
360 *p_selected_index = item_count - 1;
361 }
362 }
363 }
364 else
365 {
366 (*p_selected_index)--;
367 }
368 break;
369 case '$':
370 case KEY_END:
371 if (total_page > 0)
372 {
373 *p_page_id = total_page - 1;
374 }
375 case 'N':
376 case KEY_PGDN:
377 if (item_count > 0)
378 {
379 *p_selected_index = item_count - 1;
380 }
381 case 'j':
382 case KEY_DOWN:
383 if (*p_selected_index + 1 >= item_count) // next page
384 {
385 if (*p_page_id + 1 < total_page)
386 {
387 (*p_page_id)++;
388 *p_selected_index = 0;
389 }
390 else if (ch == KEY_DOWN || ch == 'j') // Rotate to the head of section list
391 {
392 *p_page_id = 0;
393 *p_selected_index = 0;
394 }
395 }
396 else
397 {
398 (*p_selected_index)++;
399 }
400 break;
401 case '=':
402 if (item_count > 0)
403 {
404 return FIRST_TOPIC_ARTICLE;
405 }
406 break;
407 case '\\':
408 if (item_count > 0)
409 {
410 return LAST_TOPIC_ARTICLE;
411 }
412 break;
413 case 'S':
414 if (item_count > 0)
415 {
416 return SCAN_NEW_ARTICLE;
417 }
418 break;
419 case 'A':
420 if (item_count > 0)
421 {
422 return SCAN_ARTICLE_BACKWARD_BY_USER;
423 }
424 break;
425 case 'a':
426 if (item_count > 0)
427 {
428 return SCAN_ARTICLE_FORWARD_BY_USER;
429 }
430 break;
431 case '?':
432 if (item_count > 0)
433 {
434 return SCAN_ARTICLE_BACKWARD_BY_TITLE;
435 }
436 break;
437 case '/':
438 if (item_count > 0)
439 {
440 return SCAN_ARTICLE_FORWARD_BY_TITLE;
441 }
442 break;
443 case 'u':
444 return SEARCH_USER;
445 case 'h':
446 return SHOW_HELP;
447 case 'x':
448 return VIEW_EX_DIR;
449 case 'H':
450 return SHOW_TOP10;
451 default:
452 break;
453 }
454
455 if (old_page_id != *p_page_id)
456 {
457 return CHANGE_PAGE;
458 }
459
460 if (item_count > 0 && old_selected_index != *p_selected_index)
461 {
462 if (old_selected_index >= 0)
463 {
464 moveto(4 + old_selected_index, 1);
465 outc(' ');
466 }
467 if (*p_selected_index >= 0)
468 {
469 moveto(4 + *p_selected_index, 1);
470 outc('>');
471 }
472 iflush();
473
474 old_selected_index = *p_selected_index;
475 }
476
477 if (BBS_last_access_tm - last_refresh_tm >= BBS_section_list_load_interval)
478 {
479 return CHANGE_PAGE; // force section list refresh
480 }
481 }
482
483 return EXIT_SECTION;
484 }
485
486 static int display_article_key_handler(int *p_key, DISPLAY_CTX *p_ctx)
487 {
488 switch (*p_key)
489 {
490 case 'p':
491 case Ctrl('X'):
492 section_topic_view_mode = !section_topic_view_mode;
493 case 0: // Set msg
494 if (section_topic_view_mode)
495 {
496 snprintf(p_ctx->msg, sizeof(p_ctx->msg),
497 "| 返回[\033[32m←\033[33m,\033[32mESC\033[33m] "
498 "同主题阅读[\033[32m↑\033[33m/\033[32m↓\033[33m] "
499 "切换[\033[32mp\033[33m] 回复[\033[32mr\033[33m] 帮助[\033[32mh\033[33m] |");
500 }
501 else
502 {
503 snprintf(p_ctx->msg, sizeof(p_ctx->msg),
504 "| 返回[\033[32m←\033[33m,\033[32mESC\033[33m] "
505 "移动[\033[32m↑\033[33m/\033[32m↓\033[33m/\033[32mPgUp\033[33m/\033[32mPgDn\033[33m] "
506 "切换[\033[32mp\033[33m] 回复[\033[32mr\033[33m] 帮助[\033[32mh\033[33m] |");
507 }
508 *p_key = 0;
509 break;
510 case 'r': // Reply article
511 return 1;
512 case '=': // First topic article
513 return 1;
514 case '\\': // Last topic article
515 return 1;
516 case KEY_UP:
517 case KEY_PGUP:
518 case KEY_HOME:
519 if (p_ctx->reach_begin)
520 {
521 if (section_topic_view_mode)
522 {
523 *p_key = KEY_PGUP;
524 }
525 else
526 {
527 *p_key = KEY_UP;
528 }
529 return 1;
530 }
531 break;
532 case 'k':
533 if (section_topic_view_mode)
534 {
535 *p_key = KEY_PGUP;
536 }
537 else
538 {
539 *p_key = KEY_UP;
540 }
541 return 1;
542 case KEY_DOWN:
543 case KEY_PGDN:
544 case KEY_END:
545 if (p_ctx->reach_end)
546 {
547 if (section_topic_view_mode)
548 {
549 *p_key = KEY_PGDN;
550 }
551 else
552 {
553 *p_key = KEY_DOWN;
554 }
555 return 1;
556 }
557 break;
558 case 'j':
559 if (section_topic_view_mode)
560 {
561 *p_key = KEY_PGDN;
562 }
563 else
564 {
565 *p_key = KEY_DOWN;
566 }
567 return 1;
568 }
569
570 return 0;
571 }
572
573 int section_list_display(const char *sname, int32_t aid)
574 {
575 static int display_nickname = 0;
576
577 SECTION_LIST *p_section;
578 int64_t section_index;
579 int32_t aid_location;
580 char stitle[BBS_section_title_max_len + 1];
581 char master_list[(BBS_username_max_len + 1) * 3 + 1];
582 char page_info_str[LINE_BUFFER_LEN];
583 ARTICLE *p_articles[BBS_article_limit_per_page];
584 int article_count;
585 int page_count;
586 int ontop_start_offset;
587 int page_id = 0;
588 int selected_index = 0;
589 ARTICLE_CACHE cache;
590 int ret;
591 int loop;
592 int direction;
593 ARTICLE article_new;
594 int page_id_cur;
595 const ARTICLE *p_article_locate;
596 USER_INFO user_info;
597 char user_intro[BBS_user_intro_max_len + 1];
598 char username[BBS_username_max_len + 1];
599 char username_list[1][BBS_username_max_len + 1];
600 int32_t uid;
601 int i;
602 int ok;
603 char title[BBS_article_title_max_len + 1] = "\0";
604
605 p_section = section_list_find_by_name(sname);
606 if (p_section == NULL)
607 {
608 log_error("Section %s not found\n", sname);
609 return -1;
610 }
611
612 if (!checkpriv(&BBS_priv, p_section->sid, S_LIST))
613 {
614 log_error("Forbid access to unauthorized section, sid=%d, uid=%d\n",
615 p_section->sid, BBS_priv.uid);
616 return -1;
617 }
618
619 section_index = get_section_index(p_section);
620
621 if (get_section_info(p_section, NULL, stitle, master_list) < 0)
622 {
623 log_error("get_section_info(sid=%d) error\n", p_section->sid);
624 return -4;
625 }
626
627 if (aid == 0)
628 {
629 aid_location = section_aid_locations[section_index];
630 }
631 else
632 {
633 aid_location = aid;
634 }
635
636 // Locate at article with aid_locate
637 if (aid_location > 0)
638 {
639 p_article_locate = article_block_find_by_aid(aid_location);
640 if (p_article_locate == NULL)
641 {
642 log_error("article_block_find_by_aid(%d) error\n", aid_location);
643 return -3;
644 }
645
646 ret = locate_article_in_section(p_section, p_article_locate, 0, 0,
647 &page_id, &selected_index, &article_count);
648 if (ret < 0)
649 {
650 log_error("locate_article_in_section(sid=%d, aid=%d, direction=0, step=0) error\n",
651 p_section->sid, p_article_locate->aid);
652 return -3;
653 }
654 }
655
656 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
657 {
658 log_error("section_list_draw_screen() error\n");
659 return -2;
660 }
661
662 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
663 if (ret < 0)
664 {
665 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
666 return -3;
667 }
668
669 section_topic_view_tid = -1;
670
671 if (article_count == 0) // empty section
672 {
673 selected_index = 0;
674 }
675 else if (aid > 0)
676 {
677 // Update current topic
678 section_topic_view_tid = (p_articles[selected_index]->tid == 0 ? p_articles[selected_index]->aid : p_articles[selected_index]->tid);
679
680 // Update current aid location
681 section_aid_locations[section_index] = p_articles[selected_index]->aid;
682 }
683
684 while (!SYS_server_exit)
685 {
686 ret = section_list_draw_items(page_id, p_articles, article_count, display_nickname, ontop_start_offset);
687 if (ret < 0)
688 {
689 log_error("section_list_draw_items(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
690 return -4;
691 }
692
693 snprintf(page_info_str, sizeof(page_info_str),
694 "\033[33m[第\033[36m%d\033[33m/\033[36m%d\033[33m页]",
695 page_id + 1, MAX(page_count, 1));
696
697 show_bottom(page_info_str);
698 iflush();
699
700 if (user_online_update(sname) < 0)
701 {
702 log_error("user_online_update(%s) error\n", sname);
703 }
704
705 ret = section_list_select(page_count, article_count, &page_id, &selected_index);
706
707 switch (ret)
708 {
709 case EXIT_SECTION:
710 // Update current aid location
711 if (p_articles[selected_index] != NULL)
712 {
713 section_aid_locations[section_index] = (p_articles[selected_index]->visible ? p_articles[selected_index]->aid : 0);
714 }
715 return 0;
716 case CHANGE_PAGE:
717 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
718 if (ret < 0)
719 {
720 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
721 return -3;
722 }
723 if (article_count == 0) // empty section
724 {
725 selected_index = 0;
726 }
727 else if (selected_index >= article_count)
728 {
729 selected_index = article_count - 1;
730 }
731 break;
732 case VIEW_ARTICLE:
733 do
734 {
735 loop = 0;
736
737 if (article_cache_load(&cache, VAR_ARTICLE_CACHE_DIR, p_articles[selected_index]) < 0)
738 {
739 log_error("article_cache_load(aid=%d, cid=%d) error\n", p_articles[selected_index]->aid, p_articles[selected_index]->cid);
740 break;
741 }
742
743 if (user_online_update("VIEW_ARTICLE") < 0)
744 {
745 log_error("user_online_update(VIEW_ARTICLE) error\n");
746 }
747
748 ret = display_data(cache.p_data, cache.line_total, cache.line_offsets, 0,
749 display_article_key_handler, DATA_READ_HELP);
750
751 if (article_cache_unload(&cache) < 0)
752 {
753 log_error("article_cache_unload(aid=%d, cid=%d) error\n", p_articles[selected_index]->aid, p_articles[selected_index]->cid);
754 break;
755 }
756
757 // Update article_view_log
758 if (article_view_log_set_viewed(p_articles[selected_index]->aid, &BBS_article_view_log) < 0)
759 {
760 log_error("article_view_log_set_viewed(aid=%d) error\n", p_articles[selected_index]->aid);
761 }
762
763 switch (ret)
764 {
765 case KEY_UP:
766 if (selected_index <= 0)
767 {
768 if (page_id > 0)
769 {
770 page_id--;
771 selected_index = BBS_article_limit_per_page - 1;
772
773 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
774 if (ret < 0)
775 {
776 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
777 return -3;
778 }
779
780 if (article_count != BBS_article_limit_per_page) // page is not full
781 {
782 selected_index = MAX(0, article_count - 1);
783 }
784 else
785 {
786 loop = 1;
787 }
788 }
789 }
790 else
791 {
792 selected_index--;
793 loop = 1;
794 }
795 break;
796 case KEY_DOWN:
797 if (selected_index + 1 >= article_count) // next page
798 {
799 if (page_id + 1 < page_count)
800 {
801 page_id++;
802 selected_index = 0;
803
804 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
805 if (ret < 0)
806 {
807 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
808 return -3;
809 }
810
811 if (article_count == 0) // empty page
812 {
813 selected_index = 0;
814 }
815 else
816 {
817 loop = 1;
818 }
819 }
820 }
821 else
822 {
823 selected_index++;
824 loop = 1;
825 }
826 break;
827 case KEY_PGUP:
828 case KEY_PGDN:
829 direction = (ret == KEY_PGUP ? -1 : 1);
830 ret = locate_article_in_section(p_section, p_articles[selected_index], direction, 1,
831 &page_id, &selected_index, &article_count);
832 if (ret < 0)
833 {
834 log_error("locate_article_in_section(sid=%d, aid=%d, direction=%d, step=1) error\n",
835 p_section->sid, p_articles[selected_index]->aid, direction);
836 return -3;
837 }
838 else if (ret > 0) // found
839 {
840 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
841 if (ret < 0)
842 {
843 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
844 return -3;
845 }
846 loop = 1;
847 }
848 break;
849 case 'r': // Reply article
850 if (user_online_update("REPLY_ARTICLE") < 0)
851 {
852 log_error("user_online_update(REPLY_ARTICLE) error\n");
853 }
854
855 if (article_reply(p_section, p_articles[selected_index], &article_new) < 0)
856 {
857 log_error("article_reply(aid=%d) error\n", p_articles[selected_index]->aid);
858 }
859 else if (ret > 0) // Article replied
860 {
861 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
862 if (ret < 0)
863 {
864 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
865 return -3;
866 }
867 }
868 loop = 1;
869 break;
870 case '=': // First topic article
871 case '\\': // Last topic article
872 page_id_cur = page_id;
873 direction = (ret == '=' ? -1 : 1);
874 ret = locate_article_in_section(p_section, p_articles[selected_index], direction, BBS_article_limit_per_section,
875 &page_id, &selected_index, &article_count);
876 if (ret < 0)
877 {
878 log_error("locate_article_in_section(sid=%d, aid=%d, direction=%d, step=%d) error\n",
879 p_section->sid, p_articles[selected_index]->aid, direction, BBS_article_limit_per_section);
880 return -3;
881 }
882 else if (ret > 0) // found
883 {
884 if (page_id != page_id_cur) // page changed
885 {
886 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
887 if (ret < 0)
888 {
889 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
890 return -3;
891 }
892 }
893 loop = 1;
894 }
895 break;
896 }
897 } while (loop);
898
899 // Update current topic
900 section_topic_view_tid = (p_articles[selected_index]->tid == 0 ? p_articles[selected_index]->aid : p_articles[selected_index]->tid);
901
902 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
903 {
904 log_error("section_list_draw_screen() error\n");
905 return -2;
906 }
907 break;
908 case CHANGE_NAME_DISPLAY:
909 display_nickname = !display_nickname;
910 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
911 {
912 log_error("section_list_draw_screen() error\n");
913 return -2;
914 }
915 break;
916 case POST_ARTICLE:
917 if (user_online_update("POST_ARTICLE") < 0)
918 {
919 log_error("user_online_update(POST_ARTICLE) error\n");
920 }
921
922 if ((ret = article_post(p_section, &article_new)) < 0)
923 {
924 log_error("article_post(sid=%d) error\n", p_section->sid);
925 }
926 else if (ret > 0) // New article posted
927 {
928 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
929 if (ret < 0)
930 {
931 log_error("query_section_articles(sid=%d, page_id=%d) error: %d\n", p_section->sid, page_id, ret);
932 return -3;
933 }
934 }
935 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
936 {
937 log_error("section_list_draw_screen() error\n");
938 return -2;
939 }
940 break;
941 case EDIT_ARTICLE:
942 if (!checkpriv(&BBS_priv, p_section->sid, S_POST) ||
943 p_articles[selected_index]->uid != BBS_priv.uid)
944 {
945 break; // No permission
946 }
947
948 if (user_online_update("EDIT_ARTICLE") < 0)
949 {
950 log_error("user_online_update() error\n");
951 }
952
953 if (article_modify(p_section, p_articles[selected_index], &article_new) < 0)
954 {
955 log_error("article_modify(aid=%d) error\n", p_articles[selected_index]->aid);
956 }
957 else if (ret > 0) // Article modified
958 {
959 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
960 if (ret < 0)
961 {
962 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
963 return -3;
964 }
965 }
966 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
967 {
968 log_error("section_list_draw_screen() error\n");
969 return -2;
970 }
971 break;
972 case DELETE_ARTICLE:
973 if (!checkpriv(&BBS_priv, p_section->sid, S_POST) ||
974 (!checkpriv(&BBS_priv, p_section->sid, S_MAN_S) && p_articles[selected_index]->uid != BBS_priv.uid))
975 {
976 break; // No permission
977 }
978 if ((ret = article_del(p_section, p_articles[selected_index])) < 0)
979 {
980 log_error("article_del(aid=%d) error\n", p_articles[selected_index]->aid);
981 }
982 else if (ret > 0) // Article deleted
983 {
984 do
985 {
986 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
987 if (ret >= 0 && selected_index > article_count - 1)
988 {
989 selected_index = article_count - 1;
990 break;
991 }
992 else if (ret < 0 && page_id > 0)
993 {
994 page_id--;
995 selected_index = BBS_article_limit_per_page - 1;
996 }
997 else if (ret < 0 && page_id <= 0)
998 {
999 selected_index = 0;
1000 break;
1001 }
1002 } while (ret < 0);
1003 }
1004 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
1005 {
1006 log_error("section_list_draw_screen() error\n");
1007 return -2;
1008 }
1009 break;
1010 case QUERY_ARTICLE:
1011 if ((ret = display_article_meta(p_articles[selected_index]->aid)) < 0)
1012 {
1013 log_error("display_article_meta(aid=%d) error\n", p_articles[selected_index]->aid);
1014 }
1015 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
1016 {
1017 log_error("section_list_draw_screen() error\n");
1018 return -2;
1019 }
1020 break;
1021 case QUERY_USER:
1022 if ((ret = query_user_info_by_uid(p_articles[selected_index]->uid, &user_info, user_intro, sizeof(user_intro))) < 0)
1023 {
1024 log_error("query_user_info_by_uid(uid=%d) error\n", p_articles[selected_index]->uid);
1025 return -2;
1026 }
1027 else if (ret == 0)
1028 {
1029 clearscr();
1030 prints("该用户已升天");
1031 press_any_key();
1032 }
1033 else if (user_info_display(&user_info) < 0) // && ret > 0
1034 {
1035 log_error("user_info_display(uid=%d) error\n", p_articles[selected_index]->uid);
1036 }
1037
1038 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
1039 {
1040 log_error("section_list_draw_screen() error\n");
1041 return -2;
1042 }
1043 break;
1044 case SET_FAVOR_ARTICLE:
1045 ret = article_favor_set(p_articles[selected_index]->tid == 0
1046 ? p_articles[selected_index]->aid
1047 : p_articles[selected_index]->tid,
1048 &BBS_article_favor, 1);
1049 if (ret < 0)
1050 {
1051 log_error("article_favor_set(aid=%d, 1) error\n",
1052 p_articles[selected_index]->tid == 0 ? p_articles[selected_index]->aid : p_articles[selected_index]->tid);
1053 }
1054 break;
1055 case UNSET_FAVOR_ARTICLE:
1056 ret = article_favor_set(p_articles[selected_index]->tid == 0
1057 ? p_articles[selected_index]->aid
1058 : p_articles[selected_index]->tid,
1059 &BBS_article_favor, 0);
1060 if (ret < 0)
1061 {
1062 log_error("article_favor_set(aid=%d, 0) error\n",
1063 p_articles[selected_index]->tid == 0 ? p_articles[selected_index]->aid : p_articles[selected_index]->tid);
1064 }
1065 break;
1066 case FIRST_TOPIC_ARTICLE:
1067 case LAST_TOPIC_ARTICLE:
1068 page_id_cur = page_id;
1069 direction = (ret == FIRST_TOPIC_ARTICLE ? -1 : 1);
1070 ret = locate_article_in_section(p_section, p_articles[selected_index], direction, BBS_article_limit_per_section,
1071 &page_id, &selected_index, &article_count);
1072 if (ret < 0)
1073 {
1074 log_error("locate_article_in_section(sid=%d, aid=%d, direction=%d, step=%d) error\n",
1075 p_section->sid, p_articles[selected_index]->aid, direction, BBS_article_limit_per_section);
1076 return -3;
1077 }
1078 else if (ret > 0 && page_id != page_id_cur) // found and page changed
1079 {
1080 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
1081 if (ret < 0)
1082 {
1083 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
1084 return -3;
1085 }
1086 }
1087 break;
1088 case SCAN_NEW_ARTICLE:
1089 ret = scan_unread_article_in_section(p_section, p_articles[selected_index], &p_article_locate);
1090 if (ret < 0)
1091 {
1092 log_error("scan_unread_article_in_section(sid=%d, aid=%d) error\n",
1093 p_section->sid, p_articles[selected_index]->aid);
1094 return -3;
1095 }
1096 else if (ret == 0) // not found
1097 {
1098 break;
1099 }
1100 page_id_cur = page_id;
1101 ret = locate_article_in_section(p_section, p_article_locate, 0, 0,
1102 &page_id, &selected_index, &article_count);
1103 if (ret < 0)
1104 {
1105 log_error("locate_article_in_section(sid=%d, aid=%d, direction=0, step=0) error\n",
1106 p_section->sid, p_article_locate->aid);
1107 return -3;
1108 }
1109 else if (ret > 0 && page_id != page_id_cur) // found and page changed
1110 {
1111 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
1112 if (ret < 0)
1113 {
1114 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
1115 return -3;
1116 }
1117 }
1118 break;
1119 case SCAN_ARTICLE_BACKWARD_BY_USER:
1120 case SCAN_ARTICLE_FORWARD_BY_USER:
1121 direction = (ret == SCAN_ARTICLE_FORWARD_BY_USER ? 1 : -1);
1122 strncpy(username, p_articles[selected_index]->username, sizeof(username) - 1);
1123 username[sizeof(username) - 1] = '\0';
1124 uid = 0;
1125
1126 moveto(SCREEN_ROWS, 1);
1127 clrtoeol();
1128 get_data(SCREEN_ROWS, 1,
1129 (direction == 1 ? "向下搜寻作者: " : "向上搜寻作者: "),
1130 username, sizeof(username), BBS_username_max_len);
1131
1132 if (username[0] == '\0')
1133 {
1134 break;
1135 }
1136
1137 // Verify format
1138 for (i = 0, ok = 1; ok && username[i] != '\0'; i++)
1139 {
1140 if (!(isalpha(username[i]) || (i > 0 && (isdigit(username[i]) || username[i] == '_'))))
1141 {
1142 ok = 0;
1143 }
1144 }
1145 if (ok && i > BBS_username_max_len)
1146 {
1147 ok = 0;
1148 }
1149 if (!ok)
1150 {
1151 break;
1152 }
1153
1154 ret = query_user_info_by_username(username, 1, &uid, username_list);
1155 if (ret < 0)
1156 {
1157 log_error("query_user_info_by_username(%s) error\n", username);
1158 break;
1159 }
1160
1161 if (uid > 0)
1162 {
1163 ret = scan_article_in_section_by_uid(p_section, p_articles[selected_index],
1164 direction, uid, &p_article_locate);
1165 if (ret < 0)
1166 {
1167 log_error("scan_article_in_section_by_uid(sid=%d, aid=%d, direction=%d, uid=%d) error\n",
1168 p_section->sid, p_articles[selected_index]->aid, direction, uid);
1169 return -3;
1170 }
1171 else if (ret == 0) // not found
1172 {
1173 break;
1174 }
1175 }
1176 else // uid == 0
1177 {
1178 ret = scan_article_in_section_by_username(p_section, p_articles[selected_index],
1179 direction, username, &p_article_locate);
1180 if (ret < 0)
1181 {
1182 log_error("scan_article_in_section_by_username(sid=%d, aid=%d, direction=%d, username=%s) error\n",
1183 p_section->sid, p_articles[selected_index]->aid, direction, username);
1184 return -3;
1185 }
1186 else if (ret == 0) // not found
1187 {
1188 break;
1189 }
1190 }
1191
1192 page_id_cur = page_id;
1193 ret = locate_article_in_section(p_section, p_article_locate, 0, 0,
1194 &page_id, &selected_index, &article_count);
1195 if (ret < 0)
1196 {
1197 log_error("locate_article_in_section(sid=%d, aid=%d, direction=0, step=0) error\n",
1198 p_section->sid, p_article_locate->aid);
1199 return -3;
1200 }
1201 else if (ret > 0 && page_id != page_id_cur) // found and page changed
1202 {
1203 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
1204 if (ret < 0)
1205 {
1206 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
1207 return -3;
1208 }
1209 }
1210 break;
1211 case SCAN_ARTICLE_BACKWARD_BY_TITLE:
1212 case SCAN_ARTICLE_FORWARD_BY_TITLE:
1213 direction = (ret == SCAN_ARTICLE_FORWARD_BY_TITLE ? 1 : -1);
1214
1215 moveto(SCREEN_ROWS, 1);
1216 clrtoeol();
1217 get_data(SCREEN_ROWS, 1,
1218 (direction == 1 ? "向下搜寻标题: " : "向上搜寻标题: "),
1219 title, sizeof(title), TITLE_SEARCH_MAX_LEN);
1220
1221 if (title[0] == '\0')
1222 {
1223 break;
1224 }
1225
1226 ret = scan_article_in_section_by_title(p_section, p_articles[selected_index],
1227 direction, title, &p_article_locate);
1228 if (ret < 0)
1229 {
1230 log_error("scan_article_in_section_by_title(sid=%d, aid=%d, direction=%d, title=%s) error\n",
1231 p_section->sid, p_articles[selected_index]->aid, direction, title);
1232 return -3;
1233 }
1234 else if (ret == 0) // not found
1235 {
1236 break;
1237 }
1238
1239 page_id_cur = page_id;
1240 ret = locate_article_in_section(p_section, p_article_locate, 0, 0,
1241 &page_id, &selected_index, &article_count);
1242 if (ret < 0)
1243 {
1244 log_error("locate_article_in_section(sid=%d, aid=%d, direction=0, step=0) error\n",
1245 p_section->sid, p_article_locate->aid);
1246 return -3;
1247 }
1248 else if (ret > 0 && page_id != page_id_cur) // found and page changed
1249 {
1250 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
1251 if (ret < 0)
1252 {
1253 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
1254 return -3;
1255 }
1256 }
1257 break;
1258 case SEARCH_USER:
1259 user_list_search();
1260 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
1261 {
1262 log_error("section_list_draw_screen() error\n");
1263 return -2;
1264 }
1265 break;
1266 case SHOW_HELP:
1267 // Display help information
1268 display_file(DATA_READ_HELP, 1);
1269 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
1270 {
1271 log_error("section_list_draw_screen() error\n");
1272 return -2;
1273 }
1274 break;
1275 case VIEW_EX_DIR:
1276 if (section_list_ex_dir_display(p_section) < 0)
1277 {
1278 log_error("section_list_ex_dir_display(sid=%d) error\n", p_section->sid);
1279 }
1280 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
1281 {
1282 log_error("section_list_draw_screen() error\n");
1283 return -2;
1284 }
1285 break;
1286 case SHOW_TOP10:
1287 show_top10_menu(NULL);
1288 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
1289 {
1290 log_error("section_list_draw_screen() error\n");
1291 return -2;
1292 }
1293 break;
1294 default:
1295 log_error("Unknown command %d\n", ret);
1296 }
1297 }
1298
1299 return 0;
1300 }
1301
1302 int section_list_ex_dir_display(SECTION_LIST *p_section)
1303 {
1304 MENU_SET ex_menu_set;
1305 int ch = 0;
1306
1307 if (p_section == NULL)
1308 {
1309 log_error("NULL pointer error\n");
1310 return -1;
1311 }
1312
1313 if (p_section->ex_menu_tm == 0) // N/A
1314 {
1315 moveto(2, 1);
1316 clrtoeol();
1317 prints("该版块精华区未开放");
1318 press_any_key();
1319 return 0;
1320 }
1321
1322 if (get_section_ex_menu_set(p_section, &ex_menu_set) < 0)
1323 {
1324 log_error("get_section_ex_menu_set(sid=%d) error\n", p_section->sid);
1325 return -3;
1326 }
1327 if (get_menu_shm_readonly(&ex_menu_set) < 0)
1328 {
1329 log_error("get_menu_shm_readonly(sid=%d) error\n", p_section->sid);
1330 return -3;
1331 }
1332
1333 clearscr();
1334 show_bottom("");
1335
1336 if (display_menu(&ex_menu_set) == 0)
1337 {
1338 while (!SYS_server_exit)
1339 {
1340 iflush();
1341 ch = igetch(100);
1342
1343 if (ch != KEY_NULL && ch != KEY_TIMEOUT)
1344 {
1345 BBS_last_access_tm = time(NULL);
1346 }
1347
1348 switch (ch)
1349 {
1350 case KEY_NULL: // broken pipe
1351 log_error("KEY_NULL\n");
1352 return 0;
1353 case KEY_TIMEOUT:
1354 if (time(NULL) - BBS_last_access_tm >= MAX_DELAY_TIME)
1355 {
1356 log_error("User input timeout\n");
1357 return 0;
1358 }
1359 continue;
1360 case CR:
1361 default:
1362 switch (menu_control(&ex_menu_set, ch))
1363 {
1364 case EXITMENU:
1365 ch = EXITMENU;
1366 break;
1367 case REDRAW:
1368 clearscr();
1369 show_bottom("");
1370 display_menu(&ex_menu_set);
1371 break;
1372 case NOREDRAW:
1373 case UNKNOWN_CMD:
1374 default:
1375 break;
1376 }
1377 }
1378
1379 if (ch == EXITMENU)
1380 {
1381 break;
1382 }
1383 }
1384 }
1385
1386 detach_menu_shm(&ex_menu_set);
1387
1388 return 0;
1389 }
1390
1391 int section_aid_locations_save(int uid)
1392 {
1393 char filename[FILE_PATH_LEN];
1394 FILE *fp;
1395 int i;
1396 int ret = 0;
1397
1398 snprintf(filename, sizeof(filename), "%s/%d", VAR_SECTION_AID_LOC_DIR, uid);
1399
1400 if ((fp = fopen(filename, "wb")) == NULL)
1401 {
1402 log_error("fopen(%s, wb) error: %d\n", filename, errno);
1403 return -1;
1404 }
1405
1406 for (i = 0; i < p_section_list_pool->section_count; i++)
1407 {
1408 if (fwrite(&(p_section_list_pool->sections[i].sid), sizeof(p_section_list_pool->sections[i].sid), 1, fp) != 1)
1409 {
1410 log_error("fwrite(%s, sid) error\n", filename);
1411 ret = -2;
1412 break;
1413 }
1414
1415 if (fwrite(&(section_aid_locations[i]), sizeof(section_aid_locations[i]), 1, fp) != 1)
1416 {
1417 log_error("fwrite(%s, aid) error\n", filename);
1418 ret = -2;
1419 break;
1420 }
1421 }
1422
1423 if (fclose(fp) < 0)
1424 {
1425 log_error("fclose(%s) error: %d\n", filename, errno);
1426 ret = -1;
1427 }
1428
1429 return ret;
1430 }
1431
1432 int section_aid_locations_load(int uid)
1433 {
1434 char filename[FILE_PATH_LEN];
1435 FILE *fp;
1436 int i;
1437 int32_t sid;
1438 int32_t aid;
1439 SECTION_LIST *p_section;
1440 int ret = 0;
1441
1442 snprintf(filename, sizeof(filename), "%s/%d", VAR_SECTION_AID_LOC_DIR, uid);
1443
1444 if ((fp = fopen(filename, "rb")) == NULL)
1445 {
1446 if (errno == ENOENT) // file not exist
1447 {
1448 return 0;
1449 }
1450 log_error("fopen(%s, rb) error: %d\n", filename, errno);
1451 return -1;
1452 }
1453
1454 while (!feof(fp))
1455 {
1456 if (fread(&sid, sizeof(sid), 1, fp) != 1)
1457 {
1458 if (ferror(fp) == 0)
1459 {
1460 break;
1461 }
1462 log_error("fread(%s, sid) error: %d\n", filename, ferror(fp));
1463 ret = -2;
1464 break;
1465 }
1466
1467 if (fread(&aid, sizeof(aid), 1, fp) != 1)
1468 {
1469 if (ferror(fp) == 0)
1470 {
1471 break;
1472 }
1473 log_error("fread(%s, aid) error: %d\n", filename, ferror(fp));
1474 ret = -2;
1475 break;
1476 }
1477
1478 p_section = section_list_find_by_sid(sid);
1479 if (p_section == NULL)
1480 {
1481 continue; // skip section no longer exist
1482 }
1483
1484 i = get_section_index(p_section);
1485 if (i < 0)
1486 {
1487 log_error("get_section_index(sid=%d) error\n", sid);
1488 ret = -3;
1489 break;
1490 }
1491 section_aid_locations[i] = aid;
1492 }
1493
1494 if (fclose(fp) < 0)
1495 {
1496 log_error("fclose(%s) error: %d\n", filename, errno);
1497 ret = -1;
1498 }
1499
1500 return ret;
1501 }

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