/[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.55 - (show annotations)
Fri Oct 17 01:25:08 2025 UTC (4 months, 4 weeks ago) by sysadm
Branch: MAIN
Changes since 1.54: +0 -2 lines
Content type: text/x-csrc
No longer use igetch_reset() to skip remaining \n after \r
\r\n -> \r and \n -> \r conversions have already been implemented in igetch()

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

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