/[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.16 - (show annotations)
Sat Jan 3 10:27:14 2026 UTC (2 months, 1 week ago) by sysadm
Branch: MAIN
CVS Tags: HEAD
Changes since 1.15: +1 -1 lines
Content type: text/x-csrc
Update copyright info

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

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