/[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.12 - (show annotations)
Wed Dec 17 03:47:00 2025 UTC (2 months, 4 weeks ago) by sysadm
Branch: MAIN
Changes since 1.11: +2 -0 lines
Content type: text/x-csrc
Refine debug log

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

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