/[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.2 by sysadm, Thu Oct 16 11:26:16 2025 UTC Revision 1.12 by sysadm, Wed Dec 17 03:47:00 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     */
8  /***************************************************************************  
9   *                                                                         *  #ifdef HAVE_CONFIG_H
10   *   This program is free software; you can redistribute it and/or modify  *  #include "config.h"
11   *   it under the terms of the GNU General Public License as published by  *  #endif
  *   the Free Software Foundation; either version 3 of the License, or     *  
  *   (at your option) any later version.                                   *  
  *                                                                         *  
  ***************************************************************************/  
12    
13  #include "article_favor_display.h"  #include "article_favor_display.h"
14  #include "article_view_log.h"  #include "article_view_log.h"
# Line 30  Line 26 
26    
27  enum select_cmd_t  enum select_cmd_t
28  {  {
29      EXIT_LIST = 0,          EXIT_LIST = 0,
30      LOCATE_ARTICLE,          LOCATE_ARTICLE,
31      CHANGE_PAGE,          CHANGE_PAGE,
32      SHOW_HELP,          SHOW_HELP,
33      SWITCH_NAME,          SWITCH_NAME,
34      UNSET_FAVOR,          UNSET_FAVOR,
35  };  };
36    
37  static int article_favor_draw_screen(int display_sname)  static int article_favor_draw_screen(int display_sname)
38  {  {
39      clearscr();          clearscr();
40      show_top("[主题收藏]", BBS_name, "");          show_top("[主题收藏]", BBS_name, "");
41      moveto(2, 0);          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] "          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] "                     "定位[\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",                     "%s[\033[1;32mn\033[0;37m] 帮助[\033[1;32mh\033[0;37m]\033[m",
45             (display_sname ? "用户名" : "版块名称"));                     (display_sname ? "用户名" : "版块名称"));
46      moveto(3, 0);          moveto(3, 0);
47      if (display_sname)          if (display_sname)
48      {          {
49          prints("\033[44;37m  \033[1;37m 编  号   版块名称             日  期  文章标题                               \033[m");                  prints("\033[44;37m  \033[1;37m 编  号   版块名称             日  期  文章标题                               \033[m");
50      }          }
51      else          else
52      {          {
53          prints("\033[44;37m  \033[1;37m 编  号   发 布 者     日  期  文章标题                                       \033[m");                  prints("\033[44;37m  \033[1;37m 编  号   发 布 者     日  期  文章标题                                       \033[m");
54      }          }
55    
56      return 0;          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],  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)                                                                          int article_count, int display_sname)
61  {  {
62      char str_time[LINE_BUFFER_LEN];          char str_time[LINE_BUFFER_LEN];
63      struct tm tm_sub;          struct tm tm_sub;
64      char title_f[BBS_article_title_max_len + 1];          char title_f[BBS_article_title_max_len + 1];
65      int title_f_len;          int title_f_len;
66      int eol;          int eol;
67      int len;          int len;
68      int i;          int i;
69      char article_flag;          char article_flag;
70          int is_viewed;          int is_viewed;
71      time_t tm_now;          time_t tm_now;
72    
73      time(&tm_now);          time(&tm_now);
74    
75      clrline(4, 23);          clrline(4, 23);
76    
77      for (i = 0; i < article_count; i++)          for (i = 0; i < article_count; i++)
78      {          {
79                  if (p_articles[i]->uid == BBS_priv.uid)                  if (p_articles[i]->uid == BBS_priv.uid)
80                  {                  {
81                          is_viewed = 1;                          is_viewed = 1;
# Line 94  static int article_favor_draw_items(int Line 90  static int article_favor_draw_items(int
90                          }                          }
91                  }                  }
92    
93          if (p_articles[i]->excerption)                  if (p_articles[i]->excerption)
94                  {                  {
95                          article_flag = (is_viewed ? 'm' : 'M');                          article_flag = (is_viewed ? 'm' : 'M');
96                  }                  }
# Line 107  static int article_favor_draw_items(int Line 103  static int article_favor_draw_items(int
103                          article_flag = (is_viewed ? ' ' : 'N');                          article_flag = (is_viewed ? ' ' : 'N');
104                  }                  }
105    
106          localtime_r(&p_articles[i]->sub_dt, &tm_sub);                  localtime_r(&p_articles[i]->sub_dt, &tm_sub);
107          if (tm_now - p_articles[i]->sub_dt < 3600 * 24 * 365)                  if (tm_now - p_articles[i]->sub_dt < 3600 * 24 * 365)
108          {                  {
109              strftime(str_time, sizeof(str_time), "%b %e ", &tm_sub);                          strftime(str_time, sizeof(str_time), "%b %e ", &tm_sub);
110          }                  }
111          else                  else
112          {                  {
113              strftime(str_time, sizeof(str_time), "%m/%Y", &tm_sub);                          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);                  strncpy(title_f, (p_articles[i]->tid == 0 ? "● " : ""), sizeof(title_f) - 1);
117          title_f[sizeof(title_f) - 1] = '\0';                  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)));                  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)));                  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);                  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')                  if (title_f[len] != '\0')
123          {                  {
124              title_f[len] = '\0';                          title_f[len] = '\0';
125          }                  }
126    
127          moveto(4 + i, 1);                  moveto(4 + i, 1);
   
         prints("  %7d %c %s%*s %s %s",  
                p_articles[i]->aid,  
                article_flag,  
                (display_sname ? p_snames[i] : p_articles[i]->username),  
                (display_sname  
                     ? BBS_section_name_max_len - str_length(p_snames[i], 1)  
                     : BBS_username_max_len - str_length(p_articles[i]->username, 1)),  
                "",  
                str_time,  
                title_f);  
     }  
128    
129      return 0;                  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)  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;          int old_page_id = *p_page_id;
147      int old_selected_index = *p_selected_index;          int old_selected_index = *p_selected_index;
148      int ch;          int ch;
149    
150      if (item_count > 0 && *p_selected_index >= 0)          if (item_count > 0 && *p_selected_index >= 0)
151      {          {
152          moveto(4 + *p_selected_index, 1);                  moveto(4 + *p_selected_index, 1);
153          outc('>');                  outc('>');
154          iflush();                  iflush();
155      }          }
156    
157      while (!SYS_server_exit)          while (!SYS_server_exit)
158      {          {
159          ch = igetch(100);                  ch = igetch(100);
160    
161          if (ch != KEY_NULL && ch != KEY_TIMEOUT)                  if (ch != KEY_NULL && ch != KEY_TIMEOUT)
162          {                  {
163              BBS_last_access_tm = time(NULL);                          BBS_last_access_tm = time(NULL);
164          }  
165                            // Refresh current action
166          switch (ch)                          if (user_online_update(NULL) < 0)
167          {                          {
168          case KEY_ESC:                                  log_error("user_online_update(NULL) error\n");
169          case KEY_LEFT:                          }
170          case KEY_NULL:        // broken pipe                  }
171    
172                    switch (ch)
173                    {
174                    case KEY_NULL: // broken pipe
175    #ifdef _DEBUG
176                          log_error("KEY_NULL\n");                          log_error("KEY_NULL\n");
177              return EXIT_LIST; // exit list  #endif
178          case KEY_TIMEOUT:                  case KEY_ESC:
179              if (time(NULL) - BBS_last_access_tm >= MAX_DELAY_TIME)                  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");                                  log_error("User input timeout\n");
185                  return EXIT_LIST; // exit list                                  return EXIT_LIST; // exit list
186              }                          }
187              continue;                          continue;
188          case 'n':                  case 'n':
189              return SWITCH_NAME;                          return SWITCH_NAME;
190          case '-':                  case '-':
191              if (item_count > 0)                          if (item_count > 0)
192              {                          {
193                  return UNSET_FAVOR;                                  return UNSET_FAVOR;
194              }                          }
195              break;                          break;
196          case CR:                  case CR:
197              igetch_reset();                  case KEY_RIGHT:
198          case KEY_RIGHT:                          if (item_count > 0)
199              if (item_count > 0)                          {
200              {                                  return LOCATE_ARTICLE;
201                  return LOCATE_ARTICLE;                          }
202              }                          break;
203              break;                  case KEY_HOME:
204          case KEY_HOME:                          *p_page_id = 0;
205              *p_page_id = 0;                  case 'P':
206          case 'P':                  case KEY_PGUP:
207          case KEY_PGUP:                          *p_selected_index = 0;
208              *p_selected_index = 0;                  case 'k':
209          case 'k':                  case KEY_UP:
210          case KEY_UP:                          if (*p_selected_index <= 0)
211              if (*p_selected_index <= 0)                          {
212              {                                  if (*p_page_id > 0)
213                  if (*p_page_id > 0)                                  {
214                  {                                          (*p_page_id)--;
215                      (*p_page_id)--;                                          *p_selected_index = BBS_article_limit_per_page - 1;
216                      *p_selected_index = BBS_article_limit_per_page - 1;                                  }
217                  }                                  else if (ch == KEY_UP || ch == 'k') // Rotate to the tail of list
218                  else if (ch == KEY_UP || ch == 'k') // Rotate to the tail of list                                  {
219                  {                                          if (total_page > 0)
220                      if (total_page > 0)                                          {
221                      {                                                  *p_page_id = total_page - 1;
222                          *p_page_id = total_page - 1;                                          }
223                      }                                          if (item_count > 0)
224                      if (item_count > 0)                                          {
225                      {                                                  *p_selected_index = item_count - 1;
226                          *p_selected_index = item_count - 1;                                          }
227                      }                                  }
228                  }                          }
229              }                          else
230              else                          {
231              {                                  (*p_selected_index)--;
232                  (*p_selected_index)--;                          }
233              }                          break;
234              break;                  case '$':
235          case '$':                  case KEY_END:
236          case KEY_END:                          if (total_page > 0)
237              if (total_page > 0)                          {
238              {                                  *p_page_id = total_page - 1;
239                  *p_page_id = total_page - 1;                          }
240              }                  case 'N':
241          case 'N':                  case KEY_PGDN:
242          case KEY_PGDN:                          if (item_count > 0)
243              if (item_count > 0)                          {
244              {                                  *p_selected_index = item_count - 1;
245                  *p_selected_index = item_count - 1;                          }
246              }                  case 'j':
247          case 'j':                  case KEY_DOWN:
248          case KEY_DOWN:                          if (*p_selected_index + 1 >= item_count) // next page
249              if (*p_selected_index + 1 >= item_count) // next page                          {
250              {                                  if (*p_page_id + 1 < total_page)
251                  if (*p_page_id + 1 < total_page)                                  {
252                  {                                          (*p_page_id)++;
253                      (*p_page_id)++;                                          *p_selected_index = 0;
254                      *p_selected_index = 0;                                  }
255                  }                                  else if (ch == KEY_DOWN || ch == 'j') // Rotate to the head of list
256                  else if (ch == KEY_DOWN || ch == 'j') // Rotate to the head of list                                  {
257                  {                                          *p_page_id = 0;
258                      *p_page_id = 0;                                          *p_selected_index = 0;
259                      *p_selected_index = 0;                                  }
260                  }                          }
261              }                          else
262              else                          {
263              {                                  (*p_selected_index)++;
264                  (*p_selected_index)++;                          }
265              }                          break;
266              break;                  case 'h':
267          case 'h':                          return SHOW_HELP;
268              return SHOW_HELP;                  default:
269          default:                          break;
270          }                  }
271    
272          if (old_page_id != *p_page_id)                  if (old_page_id != *p_page_id)
273          {                  {
274              return CHANGE_PAGE;                          return CHANGE_PAGE;
275          }                  }
   
         if (item_count > 0 && old_selected_index != *p_selected_index)  
         {  
             if (old_selected_index >= 0)  
             {  
                 moveto(4 + old_selected_index, 1);  
                 outc(' ');  
             }  
             if (*p_selected_index >= 0)  
             {  
                 moveto(4 + *p_selected_index, 1);  
                 outc('>');  
             }  
             iflush();  
   
             old_selected_index = *p_selected_index;  
         }  
     }  
276    
277      return EXIT_LIST;                  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)  int article_favor_display(ARTICLE_FAVOR *p_favor)
299  {  {
300      static int display_sname = 0;          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      char page_info_str[LINE_BUFFER_LEN];                  show_bottom(page_info_str);
345      char snames[BBS_article_limit_per_page][BBS_section_name_max_len + 1];                  iflush();
346      ARTICLE *p_articles[BBS_article_limit_per_page];  
347      int article_count;                  if (user_online_update("ARTICLE_FAVOR") < 0)
348      int page_count;                  {
349      int page_id = 0;                          log_error("user_online_update(ARTICLE_FAVOR) error\n");
350      int selected_index = 0;                  }
351      int ret;  
352                    ret = article_favor_select(page_count, article_count, &page_id, &selected_index);
353      if (p_favor == NULL)                  switch (ret)
354      {                  {
355          log_error("NULL pointer error\n");                  case EXIT_LIST:
356          return -1;                          return 0;
357      }                  case UNSET_FAVOR:
358                            if (article_favor_set(p_articles[selected_index]->aid, &BBS_article_favor, 0) != 1)
359      article_favor_draw_screen(display_sname);                          {
360                                    log_error("article_favor_set(aid=%d, 0) error\n", p_articles[selected_index]->aid);
361      ret = query_favor_articles(p_favor, page_id, p_articles, snames, &article_count, &page_count);                                  break;
362      if (ret < 0)                          }
363      {                          // continue to refresh list
364          log_error("query_favor_articles(page_id=%d) error\n", page_id);                  case CHANGE_PAGE:
365          return -2;                          ret = query_favor_articles(p_favor, page_id, p_articles, snames, &article_count, &page_count);
366      }                          if (ret < 0)
367                            {
368      if (article_count == 0) // empty list                                  log_error("query_favor_articles(page_id=%d) error\n", page_id);
369      {                                  return -2;
370          selected_index = 0;                          }
371      }  
372                            if (article_count == 0) // empty list
373      while (!SYS_server_exit)                          {
374      {                                  selected_index = 0;
375          ret = article_favor_draw_items(page_id, p_articles, snames, article_count, display_sname);                          }
376          if (ret < 0)                          else if (selected_index >= article_count)
377          {                          {
378              log_error("article_favor_draw_items(page_id=%d) error\n", page_id);                                  selected_index = article_count - 1;
379              return -3;                          }
380          }                          break;
381                    case LOCATE_ARTICLE:
382          snprintf(page_info_str, sizeof(page_info_str),                          if (section_list_display(snames[selected_index], p_articles[selected_index]->aid) < 0)
383                   "\033[33m[第\033[36m%d\033[33m/\033[36m%d\033[33m页]",                          {
384                   page_id + 1, MAX(page_count, 1));                                  log_error("section_list_display(sname=%s, aid=%d) error\n",
385                                                      snames[selected_index], p_articles[selected_index]->aid);
386          show_bottom(page_info_str);                          }
387          iflush();                          break;
388                    case SWITCH_NAME:
389          if (user_online_update("ARTICLE_FAVOR") < 0)                          display_sname = !display_sname;
390          {                          article_favor_draw_screen(display_sname);
391              log_error("user_online_update(ARTICLE_FAVOR) error\n");                          break;
392          }                  case SHOW_HELP:
393                            // Display help information
394          ret = article_favor_select(page_count, article_count, &page_id, &selected_index);                          display_file(DATA_READ_HELP, 1);
395          switch (ret)                          article_favor_draw_screen(display_sname);
396          {                          break;
397          case EXIT_LIST:                  default:
398              return 0;                          log_error("Unknown command %d\n", ret);
399          case UNSET_FAVOR:                  }
400              if (article_favor_set(p_articles[selected_index]->aid, &BBS_article_favor, 0) != 1)          }
             {  
                 log_error("article_favor_set(aid=%d, 0) error\n", p_articles[selected_index]->aid);  
                 break;  
             }  
             // continue to refresh list  
         case CHANGE_PAGE:  
             ret = query_favor_articles(p_favor, page_id, p_articles, snames, &article_count, &page_count);  
             if (ret < 0)  
             {  
                 log_error("query_favor_articles(page_id=%d) error\n", page_id);  
                 return -2;  
             }  
   
             if (article_count == 0) // empty list  
             {  
                 selected_index = 0;  
             }  
             else if (selected_index >= article_count)  
             {  
                 selected_index = article_count - 1;  
             }  
             break;  
         case LOCATE_ARTICLE:  
             if (section_list_display(snames[selected_index], p_articles[selected_index]->aid) < 0)  
             {  
                 log_error("section_list_display(sname=%s, aid=%d) error\n",  
                           snames[selected_index], p_articles[selected_index]->aid);  
             }  
             break;  
         case SWITCH_NAME:  
             display_sname = !display_sname;  
             article_favor_draw_screen(display_sname);  
             break;  
         case SHOW_HELP:  
             // Display help information  
             display_file(DATA_READ_HELP, 1);  
             article_favor_draw_screen(display_sname);  
             break;  
         default:  
             log_error("Unknown command %d\n", ret);  
         }  
     }  
401    
402      return 0;          return 0;
403  }  }


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

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