tin  2.4.4
About: TIN is a threaded NNTP and spool based UseNet newsreader.
  Fossies Dox: tin-2.4.4.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

group.c
Go to the documentation of this file.
1 /*
2  * Project : tin - a Usenet reader
3  * Module : group.c
4  * Author : I. Lea & R. Skrenta
5  * Created : 1991-04-01
6  * Updated : 2017-10-24
7  * Notes :
8  *
9  * Copyright (c) 1991-2020 Iain Lea <iain@bricbrac.de>, Rich Skrenta <skrenta@pbm.com>
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  *
16  * 1. Redistributions of source code must retain the above copyright notice,
17  * this list of conditions and the following disclaimer.
18  *
19  * 2. Redistributions in binary form must reproduce the above copyright
20  * notice, this list of conditions and the following disclaimer in the
21  * documentation and/or other materials provided with the distribution.
22  *
23  * 3. Neither the name of the copyright holder nor the names of its
24  * contributors may be used to endorse or promote products derived from
25  * this software without specific prior written permission.
26  *
27  * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 
41 #ifndef TIN_H
42 # include "tin.h"
43 #endif /* !TIN_H */
44 #ifndef TCURSES_H
45 # include "tcurses.h"
46 #endif /* !TCURSES_H */
47 
48 
49 /*
50  * Globally accessible pointer to currently active group
51  * Any functionality accessed from group level or below can use this pointer.
52  * Any code invoked from selection level that requires a group context will
53  * need to manually fix this up
54  */
56 static struct t_fmt grp_fmt;
57 
58 /*
59  * Local prototypes
60  */
61 static int do_search(t_function func, t_bool repeat);
62 static int enter_pager(int art, t_bool ignore_unavail);
63 static int enter_thread(int depth, t_pagerinfo *page);
64 static int find_new_pos(long old_artnum, int cur_pos);
65 static int group_catchup(t_function func);
66 static int tab_pressed(void);
67 static t_bool prompt_getart_limit(void);
68 static t_function group_left(void);
69 static t_function group_right(void);
70 static void build_sline(int i);
71 static void build_multipart_header(char *dest, int maxlen, const char *src, int cmplen, int have, int total);
72 static void draw_subject_arrow(void);
73 static void show_group_title(t_bool clear_title);
74 static void show_tagged_lines(void);
75 static void toggle_read_unread(t_bool force);
76 static void update_group_page(void);
77 
78 /*
79  * grpmenu.curr is an index into base[] and so equates to the cursor location
80  * (thread number) on group page
81  * grpmenu.first is static here
82  */
84 
85 /* TODO: find a better solution */
86 static int ret_code = 0; /* Set to < 0 when it is time to leave the group level */
87 
88 static void
90  void)
91 {
92  int i, j;
93 
94  for (i = grpmenu.first; i < grpmenu.first + NOTESLINES && i < grpmenu.max; ++i) {
95  if ((i != grpmenu.curr) && (j = line_is_tagged(base[i])))
96  mark_screen(i, mark_offset - 2, tin_ltoa(j, 3));
97  }
98 }
99 
100 
101 static t_function
103  void)
104 {
106  return SPECIAL_CATCHUP_LEFT; /* ie, not via 'c' or 'C' */
107 
108  return GLOBAL_QUIT;
109 }
110 
111 
112 static t_function
114  void)
115 {
116  if (grpmenu.curr >= 0 && HAS_FOLLOWUPS(grpmenu.curr)) {
118  return GROUP_LIST_THREAD;
119  else {
120  int n = next_unread((int) base[grpmenu.curr]);
121 
122  if (n >= 0 && grpmenu.curr == which_thread(n)) {
123  ret_code = enter_pager(n, TRUE);
124  return GLOBAL_ABORT; /* TODO: should we return something else? */
125  }
126  }
127  }
128  return GROUP_READ_BASENOTE;
129 }
130 
131 
132 /*
133  * Return Codes:
134  * GRP_EXIT 'Normal' return to selection menu
135  * GRP_RETSELECT We are en route from pager to the selection screen
136  * GRP_QUIT User has done a 'Q'
137  * GRP_NEXT User wants to move onto next group
138  * GRP_NEXTUNREAD User did a 'C'atchup
139  * GRP_ENTER 'g' command has been used to set group to enter
140  */
141 int
143  struct t_group *group)
144 {
145  char key[MAXKEYLEN];
146  int i, n, ii;
147  int thread_depth; /* Starting depth in threads we enter */
148  t_artnum old_artnum = T_ARTNUM_CONST(0);
149  struct t_art_stat sbuf;
150  struct t_article *art;
151  t_bool flag;
152  t_bool xflag = FALSE; /* 'X'-flag */
153  t_bool repeat_search;
154  t_function func;
155 
156  /*
157  * Set the group attributes
158  */
159  group->read_during_session = TRUE;
160 
161  curr_group = group; /* For global access to the current group */
162  num_of_tagged_arts = 0;
164 
165  last_resp = -1;
166  this_resp = -1;
167 
168  /*
169  * update index file. quit group level if user aborts indexing
170  */
171  if (!index_group(group)) {
172  for_each_art(i) {
173  art = &arts[i];
174  FreeAndNull(art->refs);
175  FreeAndNull(art->msgid);
176  }
177  curr_group = NULL;
178  tin_errno = 0;
179  return GRP_RETSELECT;
180  }
181 
182  /*
183  * Position 'grpmenu.curr' accordingly
184  */
186  /* reset grpmenu.first */
187  grpmenu.first = 0;
188 
189  clear_note_area();
190 
191  if (group->attribute->auto_select) {
193  do_auto_select_arts(); /* 'X' command */
194  xflag = TRUE;
195  }
196 
197  show_group_page();
198 
199 # ifdef DEBUG
200  if (debug & DEBUG_NEWSRC)
201  debug_print_bitmap(group, NULL);
202 # endif /* DEBUG */
203 
204  /* reset ret_code */
205  ret_code = 0;
206  while (ret_code >= 0) {
207  set_xclick_on();
209  func = last_search;
210  repeat_search = TRUE;
211  } else
212  repeat_search = FALSE;
213 
214  switch (func) {
215  case GLOBAL_ABORT:
216  break;
217 
218  case DIGIT_1:
219  case DIGIT_2:
220  case DIGIT_3:
221  case DIGIT_4:
222  case DIGIT_5:
223  case DIGIT_6:
224  case DIGIT_7:
225  case DIGIT_8:
226  case DIGIT_9:
227  if (grpmenu.max)
229  break;
230 
231 # ifndef NO_SHELL_ESCAPE
232  case GLOBAL_SHELL_ESCAPE:
233  do_shell_escape();
234  break;
235 # endif /* !NO_SHELL_ESCAPE */
236 
237  case GLOBAL_FIRST_PAGE: /* show first page of threads */
238  top_of_list();
239  break;
240 
241  case GLOBAL_LAST_PAGE: /* show last page of threads */
242  end_of_list();
243  break;
244 
245  case GLOBAL_LAST_VIEWED: /* go to last viewed article */
246  /*
247  * If the last art is no longer in a thread then we can't display it
248  */
249  if (this_resp < 0 || (which_thread(this_resp) == -1))
251  else
253  break;
254 
255  case GLOBAL_PIPE: /* pipe article/thread/tagged arts to command */
256  if (grpmenu.curr >= 0)
258  break;
259 
260  case GROUP_MAIL: /* mail article to somebody */
261  if (grpmenu.curr >= 0)
263  break;
264 
265 #ifndef DISABLE_PRINTING
266  case GLOBAL_PRINT: /* output art/thread/tagged arts to printer */
267  if (grpmenu.curr >= 0)
269  break;
270 #endif /* !DISABLE_PRINTING */
271 
272  case GROUP_REPOST: /* repost current article */
273  if (can_post) {
274  if (grpmenu.curr >= 0)
276  } else
278  break;
279 
280  case GROUP_SAVE: /* save articles with prompting */
281  if (grpmenu.curr >= 0)
283  break;
284 
285  case GROUP_AUTOSAVE: /* Auto-save articles without prompting */
286  if (grpmenu.curr >= 0)
288  break;
289 
290  case GLOBAL_SET_RANGE: /* set range */
291  if (grpmenu.curr >= 0 && set_range(GROUP_LEVEL, 1, grpmenu.max, grpmenu.curr + 1)) {
292  range_active = TRUE;
293  show_group_page();
294  }
295  break;
296 
299  break;
300 
305  if ((thread_depth = do_search(func, repeat_search)) != 0)
306  ret_code = enter_thread(thread_depth, NULL);
307  break;
308 
309  case GLOBAL_SEARCH_BODY: /* search article body */
310  if (grpmenu.curr >= 0) {
311  if ((n = search_body(group, (int) base[grpmenu.curr], repeat_search)) != -1)
312  ret_code = enter_pager(n, FALSE);
313  } else
315  break;
316 
317  case GROUP_READ_BASENOTE: /* read current basenote */
318  if (grpmenu.curr >= 0)
319  ret_code = enter_pager((int) base[grpmenu.curr], FALSE /*TRUE*/);
320  else
322  break;
323 
324  case GROUP_CANCEL: /* cancel current basenote */
325  if (grpmenu.curr >= 0) {
326  if (can_post || group->attribute->mailing_list != NULL) {
327  int ret;
328 
329  n = (int) base[grpmenu.curr];
330  ret = art_open(TRUE, &arts[n], group, &pgart, TRUE, _(txt_reading_article));
331  if (ret != ART_UNAVAILABLE && ret != ART_ABORT && cancel_article(group, &arts[n], n))
332  show_group_page();
333  art_close(&pgart);
334  } else
336  } else
338  break;
339 
340  case GROUP_NEXT_UNREAD_ARTICLE_OR_GROUP: /* goto next unread article/group */
341  ret_code = tab_pressed();
342  break;
343 
344  case GLOBAL_PAGE_DOWN:
345  page_down();
346  break;
347 
348  case GLOBAL_MENU_FILTER_SELECT: /* auto-select article menu */
349  case GLOBAL_MENU_FILTER_KILL: /* kill article menu */
350  if (grpmenu.curr < 0) {
352  break;
353  }
354  n = (int) base[grpmenu.curr];
355  if (filter_menu(func, group, &arts[n])) {
356  old_artnum = arts[n].artnum;
357  unfilter_articles(group);
358  filter_articles(group);
359  make_threads(group, FALSE);
360  grpmenu.curr = find_new_pos(old_artnum, grpmenu.curr);
361  }
362  show_group_page();
363  break;
364 
365  case GLOBAL_EDIT_FILTER:
367  old_artnum = grpmenu.max > 0 ? arts[(int) base[grpmenu.curr]].artnum : T_ARTNUM_CONST(-1);
368  unfilter_articles(group);
370  filter_articles(group);
371  make_threads(group, FALSE);
372  grpmenu.curr = old_artnum >= T_ARTNUM_CONST(0) ? find_new_pos(old_artnum, grpmenu.curr) : grpmenu.max - 1;
373  }
374  show_group_page();
375  break;
376 
377  case GLOBAL_QUICK_FILTER_SELECT: /* quickly auto-select article */
378  case GLOBAL_QUICK_FILTER_KILL: /* quickly kill article */
379  if (grpmenu.curr < 0) {
381  break;
382  }
384  n = (int) base[grpmenu.curr]; /* should this depend on show_only_unread_arts? */
385  if (quick_filter(func, group, &arts[n])) {
386  old_artnum = arts[n].artnum;
387  unfilter_articles(group);
388  filter_articles(group);
389  make_threads(group, FALSE);
390  grpmenu.curr = find_new_pos(old_artnum, grpmenu.curr);
391  show_group_page();
393  }
394  }
395  break;
396 
398  my_retouch();
399  set_xclick_off();
400  show_group_page();
401  break;
402 
403  case GLOBAL_LINE_DOWN:
404  move_down();
405  break;
406 
407  case GLOBAL_LINE_UP:
408  move_up();
409  break;
410 
411  case GLOBAL_PAGE_UP:
412  page_up();
413  break;
414 
415  case GLOBAL_SCROLL_DOWN:
416  scroll_down();
417  break;
418 
419  case GLOBAL_SCROLL_UP:
420  scroll_up();
421  break;
422 
424  case CATCHUP:
425  case CATCHUP_NEXT_UNREAD:
426  ret_code = group_catchup(func);
427  break;
428 
429  case GROUP_TOGGLE_SUBJECT_DISPLAY: /* toggle display of subject & subj/author */
432  show_group_page();
433  break;
434 
435  case GROUP_GOTO: /* choose a new group by name */
436  n = choose_new_group();
437  if (n >= 0 && n != selmenu.curr) {
438  selmenu.curr = n;
440  }
441  break;
442 
443  case GLOBAL_HELP:
445  show_group_page();
446  break;
447 
448  case GLOBAL_TOGGLE_HELP_DISPLAY: /* toggle mini help menu */
450  show_group_page();
451  break;
452 
453  case GLOBAL_TOGGLE_INVERSE_VIDEO: /* toggle inverse video */
455  show_group_page();
457  break;
458 
459 # ifdef HAVE_COLOR
460  case GLOBAL_TOGGLE_COLOR:
461  if (toggle_color()) {
462  show_group_page();
463  show_color_status();
464  }
465  break;
466 # endif /* HAVE_COLOR */
467 
468  case GROUP_MARK_THREAD_READ: /* mark current thread/range/tagged threads as read */
469  case MARK_THREAD_UNREAD: /* or unread */
470  if (grpmenu.curr < 0)
472  else {
473  t_function function, type;
474 
477  feed_articles(function, GROUP_LEVEL, type, group, (int) base[grpmenu.curr]);
478  }
479  break;
480 
481  case GROUP_LIST_THREAD: /* list articles within current thread */
482  ret_code = enter_thread(0, NULL); /* Enter thread at the top */
483  break;
484 
486  if ((i = prompt_msgid()) != ART_UNAVAILABLE)
487  ret_code = enter_pager(i, FALSE);
488  break;
489 
490  case GLOBAL_OPTION_MENU: /* option menu */
491  old_artnum = grpmenu.max > 0 ? arts[(int) base[grpmenu.curr]].artnum : T_ARTNUM_CONST(-1);
493  grpmenu.curr = old_artnum >= T_ARTNUM_CONST(0) ? find_new_pos(old_artnum, grpmenu.curr) : grpmenu.max - 1;
494  show_group_page();
495  break;
496 
497  case GROUP_NEXT_GROUP: /* goto next group */
498  clear_message();
499  if (selmenu.curr + 1 >= selmenu.max)
501  else {
504  xflag = FALSE;
505  }
506  selmenu.curr++;
508  }
509  break;
510 
511  case GROUP_NEXT_UNREAD_ARTICLE: /* goto next unread article */
512  if (grpmenu.curr < 0) {
514  break;
515  }
516  if ((n = next_unread((int) base[grpmenu.curr])) == -1)
518  else
519  ret_code = enter_pager(n, FALSE);
520  break;
521 
522  case GROUP_PREVIOUS_UNREAD_ARTICLE: /* go to previous unread article */
523  if (grpmenu.curr < 0) {
525  break;
526  }
527 
528  if ((n = prev_unread(prev_response((int) base[grpmenu.curr]))) == -1)
530  else
531  ret_code = enter_pager(n, FALSE);
532  break;
533 
534  case GROUP_PREVIOUS_GROUP: /* previous group */
535  clear_message();
536  for (i = selmenu.curr - 1; i >= 0; i--) {
537  if (UNREAD_GROUP(i))
538  break;
539  }
540  if (i < 0)
542  else {
545  xflag = FALSE;
546  }
547  selmenu.curr = i;
549  }
550  break;
551 
552  case GLOBAL_QUIT: /* return to group selection page */
554  break;
557  xflag = FALSE;
558  }
559  ret_code = GRP_EXIT;
560  break;
561 
562  case GLOBAL_QUIT_TIN: /* quit */
564  break;
567  xflag = FALSE;
568  }
569  ret_code = GRP_QUIT;
570  break;
571 
574  show_group_page();
575  break;
576 
578  if (prompt_getart_limit()) {
579  /*
580  * if getart limit was given via cmd-line
581  * make it inactive now in order to use
582  * tinrc.getart_limit
583  */
587  }
588  break;
589 
590  case GLOBAL_BUGREPORT:
591  bug_report();
592  break;
593 
594  case GROUP_TAG_PARTS: /* tag all in order */
595  if (0 <= grpmenu.curr) {
596  if (tag_multipart(grpmenu.curr) != 0) {
597  /*
598  * on success, move the pointer to the next
599  * untagged article just for ease of use's sake
600  */
601  n = grpmenu.curr;
603  do {
604  n++;
605  n %= grpmenu.max;
606  if (arts[base[n]].tagged == 0) {
607  move_to_item(n);
608  break;
609  }
610  } while (n != grpmenu.curr);
612  }
613  }
614  break;
615 
616  case GROUP_TAG: /* tag/untag threads for mailing/piping/printing/saving */
617  if (grpmenu.curr >= 0) {
618  t_bool tagged = TRUE;
619 
620  n = (int) base[grpmenu.curr];
621 
622  /*
623  * This loop looks for any article in the thread that
624  * isn't already tagged.
625  */
626  for (ii = n; ii != -1; ii = arts[ii].thread) {
627  if (arts[ii].tagged == 0) {
628  tagged = FALSE;
629  break;
630  }
631  }
632 
633  /*
634  * If the whole thread is tagged, untag it. Otherwise, tag
635  * any untagged articles
636  */
637  if (tagged) {
638  /*
639  * Here we repeat the tagged test in both blocks
640  * to leave the choice of tagged/untagged
641  * determination politic in the previous lines.
642  */
643  for (ii = n; ii != -1; ii = arts[ii].thread) {
644  if (arts[ii].tagged != 0) {
645  tagged = TRUE;
646  untag_article(ii);
647  }
648  }
649  } else {
650  for (ii = n; ii != -1; ii = arts[ii].thread) {
651  if (arts[ii].tagged == 0)
653  }
654  }
655  if ((ii = line_is_tagged(n)))
657  else {
658  char mark[] = { '\0', '\0' };
659 
660  stat_thread(grpmenu.curr, &sbuf);
661  mark[0] = sbuf.art_mark;
662  mark_screen(grpmenu.curr, mark_offset - 2, " "); /* clear space used by tag numbering */
664  }
665  if (tagged)
667 
668  if (grpmenu.curr + 1 < grpmenu.max)
669  move_down();
670  else
672 
674 
675  }
676  break;
677 
678  case GROUP_TOGGLE_THREADING: /* Cycle through the threading types */
679  group->attribute->thread_articles = (group->attribute->thread_articles + 1) % (THREAD_MAX + 1);
680  if (grpmenu.curr >= 0) {
681  i = base[grpmenu.curr]; /* Save a copy of current thread */
682  make_threads(group, TRUE);
683  find_base(group);
684  if ((grpmenu.curr = which_thread(i)) < 0) /* Restore current position in group */
685  grpmenu.curr = 0;
686  }
687  show_group_page();
688  break;
689 
690  case GROUP_UNTAG: /* untag all articles */
691  if (grpmenu.curr >= 0) {
692  if (untag_all_articles())
694  }
695  break;
696 
697  case GLOBAL_VERSION:
699  break;
700 
701  case GLOBAL_POST: /* post an article */
702  if (post_article(group->name))
703  show_group_page();
704  break;
705 
706  case GLOBAL_POSTPONED: /* post postponed article */
707  if (can_post) {
709  show_group_page();
710  } else
712  break;
713 
714  case GLOBAL_DISPLAY_POST_HISTORY: /* display messages posted by user */
715  if (user_posted_messages())
716  show_group_page();
717  break;
718 
719  case MARK_ARTICLE_UNREAD: /* mark base article of thread unread */
720  if (grpmenu.curr < 0)
722  else {
723  const char *ptr;
724 
725  if (range_active) {
726  /*
727  * We are tied to following base[] here, not arts[], as we operate on
728  * the base articles by definition.
729  */
730  for (ii = 0; ii < grpmenu.max; ++ii) {
731  if (arts[base[ii]].inrange) {
732  arts[base[ii]].inrange = FALSE;
733  art_mark(group, &arts[base[ii]], ART_WILL_RETURN);
735  arts[i].inrange = FALSE;
736  }
737  }
739  show_group_page();
740  ptr = _(txt_base_article_range);
741  } else {
743  ptr = _(txt_base_article);
744  }
745 
750  }
751  break;
752 
753  case MARK_FEED_READ: /* mark selected articles as read */
754  if (grpmenu.curr >= 0)
756  break;
757 
758  case MARK_FEED_UNREAD: /* mark selected articles as unread */
759  if (grpmenu.curr >= 0)
761  break;
762 
763  case GROUP_SELECT_THREAD: /* mark thread as selected */
764  case GROUP_TOGGLE_SELECT_THREAD: /* toggle thread */
765  if (grpmenu.curr < 0) {
767  break;
768  }
769 
770  flag = TRUE;
771  if (func == GROUP_TOGGLE_SELECT_THREAD) {
772  stat_thread(grpmenu.curr, &sbuf);
773  if (sbuf.selected_unread == sbuf.unread)
774  flag = FALSE;
775  }
776  n = 0;
778  arts[i].selected = flag;
779  ++n;
780  }
781  assert(n > 0);
782  {
783  char mark[] = { '\0', '\0' };
784 
785  stat_thread(grpmenu.curr, &sbuf);
786  mark[0] = sbuf.art_mark;
788  }
789 
791 
792  if (grpmenu.curr + 1 < grpmenu.max)
793  move_down();
794  else
796 
798  break;
799 
800  case GROUP_REVERSE_SELECTIONS: /* reverse selections */
801  for_each_art(i)
805  break;
806 
807  case GROUP_UNDO_SELECTIONS: /* undo selections */
808  undo_selections();
809  xflag = FALSE;
812  break;
813 
814  case GROUP_SELECT_PATTERN: /* select matching patterns */
815  if (grpmenu.curr >= 0) {
816  char pat[128];
817  char *prompt;
818  struct regex_cache cache = { NULL, NULL };
819 
822  free(prompt);
823  break;
824  }
825  free(prompt);
826 
827  if (STRCMPEQ(tinrc.default_select_pattern, "*")) { /* all */
828  if (tinrc.wildcard)
829  STRCPY(pat, ".*");
830  else
832  } else
833  snprintf(pat, sizeof(pat), REGEX_FMT, tinrc.default_select_pattern);
834 
835  if (tinrc.wildcard && !(compile_regex(pat, &cache, PCRE_CASELESS)))
836  break;
837 
838  flag = FALSE;
839  for (n = 0; n < grpmenu.max; n++) {
840  if (!match_regex(arts[base[n]].subject, pat, &cache, TRUE))
841  continue;
842 
844  arts[i].selected = TRUE;
845 
846  flag = TRUE;
847  }
848  if (flag) {
851  }
852  if (tinrc.wildcard) {
853  FreeIfNeeded(cache.re);
854  FreeIfNeeded(cache.extra);
855  }
856  }
857  break;
858 
859  case GROUP_SELECT_THREAD_IF_UNREAD_SELECTED: /* select all unread arts in thread hot if 1 is hot */
860  for (n = 0; n < grpmenu.max; n++) {
861  stat_thread(n, &sbuf);
862  if (!sbuf.selected_unread || sbuf.selected_unread == sbuf.unread)
863  continue;
864 
866  arts[i].selected = TRUE;
867  }
869  break;
870 
871  case GROUP_MARK_UNSELECTED_ARTICLES_READ: /* mark read all unselected arts */
872  if (!xflag) {
874  xflag = TRUE;
875  } else {
877  xflag = FALSE;
878  }
879  break;
880 
881  case GROUP_DO_AUTOSELECT: /* perform auto-selection on group */
882  for (n = 0; n < grpmenu.max; n++) {
884  arts[i].selected = TRUE;
885  }
888  break;
889 
892  show_group_page();
893  break;
894 
895  default:
897  break;
898  } /* switch(ch) */
899  } /* ret_code >= 0 */
900 
901  set_xclick_off();
902 
903  clear_note_area();
904  grp_del_mail_arts(group);
905 
906  art_close(&pgart); /* Close any open art */
907 
908  curr_group = NULL;
909 
910  return ret_code;
911 }
912 
913 
914 void
916  void)
917 {
918  int i;
919 
921  currmenu = &grpmenu;
922 
923  ClearScreen();
926  mark_offset = 0;
928 
929  for (i = grpmenu.first; i < grpmenu.first + NOTESLINES && i < grpmenu.max; ++i)
930  build_sline(i);
931 
933 
934  if (grpmenu.max <= 0) {
936  return;
937  }
938 
940 }
941 
942 
943 static void
945  void)
946 {
947  int i, j;
948  char mark[] = { '\0', '\0' };
949  struct t_art_stat sbuf;
950 
951  for (i = grpmenu.first; i < grpmenu.first + NOTESLINES && i < grpmenu.max; ++i) {
952  if ((j = line_is_tagged(base[i])))
953  mark_screen(i, mark_offset - 2, tin_ltoa(j, 3));
954  else {
955  stat_thread(i, &sbuf);
956  mark[0] = sbuf.art_mark;
957  mark_screen(i, mark_offset - 2, " "); /* clear space used by tag numbering */
958  mark_screen(i, mark_offset, mark);
959  if (sbuf.art_mark == tinrc.art_marked_selected)
961  }
962  }
963 
964  if (grpmenu.max <= 0)
965  return;
966 
968 }
969 
970 
971 static void
973  void)
974 {
976 
977  if (tinrc.info_in_last_line) {
978  struct t_art_stat statbuf;
979 
980  stat_thread(grpmenu.curr, &statbuf);
982  } else if (grpmenu.curr == grpmenu.max - 1)
984 }
985 
986 
987 void
989  void)
990 {
991  MoveCursor(INDEX_TOP, 0);
992  CleartoEOS();
993 }
994 
995 
996 /*
997  * If in show_only_unread_arts mode or there are unread articles we know this
998  * thread will exist after toggle. Otherwise we find the next closest to
999  * return to. 'force' can be set to force tin to show all messages
1000  */
1001 static void
1003  t_bool force)
1004 {
1005  int n, i = -1;
1006 
1007  /*
1008  * Clear art->keep_in_base if switching to !show_only_unread_arts
1009  */
1011  for_each_art(n)
1012  arts[n].keep_in_base = FALSE;
1013  }
1014 
1015  /* force currently is always false */
1016  if (force)
1017  curr_group->attribute->show_only_unread_arts = TRUE; /* Yes - really, we change it in a bit */
1018 
1021 
1022  if (grpmenu.curr >= 0) {
1024  i = base[grpmenu.curr];
1025  else if ((n = prev_unread((int) base[grpmenu.curr])) >= 0)
1026  i = n;
1027  else if ((n = next_unread((int) base[grpmenu.curr])) >= 0)
1028  i = n;
1029  }
1030 
1031  if (!force)
1033 
1035  if (i >= 0 && (n = which_thread(i)) >= 0)
1036  grpmenu.curr = n;
1037  else if (grpmenu.max > 0)
1038  grpmenu.curr = grpmenu.max - 1;
1039  clear_message();
1040 }
1041 
1042 
1043 /*
1044  * Find new index position after a kill or unkill. Because kill can work on
1045  * author it is impossible to know which, if any, articles will be left
1046  * afterwards. So we make a "best attempt" to find a new index point.
1047  */
1048 static int
1050  long old_artnum,
1051  int cur_pos)
1052 {
1053  int i, pos;
1054 
1055  if ((i = find_artnum(old_artnum)) >= 0 && (pos = which_thread(i)) >= 0)
1056  return pos;
1057 
1058  return ((cur_pos < grpmenu.max) ? cur_pos : (grpmenu.max - 1));
1059 }
1060 
1061 
1062 /*
1063  * Set grpmenu.curr to the first unread or the last thread depending on
1064  * the value of pos_first_unread
1065  */
1066 void
1068  void)
1069 {
1070  int i;
1071 
1073  for (i = 0; i < grpmenu.max; i++) {
1074  if (new_responses(i))
1075  break;
1076  }
1077  grpmenu.curr = ((i < grpmenu.max) ? i : (grpmenu.max - 1));
1078  } else
1079  grpmenu.curr = grpmenu.max - 1;
1080 }
1081 
1082 
1083 void
1085  int screen_row,
1086  int screen_col,
1087  const char *value)
1088 {
1089  if (tinrc.draw_arrow) {
1090  MoveCursor(INDEX2LNUM(screen_row), screen_col);
1091  my_fputs(value, stdout);
1092  stow_cursor();
1093  my_flush();
1094  } else {
1095 #ifdef USE_CURSES
1096  int y, x;
1097  getyx(stdscr, y, x);
1098  mvaddstr(INDEX2LNUM(screen_row), screen_col, value);
1099  MoveCursor(y, x);
1100 #else
1101  int i;
1102  for (i = 0; value[i] != '\0'; i++)
1103  screen[INDEX2SNUM(screen_row)].col[screen_col + i] = value[i];
1104  MoveCursor(INDEX2LNUM(screen_row), screen_col);
1105  my_fputs(value, stdout);
1106 #endif /* USE_CURSES */
1107  currmenu->draw_arrow();
1108  }
1109 }
1110 
1111 
1112 /*
1113  * Builds the correct header for multipart messages when sorting via
1114  * THREAD_MULTI.
1115  */
1116 static void
1118  char *dest,
1119  int maxlen,
1120  const char *src,
1121  int cmplen,
1122  int have,
1123  int total)
1124 {
1125  const char *mark = (have == total) ? "*" : "-";
1126  char *ss;
1127 
1128  if (cmplen > maxlen)
1129  strncpy(dest, src, maxlen);
1130  else {
1131  strncpy(dest, src, cmplen);
1132  ss = dest + cmplen;
1133  snprintf(ss, maxlen - cmplen, "(%s/%d)", mark, total);
1134  }
1135 }
1136 
1137 
1138 /*
1139  * Build subject line given an index into base[].
1140  *
1141  * WARNING: some other code expects to find the article mark (ART_MARK_READ,
1142  * ART_MARK_SELECTED, etc) at mark_offset from beginning of the line.
1143  * So, if you change the format used in this routine, be sure to check that
1144  * the value of mark_offset is still correct.
1145  * Yes, this is somewhat kludgy.
1146  */
1147 static void
1149  int i)
1150 {
1151  char *fmt, *buf;
1152  char *buffer;
1153  char arts_sub[HEADER_LEN];
1154  char tmp_buf[8];
1155  char tmp[LEN];
1156  int respnum;
1157  int j, k, n;
1158  size_t len;
1159  struct t_art_stat sbuf;
1160 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1161  wchar_t *wtmp, *wtmp2;
1162 #else
1163  int fill, gap;
1164  size_t len_start;
1165 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1166 
1167 #ifdef USE_CURSES
1168  /*
1169  * Allocate line buffer
1170  * make it the same size like in !USE_CURSES case to simplify the code
1171  */
1172 # if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1173  buffer = my_malloc(cCOLS * MB_CUR_MAX + 2);
1174 # else
1175  buffer = my_malloc(cCOLS + 2);
1176 # endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1177 #else
1178  buffer = screen[INDEX2SNUM(i)].col;
1179 #endif /* USE_CURSES */
1180 
1181  buffer[0] = '\0';
1182 
1183  respnum = (int) base[i];
1184 
1185  stat_thread(i, &sbuf);
1186 
1187  /*
1188  * Find index of first unread in this thread
1189  */
1190  j = (sbuf.unread) ? next_unread(respnum) : respnum;
1191 
1192  fmt = grp_fmt.str;
1193 
1194  if (tinrc.draw_arrow)
1195  strcat(buffer, " ");
1196 
1197  for (; *fmt; fmt++) {
1198  if (*fmt != '%') {
1199  strncat(buffer, fmt, 1);
1200  continue;
1201  }
1202  switch (*++fmt) {
1203  case '\0':
1204  break;
1205 
1206  case '%':
1207  strncat(buffer, fmt, 1);
1208  break;
1209 
1210  case 'D': /* date */
1211  buf = my_malloc(LEN);
1212  if (my_strftime(buf, LEN - 1, grp_fmt.date_str, localtime((const time_t *) &arts[j].date))) {
1213 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1214  if ((wtmp = char2wchar_t(buf)) != NULL) {
1215  wtmp2 = wcspart(wtmp, grp_fmt.len_date_max, TRUE);
1216  if (wcstombs(tmp, wtmp2, sizeof(tmp) - 1) != (size_t) -1)
1217  strcat(buffer, tmp);
1218 
1219  free(wtmp);
1220  free(wtmp2);
1221  }
1222 #else
1223  strncat(buffer, buf, grp_fmt.len_date_max);
1224 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1225  }
1226  free(buf);
1227  break;
1228 
1229  case 'F': /* from */
1231 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1232  get_author(FALSE, &arts[j], tmp, sizeof(tmp) - 1);
1233 
1234  if ((wtmp = char2wchar_t(tmp)) != NULL) {
1235  wtmp2 = wcspart(wtmp, grp_fmt.len_from, TRUE);
1236  if (wcstombs(tmp, wtmp2, sizeof(tmp) - 1) != (size_t) -1)
1237  strcat(buffer, tmp);
1238 
1239  free(wtmp);
1240  free(wtmp2);
1241  }
1242 #else
1243  len_start = strwidth(buffer);
1244  get_author(FALSE, &arts[j], buffer + strlen(buffer), grp_fmt.len_from);
1245  fill = grp_fmt.len_from - (strwidth(buffer) - len_start);
1246  gap = strlen(buffer);
1247  for (k = 0; k < fill; k++)
1248  buffer[gap + k] = ' ';
1249  buffer[gap + fill] = '\0';
1250 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1251  }
1252  break;
1253 
1254  case 'I': /* initials */
1255  len = MIN(grp_fmt.len_initials, sizeof(tmp) - 1);
1256  get_initials(&arts[j], tmp, len);
1257  strcat(buffer, tmp);
1258  if ((k = len - strwidth(tmp)) > 0) {
1259  buf = buffer + strlen(buffer);
1260  for (; k > 0; --k)
1261  *buf++ = ' ';
1262  *buf = '\0';
1263  }
1264  break;
1265 
1266  case 'L': /* lines */
1267  if (arts[j].line_count != -1)
1268  strcat(buffer, tin_ltoa(arts[j].line_count, grp_fmt.len_linecnt));
1269  else {
1270  buf = buffer + strlen(buffer);
1271  for (k = grp_fmt.len_linecnt; k > 1; --k)
1272  *buf++ = ' ';
1273  *buf++ = '?';
1274  *buf = '\0';
1275  }
1276  break;
1277 
1278  case 'm': /* article flags, tag number, or whatever */
1279  if (!grp_fmt.mark_offset)
1281  if ((k = line_is_tagged(respnum)))
1282  STRCPY(tmp_buf, tin_ltoa(k, 3));
1283  else
1284  snprintf(tmp_buf, sizeof(tmp_buf), " %c", sbuf.art_mark);
1285  strcat(buffer, tmp_buf);
1286  break;
1287 
1288  case 'M': /* message-id */
1289  len = MIN(grp_fmt.len_msgid, sizeof(tmp) - 1);
1290  strncpy(tmp, arts[j].refptr ? arts[j].refptr->txt : "", len);
1291  tmp[len] = '\0';
1292  strcat(buffer, tmp);
1293  if ((k = len - strwidth(tmp)) > 0) {
1294  buf = buffer + strlen(buffer);
1295  for (; k > 0; --k)
1296  *buf++ = ' ';
1297  *buf = '\0';
1298  }
1299  break;
1300 
1301  case 'n':
1302  strcat(buffer, tin_ltoa(i + 1, grp_fmt.len_linenumber));
1303  break;
1304 
1305  case 'R':
1306  n = ((curr_group->attribute->show_only_unread_arts) ? (sbuf.unread + sbuf.seen) : sbuf.total);
1307  if (n > 1)
1308  strcat(buffer, tin_ltoa(n, grp_fmt.len_respcnt));
1309  else {
1310  buf = buffer + strlen(buffer);
1311  for (k = grp_fmt.len_respcnt; k > 0; --k)
1312  *buf++ = ' ';
1313  *buf = '\0';
1314  }
1315  break;
1316 
1317  case 'S': /* score */
1318  strcat(buffer, tin_ltoa(sbuf.score, grp_fmt.len_score));
1319  break;
1320 
1321  case 's': /* thread/subject */
1323 
1324  if (sbuf.multipart_have > 1) /* We have a multipart msg so lets built our new header info. */
1325  build_multipart_header(arts_sub, len, arts[j].subject, sbuf.multipart_compare_len, sbuf.multipart_have, sbuf.multipart_total);
1326  else
1327  STRCPY(arts_sub, arts[j].subject);
1328 
1329 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1330  if ((wtmp = char2wchar_t(arts_sub)) != NULL) {
1331  wtmp2 = wcspart(wtmp, len, TRUE);
1332  if (wcstombs(tmp, wtmp2, sizeof(tmp) - 1) != (size_t) -1)
1333  strcat(buffer, tmp);
1334 
1335  free(wtmp);
1336  free(wtmp2);
1337  }
1338 #else
1339  len_start = strwidth(buffer);
1340  strncat(buffer, arts_sub, len);
1341  fill = len - (strwidth(buffer) - len_start);
1342  gap = strlen(buffer);
1343  for (k = 0; k < fill; k++)
1344  buffer[gap + k] = ' ';
1345  buffer[gap + fill] = '\0';
1346 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1347  break;
1348 
1349  default:
1350  break;
1351  }
1352  }
1353  /* protect display from non-displayable characters (e.g., form-feed) */
1355 
1356 #ifndef USE_CURSES
1357  if (tinrc.strip_blanks)
1358  strcat(strip_line(buffer), cCRLF);
1359 #endif /* !USE_CURSES */
1360 
1362 
1363 #ifdef USE_CURSES
1364  free(buffer);
1365 #endif /* USE_CURSES */
1366  if (sbuf.art_mark == tinrc.art_marked_selected)
1367  draw_mark_selected(i);
1368 }
1369 
1370 
1371 static void
1373  t_bool clear_title)
1374 {
1375  char buf[LEN], tmp[LEN], flag;
1376  int i, art_cnt = 0, recent_art_cnt = 0, selected_art_cnt = 0, read_selected_art_cnt = 0, killed_art_cnt = 0;
1377 
1378  for_each_art(i) {
1379  if (arts[i].thread == ART_EXPIRED)
1380  continue;
1381 
1383  if (arts[i].status != ART_READ) {
1384  art_cnt++;
1385  if (tinrc.recent_time && ((time((time_t *) 0) - arts[i].date) < (tinrc.recent_time * DAY)))
1386  recent_art_cnt++;
1387  }
1388  if (arts[i].killed == ART_KILLED_UNREAD)
1389  killed_art_cnt++;
1390  } else {
1391  art_cnt++;
1392  if (tinrc.recent_time && ((time((time_t *) 0) - arts[i].date) < (tinrc.recent_time * DAY)))
1393  recent_art_cnt++;
1394 
1395  if (arts[i].killed)
1396  killed_art_cnt++;
1397  }
1398  if (arts[i].selected) {
1399  if (arts[i].status != ART_READ)
1400  selected_art_cnt++;
1401  else
1402  read_selected_art_cnt++;
1403  }
1404  }
1405 
1406  /*
1407  * build the group title
1408  */
1409  /* group name and thread count */
1410  snprintf(buf, sizeof(buf), "%s (%d%c",
1413 
1414  /* article count */
1416  snprintf(tmp, sizeof(tmp), " %d/%d%c",
1419  else
1420  snprintf(tmp, sizeof(tmp), " %d%c",
1421  art_cnt,
1423  if (sizeof(buf) > strlen(buf) + strlen(tmp))
1424  strcat(buf, tmp);
1425 
1426  /* selected articles */
1428  snprintf(tmp, sizeof(tmp), " %d%c",
1429  selected_art_cnt, tinrc.art_marked_selected);
1430  else
1431  snprintf(tmp, sizeof(tmp), " %d%c %d%c",
1432  selected_art_cnt, tinrc.art_marked_selected,
1433  read_selected_art_cnt, tinrc.art_marked_read_selected);
1434  if (sizeof(buf) > strlen(buf) + strlen(tmp))
1435  strcat(buf, tmp);
1436 
1437  /* recent articles */
1438  if (tinrc.recent_time) {
1439  snprintf(tmp, sizeof(tmp), " %d%c",
1440  recent_art_cnt, tinrc.art_marked_recent);
1441 
1442  if (sizeof(buf) > strlen(buf) + strlen(tmp))
1443  strcat(buf, tmp);
1444  }
1445 
1446  /* killed articles */
1447  snprintf(tmp, sizeof(tmp), " %d%c",
1448  killed_art_cnt, tinrc.art_marked_killed);
1449  if (sizeof(buf) > strlen(buf) + strlen(tmp))
1450  strcat(buf, tmp);
1451 
1452  /* group flag */
1453  if ((flag = group_flag(curr_group->moderated)) == ' ')
1454  snprintf(tmp, sizeof(tmp), ")");
1455  else
1456  snprintf(tmp, sizeof(tmp), ") %c", flag);
1457  if (sizeof(buf) > strlen(buf) + strlen(tmp))
1458  strcat(buf, tmp);
1459 
1460  if (clear_title) {
1461  MoveCursor(0, 0);
1462  CleartoEOLN();
1463  }
1464  show_title(buf);
1465 }
1466 
1467 
1468 /*
1469  * Search for type SUBJ/AUTH in direction (TRUE = forwards)
1470  * Return 0 if all is done, or a >0 thread_depth to enter the thread menu
1471  */
1472 static int
1474  t_function func,
1475  t_bool repeat)
1476 {
1477  int start, n;
1478 
1479  if (grpmenu.curr < 0)
1480  return 0;
1481 
1482  /*
1483  * Not intuitive to search current thread in fwd search
1484  */
1485  start = ((func == GLOBAL_SEARCH_SUBJECT_FORWARD || func == GLOBAL_SEARCH_AUTHOR_FORWARD)
1486  && grpmenu.curr < grpmenu.max - 1) ? prev_response((int) base[grpmenu.curr + 1]) : (int) base[grpmenu.curr];
1487 
1488  if (start >= 0 && ((n = search(func, start, repeat)) != -1)) {
1489  grpmenu.curr = which_thread(n);
1490 
1491  /*
1492  * If the search found something deeper in a thread(not the base art)
1493  * then enter the thread
1494  */
1495  if ((n = which_response(n)) != 0)
1496  return n;
1497 
1498  show_group_page();
1499  }
1500  return 0;
1501 }
1502 
1503 
1504 /*
1505  * We don't directly invoke the pager, but pass through the thread menu
1506  * to keep navigation sane.
1507  * 'art' is the arts[art] we wish to read
1508  * ignore_unavail should be set if we wish to 'keep going' after 'article unavailable'
1509  * Return a -ve ret_code if we must exit the group menu on return
1510  */
1511 static int
1513  int art,
1514  t_bool ignore_unavail)
1515 {
1516  t_pagerinfo page;
1517 
1518  page.art = art;
1519  page.ignore_unavail = ignore_unavail;
1520 
1521  return enter_thread(0, &page);
1522 }
1523 
1524 
1525 /*
1526  * Handle entry/exit with the thread menu
1527  * Return -ve ret_code if we must exit the group menu on return
1528  */
1529 static int
1531  int depth,
1532  t_pagerinfo *page)
1533 {
1534  int i, n;
1535 
1536  if (grpmenu.curr < 0) {
1538  return 0;
1539  }
1540 
1541  forever {
1542  switch (i = thread_page(curr_group, (int) base[grpmenu.curr], depth, page)) {
1543  case GRP_QUIT: /* 'Q'uit */
1544  case GRP_RETSELECT: /* Back to selection screen */
1545  return i;
1546  /* NOTREACHED */
1547  break;
1548 
1549  case GRP_NEXT: /* 'c'atchup */
1550  show_group_page();
1551  move_down();
1552  return 0;
1553  /* NOTREACHED */
1554  break;
1555 
1556  case GRP_NEXTUNREAD: /* 'C'atchup */
1557  if ((n = next_unread((int) base[grpmenu.curr])) >= 0) {
1558  if (page)
1559  page->art = n;
1560  if ((n = which_thread(n)) >= 0) {
1561  grpmenu.curr = n;
1562  depth = 0;
1563  break; /* Drop into next thread with unread */
1564  }
1565  }
1566  /* No more unread threads in this group, enter next group */
1567  grpmenu.curr = 0;
1568  return GRP_NEXTUNREAD;
1569  /* NOTREACHED */
1570  break;
1571 
1572  case GRP_KILLED:
1573  grpmenu.curr = 0;
1574  /* FALLTHROUGH */
1575 
1576  case GRP_EXIT:
1577  /* case GRP_GOTOTHREAD will never make it up this far */
1578  default: /* ie >= 0 Shouldn't happen any more? */
1579  clear_note_area();
1580  show_group_page();
1581  return 0;
1582  /* NOTREACHED */
1583  break;
1584  }
1585  }
1586  /* NOTREACHED */
1587  return 0;
1588 }
1589 
1590 
1591 /*
1592  * Return a ret_code
1593  */
1594 static int
1596  void)
1597 {
1598  int n;
1599 
1600  if ((n = ((grpmenu.curr < 0) ? -1 : next_unread((int) base[grpmenu.curr]))) < 0)
1601  return GRP_NEXTUNREAD; /* => Enter next unread group */
1602 
1603  /* We still have unread arts in the current group ... */
1604  return enter_pager(n, TRUE);
1605 }
1606 
1607 
1608 /*
1609  * There are three ways this is called
1610  * catchup & return to group menu
1611  * catchup & go to next group with unread articles
1612  * group exit via left arrow if auto-catchup is set
1613  * Return a -ve ret_code if we're done with the group menu
1614  */
1615 static int
1617  t_function func)
1618 {
1619  char buf[LEN];
1620  int pyn = 1;
1621 
1623  return 0;
1624 
1626 
1627  if (!curr_group->newsrc.num_unread || (!TINRC_CONFIRM_ACTION) || (pyn = prompt_yn(buf, TRUE)) == 1)
1629 
1630  switch (func) {
1631  case CATCHUP: /* 'c' */
1632  if (pyn == 1)
1633  return GRP_NEXT;
1634  break;
1635 
1636  case CATCHUP_NEXT_UNREAD: /* 'C' */
1637  if (pyn == 1)
1638  return GRP_NEXTUNREAD;
1639  break;
1640 
1641  case SPECIAL_CATCHUP_LEFT: /* <- group catchup on exit */
1642  switch (pyn) {
1643  case -1: /* ESCAPE - do nothing */
1644  break;
1645 
1646  case 1: /* We caught up - advance group */
1647  return GRP_NEXT;
1648  /* NOTREACHED */
1649  break;
1650 
1651  default: /* Just leave the group */
1652  return GRP_EXIT;
1653  /* NOTREACHED */
1654  break;
1655  }
1656  /* FALLTHROUGH */
1657  default: /* Should not be here */
1658  break;
1659  }
1660  return 0; /* Stay in this menu by default */
1661 }
1662 
1663 
1664 static t_bool
1666  void)
1667 {
1668  char *p;
1669  t_bool ret = FALSE;
1670 
1671  clear_message();
1672  if ((p = tin_getline(_(txt_enter_getart_limit), 2, NULL, 0, FALSE, HIST_OTHER)) != NULL) {
1673  tinrc.getart_limit = atoi(p);
1674  ret = TRUE;
1675  }
1676  clear_message();
1677  return ret;
1678 }
1679 
1680 
1681 /*
1682  * Redraw all necessary parts of the screen after FEED_MARK_(UN)READ
1683  * Move cursor to next unread item if needed
1684  *
1685  * Returns TRUE when no next unread art, FALSE otherwise
1686  */
1687 t_bool
1689  int function,
1690  t_function feed_type,
1691  int respnum)
1692 {
1693  int n;
1694 
1696  switch (function) {
1697  case (FEED_MARK_READ):
1698  if (feed_type == FEED_THREAD || feed_type == FEED_ARTICLE)
1700  else
1701  show_group_page();
1702 
1703  if ((n = next_unread(next_response(respnum))) == -1) {
1705  return TRUE;
1706  }
1707 
1709  break;
1710 
1711  case (FEED_MARK_UNREAD):
1712  if (feed_type == FEED_THREAD || feed_type == FEED_ARTICLE)
1714  else
1715  show_group_page();
1716 
1718  break;
1719 
1720  default:
1721  break;
1722  }
1723  return FALSE;
1724 }
t_config::wildcard
int wildcard
Definition: tinrc.h:155
do_search
static int do_search(t_function func, t_bool repeat)
Definition: group.c:1473
tag_multipart
int tag_multipart(int base_index)
Definition: tags.c:210
GROUP_NEXT_UNREAD_ARTICLE
@ GROUP_NEXT_UNREAD_ARTICLE
Definition: keymap.h:241
t_article
Definition: tin.h:1510
show_group_title
static void show_group_title(t_bool clear_title)
Definition: group.c:1372
GROUP_PREVIOUS_GROUP
@ GROUP_PREVIOUS_GROUP
Definition: keymap.h:243
HIST_SELECT_PATTERN
@ HIST_SELECT_PATTERN
Definition: extern.h:1552
t_config::recent_time
int recent_time
Definition: tinrc.h:136
t_config::art_marked_killed
char art_marked_killed
Definition: tinrc.h:66
curr_group
struct t_group * curr_group
Definition: group.c:55
make_threads
void make_threads(struct t_group *group, t_bool rethread)
Definition: art.c:1194
txt_base_article
constext txt_base_article[]
Definition: lang.c:114
group_page
int group_page(struct t_group *group)
Definition: group.c:142
find_artnum
int find_artnum(t_artnum art)
Definition: art.c:3192
t_art_stat::multipart_have
int multipart_have
Definition: tin.h:1954
t_config::strip_blanks
t_bool strip_blanks
Definition: tinrc.h:239
GROUP_LEVEL
#define GROUP_LEVEL
Definition: tin.h:1102
GLOBAL_PAGE_DOWN
@ GLOBAL_PAGE_DOWN
Definition: keymap.h:200
_
#define _(Text)
Definition: tin.h:94
grp_del_mail_arts
void grp_del_mail_arts(struct t_group *group)
Definition: mail.c:604
GLOBAL_SHELL_ESCAPE
@ GLOBAL_SHELL_ESCAPE
Definition: keymap.h:223
txt_reading_article
constext txt_reading_article[]
Definition: lang.c:759
t_attribute::auto_select
unsigned auto_select
Definition: tin.h:1609
txt_prefix_tagged
constext txt_prefix_tagged[]
Definition: lang.c:732
FEED_PIPE
#define FEED_PIPE
Definition: tin.h:1115
build_sline
static void build_sline(int i)
Definition: group.c:1148
t_fmt::len_msgid
size_t len_msgid
Definition: tin.h:1822
INDEX_TOP
#define INDEX_TOP
Definition: tin.h:1008
txt_catchup_despite_tags
constext txt_catchup_despite_tags[]
Definition: lang.c:139
txt_no_prev_group
constext txt_no_prev_group[]
Definition: lang.c:682
GROUP_TOGGLE_THREADING
@ GROUP_TOGGLE_THREADING
Definition: keymap.h:258
txt_end_of_arts
constext txt_end_of_arts[]
Definition: lang.c:166
invoke_editor
t_bool invoke_editor(const char *filename, int lineno, struct t_group *group)
Definition: misc.c:372
GLOBAL_SEARCH_AUTHOR_FORWARD
@ GLOBAL_SEARCH_AUTHOR_FORWARD
Definition: keymap.h:218
txt_no_prev_search
constext txt_no_prev_search[]
Definition: lang.c:683
txt_info_add_kill
constext txt_info_add_kill[]
Definition: lang.c:539
draw_subject_arrow
static void draw_subject_arrow(void)
Definition: group.c:972
txt_base_article_range
constext txt_base_article_range[]
Definition: lang.c:115
txt_cannot_post
constext txt_cannot_post[]
Definition: lang.c:130
t_group
Definition: tin.h:1772
MARK_FEED_READ
@ MARK_FEED_READ
Definition: keymap.h:263
parse_format_string
void parse_format_string(const char *fmtstr, struct t_fmt *fmt)
Definition: string.c:1430
t_fmt::len_date_max
size_t len_date_max
Definition: tin.h:1813
MARK_ARTICLE_UNREAD
@ MARK_ARTICLE_UNREAD
Definition: keymap.h:261
CATCHUP
@ CATCHUP
Definition: keymap.h:169
DIGIT_8
@ DIGIT_8
Definition: keymap.h:158
bug_report
void bug_report(void)
Definition: global.c:430
prompt_getart_limit
static t_bool prompt_getart_limit(void)
Definition: group.c:1665
GROUP_LIST_THREAD
@ GROUP_LIST_THREAD
Definition: keymap.h:236
GLOBAL_TOGGLE_INFO_LAST_LINE
@ GLOBAL_TOGGLE_INFO_LAST_LINE
Definition: keymap.h:229
GLOBAL_DISPLAY_POST_HISTORY
@ GLOBAL_DISPLAY_POST_HISTORY
Definition: keymap.h:188
txt_thread_singular
constext txt_thread_singular[]
Definition: lang.c:884
group_left
static t_function group_left(void)
Definition: group.c:102
t_fmt::date_str
char date_str[1024]
Definition: tin.h:1811
find_new_pos
static int find_new_pos(long old_artnum, int cur_pos)
Definition: group.c:1049
txt_bad_command
constext txt_bad_command[]
Definition: lang.c:112
GLOBAL_SEARCH_SUBJECT_FORWARD
@ GLOBAL_SEARCH_SUBJECT_FORWARD
Definition: keymap.h:220
show_title
void show_title(const char *title)
Definition: screen.c:405
GROUP_UNDO_SELECTIONS
@ GROUP_UNDO_SELECTIONS
Definition: keymap.h:259
art_mark
void art_mark(struct t_group *group, struct t_article *art, int flag)
Definition: newsrc.c:1571
t_article::selected
t_bool selected
Definition: tin.h:1533
base
t_artnum * base
Definition: memory.c:65
move_down
void move_down(void)
Definition: global.c:110
t_attribute::mailing_list
char * mailing_list
Definition: tin.h:1578
DIGIT_5
@ DIGIT_5
Definition: keymap.h:155
last_search
t_function last_search
Definition: init.c:117
screen
struct t_screen * screen
Definition: screen.c:51
t_attribute::group_format
char * group_format
Definition: tin.h:1569
my_flush
#define my_flush()
Definition: tcurses.h:171
ClearScreen
void ClearScreen(void)
Definition: curses.c:410
GLOBAL_LOOKUP_MESSAGEID
@ GLOBAL_LOOKUP_MESSAGEID
Definition: keymap.h:196
GLOBAL_OPTION_MENU
@ GLOBAL_OPTION_MENU
Definition: keymap.h:199
scroll_up
void scroll_up(void)
Definition: global.c:278
cCRLF
#define cCRLF
Definition: tcurses.h:150
for_each_art_in_thread
#define for_each_art_in_thread(x, y)
Definition: tin.h:2212
ret_code
static int ret_code
Definition: group.c:86
art
static t_openartinfo * art
Definition: cook.c:78
t_art_stat::multipart_total
int multipart_total
Definition: tin.h:1953
DIGIT_3
@ DIGIT_3
Definition: keymap.h:153
tinrc
struct t_config tinrc
Definition: init.c:191
txt_index_page_com
constext txt_index_page_com[]
Definition: lang.c:538
value
Definition: plp_snprintf.c:180
wait_message
void wait_message(unsigned int sdelay, const char *fmt,...)
Definition: screen.c:133
HIST_OTHER
@ HIST_OTHER
Definition: extern.h:1538
FEED_SAVE
#define FEED_SAVE
Definition: tin.h:1117
FreeAndNull
#define FreeAndNull(p)
Definition: tin.h:2204
t_config::default_select_pattern
char default_select_pattern[LEN]
Definition: tinrc.h:91
filter_file_offset
int filter_file_offset
Definition: filter.c:93
signal_context
int signal_context
Definition: signal.c:105
GROUP_NEXT_UNREAD_ARTICLE_OR_GROUP
@ GROUP_NEXT_UNREAD_ARTICLE_OR_GROUP
Definition: keymap.h:242
ART_UNAVAILABLE
#define ART_UNAVAILABLE
Definition: tin.h:1323
CATCHUP_NEXT_UNREAD
@ CATCHUP_NEXT_UNREAD
Definition: keymap.h:170
group_keys
struct keylist group_keys
Definition: keymap.c:67
regex_cache::extra
pcre_extra * extra
Definition: tin.h:1919
MIN
#define MIN(a, b)
Definition: tin.h:805
search
int search(t_function func, int current_art, t_bool repeat)
Definition: search.c:551
GLOBAL_POSTPONED
@ GLOBAL_POSTPONED
Definition: keymap.h:204
GLOBAL_SCROLL_DOWN
@ GLOBAL_SCROLL_DOWN
Definition: keymap.h:213
GROUP_MARK_UNSELECTED_ARTICLES_READ
@ GROUP_MARK_UNSELECTED_ARTICLES_READ
Definition: keymap.h:239
txt_enter_next_unread_group
constext txt_enter_next_unread_group[]
Definition: lang.c:177
fmt_string
char * fmt_string(const char *fmt,...)
Definition: string.c:1379
GROUP_TOGGLE_SELECT_THREAD
@ GROUP_TOGGLE_SELECT_THREAD
Definition: keymap.h:257
GROUP_REVERSE_SELECTIONS
@ GROUP_REVERSE_SELECTIONS
Definition: keymap.h:247
pickup_postponed_articles
t_bool pickup_postponed_articles(t_bool ask, t_bool all)
Definition: post.c:2462
TINRC_CONFIRM_ACTION
#define TINRC_CONFIRM_ACTION
Definition: tin.h:947
pos_first_unread_thread
void pos_first_unread_thread(void)
Definition: group.c:1067
which_response
int which_response(int n)
Definition: thread.c:1029
DAY
#define DAY
Definition: tin.h:864
prompt_item_num
void prompt_item_num(int ch, const char *prompt)
Definition: global.c:200
show_group_page
void show_group_page(void)
Definition: group.c:915
t_config::art_marked_selected
char art_marked_selected
Definition: tinrc.h:62
MoveCursor
void MoveCursor(int row, int col)
Definition: curses.c:441
GRP_NEXTUNREAD
@ GRP_NEXTUNREAD
Definition: tin.h:1262
CMDLINE_GETART_LIMIT
#define CMDLINE_GETART_LIMIT
Definition: tin.h:1091
tcurses.h
txt_no_next_unread_art
constext txt_no_next_unread_art[]
Definition: lang.c:681
GROUP_TOGGLE_SUBJECT_DISPLAY
@ GROUP_TOGGLE_SUBJECT_DISPLAY
Definition: keymap.h:256
GLOBAL_SCROLL_UP
@ GLOBAL_SCROLL_UP
Definition: keymap.h:214
txt_all
constext txt_all[]
Definition: lang.c:50
GROUP_TOGGLE_READ_UNREAD
@ GROUP_TOGGLE_READ_UNREAD
Definition: keymap.h:255
t_config::art_marked_read
char art_marked_read
Definition: tinrc.h:65
t_menu::max
int max
Definition: tin.h:2007
GROUP_SAVE
@ GROUP_SAVE
Definition: keymap.h:248
info_message
void info_message(const char *fmt,...)
Definition: screen.c:102
tin.h
t_art_stat::score
int score
Definition: tin.h:1952
get_author
void get_author(t_bool thread, struct t_article *art, char *str, size_t len)
Definition: misc.c:1019
DEBUG_NEWSRC
#define DEBUG_NEWSRC
Definition: debug.h:50
GLOBAL_LAST_PAGE
@ GLOBAL_LAST_PAGE
Definition: keymap.h:192
CleartoEOLN
void CleartoEOLN(void)
Definition: curses.c:458
t_art_stat::killed
int killed
Definition: tin.h:1951
t_art_stat::multipart_compare_len
int multipart_compare_len
Definition: tin.h:1955
read_filter_file
t_bool read_filter_file(const char *file)
Definition: filter.c:308
enter_thread
static int enter_thread(int depth, t_pagerinfo *page)
Definition: group.c:1530
GROUP_CANCEL
@ GROUP_CANCEL
Definition: keymap.h:233
prompt_msgid
int prompt_msgid(void)
Definition: prompt.c:592
txt_info_no_previous_expression
constext txt_info_no_previous_expression[]
Definition: lang.c:548
t_attribute::group_catchup_on_exit
unsigned group_catchup_on_exit
Definition: tin.h:1613
DIGIT_4
@ DIGIT_4
Definition: keymap.h:154
mark_screen
void mark_screen(int screen_row, int screen_col, const char *value)
Definition: group.c:1084
SHOW_FROM_NONE
#define SHOW_FROM_NONE
Definition: tin.h:1141
GRP_EXIT
@ GRP_EXIT
Definition: tin.h:1269
can_post
t_bool can_post
Definition: nntplib.c:32
cmdline
struct t_cmdlineopts cmdline
Definition: init.c:189
FEED_PRINT
#define FEED_PRINT
Definition: tin.h:1116
prev_response
int prev_response(int n)
Definition: thread.c:1247
SHOW_FROM_BOTH
#define SHOW_FROM_BOTH
Definition: tin.h:1144
search_body
int search_body(struct t_group *group, int current_art, t_bool repeat)
Definition: search.c:709
strip_line
char * strip_line(char *line)
Definition: misc.c:3599
t_fmt
Definition: tin.h:1809
t_art_stat
Definition: tin.h:1941
SPECIAL_CATCHUP_LEFT
@ SPECIAL_CATCHUP_LEFT
Definition: keymap.h:167
GLOBAL_TOGGLE_HELP_DISPLAY
@ GLOBAL_TOGGLE_HELP_DISPLAY
Definition: keymap.h:228
choose_new_group
int choose_new_group(void)
Definition: select.c:984
tin_getline
char * tin_getline(const char *prompt, int number_only, const char *str, int max_chars, t_bool passwd, int which_hist)
Definition: getline.c:85
prompt_string_default
char * prompt_string_default(const char *prompt, char *def, const char *failtext, int history)
Definition: prompt.c:558
page_up
void page_up(void)
Definition: global.c:130
filter_file
char filter_file[PATH_LEN]
Definition: init.c:89
t_fmt::mark_offset
size_t mark_offset
Definition: tin.h:1828
forever
#define forever
Definition: tin.h:810
show_help_page
void show_help_page(const int level, const char *title)
Definition: help.c:694
feed_articles
int feed_articles(int function, int level, t_function type, struct t_group *group, int respnum)
Definition: feed.c:571
MARK_THREAD_UNREAD
@ MARK_THREAD_UNREAD
Definition: keymap.h:262
stat_thread
int stat_thread(int n, struct t_art_stat *sbuf)
Definition: thread.c:1118
FEED_REPOST
#define FEED_REPOST
Definition: tin.h:1119
quick_filter
t_bool quick_filter(t_function type, struct t_group *group, struct t_article *art)
Definition: filter.c:1489
STRCMPEQ
#define STRCMPEQ(s1, s2)
Definition: tin.h:816
ART_EXPIRED
#define ART_EXPIRED
Definition: tin.h:1310
strwidth
int strwidth(const char *str)
Definition: string.c:1043
t_art_stat::art_mark
char art_mark
Definition: tin.h:1942
t_fmt::len_from
size_t len_from
Definition: tin.h:1815
GROUP_TAG_PARTS
@ GROUP_TAG_PARTS
Definition: keymap.h:253
mark_offset
int mark_offset
Definition: screen.c:48
THREAD_MAX
#define THREAD_MAX
Definition: tin.h:1134
t_attribute::pos_first_unread
unsigned pos_first_unread
Definition: tin.h:1618
t_fmt::len_score
size_t len_score
Definition: tin.h:1824
GROUP_SELECT_PATTERN
@ GROUP_SELECT_PATTERN
Definition: keymap.h:249
ART_ABORT
#define ART_ABORT
Definition: tin.h:1335
grp_fmt
static struct t_fmt grp_fmt
Definition: group.c:56
txt_select_thread
constext txt_select_thread[]
Definition: lang.c:840
GLOBAL_VERSION
@ GLOBAL_VERSION
Definition: keymap.h:231
GLOBAL_EDIT_FILTER
@ GLOBAL_EDIT_FILTER
Definition: keymap.h:189
clear_note_area
void clear_note_area(void)
Definition: group.c:988
draw_arrow_mark
void draw_arrow_mark(int line)
Definition: screen.c:300
t_fmt::len_initials
size_t len_initials
Definition: tin.h:1819
GLOBAL_QUICK_FILTER_KILL
@ GLOBAL_QUICK_FILTER_KILL
Definition: keymap.h:208
WriteLine
#define WriteLine(row, buffer)
Definition: tcurses.h:174
GROUP_REPOST
@ GROUP_REPOST
Definition: keymap.h:246
index_group
t_bool index_group(struct t_group *group)
Definition: art.c:396
MARK_FEED_UNREAD
@ MARK_FEED_UNREAD
Definition: keymap.h:264
t_config::art_marked_unread
char art_marked_unread
Definition: tinrc.h:64
art_open
int art_open(t_bool wrap_lines, struct t_article *art, struct t_group *group, t_openartinfo *artinfo, t_bool show_progress_meter, const char *pmesg)
Definition: rfc2046.c:1547
DIGIT_7
@ DIGIT_7
Definition: keymap.h:157
toggle_mini_help
void toggle_mini_help(int level)
Definition: help.c:1020
GLOBAL_BUGREPORT
@ GLOBAL_BUGREPORT
Definition: keymap.h:187
handle_keypad
t_function handle_keypad(t_function(*left_action)(void), t_function(*right_action)(void), t_function(*mouse_action)(t_function(*left_action)(void), t_function(*right_action)(void)), const struct keylist keys)
Definition: global.c:355
find_base
void find_base(struct t_group *group)
Definition: art.c:124
t_fmt::str
char str[1024]
Definition: tin.h:1810
ART_READ
#define ART_READ
Definition: tin.h:1320
GLOBAL_MENU_FILTER_SELECT
@ GLOBAL_MENU_FILTER_SELECT
Definition: keymap.h:198
t_config::info_in_last_line
t_bool info_in_last_line
Definition: tinrc.h:215
buf
static char buf[16]
Definition: langinfo.c:50
txt_no_prev_unread_art
constext txt_no_prev_unread_art[]
Definition: lang.c:684
convert_to_printable
char * convert_to_printable(char *buf, t_bool keep_tab)
Definition: charset.c:385
GLOBAL_PRINT
@ GLOBAL_PRINT
Definition: keymap.h:206
txt_reading_arts
constext txt_reading_arts[]
Definition: lang.c:760
GLOBAL_PIPE
@ GLOBAL_PIPE
Definition: keymap.h:202
t_menu
Definition: tin.h:2005
GLOBAL_LINE_DOWN
@ GLOBAL_LINE_DOWN
Definition: keymap.h:194
group_catchup
static int group_catchup(t_function func)
Definition: group.c:1616
FreeIfNeeded
#define FreeIfNeeded(p)
Definition: tin.h:2203
set_xclick_on
void set_xclick_on(void)
Definition: curses.c:691
show_mini_help
void show_mini_help(int level)
Definition: help.c:754
FEED_THREAD
@ FEED_THREAD
Definition: keymap.h:177
build_multipart_header
static void build_multipart_header(char *dest, int maxlen, const char *src, int cmplen, int have, int total)
Definition: group.c:1117
post_article
t_bool post_article(const char *groupname)
Definition: post.c:2554
enter_pager
static int enter_pager(int art, t_bool ignore_unavail)
Definition: group.c:1512
t_group::moderated
char moderated
Definition: tin.h:1777
config_page
void config_page(const char *grpname, enum context level)
Definition: options_menu.c:921
FEED_MAIL
#define FEED_MAIL
Definition: tin.h:1114
tab_pressed
static int tab_pressed(void)
Definition: group.c:1595
GLOBAL_LAST_VIEWED
@ GLOBAL_LAST_VIEWED
Definition: keymap.h:193
untag_article
void untag_article(long art)
Definition: tags.c:298
t_attribute::show_only_unread_arts
unsigned show_only_unread_arts
Definition: tin.h:1627
FEED_RANGE
@ FEED_RANGE
Definition: keymap.h:180
assert
#define assert(p)
Definition: tin.h:1295
do_auto_select_arts
void do_auto_select_arts(void)
Definition: tags.c:522
GLOBAL_LINE_UP
@ GLOBAL_LINE_UP
Definition: keymap.h:195
t_article::keep_in_base
t_bool keep_in_base
Definition: tin.h:1536
t_config::art_marked_read_selected
char art_marked_read_selected
Definition: tinrc.h:67
group_right
static t_function group_right(void)
Definition: group.c:113
GRP_KILLED
@ GRP_KILLED
Definition: tin.h:1266
top_of_list
void top_of_list(void)
Definition: global.c:182
PCRE_CASELESS
#define PCRE_CASELESS
Definition: pcre.h:98
stow_cursor
void stow_cursor(void)
Definition: screen.c:59
t_fmt::len_subj
size_t len_subj
Definition: tin.h:1825
txt_quit_despite_tags
constext txt_quit_despite_tags[]
Definition: lang.c:747
GLOBAL_SEARCH_SUBJECT_BACKWARD
@ GLOBAL_SEARCH_SUBJECT_BACKWARD
Definition: keymap.h:219
line_is_tagged
int line_is_tagged(int n)
Definition: tags.c:254
THREAD_NONE
#define THREAD_NONE
Definition: tin.h:1127
GROUP_TOGGLE_GET_ARTICLES_LIMIT
@ GROUP_TOGGLE_GET_ARTICLES_LIMIT
Definition: keymap.h:254
DIGIT_9
@ DIGIT_9
Definition: keymap.h:159
t_article::inrange
t_bool inrange
Definition: tin.h:1534
cCOLS
int cCOLS
Definition: curses.c:53
LEN
#define LEN
Definition: tin.h:854
T_ARTNUM_CONST
#define T_ARTNUM_CONST(v)
Definition: tin.h:229
GLOBAL_SEARCH_AUTHOR_BACKWARD
@ GLOBAL_SEARCH_AUTHOR_BACKWARD
Definition: keymap.h:217
t_article::tagged
int tagged
Definition: tin.h:1525
last_resp
int last_resp
Definition: page.c:70
t_function
enum defined_functions t_function
Definition: keymap.h:373
txt_confirm_select_on_exit
constext txt_confirm_select_on_exit[]
Definition: lang.c:152
toggle_inverse_video
void toggle_inverse_video(void)
Definition: misc.c:1058
txt_select_pattern
constext txt_select_pattern[]
Definition: lang.c:839
filter_menu
t_bool filter_menu(t_function type, struct t_group *group, struct t_article *art)
Definition: filter.c:1054
txt_info_all_parts_tagged
constext txt_info_all_parts_tagged[]
Definition: lang.c:541
txt_autoselecting_articles
constext txt_autoselecting_articles[]
Definition: lang.c:108
currmenu
t_menu * currmenu
Definition: init.c:165
grpmenu
t_menu grpmenu
Definition: group.c:83
thread_page
int thread_page(struct t_group *group, int respnum, int thread_depth, t_pagerinfo *page)
Definition: thread.c:424
t_article::artnum
t_artnum artnum
Definition: tin.h:1511
which_thread
int which_thread(int n)
Definition: thread.c:1003
update_group_page
static void update_group_page(void)
Definition: group.c:944
new_responses
int new_responses(int thread)
Definition: thread.c:975
GLOBAL_FIRST_PAGE
@ GLOBAL_FIRST_PAGE
Definition: keymap.h:190
GROUP_MARK_THREAD_READ
@ GROUP_MARK_THREAD_READ
Definition: keymap.h:238
GLOBAL_POST
@ GLOBAL_POST
Definition: keymap.h:203
txt_no_more_groups
constext txt_no_more_groups[]
Definition: lang.c:679
cGroup
@ cGroup
Definition: tin.h:107
t_article::thread
int thread
Definition: tin.h:1526
t_article::subject
char * subject
Definition: tin.h:1512
GRP_NEXT
@ GRP_NEXT
Definition: tin.h:1263
set_xclick_off
void set_xclick_off(void)
Definition: curses.c:703
compile_regex
t_bool compile_regex(const char *regex, struct regex_cache *cache, int options)
Definition: regex.c:111
regex_cache::re
pcre * re
Definition: tin.h:1918
untag_all_articles
t_bool untag_all_articles(void)
Definition: tags.c:318
FEED_MARK_UNREAD
#define FEED_MARK_UNREAD
Definition: tin.h:1121
my_fputs
#define my_fputs(str, stream)
Definition: tcurses.h:153
func_to_key
char func_to_key(t_function func, const struct keylist keys)
Definition: keymap.c:124
my_retouch
#define my_retouch()
Definition: tcurses.h:173
txt_no_last_message
constext txt_no_last_message[]
Definition: lang.c:675
ART_WILL_RETURN
#define ART_WILL_RETURN
Definition: tin.h:1322
unfilter_articles
void unfilter_articles(struct t_group *group)
Definition: filter.c:1811
GROUP_SELECT_THREAD
@ GROUP_SELECT_THREAD
Definition: keymap.h:250
buffer
static uschar * buffer
Definition: pcretest.c:154
bool_not
#define bool_not(b)
Definition: bool.h:81
filter_articles
t_bool filter_articles(struct t_group *group)
Definition: filter.c:1836
GROUP_MAIL
@ GROUP_MAIL
Definition: keymap.h:237
UNREAD_GROUP
#define UNREAD_GROUP(i)
Definition: tin.h:1048
t_config::art_marked_recent
char art_marked_recent
Definition: tinrc.h:63
t_attribute::auto_list_thread
unsigned auto_list_thread
Definition: tin.h:1608
scroll_down
void scroll_down(void)
Definition: global.c:252
MAXKEYLEN
#define MAXKEYLEN
Definition: keymap.h:136
t_pagerinfo::ignore_unavail
t_bool ignore_unavail
Definition: tin.h:2020
txt_enter_getart_limit
constext txt_enter_getart_limit[]
Definition: lang.c:173
t_cmdlineopts::args
unsigned int args
Definition: tin.h:1471
t_menu::curr
int curr
Definition: tin.h:2006
t_menu::draw_arrow
void(* draw_arrow)(void)
Definition: tin.h:2010
atoi
int atoi(const char *s)
INDEX2LNUM
#define INDEX2LNUM(i)
Definition: tin.h:1009
t_group::name
char * name
Definition: tin.h:1773
t_group::newsrc
struct t_newsrc newsrc
Definition: tin.h:1789
t_attribute::mark_ignore_tags
unsigned mark_ignore_tags
Definition: tin.h:1616
t_screen::col
char * col
Definition: tin.h:1930
GLOBAL_MENU_FILTER_KILL
@ GLOBAL_MENU_FILTER_KILL
Definition: keymap.h:197
get_initials
int get_initials(struct t_article *art, char *s, int maxsize)
Definition: misc.c:1995
t_art_stat::time
time_t time
Definition: tin.h:1956
GLOBAL_SET_RANGE
@ GLOBAL_SET_RANGE
Definition: keymap.h:221
GROUP_DO_AUTOSELECT
@ GROUP_DO_AUTOSELECT
Definition: keymap.h:234
cancel_article
t_bool cancel_article(struct t_group *group, struct t_article *art, int respnum)
Definition: post.c:3770
GROUP_PREVIOUS_UNREAD_ARTICLE
@ GROUP_PREVIOUS_UNREAD_ARTICLE
Definition: keymap.h:244
txt_info_add_select
constext txt_info_add_select[]
Definition: lang.c:540
GROUP_NEXT_GROUP
@ GROUP_NEXT_GROUP
Definition: keymap.h:240
FALSE
#define FALSE
Definition: bool.h:70
STRCPY
#define STRCPY(dst, src)
Definition: tin.h:814
FEED_AUTOSAVE
#define FEED_AUTOSAVE
Definition: tin.h:1118
num_of_tagged_arts
int num_of_tagged_arts
Definition: tags.c:50
GROUP_GOTO
@ GROUP_GOTO
Definition: keymap.h:235
debug
unsigned short debug
Definition: debug.c:51
CleartoEOS
void CleartoEOS(void)
Definition: curses.c:470
GLOBAL_QUIT_TIN
@ GLOBAL_QUIT_TIN
Definition: keymap.h:211
GLOBAL_PAGE_UP
@ GLOBAL_PAGE_UP
Definition: keymap.h:201
regex_cache
Definition: tin.h:1917
this_resp
int this_resp
Definition: page.c:71
tin_ltoa
char * tin_ltoa(t_artnum value, int digits)
Definition: string.c:80
end_of_list
void end_of_list(void)
Definition: global.c:191
grp_mark_read
void grp_mark_read(struct t_group *group, struct t_article *art)
Definition: newsrc.c:690
t_cmdlineopts::getart_limit
int getart_limit
Definition: tin.h:1467
FEED_MARK_READ
#define FEED_MARK_READ
Definition: tin.h:1120
draw_mark_selected
void draw_mark_selected(int i)
Definition: misc.c:4123
snprintf
#define snprintf
Definition: tin.h:2417
next_response
int next_response(int n)
Definition: thread.c:1206
GLOBAL_SEARCH_REPEAT
@ GLOBAL_SEARCH_REPEAT
Definition: keymap.h:216
t_pagerinfo
Definition: tin.h:2018
move_to_item
void move_to_item(int n)
Definition: global.c:227
DIGIT_2
@ DIGIT_2
Definition: keymap.h:152
t_fmt::len_linenumber
size_t len_linenumber
Definition: tin.h:1820
GROUP_READ_BASENOTE
@ GROUP_READ_BASENOTE
Definition: keymap.h:245
show_tagged_lines
static void show_tagged_lines(void)
Definition: group.c:89
t_artnum
long t_artnum
Definition: tin.h:226
error_message
void error_message(unsigned int sdelay, const char *fmt,...)
Definition: screen.c:184
GRP_QUIT
@ GRP_QUIT
Definition: tin.h:1261
GROUP_UNTAG
@ GROUP_UNTAG
Definition: keymap.h:260
TINRC_CONFIRM_SELECT
#define TINRC_CONFIRM_SELECT
Definition: tin.h:949
t_group::attribute
struct t_attribute * attribute
Definition: tin.h:1790
GLOBAL_HELP
@ GLOBAL_HELP
Definition: keymap.h:191
txt_quick_filter_select
constext txt_quick_filter_select[]
Definition: lang.c:744
t_menu::first
int first
Definition: tin.h:2008
GLOBAL_ABORT
@ GLOBAL_ABORT
Definition: keymap.h:186
REGEX_FMT
#define REGEX_FMT
Definition: tin.h:1016
GLOBAL_QUICK_FILTER_SELECT
@ GLOBAL_QUICK_FILTER_SELECT
Definition: keymap.h:209
GRP_RETSELECT
@ GRP_RETSELECT
Definition: tin.h:1260
art_close
void art_close(t_openartinfo *artinfo)
Definition: rfc2046.c:1604
move_up
void move_up(void)
Definition: global.c:81
DIGIT_6
@ DIGIT_6
Definition: keymap.h:156
undo_auto_select_arts
void undo_auto_select_arts(void)
Definition: tags.c:549
txt_quick_filter_kill
constext txt_quick_filter_kill[]
Definition: lang.c:743
t_fmt::len_respcnt
size_t len_respcnt
Definition: tin.h:1823
selmenu
t_menu selmenu
Definition: select.c:85
t_art_stat::seen
int seen
Definition: tin.h:1945
ART_KILLED_UNREAD
#define ART_KILLED_UNREAD
Definition: tin.h:1330
range_active
t_bool range_active
Definition: init.c:147
txt_thread_marked_as_deselected
constext txt_thread_marked_as_deselected[]
Definition: lang.c:879
t_art_stat::total
int total
Definition: tin.h:1943
t_attribute::thread_articles
unsigned thread_articles
Definition: tin.h:1631
next_unread
int next_unread(int n)
Definition: thread.c:1289
t_bool
unsigned t_bool
Definition: bool.h:77
group_flag
char group_flag(char ch)
Definition: active.c:1248
FEED_ARTICLE
@ FEED_ARTICLE
Definition: keymap.h:176
txt_select_art
constext txt_select_art[]
Definition: lang.c:836
toggle_read_unread
static void toggle_read_unread(t_bool force)
Definition: group.c:1002
printascii
char * printascii(char *buf, int ch)
Definition: keymap.c:271
t_group::read_during_session
t_bool read_during_session
Definition: tin.h:1783
txt_unread
constext txt_unread[]
Definition: lang.c:903
match_regex
t_bool match_regex(const char *string, char *pattern, struct regex_cache *cache, t_bool icase)
Definition: regex.c:59
prompt_yn
int prompt_yn(const char *prompt, t_bool default_answer)
Definition: prompt.c:165
TRUE
#define TRUE
Definition: bool.h:74
global_mouse_action
t_function global_mouse_action(t_function(*left_action)(void), t_function(*right_action)(void))
Definition: global.c:321
txt_threading
constext * txt_threading[]
Definition: lang.c:1263
for_each_art
#define for_each_art(x)
Definition: tin.h:2211
t_newsrc::num_unread
t_artnum num_unread
Definition: tin.h:1762
GRP_ENTER
@ GRP_ENTER
Definition: tin.h:1268
tin_errno
int tin_errno
Definition: read.c:59
GLOBAL_REDRAW_SCREEN
@ GLOBAL_REDRAW_SCREEN
Definition: keymap.h:212
HEADER_LEN
#define HEADER_LEN
Definition: tin.h:857
GLOBAL_TOGGLE_INVERSE_VIDEO
@ GLOBAL_TOGGLE_INVERSE_VIDEO
Definition: keymap.h:230
txt_mark_arts_read
constext txt_mark_arts_read[]
Definition: lang.c:624
undo_selections
void undo_selections(void)
Definition: tags.c:573
show_inverse_video_status
void show_inverse_video_status(void)
Definition: misc.c:1073
arts
struct t_article * arts
Definition: memory.c:69
set_range
t_bool set_range(int level, int min, int max, int curr)
Definition: tags.c:353
my_strftime
size_t my_strftime(char *s, size_t maxsize, const char *format, struct tm *timeptr)
Definition: strftime.c:64
txt_marked_as_unread
constext txt_marked_as_unread[]
Definition: lang.c:620
GLOBAL_SEARCH_BODY
@ GLOBAL_SEARCH_BODY
Definition: keymap.h:215
t_config::getart_limit
int getart_limit
Definition: tinrc.h:135
txt_thread_marked_as_selected
constext txt_thread_marked_as_selected[]
Definition: lang.c:880
GROUP_TAG
@ GROUP_TAG
Definition: keymap.h:252
DIGIT_1
@ DIGIT_1
Definition: keymap.h:151
GLOBAL_QUIT
@ GLOBAL_QUIT
Definition: keymap.h:210
cvers
char cvers[LEN]
Definition: init.c:70
NOTESLINES
int NOTESLINES
Definition: signal.c:111
t_attribute::show_author
unsigned show_author
Definition: tin.h:1634
do_shell_escape
void do_shell_escape(void)
Definition: misc.c:542
INDEX2SNUM
#define INDEX2SNUM(i)
Definition: tin.h:1011
group_mark_postprocess
t_bool group_mark_postprocess(int function, t_function feed_type, int respnum)
Definition: group.c:1688
GROUP_SELECT_THREAD_IF_UNREAD_SELECTED
@ GROUP_SELECT_THREAD_IF_UNREAD_SELECTED
Definition: keymap.h:251
prev_unread
int prev_unread(int n)
Definition: thread.c:1319
GROUP_AUTOSAVE
@ GROUP_AUTOSAVE
Definition: keymap.h:232
pgart
t_openartinfo pgart
Definition: page.c:63
t_fmt::len_linecnt
size_t len_linecnt
Definition: tin.h:1821
t_pagerinfo::art
int art
Definition: tin.h:2019
NOT_ASSIGNED
@ NOT_ASSIGNED
Definition: keymap.h:149
page_down
void page_down(void)
Definition: global.c:155
clear_message
void clear_message(void)
Definition: screen.c:243
txt_no_arts
constext txt_no_arts[]
Definition: lang.c:667
t_art_stat::selected_unread
int selected_unread
Definition: tin.h:1949
t_config::draw_arrow
t_bool draw_arrow
Definition: tinrc.h:212
HAS_FOLLOWUPS
#define HAS_FOLLOWUPS(i)
Definition: tin.h:1029
my_malloc
#define my_malloc(size)
Definition: tin.h:2196
txt_prefix_untagged
constext txt_prefix_untagged[]
Definition: lang.c:733
user_posted_messages
t_bool user_posted_messages(void)
Definition: post.c:466
t_art_stat::unread
int unread
Definition: tin.h:1944
set_first_screen_item
void set_first_screen_item(void)
Definition: global.c:61