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

Contents of /lbbs/src/article_favor_display.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.7 - (show annotations)
Tue Nov 4 14:58:56 2025 UTC (4 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.6: +1 -1 lines
Content type: text/x-csrc
Refine file header information comments

1 /* SPDX-License-Identifier: GPL-3.0-or-later */
2 /*
3 * article_favor_display
4 * - user interactive feature to display favorite articles
5 *
6 * Copyright (C) 2004-2025 Leaflet <leaflet@leafok.com>
7 */
8
9 #include "article_favor_display.h"
10 #include "article_view_log.h"
11 #include "io.h"
12 #include "log.h"
13 #include "login.h"
14 #include "screen.h"
15 #include "str_process.h"
16 #include "section_list.h"
17 #include "section_list_display.h"
18 #include "user_priv.h"
19 #include <string.h>
20 #include <time.h>
21 #include <sys/param.h>
22
23 enum select_cmd_t
24 {
25 EXIT_LIST = 0,
26 LOCATE_ARTICLE,
27 CHANGE_PAGE,
28 SHOW_HELP,
29 SWITCH_NAME,
30 UNSET_FAVOR,
31 };
32
33 static int article_favor_draw_screen(int display_sname)
34 {
35 clearscr();
36 show_top("[主题收藏]", BBS_name, "");
37 moveto(2, 0);
38 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] "
39 "定位[\033[1;32m→\033[0;37m,\033[1;32mENTER\033[0;37m] 移除[\033[1;32m-\033[0;37m\033[0;37m] "
40 "%s[\033[1;32mn\033[0;37m] 帮助[\033[1;32mh\033[0;37m]\033[m",
41 (display_sname ? "用户名" : "版块名称"));
42 moveto(3, 0);
43 if (display_sname)
44 {
45 prints("\033[44;37m \033[1;37m 编 号 版块名称 日 期 文章标题 \033[m");
46 }
47 else
48 {
49 prints("\033[44;37m \033[1;37m 编 号 发 布 者 日 期 文章标题 \033[m");
50 }
51
52 return 0;
53 }
54
55 static int article_favor_draw_items(int page_id, ARTICLE *p_articles[], char p_snames[][BBS_section_name_max_len + 1],
56 int article_count, int display_sname)
57 {
58 char str_time[LINE_BUFFER_LEN];
59 struct tm tm_sub;
60 char title_f[BBS_article_title_max_len + 1];
61 int title_f_len;
62 int eol;
63 int len;
64 int i;
65 char article_flag;
66 int is_viewed;
67 time_t tm_now;
68
69 time(&tm_now);
70
71 clrline(4, 23);
72
73 for (i = 0; i < article_count; i++)
74 {
75 if (p_articles[i]->uid == BBS_priv.uid)
76 {
77 is_viewed = 1;
78 }
79 else
80 {
81 is_viewed = article_view_log_is_viewed(p_articles[i]->aid, &BBS_article_view_log);
82 if (is_viewed < 0)
83 {
84 log_error("article_view_log_is_viewed(aid=%d) error\n", p_articles[i]->aid);
85 is_viewed = 0;
86 }
87 }
88
89 if (p_articles[i]->excerption)
90 {
91 article_flag = (is_viewed ? 'm' : 'M');
92 }
93 else if (p_articles[i]->lock && is_viewed)
94 {
95 article_flag = 'x';
96 }
97 else
98 {
99 article_flag = (is_viewed ? ' ' : 'N');
100 }
101
102 localtime_r(&p_articles[i]->sub_dt, &tm_sub);
103 if (tm_now - p_articles[i]->sub_dt < 3600 * 24 * 365)
104 {
105 strftime(str_time, sizeof(str_time), "%b %e ", &tm_sub);
106 }
107 else
108 {
109 strftime(str_time, sizeof(str_time), "%m/%Y", &tm_sub);
110 }
111
112 strncpy(title_f, (p_articles[i]->tid == 0 ? "● " : ""), sizeof(title_f) - 1);
113 title_f[sizeof(title_f) - 1] = '\0';
114 strncat(title_f, (p_articles[i]->transship ? "[转载]" : ""), sizeof(title_f) - 1 - strnlen(title_f, sizeof(title_f)));
115 strncat(title_f, p_articles[i]->title, sizeof(title_f) - 1 - strnlen(title_f, sizeof(title_f)));
116
117 len = split_line(title_f, 59 - (display_sname ? BBS_section_name_max_len : BBS_username_max_len), &eol, &title_f_len, 1);
118 if (title_f[len] != '\0')
119 {
120 title_f[len] = '\0';
121 }
122
123 moveto(4 + i, 1);
124
125 prints(" %7d %c %s%*s %s %s",
126 p_articles[i]->aid,
127 article_flag,
128 (display_sname ? p_snames[i] : p_articles[i]->username),
129 (display_sname
130 ? BBS_section_name_max_len - str_length(p_snames[i], 1)
131 : BBS_username_max_len - str_length(p_articles[i]->username, 1)),
132 "",
133 str_time,
134 title_f);
135 }
136
137 return 0;
138 }
139
140 static enum select_cmd_t article_favor_select(int total_page, int item_count, int *p_page_id, int *p_selected_index)
141 {
142 int old_page_id = *p_page_id;
143 int old_selected_index = *p_selected_index;
144 int ch;
145
146 if (item_count > 0 && *p_selected_index >= 0)
147 {
148 moveto(4 + *p_selected_index, 1);
149 outc('>');
150 iflush();
151 }
152
153 while (!SYS_server_exit)
154 {
155 ch = igetch(100);
156
157 if (ch != KEY_NULL && ch != KEY_TIMEOUT)
158 {
159 BBS_last_access_tm = time(NULL);
160 }
161
162 switch (ch)
163 {
164 case KEY_NULL: // broken pipe
165 log_error("KEY_NULL\n");
166 case KEY_ESC:
167 case KEY_LEFT:
168 return EXIT_LIST; // exit list
169 case KEY_TIMEOUT:
170 if (time(NULL) - BBS_last_access_tm >= MAX_DELAY_TIME)
171 {
172 log_error("User input timeout\n");
173 return EXIT_LIST; // exit list
174 }
175 continue;
176 case 'n':
177 return SWITCH_NAME;
178 case '-':
179 if (item_count > 0)
180 {
181 return UNSET_FAVOR;
182 }
183 break;
184 case CR:
185 case KEY_RIGHT:
186 if (item_count > 0)
187 {
188 return LOCATE_ARTICLE;
189 }
190 break;
191 case KEY_HOME:
192 *p_page_id = 0;
193 case 'P':
194 case KEY_PGUP:
195 *p_selected_index = 0;
196 case 'k':
197 case KEY_UP:
198 if (*p_selected_index <= 0)
199 {
200 if (*p_page_id > 0)
201 {
202 (*p_page_id)--;
203 *p_selected_index = BBS_article_limit_per_page - 1;
204 }
205 else if (ch == KEY_UP || ch == 'k') // Rotate to the tail of list
206 {
207 if (total_page > 0)
208 {
209 *p_page_id = total_page - 1;
210 }
211 if (item_count > 0)
212 {
213 *p_selected_index = item_count - 1;
214 }
215 }
216 }
217 else
218 {
219 (*p_selected_index)--;
220 }
221 break;
222 case '$':
223 case KEY_END:
224 if (total_page > 0)
225 {
226 *p_page_id = total_page - 1;
227 }
228 case 'N':
229 case KEY_PGDN:
230 if (item_count > 0)
231 {
232 *p_selected_index = item_count - 1;
233 }
234 case 'j':
235 case KEY_DOWN:
236 if (*p_selected_index + 1 >= item_count) // next page
237 {
238 if (*p_page_id + 1 < total_page)
239 {
240 (*p_page_id)++;
241 *p_selected_index = 0;
242 }
243 else if (ch == KEY_DOWN || ch == 'j') // Rotate to the head of list
244 {
245 *p_page_id = 0;
246 *p_selected_index = 0;
247 }
248 }
249 else
250 {
251 (*p_selected_index)++;
252 }
253 break;
254 case 'h':
255 return SHOW_HELP;
256 default:
257 break;
258 }
259
260 if (old_page_id != *p_page_id)
261 {
262 return CHANGE_PAGE;
263 }
264
265 if (item_count > 0 && old_selected_index != *p_selected_index)
266 {
267 if (old_selected_index >= 0)
268 {
269 moveto(4 + old_selected_index, 1);
270 outc(' ');
271 }
272 if (*p_selected_index >= 0)
273 {
274 moveto(4 + *p_selected_index, 1);
275 outc('>');
276 }
277 iflush();
278
279 old_selected_index = *p_selected_index;
280 }
281 }
282
283 return EXIT_LIST;
284 }
285
286 int article_favor_display(ARTICLE_FAVOR *p_favor)
287 {
288 static int display_sname = 0;
289
290 char page_info_str[LINE_BUFFER_LEN];
291 char snames[BBS_article_limit_per_page][BBS_section_name_max_len + 1];
292 ARTICLE *p_articles[BBS_article_limit_per_page];
293 int article_count;
294 int page_count;
295 int page_id = 0;
296 int selected_index = 0;
297 int ret;
298
299 if (p_favor == NULL)
300 {
301 log_error("NULL pointer error\n");
302 return -1;
303 }
304
305 article_favor_draw_screen(display_sname);
306
307 ret = query_favor_articles(p_favor, page_id, p_articles, snames, &article_count, &page_count);
308 if (ret < 0)
309 {
310 log_error("query_favor_articles(page_id=%d) error\n", page_id);
311 return -2;
312 }
313
314 if (article_count == 0) // empty list
315 {
316 selected_index = 0;
317 }
318
319 while (!SYS_server_exit)
320 {
321 ret = article_favor_draw_items(page_id, p_articles, snames, article_count, display_sname);
322 if (ret < 0)
323 {
324 log_error("article_favor_draw_items(page_id=%d) error\n", page_id);
325 return -3;
326 }
327
328 snprintf(page_info_str, sizeof(page_info_str),
329 "\033[33m[第\033[36m%d\033[33m/\033[36m%d\033[33m页]",
330 page_id + 1, MAX(page_count, 1));
331
332 show_bottom(page_info_str);
333 iflush();
334
335 if (user_online_update("ARTICLE_FAVOR") < 0)
336 {
337 log_error("user_online_update(ARTICLE_FAVOR) error\n");
338 }
339
340 ret = article_favor_select(page_count, article_count, &page_id, &selected_index);
341 switch (ret)
342 {
343 case EXIT_LIST:
344 return 0;
345 case UNSET_FAVOR:
346 if (article_favor_set(p_articles[selected_index]->aid, &BBS_article_favor, 0) != 1)
347 {
348 log_error("article_favor_set(aid=%d, 0) error\n", p_articles[selected_index]->aid);
349 break;
350 }
351 // continue to refresh list
352 case CHANGE_PAGE:
353 ret = query_favor_articles(p_favor, page_id, p_articles, snames, &article_count, &page_count);
354 if (ret < 0)
355 {
356 log_error("query_favor_articles(page_id=%d) error\n", page_id);
357 return -2;
358 }
359
360 if (article_count == 0) // empty list
361 {
362 selected_index = 0;
363 }
364 else if (selected_index >= article_count)
365 {
366 selected_index = article_count - 1;
367 }
368 break;
369 case LOCATE_ARTICLE:
370 if (section_list_display(snames[selected_index], p_articles[selected_index]->aid) < 0)
371 {
372 log_error("section_list_display(sname=%s, aid=%d) error\n",
373 snames[selected_index], p_articles[selected_index]->aid);
374 }
375 break;
376 case SWITCH_NAME:
377 display_sname = !display_sname;
378 article_favor_draw_screen(display_sname);
379 break;
380 case SHOW_HELP:
381 // Display help information
382 display_file(DATA_READ_HELP, 1);
383 article_favor_draw_screen(display_sname);
384 break;
385 default:
386 log_error("Unknown command %d\n", ret);
387 }
388 }
389
390 return 0;
391 }

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