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

Diff of /lbbs/src/article_favor_display.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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


Legend:
Removed lines/characters  
Changed lines/characters
  Added lines/characters

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