/[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.62 - (show annotations)
Sun Nov 2 15:11:47 2025 UTC (4 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.61: +9 -3 lines
Content type: text/x-csrc
Fix bug: selected_index might be invalid after returning from section_list_select() while the ret == CHANGE_PAGE
Update section_aid_locations[selected_index] on exit of section only

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

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