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

Annotation of /lbbs/src/section_list_display.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.62 - (hide annotations)
Sun Nov 2 15:11:47 2025 UTC (4 months, 2 weeks 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 sysadm 1.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 sysadm 1.9 #include "article_cache.h"
18 sysadm 1.53 #include "article_favor.h"
19 sysadm 1.41 #include "article_op.h"
20 sysadm 1.20 #include "article_post.h"
21 sysadm 1.34 #include "article_view_log.h"
22 sysadm 1.26 #include "article_del.h"
23 sysadm 1.1 #include "common.h"
24     #include "io.h"
25 sysadm 1.34 #include "log.h"
26     #include "login.h"
27 sysadm 1.37 #include "menu.h"
28 sysadm 1.48 #include "menu_proc.h"
29 sysadm 1.34 #include "section_list_display.h"
30     #include "section_list_loader.h"
31 sysadm 1.1 #include "screen.h"
32 sysadm 1.34 #include "str_process.h"
33 sysadm 1.57 #include "user_info_display.h"
34 sysadm 1.18 #include "user_priv.h"
35 sysadm 1.59 #include <errno.h>
36 sysadm 1.29 #include <string.h>
37 sysadm 1.1 #include <time.h>
38 sysadm 1.6 #include <sys/param.h>
39 sysadm 1.1
40 sysadm 1.59 static int32_t section_aid_locations[BBS_max_section] = {0};
41 sysadm 1.11 static int section_topic_view_mode = 0;
42 sysadm 1.13 static int section_topic_view_tid = -1;
43 sysadm 1.11
44 sysadm 1.1 enum select_cmd_t
45     {
46     EXIT_SECTION = 0,
47 sysadm 1.41 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 sysadm 1.57 QUERY_USER,
56 sysadm 1.53 SET_FAVOR_ARTICLE,
57     UNSET_FAVOR_ARTICLE,
58 sysadm 1.41 FIRST_TOPIC_ARTICLE,
59     LAST_TOPIC_ARTICLE,
60 sysadm 1.45 SCAN_NEW_ARTICLE,
61 sysadm 1.41 VIEW_EX_DIR,
62 sysadm 1.48 SHOW_TOP10,
63 sysadm 1.1 };
64    
65 sysadm 1.36 static int section_list_draw_items(int page_id, ARTICLE *p_articles[], int article_count, int display_nickname, int ontop_start_offset)
66 sysadm 1.1 {
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 sysadm 1.42 size_t j;
75 sysadm 1.3 char article_flag;
76 sysadm 1.17 int is_viewed;
77 sysadm 1.53 int is_favor;
78 sysadm 1.3 time_t tm_now;
79    
80     time(&tm_now);
81 sysadm 1.1
82     clrline(4, 23);
83    
84     for (i = 0; i < article_count; i++)
85     {
86 sysadm 1.18 if (p_articles[i]->uid == BBS_priv.uid)
87 sysadm 1.17 {
88 sysadm 1.18 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 sysadm 1.17 }
99    
100 sysadm 1.53 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 sysadm 1.3 if (p_articles[i]->excerption)
115     {
116 sysadm 1.17 article_flag = (is_viewed ? 'm' : 'M');
117 sysadm 1.3 }
118 sysadm 1.17 else if (p_articles[i]->lock && is_viewed)
119 sysadm 1.3 {
120     article_flag = 'x';
121     }
122 sysadm 1.35 else
123     {
124     article_flag = (is_viewed ? ' ' : 'N');
125     }
126 sysadm 1.3
127 sysadm 1.1 localtime_r(&p_articles[i]->sub_dt, &tm_sub);
128 sysadm 1.3 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 sysadm 1.40 strncpy(title_f, (p_articles[i]->tid == 0 ? "● " : ""), sizeof(title_f) - 1);
138 sysadm 1.1 title_f[sizeof(title_f) - 1] = '\0';
139 sysadm 1.40 strncat(title_f, (p_articles[i]->transship ? "[转载]" : ""), sizeof(title_f) - 1 - strnlen(title_f, sizeof(title_f)));
140 sysadm 1.42
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 sysadm 1.51 len = split_line(title_f, 59 - (display_nickname ? BBS_nickname_max_len / 2 : BBS_username_max_len), &eol, &title_f_len, 1);
161 sysadm 1.1 if (title_f[len] != '\0')
162     {
163     title_f[len] = '\0';
164     }
165    
166     moveto(4 + i, 1);
167 sysadm 1.36 if (i >= ontop_start_offset)
168     {
169 sysadm 1.53 prints(" \033[1;33m[提示]\033[m%c%c %s%*s %s %s%s\033[m",
170     (is_favor ? '@' : ' '),
171 sysadm 1.36 article_flag,
172     (display_nickname ? p_articles[i]->nickname : p_articles[i]->username),
173 sysadm 1.43 (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 sysadm 1.36 "",
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 sysadm 1.53 prints(" %s%7d\033[m%c%c %s%*s %s %s%s\033[m",
187 sysadm 1.36 (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 sysadm 1.53 (is_favor ? '@' : ' '),
194 sysadm 1.36 article_flag,
195     (display_nickname ? p_articles[i]->nickname : p_articles[i]->username),
196 sysadm 1.43 (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 sysadm 1.36 "",
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 sysadm 1.1 }
208    
209     return 0;
210     }
211    
212 sysadm 1.5 static int section_list_draw_screen(const char *sname, const char *stitle, const char *master_list, int display_nickname)
213 sysadm 1.1 {
214 sysadm 1.40 char str_section_master[LINE_BUFFER_LEN] = "诚征版主中";
215 sysadm 1.1 char str_section_name[LINE_BUFFER_LEN];
216    
217 sysadm 1.5 if (master_list[0] != '\0')
218 sysadm 1.1 {
219 sysadm 1.40 snprintf(str_section_master, sizeof(str_section_master), "版主:%s", master_list);
220 sysadm 1.1 }
221 sysadm 1.40 snprintf(str_section_name, sizeof(str_section_name), "讨论区 [%s]", sname);
222 sysadm 1.1
223     clearscr();
224 sysadm 1.5 show_top(str_section_master, stitle, str_section_name);
225 sysadm 1.1 moveto(2, 0);
226 sysadm 1.40 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 sysadm 1.1 moveto(3, 0);
231 sysadm 1.4 if (display_nickname)
232     {
233 sysadm 1.40 prints("\033[44;37m \033[1;37m 编 号 发布者昵称 日 期 文章标题 \033[m");
234 sysadm 1.4 }
235     else
236     {
237 sysadm 1.40 prints("\033[44;37m \033[1;37m 编 号 发 布 者 日 期 文章标题 \033[m");
238 sysadm 1.4 }
239 sysadm 1.1
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 sysadm 1.30 time_t last_refresh_tm = time(NULL);
249 sysadm 1.1
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 sysadm 1.54 if (ch != KEY_NULL && ch != KEY_TIMEOUT)
262     {
263     BBS_last_access_tm = time(NULL);
264     }
265    
266 sysadm 1.1 switch (ch)
267     {
268 sysadm 1.57 case KEY_NULL: // broken pipe
269 sysadm 1.54 log_error("KEY_NULL\n");
270     return EXIT_SECTION;
271 sysadm 1.1 case KEY_TIMEOUT:
272 sysadm 1.30 if (time(NULL) - BBS_last_access_tm >= MAX_DELAY_TIME)
273 sysadm 1.1 {
274 sysadm 1.54 log_error("User input timeout\n");
275     return EXIT_SECTION;
276 sysadm 1.1 }
277     continue;
278 sysadm 1.54 case KEY_ESC:
279     case KEY_LEFT:
280     return EXIT_SECTION;
281 sysadm 1.4 case 'n':
282     return CHANGE_NAME_DISPLAY;
283 sysadm 1.1 case CR:
284 sysadm 1.28 case 'r':
285 sysadm 1.1 case KEY_RIGHT:
286     if (item_count > 0)
287     {
288     return VIEW_ARTICLE;
289     }
290     break;
291 sysadm 1.20 case Ctrl('P'):
292     return POST_ARTICLE;
293     case 'E':
294 sysadm 1.41 if (item_count > 0)
295     {
296     return EDIT_ARTICLE;
297     }
298     break;
299 sysadm 1.26 case 'd':
300 sysadm 1.41 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 sysadm 1.57 case Ctrl('A'):
312     if (item_count > 0)
313     {
314     return QUERY_USER;
315     }
316     break;
317 sysadm 1.53 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 sysadm 1.1 case KEY_HOME:
330     *p_page_id = 0;
331 sysadm 1.28 case 'P':
332 sysadm 1.1 case KEY_PGUP:
333     *p_selected_index = 0;
334 sysadm 1.28 case 'k':
335 sysadm 1.1 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 sysadm 1.44 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 sysadm 1.1 }
355     else
356     {
357     (*p_selected_index)--;
358     }
359     break;
360 sysadm 1.28 case '$':
361 sysadm 1.1 case KEY_END:
362     if (total_page > 0)
363     {
364     *p_page_id = total_page - 1;
365     }
366 sysadm 1.28 case 'N':
367 sysadm 1.1 case KEY_PGDN:
368     if (item_count > 0)
369     {
370     *p_selected_index = item_count - 1;
371     }
372 sysadm 1.28 case 'j':
373 sysadm 1.1 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 sysadm 1.44 else if (ch == KEY_DOWN || ch == 'j') // Rotate to the head of section list
382 sysadm 1.25 {
383 sysadm 1.44 *p_page_id = 0;
384     *p_selected_index = 0;
385 sysadm 1.25 }
386 sysadm 1.1 }
387     else
388     {
389     (*p_selected_index)++;
390     }
391     break;
392 sysadm 1.31 case '=':
393 sysadm 1.41 if (item_count > 0)
394     {
395     return FIRST_TOPIC_ARTICLE;
396     }
397     break;
398 sysadm 1.31 case '\\':
399 sysadm 1.41 if (item_count > 0)
400     {
401     return LAST_TOPIC_ARTICLE;
402     }
403     break;
404 sysadm 1.45 case 'S':
405     if (item_count > 0)
406     {
407     return SCAN_NEW_ARTICLE;
408     }
409     break;
410 sysadm 1.28 case 'h':
411     return SHOW_HELP;
412 sysadm 1.37 case 'x':
413     return VIEW_EX_DIR;
414 sysadm 1.49 case 'H':
415 sysadm 1.48 return SHOW_TOP10;
416 sysadm 1.1 default:
417 sysadm 1.56 break;
418 sysadm 1.1 }
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 sysadm 1.30 if (BBS_last_access_tm - last_refresh_tm >= BBS_section_list_load_interval)
443     {
444     return CHANGE_PAGE; // force section list refresh
445     }
446 sysadm 1.1 }
447    
448     return EXIT_SECTION;
449     }
450    
451 sysadm 1.11 static int display_article_key_handler(int *p_key, DISPLAY_CTX *p_ctx)
452 sysadm 1.10 {
453 sysadm 1.11 switch (*p_key)
454 sysadm 1.10 {
455 sysadm 1.11 case 'p':
456 sysadm 1.28 case Ctrl('X'):
457 sysadm 1.11 section_topic_view_mode = !section_topic_view_mode;
458 sysadm 1.10 case 0: // Set msg
459 sysadm 1.11 if (section_topic_view_mode)
460 sysadm 1.10 {
461 sysadm 1.11 snprintf(p_ctx->msg, sizeof(p_ctx->msg),
462 sysadm 1.40 "| 返回[\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 sysadm 1.10 }
466     else
467     {
468 sysadm 1.11 snprintf(p_ctx->msg, sizeof(p_ctx->msg),
469 sysadm 1.40 "| 返回[\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 sysadm 1.10 }
473 sysadm 1.11 *p_key = 0;
474 sysadm 1.10 break;
475 sysadm 1.20 case 'r': // Reply article
476     return 1;
477 sysadm 1.31 case '=': // First topic article
478     return 1;
479     case '\\': // Last topic article
480     return 1;
481 sysadm 1.12 case KEY_UP:
482 sysadm 1.16 case KEY_PGUP:
483     case KEY_HOME:
484 sysadm 1.12 if (p_ctx->reach_begin)
485     {
486     if (section_topic_view_mode)
487     {
488     *p_key = KEY_PGUP;
489     }
490 sysadm 1.16 else
491     {
492     *p_key = KEY_UP;
493     }
494 sysadm 1.12 return 1;
495     }
496     break;
497 sysadm 1.28 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 sysadm 1.12 case KEY_DOWN:
508 sysadm 1.16 case KEY_PGDN:
509     case KEY_END:
510 sysadm 1.12 if (p_ctx->reach_end)
511     {
512     if (section_topic_view_mode)
513     {
514     *p_key = KEY_PGDN;
515     }
516 sysadm 1.16 else
517     {
518     *p_key = KEY_DOWN;
519     }
520 sysadm 1.12 return 1;
521     }
522     break;
523 sysadm 1.28 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 sysadm 1.10 }
534    
535     return 0;
536     }
537    
538 sysadm 1.46 int section_list_display(const char *sname, int32_t aid)
539 sysadm 1.1 {
540 sysadm 1.4 static int display_nickname = 0;
541    
542 sysadm 1.1 SECTION_LIST *p_section;
543 sysadm 1.46 int64_t section_index;
544     int32_t aid_location;
545 sysadm 1.5 char stitle[BBS_section_title_max_len + 1];
546     char master_list[(BBS_username_max_len + 1) * 3 + 1];
547 sysadm 1.6 char page_info_str[LINE_BUFFER_LEN];
548 sysadm 1.1 ARTICLE *p_articles[BBS_article_limit_per_page];
549     int article_count;
550 sysadm 1.6 int page_count;
551 sysadm 1.36 int ontop_start_offset;
552 sysadm 1.1 int page_id = 0;
553     int selected_index = 0;
554 sysadm 1.10 ARTICLE_CACHE cache;
555 sysadm 1.1 int ret;
556 sysadm 1.12 int loop;
557     int direction;
558 sysadm 1.24 ARTICLE article_new;
559 sysadm 1.31 int page_id_cur;
560 sysadm 1.46 const ARTICLE *p_article_locate;
561 sysadm 1.57 USER_INFO user_info;
562 sysadm 1.61 char user_intro[BBS_user_intro_max_len];
563 sysadm 1.1
564 sysadm 1.50 p_section = section_list_find_by_name(sname);
565 sysadm 1.1 if (p_section == NULL)
566     {
567     log_error("Section %s not found\n", sname);
568     return -1;
569     }
570    
571 sysadm 1.52 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 sysadm 1.50 section_index = get_section_index(p_section);
579    
580 sysadm 1.58 if (get_section_info(p_section, NULL, stitle, master_list) < 0)
581 sysadm 1.5 {
582 sysadm 1.58 log_error("get_section_info(sid=%d) error\n", p_section->sid);
583     return -4;
584 sysadm 1.5 }
585    
586 sysadm 1.46 if (aid == 0)
587     {
588     aid_location = section_aid_locations[section_index];
589     }
590     else
591     {
592     aid_location = aid;
593 sysadm 1.51 }
594 sysadm 1.46
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 sysadm 1.5 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
616 sysadm 1.1 {
617     log_error("section_list_draw_screen() error\n");
618     return -2;
619     }
620    
621 sysadm 1.36 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
622 sysadm 1.5 if (ret < 0)
623 sysadm 1.1 {
624 sysadm 1.5 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
625     return -3;
626 sysadm 1.1 }
627 sysadm 1.5
628 sysadm 1.46 section_topic_view_tid = -1;
629    
630 sysadm 1.5 if (article_count == 0) // empty section
631 sysadm 1.1 {
632     selected_index = 0;
633     }
634 sysadm 1.46 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 sysadm 1.1
643     while (!SYS_server_exit)
644     {
645 sysadm 1.36 ret = section_list_draw_items(page_id, p_articles, article_count, display_nickname, ontop_start_offset);
646 sysadm 1.1 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 sysadm 1.6
652 sysadm 1.7 snprintf(page_info_str, sizeof(page_info_str),
653 sysadm 1.40 "\033[33m[第\033[36m%d\033[33m/\033[36m%d\033[33m页]",
654 sysadm 1.7 page_id + 1, MAX(page_count, 1));
655 sysadm 1.8
656 sysadm 1.6 show_bottom(page_info_str);
657 sysadm 1.1 iflush();
658    
659 sysadm 1.33 if (user_online_update(sname) < 0)
660     {
661     log_error("user_online_update(%s) error\n", sname);
662     }
663    
664 sysadm 1.6 ret = section_list_select(page_count, article_count, &page_id, &selected_index);
665 sysadm 1.60
666 sysadm 1.1 switch (ret)
667     {
668     case EXIT_SECTION:
669 sysadm 1.62 // 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 sysadm 1.1 return 0;
679     case CHANGE_PAGE:
680 sysadm 1.36 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
681 sysadm 1.5 if (ret < 0)
682 sysadm 1.1 {
683 sysadm 1.5 log_error("query_section_articles(sid=%d, page_id=%d) error\n", p_section->sid, page_id);
684     return -3;
685 sysadm 1.1 }
686 sysadm 1.5 if (article_count == 0) // empty section
687 sysadm 1.1 {
688     selected_index = 0;
689     }
690 sysadm 1.5 else if (selected_index >= article_count)
691 sysadm 1.1 {
692     selected_index = article_count - 1;
693     }
694     break;
695     case VIEW_ARTICLE:
696 sysadm 1.12 do
697 sysadm 1.9 {
698 sysadm 1.12 loop = 0;
699 sysadm 1.9
700 sysadm 1.12 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 sysadm 1.33 if (user_online_update("VIEW_ARTICLE") < 0)
707     {
708     log_error("user_online_update(VIEW_ARTICLE) error\n");
709     }
710    
711 sysadm 1.19 ret = display_data(cache.p_data, cache.line_total, cache.line_offsets, 0,
712 sysadm 1.12 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 sysadm 1.17 // 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 sysadm 1.12 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 sysadm 1.36 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
737 sysadm 1.12 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 sysadm 1.36 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
768 sysadm 1.12 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 sysadm 1.31 ret = locate_article_in_section(p_section, p_articles[selected_index], direction, 1,
794     &page_id, &selected_index, &article_count);
795 sysadm 1.12 if (ret < 0)
796     {
797 sysadm 1.31 log_error("locate_article_in_section(sid=%d, aid=%d, direction=%d, step=1) error\n",
798 sysadm 1.12 p_section->sid, p_articles[selected_index]->aid, direction);
799     return -3;
800     }
801 sysadm 1.31 else if (ret > 0) // found
802 sysadm 1.12 {
803 sysadm 1.36 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
804 sysadm 1.12 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 sysadm 1.20 case 'r': // Reply article
813 sysadm 1.33 if (user_online_update("REPLY_ARTICLE") < 0)
814     {
815     log_error("user_online_update(REPLY_ARTICLE) error\n");
816     }
817    
818 sysadm 1.24 if (article_reply(p_section, p_articles[selected_index], &article_new) < 0)
819 sysadm 1.20 {
820 sysadm 1.33 log_error("article_reply(aid=%d) error\n", p_articles[selected_index]->aid);
821 sysadm 1.20 }
822     loop = 1;
823     break;
824 sysadm 1.31 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 sysadm 1.36 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
841 sysadm 1.31 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 sysadm 1.12 }
851     } while (loop);
852 sysadm 1.13
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 sysadm 1.46
856 sysadm 1.35 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 sysadm 1.4 case CHANGE_NAME_DISPLAY:
863     display_nickname = !display_nickname;
864 sysadm 1.5 if (section_list_draw_screen(sname, stitle, master_list, display_nickname) < 0)
865 sysadm 1.1 {
866     log_error("section_list_draw_screen() error\n");
867     return -2;
868     }
869     break;
870 sysadm 1.20 case POST_ARTICLE:
871 sysadm 1.33 if (user_online_update("POST_ARTICLE") < 0)
872     {
873     log_error("user_online_update(POST_ARTICLE) error\n");
874     }
875    
876 sysadm 1.30 if ((ret = article_post(p_section, &article_new)) < 0)
877 sysadm 1.20 {
878 sysadm 1.26 log_error("article_post(sid=%d) error\n", p_section->sid);
879 sysadm 1.20 }
880 sysadm 1.24 else if (ret > 0) // New article posted
881     {
882 sysadm 1.36 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
883 sysadm 1.24 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 sysadm 1.20 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 sysadm 1.26 if (!checkpriv(&BBS_priv, p_section->sid, S_POST) ||
897     p_articles[selected_index]->uid != BBS_priv.uid)
898 sysadm 1.20 {
899 sysadm 1.26 break; // No permission
900 sysadm 1.20 }
901 sysadm 1.33
902     if (user_online_update("EDIT_ARTICLE") < 0)
903     {
904     log_error("user_online_update() error\n");
905     }
906    
907 sysadm 1.24 if (article_modify(p_section, p_articles[selected_index], &article_new) < 0)
908 sysadm 1.20 {
909 sysadm 1.26 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 sysadm 1.30 if ((ret = article_del(p_section, p_articles[selected_index])) < 0)
924 sysadm 1.26 {
925     log_error("article_del(aid=%d) error\n", p_articles[selected_index]->aid);
926 sysadm 1.20 }
927 sysadm 1.30 else if (ret > 0) // Article deleted
928     {
929 sysadm 1.36 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
930 sysadm 1.30 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 sysadm 1.20 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 sysadm 1.41 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 sysadm 1.57 case QUERY_USER:
954 sysadm 1.61 if ((ret = query_user_info_by_uid(p_articles[selected_index]->uid, &user_info, user_intro, sizeof(user_intro))) < 0)
955 sysadm 1.57 {
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 sysadm 1.53 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 sysadm 1.31 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 sysadm 1.36 ret = query_section_articles(p_section, page_id, p_articles, &article_count, &page_count, &ontop_start_offset);
1013 sysadm 1.31 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 sysadm 1.45 case SCAN_NEW_ARTICLE:
1021 sysadm 1.46 ret = scan_unread_article_in_section(p_section, p_articles[selected_index], &p_article_locate);
1022 sysadm 1.45 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 sysadm 1.46 ret = locate_article_in_section(p_section, p_article_locate, 0, 0,
1034 sysadm 1.45 &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 sysadm 1.46 p_section->sid, p_article_locate->aid);
1039 sysadm 1.45 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 sysadm 1.28 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 sysadm 1.37 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 sysadm 1.48 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 sysadm 1.1 default:
1080     log_error("Unknown command %d\n", ret);
1081     }
1082     }
1083    
1084     return 0;
1085     }
1086 sysadm 1.37
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 sysadm 1.39 if (p_section->ex_menu_tm == 0) // N/A
1099     {
1100     moveto(2, 1);
1101     clrtoeol();
1102 sysadm 1.40 prints("该版块精华区未开放");
1103 sysadm 1.39 press_any_key();
1104     return 0;
1105     }
1106    
1107 sysadm 1.37 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 sysadm 1.39 log_error("get_menu_shm_readonly(sid=%d) error\n", p_section->sid);
1115 sysadm 1.37 return -3;
1116     }
1117    
1118     clearscr();
1119 sysadm 1.38 show_bottom("");
1120 sysadm 1.37
1121     if (display_menu(&ex_menu_set) == 0)
1122     {
1123     while (!SYS_server_exit)
1124     {
1125     iflush();
1126     ch = igetch(100);
1127 sysadm 1.54
1128     if (ch != KEY_NULL && ch != KEY_TIMEOUT)
1129     {
1130     BBS_last_access_tm = time(NULL);
1131     }
1132    
1133 sysadm 1.37 switch (ch)
1134     {
1135     case KEY_NULL: // broken pipe
1136 sysadm 1.54 log_error("KEY_NULL\n");
1137 sysadm 1.37 return 0;
1138     case KEY_TIMEOUT:
1139     if (time(NULL) - BBS_last_access_tm >= MAX_DELAY_TIME)
1140     {
1141 sysadm 1.54 log_error("User input timeout\n");
1142 sysadm 1.37 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 sysadm 1.38 show_bottom("");
1155 sysadm 1.37 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 sysadm 1.59
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