/[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.53 - (show annotations)
Wed Oct 15 01:05:18 2025 UTC (5 months ago) by sysadm
Branch: MAIN
Changes since 1.52: +56 -2 lines
Content type: text/x-csrc
Add article favor state display and set/unset in section article list

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 switch (ch)
259 {
260 case KEY_ESC:
261 case KEY_LEFT:
262 BBS_last_access_tm = time(NULL);
263 case KEY_NULL: // broken pipe
264 return EXIT_SECTION; // exit section
265 case KEY_TIMEOUT:
266 if (time(NULL) - BBS_last_access_tm >= MAX_DELAY_TIME)
267 {
268 return EXIT_SECTION; // exit section
269 }
270 continue;
271 case 'n':
272 BBS_last_access_tm = time(NULL);
273 return CHANGE_NAME_DISPLAY;
274 case CR:
275 igetch_reset();
276 case 'r':
277 case KEY_RIGHT:
278 if (item_count > 0)
279 {
280 BBS_last_access_tm = time(NULL);
281 return VIEW_ARTICLE;
282 }
283 break;
284 case Ctrl('P'):
285 return POST_ARTICLE;
286 case 'E':
287 if (item_count > 0)
288 {
289 return EDIT_ARTICLE;
290 }
291 break;
292 case 'd':
293 if (item_count > 0)
294 {
295 return DELETE_ARTICLE;
296 }
297 break;
298 case Ctrl('Q'):
299 if (item_count > 0)
300 {
301 return QUERY_ARTICLE;
302 }
303 break;
304 case 'F':
305 if (item_count > 0)
306 {
307 return SET_FAVOR_ARTICLE;
308 }
309 break;
310 case '-':
311 if (item_count > 0)
312 {
313 return UNSET_FAVOR_ARTICLE;
314 }
315 break;
316 case KEY_HOME:
317 *p_page_id = 0;
318 case 'P':
319 case KEY_PGUP:
320 *p_selected_index = 0;
321 case 'k':
322 case KEY_UP:
323 if (*p_selected_index <= 0)
324 {
325 if (*p_page_id > 0)
326 {
327 (*p_page_id)--;
328 *p_selected_index = BBS_article_limit_per_page - 1;
329 }
330 else if (ch == KEY_UP || ch == 'k') // Rotate to the tail of section list
331 {
332 if (total_page > 0)
333 {
334 *p_page_id = total_page - 1;
335 }
336 if (item_count > 0)
337 {
338 *p_selected_index = item_count - 1;
339 }
340 }
341 }
342 else
343 {
344 (*p_selected_index)--;
345 }
346 break;
347 case '$':
348 case KEY_END:
349 if (total_page > 0)
350 {
351 *p_page_id = total_page - 1;
352 }
353 case 'N':
354 case KEY_PGDN:
355 if (item_count > 0)
356 {
357 *p_selected_index = item_count - 1;
358 }
359 case 'j':
360 case KEY_DOWN:
361 if (*p_selected_index + 1 >= item_count) // next page
362 {
363 if (*p_page_id + 1 < total_page)
364 {
365 (*p_page_id)++;
366 *p_selected_index = 0;
367 }
368 else if (ch == KEY_DOWN || ch == 'j') // Rotate to the head of section list
369 {
370 *p_page_id = 0;
371 *p_selected_index = 0;
372 }
373 }
374 else
375 {
376 (*p_selected_index)++;
377 }
378 break;
379 case '=':
380 if (item_count > 0)
381 {
382 return FIRST_TOPIC_ARTICLE;
383 }
384 break;
385 case '\\':
386 if (item_count > 0)
387 {
388 return LAST_TOPIC_ARTICLE;
389 }
390 break;
391 case 'S':
392 if (item_count > 0)
393 {
394 return SCAN_NEW_ARTICLE;
395 }
396 break;
397 case 'h':
398 return SHOW_HELP;
399 case 'x':
400 return VIEW_EX_DIR;
401 case 'H':
402 return SHOW_TOP10;
403 default:
404 }
405
406 if (old_page_id != *p_page_id)
407 {
408 return CHANGE_PAGE;
409 }
410
411 if (item_count > 0 && old_selected_index != *p_selected_index)
412 {
413 if (old_selected_index >= 0)
414 {
415 moveto(4 + old_selected_index, 1);
416 outc(' ');
417 }
418 if (*p_selected_index >= 0)
419 {
420 moveto(4 + *p_selected_index, 1);
421 outc('>');
422 }
423 iflush();
424
425 old_selected_index = *p_selected_index;
426 }
427
428 BBS_last_access_tm = time(NULL);
429 if (BBS_last_access_tm - last_refresh_tm >= BBS_section_list_load_interval)
430 {
431 return CHANGE_PAGE; // force section list refresh
432 }
433 }
434
435 return EXIT_SECTION;
436 }
437
438 static int display_article_key_handler(int *p_key, DISPLAY_CTX *p_ctx)
439 {
440 switch (*p_key)
441 {
442 case 'p':
443 case Ctrl('X'):
444 section_topic_view_mode = !section_topic_view_mode;
445 case 0: // Set msg
446 if (section_topic_view_mode)
447 {
448 snprintf(p_ctx->msg, sizeof(p_ctx->msg),
449 "| 返回[\033[32m←\033[33m,\033[32mESC\033[33m] "
450 "同主题阅读[\033[32m↑\033[33m/\033[32m↓\033[33m] "
451 "切换[\033[32mp\033[33m] 回复[\033[32mr\033[33m] 帮助[\033[32mh\033[33m] |");
452 }
453 else
454 {
455 snprintf(p_ctx->msg, sizeof(p_ctx->msg),
456 "| 返回[\033[32m←\033[33m,\033[32mESC\033[33m] "
457 "移动[\033[32m↑\033[33m/\033[32m↓\033[33m/\033[32mPgUp\033[33m/\033[32mPgDn\033[33m] "
458 "切换[\033[32mp\033[33m] 回复[\033[32mr\033[33m] 帮助[\033[32mh\033[33m] |");
459 }
460 *p_key = 0;
461 break;
462 case 'r': // Reply article
463 return 1;
464 case '=': // First topic article
465 return 1;
466 case '\\': // Last topic article
467 return 1;
468 case KEY_UP:
469 case KEY_PGUP:
470 case KEY_HOME:
471 if (p_ctx->reach_begin)
472 {
473 if (section_topic_view_mode)
474 {
475 *p_key = KEY_PGUP;
476 }
477 else
478 {
479 *p_key = KEY_UP;
480 }
481 return 1;
482 }
483 break;
484 case 'k':
485 if (section_topic_view_mode)
486 {
487 *p_key = KEY_PGUP;
488 }
489 else
490 {
491 *p_key = KEY_UP;
492 }
493 return 1;
494 case KEY_DOWN:
495 case KEY_PGDN:
496 case KEY_END:
497 if (p_ctx->reach_end)
498 {
499 if (section_topic_view_mode)
500 {
501 *p_key = KEY_PGDN;
502 }
503 else
504 {
505 *p_key = KEY_DOWN;
506 }
507 return 1;
508 }
509 break;
510 case 'j':
511 if (section_topic_view_mode)
512 {
513 *p_key = KEY_PGDN;
514 }
515 else
516 {
517 *p_key = KEY_DOWN;
518 }
519 return 1;
520 }
521
522 return 0;
523 }
524
525 int section_list_display(const char *sname, int32_t aid)
526 {
527 static int display_nickname = 0;
528
529 SECTION_LIST *p_section;
530 int64_t section_index;
531 int32_t aid_location;
532 char stitle[BBS_section_title_max_len + 1];
533 char master_list[(BBS_username_max_len + 1) * 3 + 1];
534 char page_info_str[LINE_BUFFER_LEN];
535 ARTICLE *p_articles[BBS_article_limit_per_page];
536 int article_count;
537 int page_count;
538 int ontop_start_offset;
539 int page_id = 0;
540 int selected_index = 0;
541 ARTICLE_CACHE cache;
542 int ret;
543 int loop;
544 int direction;
545 ARTICLE article_new;
546 int page_id_cur;
547 const ARTICLE *p_article_locate;
548
549 p_section = section_list_find_by_name(sname);
550 if (p_section == NULL)
551 {
552 log_error("Section %s not found\n", sname);
553 return -1;
554 }
555
556 if (!checkpriv(&BBS_priv, p_section->sid, S_LIST))
557 {
558 log_error("Forbid access to unauthorized section, sid=%d, uid=%d\n",
559 p_section->sid, BBS_priv.uid);
560 return -1;
561 }
562
563 section_index = get_section_index(p_section);
564
565 if ((ret = section_list_rd_lock(p_section)) < 0)
566 {
567 log_error("section_list_rd_lock(sid = 0) error\n");
568 return -2;
569 }
570
571 strncpy(stitle, p_section->stitle, sizeof(stitle) - 1);
572 stitle[sizeof(stitle) - 1] = '\0';
573 strncpy(master_list, p_section->master_list, sizeof(master_list) - 1);
574 master_list[sizeof(master_list) - 1] = '\0';
575
576 if ((ret = section_list_rd_unlock(p_section)) < 0)
577 {
578 log_error("section_list_rd_unlock(sid = 0) error\n");
579 return -2;
580 }
581
582 if (aid == 0)
583 {
584 aid_location = section_aid_locations[section_index];
585 }
586 else
587 {
588 aid_location = aid;
589 }
590
591 // Locate at article with aid_locate
592 if (aid_location > 0)
593 {
594 p_article_locate = article_block_find_by_aid(aid_location);
595 if (p_article_locate == NULL)
596 {
597 log_error("article_block_find_by_aid(%d) error\n", aid_location);
598 return -3;
599 }
600
601 ret = locate_article_in_section(p_section, p_article_locate, 0, 0,
602 &page_id, &selected_index, &article_count);
603 if (ret < 0)
604 {
605 log_error("locate_article_in_section(sid=%d, aid=%d, direction=0, step=0) error\n",
606 p_section->sid, p_article_locate->aid);
607 return -3;
608 }
609 }
610
611 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
612 {
613 log_error("section_list_draw_screen() error\n");
614 return -2;
615 }
616
617 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
618 if (ret < 0)
619 {
620 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
621 return -3;
622 }
623
624 section_topic_view_tid = -1;
625
626 if (article_count == 0) // empty section
627 {
628 selected_index = 0;
629 }
630 else if (aid > 0)
631 {
632 // Update current topic
633 section_topic_view_tid = (p_articles[selected_index]->tid == 0 ? p_articles[selected_index]->aid : p_articles[selected_index]->tid);
634
635 // Update current aid location
636 section_aid_locations[section_index] = p_articles[selected_index]->aid;
637 }
638
639 while (!SYS_server_exit)
640 {
641 ret = section_list_draw_items(page_id, p_articles, article_count, display_nickname, ontop_start_offset);
642 if (ret < 0)
643 {
644 log_error("section_list_draw_items(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
645 return -4;
646 }
647
648 snprintf(page_info_str, sizeof(page_info_str),
649 "\033[33m[第\033[36m%d\033[33m/\033[36m%d\033[33m页]",
650 page_id + 1, MAX(page_count, 1));
651
652 show_bottom(page_info_str);
653 iflush();
654
655 if (user_online_update(sname) < 0)
656 {
657 log_error("user_online_update(%s) error\n", sname);
658 }
659
660 ret = section_list_select(page_count, article_count, &page_id, &selected_index);
661 switch (ret)
662 {
663 case EXIT_SECTION:
664 return 0;
665 case CHANGE_PAGE:
666 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
667 if (ret < 0)
668 {
669 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
670 return -3;
671 }
672 if (article_count == 0) // empty section
673 {
674 selected_index = 0;
675 }
676 else if (selected_index >= article_count)
677 {
678 selected_index = article_count - 1;
679 }
680 break;
681 case VIEW_ARTICLE:
682 do
683 {
684 loop = 0;
685
686 if (article_cache_load(&cache, VAR_ARTICLE_CACHE_DIR, p_articles[selected_index]) < 0)
687 {
688 log_error("article_cache_load(aid=%d, cid=%d) error\n", p_articles[selected_index]->aid, p_articles[selected_index]->cid);
689 break;
690 }
691
692 if (user_online_update("VIEW_ARTICLE") < 0)
693 {
694 log_error("user_online_update(VIEW_ARTICLE) error\n");
695 }
696
697 ret = display_data(cache.p_data, cache.line_total, cache.line_offsets, 0,
698 display_article_key_handler, DATA_READ_HELP);
699
700 if (article_cache_unload(&cache) < 0)
701 {
702 log_error("article_cache_unload(aid=%d, cid=%d) error\n", p_articles[selected_index]->aid, p_articles[selected_index]->cid);
703 break;
704 }
705
706 // Update article_view_log
707 if (article_view_log_set_viewed(p_articles[selected_index]->aid, &BBS_article_view_log) < 0)
708 {
709 log_error("article_view_log_set_viewed(aid=%d) error\n", p_articles[selected_index]->aid);
710 }
711
712 switch (ret)
713 {
714 case KEY_UP:
715 if (selected_index <= 0)
716 {
717 if (page_id > 0)
718 {
719 page_id--;
720 selected_index = BBS_article_limit_per_page - 1;
721
722 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
723 if (ret < 0)
724 {
725 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
726 return -3;
727 }
728
729 if (article_count != BBS_article_limit_per_page) // page is not full
730 {
731 selected_index = MAX(0, article_count - 1);
732 }
733 else
734 {
735 loop = 1;
736 }
737 }
738 }
739 else
740 {
741 selected_index--;
742 loop = 1;
743 }
744 break;
745 case KEY_DOWN:
746 if (selected_index + 1 >= article_count) // next page
747 {
748 if (page_id + 1 < page_count)
749 {
750 page_id++;
751 selected_index = 0;
752
753 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
754 if (ret < 0)
755 {
756 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
757 return -3;
758 }
759
760 if (article_count == 0) // empty page
761 {
762 selected_index = 0;
763 }
764 else
765 {
766 loop = 1;
767 }
768 }
769 }
770 else
771 {
772 selected_index++;
773 loop = 1;
774 }
775 break;
776 case KEY_PGUP:
777 case KEY_PGDN:
778 direction = (ret == KEY_PGUP ? -1 : 1);
779 ret = locate_article_in_section(p_section, p_articles[selected_index], direction, 1,
780 &page_id, &selected_index, &article_count);
781 if (ret < 0)
782 {
783 log_error("locate_article_in_section(sid=%d, aid=%d, direction=%d, step=1) error\n",
784 p_section->sid, p_articles[selected_index]->aid, direction);
785 return -3;
786 }
787 else if (ret > 0) // found
788 {
789 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
790 if (ret < 0)
791 {
792 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
793 return -3;
794 }
795 loop = 1;
796 }
797 break;
798 case 'r': // Reply article
799 if (user_online_update("REPLY_ARTICLE") < 0)
800 {
801 log_error("user_online_update(REPLY_ARTICLE) error\n");
802 }
803
804 if (article_reply(p_section, p_articles[selected_index], &article_new) < 0)
805 {
806 log_error("article_reply(aid=%d) error\n", p_articles[selected_index]->aid);
807 }
808 loop = 1;
809 break;
810 case '=': // First topic article
811 case '\\': // Last topic article
812 page_id_cur = page_id;
813 direction = (ret == '=' ? -1 : 1);
814 ret = locate_article_in_section(p_section, p_articles[selected_index], direction, BBS_article_limit_per_section,
815 &page_id, &selected_index, &article_count);
816 if (ret < 0)
817 {
818 log_error("locate_article_in_section(sid=%d, aid=%d, direction=%d, step=%d) error\n",
819 p_section->sid, p_articles[selected_index]->aid, direction, BBS_article_limit_per_section);
820 return -3;
821 }
822 else if (ret > 0) // found
823 {
824 if (page_id != page_id_cur) // page changed
825 {
826 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
827 if (ret < 0)
828 {
829 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
830 return -3;
831 }
832 }
833 loop = 1;
834 }
835 break;
836 }
837 } while (loop);
838
839 // Update current topic
840 section_topic_view_tid = (p_articles[selected_index]->tid == 0 ? p_articles[selected_index]->aid : p_articles[selected_index]->tid);
841
842 // Update current aid location
843 section_aid_locations[section_index] = p_articles[selected_index]->aid;
844
845 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
846 {
847 log_error("section_list_draw_screen() error\n");
848 return -2;
849 }
850 break;
851 case CHANGE_NAME_DISPLAY:
852 display_nickname = !display_nickname;
853 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
854 {
855 log_error("section_list_draw_screen() error\n");
856 return -2;
857 }
858 break;
859 case POST_ARTICLE:
860 if (user_online_update("POST_ARTICLE") < 0)
861 {
862 log_error("user_online_update(POST_ARTICLE) error\n");
863 }
864
865 if ((ret = article_post(p_section, &article_new)) < 0)
866 {
867 log_error("article_post(sid=%d) error\n", p_section->sid);
868 }
869 else if (ret > 0) // New article posted
870 {
871 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
872 if (ret < 0)
873 {
874 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
875 return -3;
876 }
877 }
878 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
879 {
880 log_error("section_list_draw_screen() error\n");
881 return -2;
882 }
883 break;
884 case EDIT_ARTICLE:
885 if (!checkpriv(&BBS_priv, p_section->sid, S_POST) ||
886 p_articles[selected_index]->uid != BBS_priv.uid)
887 {
888 break; // No permission
889 }
890
891 if (user_online_update("EDIT_ARTICLE") < 0)
892 {
893 log_error("user_online_update() error\n");
894 }
895
896 if (article_modify(p_section, p_articles[selected_index], &article_new) < 0)
897 {
898 log_error("article_modify(aid=%d) error\n", p_articles[selected_index]->aid);
899 }
900 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
901 {
902 log_error("section_list_draw_screen() error\n");
903 return -2;
904 }
905 break;
906 case DELETE_ARTICLE:
907 if (!checkpriv(&BBS_priv, p_section->sid, S_POST) ||
908 (!checkpriv(&BBS_priv, p_section->sid, S_MAN_S) && p_articles[selected_index]->uid != BBS_priv.uid))
909 {
910 break; // No permission
911 }
912 if ((ret = article_del(p_section, p_articles[selected_index])) < 0)
913 {
914 log_error("article_del(aid=%d) error\n", p_articles[selected_index]->aid);
915 }
916 else if (ret > 0) // Article deleted
917 {
918 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
919 if (ret < 0)
920 {
921 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
922 return -3;
923 }
924 }
925 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
926 {
927 log_error("section_list_draw_screen() error\n");
928 return -2;
929 }
930 break;
931 case QUERY_ARTICLE:
932 if ((ret = display_article_meta(p_articles[selected_index]->aid)) < 0)
933 {
934 log_error("display_article_meta(aid=%d) error\n", p_articles[selected_index]->aid);
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 SET_FAVOR_ARTICLE:
943 ret = article_favor_set(p_articles[selected_index]->tid == 0
944 ? p_articles[selected_index]->aid
945 : p_articles[selected_index]->tid,
946 &BBS_article_favor, 1);
947 if (ret < 0)
948 {
949 log_error("article_favor_set(aid=%d, 1) error\n",
950 p_articles[selected_index]->tid == 0 ? p_articles[selected_index]->aid : p_articles[selected_index]->tid);
951 }
952 break;
953 case UNSET_FAVOR_ARTICLE:
954 ret = article_favor_set(p_articles[selected_index]->tid == 0
955 ? p_articles[selected_index]->aid
956 : p_articles[selected_index]->tid,
957 &BBS_article_favor, 0);
958 if (ret < 0)
959 {
960 log_error("article_favor_set(aid=%d, 0) error\n",
961 p_articles[selected_index]->tid == 0 ? p_articles[selected_index]->aid : p_articles[selected_index]->tid);
962 }
963 break;
964 case FIRST_TOPIC_ARTICLE:
965 case LAST_TOPIC_ARTICLE:
966 page_id_cur = page_id;
967 direction = (ret == FIRST_TOPIC_ARTICLE ? -1 : 1);
968 ret = locate_article_in_section(p_section, p_articles[selected_index], direction, BBS_article_limit_per_section,
969 &page_id, &selected_index, &article_count);
970 if (ret < 0)
971 {
972 log_error("locate_article_in_section(sid=%d, aid=%d, direction=%d, step=%d) error\n",
973 p_section->sid, p_articles[selected_index]->aid, direction, BBS_article_limit_per_section);
974 return -3;
975 }
976 else if (ret > 0 && page_id != page_id_cur) // found and page changed
977 {
978 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
979 if (ret < 0)
980 {
981 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
982 return -3;
983 }
984 }
985 break;
986 case SCAN_NEW_ARTICLE:
987 ret = scan_unread_article_in_section(p_section, p_articles[selected_index], &p_article_locate);
988 if (ret < 0)
989 {
990 log_error("scan_unread_article_in_section(sid=%d, aid=%d) error\n",
991 p_section->sid, p_articles[selected_index]->aid);
992 return -3;
993 }
994 else if (ret == 0) // not found
995 {
996 break;
997 }
998 page_id_cur = page_id;
999 ret = locate_article_in_section(p_section, p_article_locate, 0, 0,
1000 &page_id, &selected_index, &article_count);
1001 if (ret < 0)
1002 {
1003 log_error("locate_article_in_section(sid=%d, aid=%d, direction=0, step=0) error\n",
1004 p_section->sid, p_article_locate->aid);
1005 return -3;
1006 }
1007 else if (ret > 0 && page_id != page_id_cur) // found and page changed
1008 {
1009 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
1010 if (ret < 0)
1011 {
1012 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
1013 return -3;
1014 }
1015 }
1016 break;
1017 case SHOW_HELP:
1018 // Display help information
1019 display_file(DATA_READ_HELP, 1);
1020 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
1021 {
1022 log_error("section_list_draw_screen() error\n");
1023 return -2;
1024 }
1025 break;
1026 case VIEW_EX_DIR:
1027 if (section_list_ex_dir_display(p_section) < 0)
1028 {
1029 log_error("section_list_ex_dir_display(sid=%d) error\n", p_section->sid);
1030 }
1031 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
1032 {
1033 log_error("section_list_draw_screen() error\n");
1034 return -2;
1035 }
1036 break;
1037 case SHOW_TOP10:
1038 show_top10_menu(NULL);
1039 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
1040 {
1041 log_error("section_list_draw_screen() error\n");
1042 return -2;
1043 }
1044 break;
1045 default:
1046 log_error("Unknown command %d\n", ret);
1047 }
1048 }
1049
1050 return 0;
1051 }
1052
1053 int section_list_ex_dir_display(SECTION_LIST *p_section)
1054 {
1055 MENU_SET ex_menu_set;
1056 int ch = 0;
1057
1058 if (p_section == NULL)
1059 {
1060 log_error("NULL pointer error\n");
1061 return -1;
1062 }
1063
1064 if (p_section->ex_menu_tm == 0) // N/A
1065 {
1066 moveto(2, 1);
1067 clrtoeol();
1068 prints("该版块精华区未开放");
1069 press_any_key();
1070 return 0;
1071 }
1072
1073 if (get_section_ex_menu_set(p_section, &ex_menu_set) < 0)
1074 {
1075 log_error("get_section_ex_menu_set(sid=%d) error\n", p_section->sid);
1076 return -3;
1077 }
1078 if (get_menu_shm_readonly(&ex_menu_set) < 0)
1079 {
1080 log_error("get_menu_shm_readonly(sid=%d) error\n", p_section->sid);
1081 return -3;
1082 }
1083
1084 clearscr();
1085 show_bottom("");
1086
1087 if (display_menu(&ex_menu_set) == 0)
1088 {
1089 while (!SYS_server_exit)
1090 {
1091 iflush();
1092 ch = igetch(100);
1093 switch (ch)
1094 {
1095 case KEY_NULL: // broken pipe
1096 return 0;
1097 case KEY_TIMEOUT:
1098 if (time(NULL) - BBS_last_access_tm >= MAX_DELAY_TIME)
1099 {
1100 return 0;
1101 }
1102 continue;
1103 case CR:
1104 igetch_reset();
1105 default:
1106 switch (menu_control(&ex_menu_set, ch))
1107 {
1108 case EXITMENU:
1109 ch = EXITMENU;
1110 break;
1111 case REDRAW:
1112 clearscr();
1113 show_bottom("");
1114 display_menu(&ex_menu_set);
1115 break;
1116 case NOREDRAW:
1117 case UNKNOWN_CMD:
1118 default:
1119 break;
1120 }
1121 }
1122
1123 BBS_last_access_tm = time(NULL);
1124
1125 if (ch == EXITMENU)
1126 {
1127 break;
1128 }
1129 }
1130 }
1131
1132 detach_menu_shm(&ex_menu_set);
1133
1134 return 0;
1135 }

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