/[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.63 - (show annotations)
Mon Nov 3 02:32:11 2025 UTC (4 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.62: +12 -0 lines
Content type: text/x-csrc
Add user search in section list display

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

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