/[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.9 - (show annotations)
Tue Nov 11 00:28:05 2025 UTC (4 months ago) by sysadm
Branch: MAIN
Changes since 1.8: +4 -0 lines
Content type: text/x-csrc
Use config.h

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 #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, 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\n", 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
166 switch (ch)
167 {
168 case KEY_NULL: // broken pipe
169 log_error("KEY_NULL\n");
170 case KEY_ESC:
171 case KEY_LEFT:
172 return EXIT_LIST; // exit list
173 case KEY_TIMEOUT:
174 if (time(NULL) - BBS_last_access_tm >= BBS_max_user_idle_time)
175 {
176 log_error("User input timeout\n");
177 return EXIT_LIST; // exit list
178 }
179 continue;
180 case 'n':
181 return SWITCH_NAME;
182 case '-':
183 if (item_count > 0)
184 {
185 return UNSET_FAVOR;
186 }
187 break;
188 case CR:
189 case KEY_RIGHT:
190 if (item_count > 0)
191 {
192 return LOCATE_ARTICLE;
193 }
194 break;
195 case KEY_HOME:
196 *p_page_id = 0;
197 case 'P':
198 case KEY_PGUP:
199 *p_selected_index = 0;
200 case 'k':
201 case KEY_UP:
202 if (*p_selected_index <= 0)
203 {
204 if (*p_page_id > 0)
205 {
206 (*p_page_id)--;
207 *p_selected_index = BBS_article_limit_per_page - 1;
208 }
209 else if (ch == KEY_UP || ch == 'k') // Rotate to the tail of list
210 {
211 if (total_page > 0)
212 {
213 *p_page_id = total_page - 1;
214 }
215 if (item_count > 0)
216 {
217 *p_selected_index = item_count - 1;
218 }
219 }
220 }
221 else
222 {
223 (*p_selected_index)--;
224 }
225 break;
226 case '$':
227 case KEY_END:
228 if (total_page > 0)
229 {
230 *p_page_id = total_page - 1;
231 }
232 case 'N':
233 case KEY_PGDN:
234 if (item_count > 0)
235 {
236 *p_selected_index = item_count - 1;
237 }
238 case 'j':
239 case KEY_DOWN:
240 if (*p_selected_index + 1 >= item_count) // next page
241 {
242 if (*p_page_id + 1 < total_page)
243 {
244 (*p_page_id)++;
245 *p_selected_index = 0;
246 }
247 else if (ch == KEY_DOWN || ch == 'j') // Rotate to the head of list
248 {
249 *p_page_id = 0;
250 *p_selected_index = 0;
251 }
252 }
253 else
254 {
255 (*p_selected_index)++;
256 }
257 break;
258 case 'h':
259 return SHOW_HELP;
260 default:
261 break;
262 }
263
264 if (old_page_id != *p_page_id)
265 {
266 return CHANGE_PAGE;
267 }
268
269 if (item_count > 0 && old_selected_index != *p_selected_index)
270 {
271 if (old_selected_index >= 0)
272 {
273 moveto(4 + old_selected_index, 1);
274 outc(' ');
275 }
276 if (*p_selected_index >= 0)
277 {
278 moveto(4 + *p_selected_index, 1);
279 outc('>');
280 }
281 iflush();
282
283 old_selected_index = *p_selected_index;
284 }
285 }
286
287 return EXIT_LIST;
288 }
289
290 int article_favor_display(ARTICLE_FAVOR *p_favor)
291 {
292 static int display_sname = 0;
293
294 char page_info_str[LINE_BUFFER_LEN];
295 char snames[BBS_article_limit_per_page][BBS_section_name_max_len + 1];
296 ARTICLE *p_articles[BBS_article_limit_per_page];
297 int article_count;
298 int page_count;
299 int page_id = 0;
300 int selected_index = 0;
301 int ret;
302
303 if (p_favor == NULL)
304 {
305 log_error("NULL pointer error\n");
306 return -1;
307 }
308
309 article_favor_draw_screen(display_sname);
310
311 ret = query_favor_articles(p_favor, page_id, p_articles, snames, &article_count, &page_count);
312 if (ret < 0)
313 {
314 log_error("query_favor_articles(page_id=%d) error\n", page_id);
315 return -2;
316 }
317
318 if (article_count == 0) // empty list
319 {
320 selected_index = 0;
321 }
322
323 while (!SYS_server_exit)
324 {
325 ret = article_favor_draw_items(page_id, p_articles, snames, article_count, display_sname);
326 if (ret < 0)
327 {
328 log_error("article_favor_draw_items(page_id=%d) error\n", page_id);
329 return -3;
330 }
331
332 snprintf(page_info_str, sizeof(page_info_str),
333 "\033[33m[第\033[36m%d\033[33m/\033[36m%d\033[33m页]",
334 page_id + 1, MAX(page_count, 1));
335
336 show_bottom(page_info_str);
337 iflush();
338
339 if (user_online_update("ARTICLE_FAVOR") < 0)
340 {
341 log_error("user_online_update(ARTICLE_FAVOR) error\n");
342 }
343
344 ret = article_favor_select(page_count, article_count, &page_id, &selected_index);
345 switch (ret)
346 {
347 case EXIT_LIST:
348 return 0;
349 case UNSET_FAVOR:
350 if (article_favor_set(p_articles[selected_index]->aid, &BBS_article_favor, 0) != 1)
351 {
352 log_error("article_favor_set(aid=%d, 0) error\n", p_articles[selected_index]->aid);
353 break;
354 }
355 // continue to refresh list
356 case CHANGE_PAGE:
357 ret = query_favor_articles(p_favor, page_id, p_articles, snames, &article_count, &page_count);
358 if (ret < 0)
359 {
360 log_error("query_favor_articles(page_id=%d) error\n", page_id);
361 return -2;
362 }
363
364 if (article_count == 0) // empty list
365 {
366 selected_index = 0;
367 }
368 else if (selected_index >= article_count)
369 {
370 selected_index = article_count - 1;
371 }
372 break;
373 case LOCATE_ARTICLE:
374 if (section_list_display(snames[selected_index], p_articles[selected_index]->aid) < 0)
375 {
376 log_error("section_list_display(sname=%s, aid=%d) error\n",
377 snames[selected_index], p_articles[selected_index]->aid);
378 }
379 break;
380 case SWITCH_NAME:
381 display_sname = !display_sname;
382 article_favor_draw_screen(display_sname);
383 break;
384 case SHOW_HELP:
385 // Display help information
386 display_file(DATA_READ_HELP, 1);
387 article_favor_draw_screen(display_sname);
388 break;
389 default:
390 log_error("Unknown command %d\n", ret);
391 }
392 }
393
394 return 0;
395 }

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