tin  2.6.1
About: TIN is a threaded NNTP and spool based UseNet newsreader.
  Fossies Dox: tin-2.6.1.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 : 2021-07-25
7 * Notes :
8 *
9 * Copyright (c) 1991-2022 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 */
56static struct t_fmt grp_fmt;
57
58/*
59 * Local prototypes
60 */
61static int do_search(t_function func, t_bool repeat);
62static int enter_pager(int art, t_bool ignore_unavail);
63static int enter_thread(int depth, t_pagerinfo *page);
64static int find_new_pos(long old_artnum, int cur_pos);
65static int group_catchup(t_function func);
66static int tab_pressed(void);
67static t_bool prompt_getart_limit(void);
68static t_function group_left(void);
69static t_function group_right(void);
70static void build_sline(int i);
71static void build_multipart_header(char *dest, int maxlen, const char *src, int cmplen, int have, int total);
72static void draw_subject_arrow(void);
73static void show_group_title(t_bool clear_title);
74static void show_tagged_lines(void);
75static void toggle_read_unread(t_bool force);
76static 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 */
86static int ret_code = 0; /* Set to < 0 when it is time to leave the group level */
87
88static void
90 void)
91{
92 int i, j;
93#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
94 wchar_t *wtmp;
95#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
96
97 for (i = grpmenu.first; i < grpmenu.first + NOTESLINES && i < grpmenu.max; ++i) {
98 if ((i != grpmenu.curr) && (j = line_is_tagged((int) base[i]))) {
99#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
100 if ((wtmp = char2wchar_t(tin_ltoa(j, 3)))) {
101 mark_screen(i, mark_offset - (3 - art_mark_width), wtmp);
102 free(wtmp);
103 }
104#else
105 mark_screen(i, mark_offset - 2, tin_ltoa(j, 3));
106#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
107 }
108 }
109}
110
111
112static t_function
114 void)
115{
117 return SPECIAL_CATCHUP_LEFT; /* ie, not via 'c' or 'C' */
118
119 return GLOBAL_QUIT;
120}
121
122
123static t_function
125 void)
126{
127 if (grpmenu.curr >= 0 && HAS_FOLLOWUPS(grpmenu.curr)) {
129 return GROUP_LIST_THREAD;
130 else {
131 int n = next_unread((int) base[grpmenu.curr]);
132
133 if (n >= 0 && grpmenu.curr == which_thread(n)) {
135 return GLOBAL_ABORT; /* TODO: should we return something else? */
136 }
137 }
138 }
139 return GROUP_READ_BASENOTE;
140}
141
142
143/*
144 * Return Codes:
145 * GRP_EXIT 'Normal' return to selection menu
146 * GRP_RETSELECT We are en route from pager to the selection screen
147 * GRP_QUIT User has done a 'Q'
148 * GRP_NEXT User wants to move onto next group
149 * GRP_NEXTUNREAD User did a 'C'atchup
150 * GRP_ENTER 'g' command has been used to set group to enter
151 */
152int
154 struct t_group *group)
155{
156 char key[MAXKEYLEN];
157 int i, n, ii;
158 int thread_depth; /* Starting depth in threads we enter */
159 t_artnum old_artnum;
160 struct t_art_stat sbuf;
161 struct t_article *art;
162 t_bool flag;
163 t_bool xflag = FALSE; /* 'X'-flag */
164 t_bool repeat_search;
166#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
167 wchar_t *wtmp;
168#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
169
170 /*
171 * Set the group attributes
172 */
173 group->read_during_session = TRUE;
174
175 curr_group = group; /* For global access to the current group */
178
179 last_resp = -1;
180 this_resp = -1;
181
182 /*
183 * update index file. quit group level if user aborts indexing
184 */
185 if (!index_group(group)) {
186 for_each_art(i) {
187 art = &arts[i];
188 FreeAndNull(art->refs);
189 FreeAndNull(art->msgid);
190 }
191 curr_group = NULL;
192 tin_errno = 0;
193 return GRP_RETSELECT;
194 }
195
196 /*
197 * Position 'grpmenu.curr' accordingly
198 */
200 /* reset grpmenu.first */
201 grpmenu.first = 0;
202
204
205 if (group->attribute->auto_select) {
207 do_auto_select_arts(); /* 'X' command */
208 xflag = TRUE;
209 }
210
212
213#ifdef DEBUG
214 if (debug & DEBUG_NEWSRC)
215 debug_print_bitmap(group, NULL);
216#endif /* DEBUG */
217
218 /* reset ret_code */
219 ret_code = 0;
220 while (ret_code >= 0) {
224 repeat_search = TRUE;
225 } else
226 repeat_search = FALSE;
227
228 switch (func) {
229 case GLOBAL_ABORT:
230 break;
231
232 case DIGIT_1:
233 case DIGIT_2:
234 case DIGIT_3:
235 case DIGIT_4:
236 case DIGIT_5:
237 case DIGIT_6:
238 case DIGIT_7:
239 case DIGIT_8:
240 case DIGIT_9:
241 if (grpmenu.max)
243 break;
244
245#ifndef NO_SHELL_ESCAPE
248 break;
249#endif /* !NO_SHELL_ESCAPE */
250
251 case GLOBAL_FIRST_PAGE: /* show first page of threads */
252 top_of_list();
253 break;
254
255 case GLOBAL_LAST_PAGE: /* show last page of threads */
256 end_of_list();
257 break;
258
259 case GLOBAL_LAST_VIEWED: /* go to last viewed article */
260 /*
261 * If the last art is no longer in a thread then we can't display it
262 */
263 if (this_resp < 0 || (which_thread(this_resp) == -1))
265 else
267 break;
268
269 case GLOBAL_PIPE: /* pipe article/thread/tagged arts to command */
270 if (grpmenu.curr >= 0)
272 break;
273
274 case GROUP_MAIL: /* mail article to somebody */
275 if (grpmenu.curr >= 0)
277 break;
278
279#ifndef DISABLE_PRINTING
280 case GLOBAL_PRINT: /* output art/thread/tagged arts to printer */
281 if (grpmenu.curr >= 0)
283 break;
284#endif /* !DISABLE_PRINTING */
285
286 case GROUP_REPOST: /* repost current article */
287 if (can_post) {
288 if (grpmenu.curr >= 0)
290 } else
292 break;
293
294 case GROUP_SAVE: /* save articles with prompting */
295 if (grpmenu.curr >= 0)
297 break;
298
299 case GROUP_AUTOSAVE: /* Auto-save articles without prompting */
300 if (grpmenu.curr >= 0)
302 break;
303
304 case GLOBAL_SET_RANGE: /* set range */
305 if (grpmenu.curr >= 0 && set_range(GROUP_LEVEL, 1, grpmenu.max, grpmenu.curr + 1)) {
308 }
309 break;
310
313 break;
314
319 if ((thread_depth = do_search(func, repeat_search)) != 0)
320 ret_code = enter_thread(thread_depth, NULL);
321 break;
322
323 case GLOBAL_SEARCH_BODY: /* search article body */
324 if (grpmenu.curr >= 0) {
325 if ((n = search_body(group, (int) base[grpmenu.curr], repeat_search)) != -1)
327 } else
329 break;
330
331 case GROUP_READ_BASENOTE: /* read current basenote */
332 if (grpmenu.curr >= 0)
333 ret_code = enter_pager((int) base[grpmenu.curr], FALSE /*TRUE*/);
334 else
336 break;
337
338 case GROUP_CANCEL: /* cancel current basenote */
339 if (grpmenu.curr >= 0) {
340 if (can_post || group->attribute->mailing_list != NULL) {
341 int ret;
342
343 n = (int) base[grpmenu.curr];
344 ret = art_open(TRUE, &arts[n], group, &pgart, TRUE, _(txt_reading_article));
345 if (ret != ART_UNAVAILABLE && ret != ART_ABORT && cancel_article(group, &arts[n], n))
348 } else
350 } else
352 break;
353
354 case GROUP_NEXT_UNREAD_ARTICLE_OR_GROUP: /* goto next unread article/group */
356 break;
357
358 case GLOBAL_PAGE_DOWN:
359 page_down();
360 break;
361
362 case GLOBAL_MENU_FILTER_SELECT: /* auto-select article menu */
363 case GLOBAL_MENU_FILTER_KILL: /* kill article menu */
364 if (grpmenu.curr < 0) {
366 break;
367 }
368 n = (int) base[grpmenu.curr];
369 if (filter_menu(func, group, &arts[n])) {
370 old_artnum = arts[n].artnum;
371 unfilter_articles(group);
372 filter_articles(group);
373 make_threads(group, FALSE);
374 grpmenu.curr = find_new_pos(old_artnum, grpmenu.curr);
375 }
377 break;
378
381 old_artnum = grpmenu.max > 0 ? arts[(int) base[grpmenu.curr]].artnum : T_ARTNUM_CONST(-1);
382 unfilter_articles(group);
384 filter_articles(group);
385 make_threads(group, FALSE);
386 grpmenu.curr = old_artnum >= T_ARTNUM_CONST(0) ? find_new_pos(old_artnum, grpmenu.curr) : grpmenu.max - 1;
387 }
389 break;
390
391 case GLOBAL_QUICK_FILTER_SELECT: /* quickly auto-select article */
392 case GLOBAL_QUICK_FILTER_KILL: /* quickly kill article */
393 if (grpmenu.curr < 0) {
395 break;
396 }
398 n = (int) base[grpmenu.curr]; /* should this depend on show_only_unread_arts? */
399 if (quick_filter(func, group, &arts[n])) {
400 old_artnum = arts[n].artnum;
401 unfilter_articles(group);
402 filter_articles(group);
403 make_threads(group, FALSE);
404 grpmenu.curr = find_new_pos(old_artnum, grpmenu.curr);
407 }
408 }
409 break;
410
412 my_retouch();
415 break;
416
417 case GLOBAL_LINE_DOWN:
418 move_down();
419 break;
420
421 case GLOBAL_LINE_UP:
422 move_up();
423 break;
424
425 case GLOBAL_PAGE_UP:
426 page_up();
427 break;
428
430 scroll_down();
431 break;
432
433 case GLOBAL_SCROLL_UP:
434 scroll_up();
435 break;
436
438 case CATCHUP:
441 break;
442
443 case GROUP_TOGGLE_SUBJECT_DISPLAY: /* toggle display of subject & subj/author */
447 break;
448
449 case GROUP_GOTO: /* choose a new group by name */
450 n = choose_new_group();
451 if (n >= 0 && n != selmenu.curr) {
452 selmenu.curr = n;
454 }
455 break;
456
457 case GLOBAL_HELP:
460 break;
461
462 case GLOBAL_TOGGLE_HELP_DISPLAY: /* toggle mini help menu */
465 break;
466
467 case GLOBAL_TOGGLE_INVERSE_VIDEO: /* toggle inverse video */
471 break;
472
473#ifdef HAVE_COLOR
474 case GLOBAL_TOGGLE_COLOR:
475 if (toggle_color()) {
477 show_color_status();
478 }
479 break;
480#endif /* HAVE_COLOR */
481
482 case GROUP_MARK_THREAD_READ: /* mark current thread/range/tagged threads as read */
483 case MARK_THREAD_UNREAD: /* or unread */
484 if (grpmenu.curr < 0)
486 else {
487 t_function function, type;
488
491 feed_articles(function, GROUP_LEVEL, type, group, (int) base[grpmenu.curr]);
492 }
493 break;
494
495 case GROUP_LIST_THREAD: /* list articles within current thread */
496 ret_code = enter_thread(0, NULL); /* Enter thread at the top */
497 break;
498
500 if ((i = prompt_msgid()) != ART_UNAVAILABLE)
502 break;
503
504 case GLOBAL_OPTION_MENU: /* option menu */
505 old_artnum = grpmenu.max > 0 ? arts[(int) base[grpmenu.curr]].artnum : T_ARTNUM_CONST(-1);
507 grpmenu.curr = old_artnum >= T_ARTNUM_CONST(0) ? find_new_pos(old_artnum, grpmenu.curr) : grpmenu.max - 1;
509 break;
510
511 case GROUP_NEXT_GROUP: /* goto next group */
513 if (selmenu.curr + 1 >= selmenu.max)
515 else {
518 xflag = FALSE;
519 }
520 selmenu.curr++;
522 }
523 break;
524
525 case GROUP_NEXT_UNREAD_ARTICLE: /* goto next unread article */
526 if (grpmenu.curr < 0) {
528 break;
529 }
530 if ((n = next_unread((int) base[grpmenu.curr])) == -1)
532 else
534 break;
535
536 case GROUP_PREVIOUS_UNREAD_ARTICLE: /* go to previous unread article */
537 if (grpmenu.curr < 0) {
539 break;
540 }
541
542 if ((n = prev_unread(prev_response((int) base[grpmenu.curr]))) == -1)
544 else
546 break;
547
548 case GROUP_PREVIOUS_GROUP: /* previous group */
550 for (i = selmenu.curr - 1; i >= 0; i--) {
551 if (UNREAD_GROUP(i))
552 break;
553 }
554 if (i < 0)
556 else {
559 xflag = FALSE;
560 }
561 selmenu.curr = i;
563 }
564 break;
565
566 case GLOBAL_QUIT: /* return to group selection page */
568 break;
571 xflag = FALSE;
572 }
574 break;
575
576 case GLOBAL_QUIT_TIN: /* quit */
578 break;
581 xflag = FALSE;
582 }
584 break;
585
589 break;
590
592 if (prompt_getart_limit()) {
593 /*
594 * if getart limit was given via cmd-line
595 * make it inactive now in order to use
596 * tinrc.getart_limit
597 */
599 cmdline.args &= ~CMDLINE_GETART_LIMIT;
601 }
602 break;
603
604 case GLOBAL_BUGREPORT:
605 bug_report();
606 break;
607
608 case GROUP_TAG_PARTS: /* tag all in order */
609 if (0 <= grpmenu.curr) {
610 int old_num = num_of_tagged_arts;
611
612 if (tag_multipart((int) base[grpmenu.curr]) != 0) {
613 /*
614 * on success, move the pointer to the next
615 * untagged article just for ease of use's sake
616 */
617 n = grpmenu.curr;
619 do {
620 n++;
621 n %= grpmenu.max;
622 if (arts[base[n]].tagged == 0) {
623 move_to_item(n);
624 break;
625 }
626 } while (n != grpmenu.curr);
627 if (old_num < num_of_tagged_arts)
629 else
631 }
632 }
633 break;
634
635 case GROUP_TAG: /* tag/untag threads for mailing/piping/printing/saving */
636 if (grpmenu.curr >= 0) {
638
639 n = (int) base[grpmenu.curr];
640
641 /*
642 * This loop looks for any article in the thread that
643 * isn't already tagged.
644 */
645 for (ii = n; ii != -1; ii = arts[ii].thread) {
646 if (arts[ii].tagged == 0) {
647 tagged = FALSE;
648 break;
649 }
650 }
651
652 /*
653 * If the whole thread is tagged, untag it. Otherwise, tag
654 * any untagged articles
655 */
656 if (tagged) {
657 /*
658 * Here we repeat the tagged test in both blocks
659 * to leave the choice of tagged/untagged
660 * determination politic in the previous lines.
661 */
662 for (ii = n; ii != -1; ii = arts[ii].thread) {
663 if (arts[ii].tagged != 0) {
664 tagged = TRUE;
665 untag_article(ii);
666 }
667 }
668 } else {
669 for (ii = n; ii != -1; ii = arts[ii].thread) {
670 if (arts[ii].tagged == 0)
672 }
673 }
674 if ((ii = line_is_tagged(n))) {
675#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
676 if ((wtmp = char2wchar_t(tin_ltoa(ii, 3)))) {
678 free(wtmp);
679 }
680#else
682#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
683 } else {
684#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
685 wchar_t mark[] = { L'\0', L'\0' };
686#else
687 char mark[] = { '\0', '\0' };
688#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
689
690 stat_thread(grpmenu.curr, &sbuf);
691 mark[0] = sbuf.art_mark;
692#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
693 mark_screen(grpmenu.curr, mark_offset - (3 - art_mark_width), L" "); /* clear space used by tag numbering */
694 mark_screen(grpmenu.curr, mark_offset + (art_mark_width - wcwidth(mark[0])), mark);
695#else
696 mark_screen(grpmenu.curr, mark_offset - 2, " "); /* clear space used by tag numbering */
698#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
699 }
700 if (tagged)
702
703 if (grpmenu.curr + 1 < grpmenu.max)
704 move_down();
705 else
707
709
710 }
711 break;
712
713 case GROUP_TOGGLE_THREADING: /* Cycle through the threading types */
714 group->attribute->thread_articles = CAST_BITS((group->attribute->thread_articles + 1) % (THREAD_MAX + 1), thread_articles);
715 if (grpmenu.curr >= 0) {
716 i = (int) base[grpmenu.curr]; /* Save a copy of current thread */
717 make_threads(group, TRUE);
718 find_base(group);
719 if ((grpmenu.curr = which_thread(i)) < 0) /* Restore current position in group */
720 grpmenu.curr = 0;
721 }
723 break;
724
725 case GROUP_UNTAG: /* untag all articles */
726 if (grpmenu.curr >= 0) {
727 if (untag_all_articles())
729 }
730 break;
731
732 case GLOBAL_VERSION:
734 break;
735
736 case GLOBAL_POST: /* post an article */
737 if (post_article(group->name))
739 break;
740
741 case GLOBAL_POSTPONED: /* post postponed article */
742 if (can_post) {
745 } else
747 break;
748
749 case GLOBAL_DISPLAY_POST_HISTORY: /* display messages posted by user */
750 if (post_hist_page()) {
751 if (grpmenu.curr == -1 && grpmenu.max > 0)
752 grpmenu.curr = 0;
754 }
755 break;
756
757 case MARK_ARTICLE_UNREAD: /* mark base article of thread unread */
758 if (grpmenu.curr < 0)
760 else {
761 const char *ptr;
762
763 if (range_active) {
764 /*
765 * We are tied to following base[] here, not arts[], as we operate on
766 * the base articles by definition.
767 */
768 for (ii = 0; ii < grpmenu.max; ++ii) {
769 if (arts[base[ii]].inrange) {
770 arts[base[ii]].inrange = FALSE;
771 art_mark(group, &arts[base[ii]], ART_WILL_RETURN);
773 arts[i].inrange = FALSE;
774 }
775 }
779 } else {
781 ptr = _(txt_base_article);
782 }
783
788 }
789 break;
790
791 case MARK_FEED_READ: /* mark selected articles as read */
792 if (grpmenu.curr >= 0)
794 break;
795
796 case MARK_FEED_UNREAD: /* mark selected articles as unread */
797 if (grpmenu.curr >= 0)
799 break;
800
801 case GROUP_SELECT_THREAD: /* mark thread as selected */
802 case GROUP_TOGGLE_SELECT_THREAD: /* toggle thread */
803 if (grpmenu.curr < 0) {
805 break;
806 }
807
808 flag = TRUE;
810 stat_thread(grpmenu.curr, &sbuf);
811 if (sbuf.selected_unread == sbuf.unread)
812 flag = FALSE;
813 }
814 n = 0;
816 arts[i].selected = CAST_BOOL(flag);
817 ++n;
818 }
819 assert(n > 0);
820 {
821#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
822 wchar_t mark[] = { L'\0', L'\0' };
823#else
824 char mark[] = { '\0', '\0' };
825#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
826
827 stat_thread(grpmenu.curr, &sbuf);
828 mark[0] = sbuf.art_mark;
829#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
830 mark_screen(grpmenu.curr, mark_offset + (art_mark_width - wcwidth(mark[0])), mark);
831#else
833#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
834 }
835
837
838 if (grpmenu.curr + 1 < grpmenu.max)
839 move_down();
840 else
842
844 break;
845
846 case GROUP_REVERSE_SELECTIONS: /* reverse selections */
847 for_each_art(i)
851 break;
852
853 case GROUP_UNDO_SELECTIONS: /* undo selections */
855 xflag = FALSE;
858 break;
859
860 case GROUP_SELECT_PATTERN: /* select matching patterns */
861 if (grpmenu.curr >= 0) {
862 char pat[128];
863 char *prompt;
864 struct regex_cache cache = { NULL, NULL };
865
868 free(prompt);
869 break;
870 }
871 free(prompt);
872
873 if (STRCMPEQ(tinrc.default_select_pattern, "*")) { /* all */
874 if (tinrc.wildcard)
875 STRCPY(pat, ".*");
876 else
878 } else
880
881 if (tinrc.wildcard && !(compile_regex(pat, &cache, PCRE_CASELESS)))
882 break;
883
884 flag = FALSE;
885 for (n = 0; n < grpmenu.max; n++) {
886 if (!match_regex(arts[base[n]].subject, pat, &cache, TRUE))
887 continue;
888
890 arts[i].selected = TRUE;
891
892 flag = TRUE;
893 }
894 if (flag) {
897 }
898 if (tinrc.wildcard) {
899 FreeIfNeeded(cache.re);
900 FreeIfNeeded(cache.extra);
901 }
902 }
903 break;
904
905 case GROUP_SELECT_THREAD_IF_UNREAD_SELECTED: /* select all unread arts in thread hot if 1 is hot */
906 for (n = 0; n < grpmenu.max; n++) {
907 stat_thread(n, &sbuf);
908 if (!sbuf.selected_unread || sbuf.selected_unread == sbuf.unread)
909 continue;
910
912 arts[i].selected = TRUE;
913 }
915 break;
916
917 case GROUP_MARK_UNSELECTED_ARTICLES_READ: /* mark read all unselected arts */
918 if (!xflag) {
920 xflag = TRUE;
921 } else {
923 xflag = FALSE;
924 }
925 break;
926
927 case GROUP_DO_AUTOSELECT: /* perform auto-selection on group */
928 for (n = 0; n < grpmenu.max; n++) {
930 arts[i].selected = TRUE;
931 }
934 break;
935
939 break;
940
941 default:
943 break;
944 } /* switch(ch) */
945 } /* ret_code >= 0 */
946
948
950 grp_del_mail_arts(group);
951
952 art_close(&pgart); /* Close any open art */
953
954 curr_group = NULL;
955
956 return ret_code;
957}
958
959
960void
962 void)
963{
964 int i;
965
967 currmenu = &grpmenu;
968
969 ClearScreen();
972 mark_offset = 0;
974
975 for (i = grpmenu.first; i < grpmenu.first + NOTESLINES && i < grpmenu.max; ++i)
976 build_sline(i);
977
979
980 if (grpmenu.max <= 0) {
982 return;
983 }
984
986}
987
988
989static void
991 void)
992{
993 int i, j;
994#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
995 wchar_t mark[] = { L'\0', L'\0' };
996 wchar_t *wtmp;
997#else
998 char mark[] = { '\0', '\0' };
999#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1000 struct t_art_stat sbuf;
1001
1002 for (i = grpmenu.first; i < grpmenu.first + NOTESLINES && i < grpmenu.max; ++i) {
1003 if ((j = line_is_tagged((int) base[i]))) {
1004#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1005 if ((wtmp = char2wchar_t(tin_ltoa(j, 3)))) {
1006 mark_screen(i, mark_offset - (3 - art_mark_width), wtmp);
1007 free(wtmp);
1008 }
1009#else
1010 mark_screen(i, mark_offset - 2, tin_ltoa(j, 3));
1011#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1012 } else {
1013 stat_thread(i, &sbuf);
1014 mark[0] = sbuf.art_mark;
1015#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1016 mark_screen(i, mark_offset - (3 - art_mark_width), L" "); /* clear space used by tag numbering */
1017 mark_screen(i, mark_offset + (art_mark_width - wcwidth(mark[0])), mark);
1018#else
1019 mark_screen(i, mark_offset - 2, " "); /* clear space used by tag numbering */
1020 mark_screen(i, mark_offset, mark);
1021#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1024 }
1025 }
1026
1027 if (grpmenu.max <= 0)
1028 return;
1029
1031}
1032
1033
1034static void
1036 void)
1037{
1039
1041 struct t_art_stat statbuf;
1042
1043 stat_thread(grpmenu.curr, &statbuf);
1044 info_message("%s", arts[(statbuf.unread ? next_unread((int) base[grpmenu.curr]) : base[grpmenu.curr])].subject);
1045 } else if (grpmenu.curr == grpmenu.max - 1)
1047}
1048
1049
1050void
1052 void)
1053{
1055 CleartoEOS();
1056}
1057
1058
1059/*
1060 * If in show_only_unread_arts mode or there are unread articles we know this
1061 * thread will exist after toggle. Otherwise we find the next closest to
1062 * return to. 'force' can be set to force tin to show all messages
1063 */
1064static void
1066 t_bool force)
1067{
1068 int n, i = -1;
1069
1070 /*
1071 * Clear art->keep_in_base if switching to !show_only_unread_arts
1072 */
1074 for_each_art(n)
1075 arts[n].keep_in_base = FALSE;
1076 }
1077
1078 /* force currently is always false */
1079 if (force)
1080 curr_group->attribute->show_only_unread_arts = TRUE; /* Yes - really, we change it in a bit */
1081
1084
1085 if (grpmenu.curr >= 0) {
1087 i = (int) base[grpmenu.curr];
1088 else if ((n = prev_unread((int) base[grpmenu.curr])) >= 0)
1089 i = n;
1090 else if ((n = next_unread((int) base[grpmenu.curr])) >= 0)
1091 i = n;
1092 }
1093
1094 if (!force)
1096
1098 if (i >= 0 && (n = which_thread(i)) >= 0)
1099 grpmenu.curr = n;
1100 else if (grpmenu.max > 0)
1101 grpmenu.curr = grpmenu.max - 1;
1102 clear_message();
1103}
1104
1105
1106/*
1107 * Find new index position after a kill or unkill. Because kill can work on
1108 * author it is impossible to know which, if any, articles will be left
1109 * afterwards. So we make a "best attempt" to find a new index point.
1110 */
1111static int
1113 long old_artnum,
1114 int cur_pos)
1115{
1116 int i, pos;
1117
1118 if ((i = find_artnum(old_artnum)) >= 0 && (pos = which_thread(i)) >= 0)
1119 return pos;
1120
1121 return ((cur_pos < grpmenu.max) ? cur_pos : (grpmenu.max - 1));
1122}
1123
1124
1125/*
1126 * Set grpmenu.curr to the first unread or the last thread depending on
1127 * the value of pos_first_unread
1128 */
1129void
1131 void)
1132{
1133 int i;
1134
1136 for (i = 0; i < grpmenu.max; i++) {
1137 if (new_responses(i))
1138 break;
1139 }
1140 grpmenu.curr = ((i < grpmenu.max) ? i : (grpmenu.max - 1));
1141 } else
1142 grpmenu.curr = grpmenu.max - 1;
1143}
1144
1145
1146void
1148 int screen_row,
1149 int screen_col,
1150#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1151 const wchar_t *value)
1152#else
1153 const char *value)
1154#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1155{
1156
1157 if (tinrc.draw_arrow) {
1158 MoveCursor(INDEX2LNUM(screen_row), screen_col);
1159#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1160 my_fputws(value, stdout);
1161#else
1162 my_fputs(value, stdout);
1163#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1164 stow_cursor();
1165 my_flush();
1166 } else {
1167#ifdef USE_CURSES
1168# if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1169 char *tmp;
1170# endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1171 int y, x;
1172
1173 getyx(stdscr, y, x);
1174# if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1175 if ((tmp = wchar_t2char(value))) {
1176 mvaddstr(INDEX2LNUM(screen_row), screen_col, tmp);
1177 free(tmp);
1178 }
1179# else
1180 mvaddstr(INDEX2LNUM(screen_row), screen_col, value);
1181# endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1182 MoveCursor(y, x);
1183#else
1184 int i;
1185
1186 for (i = 0; value[i] != '\0'; i++)
1187 screen[INDEX2SNUM(screen_row)].col[screen_col + i] = value[i];
1188
1189 MoveCursor(INDEX2LNUM(screen_row), screen_col);
1190# if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1191 my_fputws(value, stdout);
1192# else
1193 my_fputs(value, stdout);
1194# endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1195#endif /* USE_CURSES */
1197 }
1198}
1199
1200
1201/*
1202 * Builds the correct header for multipart messages when sorting via
1203 * THREAD_MULTI.
1204 */
1205static void
1207 char *dest,
1208 int maxlen,
1209 const char *src,
1210 int cmplen,
1211 int have,
1212 int total)
1213{
1214 const char *mark = (have == total) ? "*" : "-";
1215 char *ss;
1216
1217 if (cmplen > maxlen)
1218 strncpy(dest, src, (size_t) maxlen);
1219 else {
1220 strncpy(dest, src, (size_t) cmplen);
1221 ss = dest + cmplen;
1222 snprintf(ss, (size_t) (maxlen - cmplen), "(%s/%d)", mark, total);
1223 }
1224}
1225
1226
1227/*
1228 * Build subject line given an index into base[].
1229 *
1230 * WARNING: some other code expects to find the article mark (ART_MARK_READ,
1231 * ART_MARK_SELECTED, etc) at mark_offset from beginning of the line.
1232 * So, if you change the format used in this routine, be sure to check that
1233 * the value of mark_offset is still correct.
1234 * Yes, this is somewhat kludgy.
1235 */
1236static void
1238 int i)
1239{
1240 char *fmt, *buf;
1241 char *buffer;
1242 char arts_sub[HEADER_LEN];
1243 char tmp_buf[8];
1244 char tmp[LEN];
1245 int respnum;
1246 int j, k, n;
1247 size_t len;
1248 struct t_art_stat sbuf;
1249 t_bool tagged = FALSE;
1250#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1251 wchar_t *wtmp, *wtmp2;
1252#else
1253 int fill, gap;
1254 size_t len_start;
1255#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1256
1257#ifdef USE_CURSES
1258 /*
1259 * Allocate line buffer
1260 * make it the same size like in !USE_CURSES case to simplify the code
1261 */
1262# if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1263 buffer = my_malloc(cCOLS * MB_CUR_MAX + 2);
1264# else
1265 buffer = my_malloc(cCOLS + 2);
1266# endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1267#else
1268 buffer = screen[INDEX2SNUM(i)].col;
1269#endif /* USE_CURSES */
1270
1271 buffer[0] = '\0';
1272
1273 respnum = (int) base[i];
1274
1275 stat_thread(i, &sbuf);
1276
1277 /*
1278 * Find index of first unread in this thread
1279 */
1280 j = (sbuf.unread) ? next_unread(respnum) : respnum;
1281
1282 fmt = grp_fmt.str;
1283
1284 if (tinrc.draw_arrow)
1285 strcat(buffer, " ");
1286
1287 for (; *fmt; fmt++) {
1288 if (*fmt != '%') {
1289 strncat(buffer, fmt, 1);
1290 continue;
1291 }
1292 switch (*++fmt) {
1293 case '\0':
1294 break;
1295
1296 case '%':
1297 strncat(buffer, fmt, 1);
1298 break;
1299
1300 case 'D': /* date */
1301 buf = my_malloc(LEN);
1302 if (my_strftime(buf, LEN - 1, grp_fmt.date_str, localtime((const time_t *) &arts[j].date))) {
1303#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1304 if ((wtmp = char2wchar_t(buf)) != NULL) {
1305 wtmp2 = wcspart(wtmp, (int) grp_fmt.len_date_max, TRUE);
1306 if (wcstombs(tmp, wtmp2, sizeof(tmp) - 1) != (size_t) -1)
1307 strcat(buffer, tmp);
1308
1309 free(wtmp);
1310 free(wtmp2);
1311 }
1312#else
1313 strncat(buffer, buf, grp_fmt.len_date_max);
1314#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1315 }
1316 free(buf);
1317 break;
1318
1319 case 'F': /* from */
1321#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1322 get_author(FALSE, &arts[j], tmp, sizeof(tmp) - 1);
1323
1324 if ((wtmp = char2wchar_t(tmp)) != NULL) {
1325 wtmp2 = wcspart(wtmp, (int) grp_fmt.len_from, TRUE);
1326 if (wcstombs(tmp, wtmp2, sizeof(tmp) - 1) != (size_t) -1)
1327 strcat(buffer, tmp);
1328
1329 free(wtmp);
1330 free(wtmp2);
1331 }
1332#else
1333 len_start = strwidth(buffer);
1334 get_author(FALSE, &arts[j], buffer + strlen(buffer), grp_fmt.len_from);
1335 fill = grp_fmt.len_from - (strwidth(buffer) - len_start);
1336 gap = strlen(buffer);
1337 for (k = 0; k < fill; k++)
1338 buffer[gap + k] = ' ';
1339 buffer[gap + fill] = '\0';
1340#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1341 }
1342 break;
1343
1344 case 'I': /* initials */
1345 len = MIN(grp_fmt.len_initials, sizeof(tmp) - 1);
1346 get_initials(&arts[j], tmp, (int) len);
1347 strcat(buffer, tmp);
1348 if ((k = (int) (len - (size_t) strwidth(tmp))) > 0) {
1349 buf = buffer + strlen(buffer);
1350 for (; k > 0; --k)
1351 *buf++ = ' ';
1352 *buf = '\0';
1353 }
1354 break;
1355
1356 case 'L': /* lines */
1357 if (arts[j].line_count != -1)
1358 strcat(buffer, tin_ltoa(arts[j].line_count, (int) grp_fmt.len_linecnt));
1359 else {
1360 buf = buffer + strlen(buffer);
1361 for (k = (int) grp_fmt.len_linecnt; k > 1; --k)
1362 *buf++ = ' ';
1363 *buf++ = '?';
1364 *buf = '\0';
1365 }
1366 break;
1367
1368 case 'm': /* article flags, tag number, or whatever */
1369 if (!grp_fmt.mark_offset)
1370 grp_fmt.mark_offset = (size_t) (mark_offset = strwidth(buffer) + 2);
1371 if ((k = line_is_tagged(respnum))) {
1372 STRCPY(tmp_buf, tin_ltoa(k, 3));
1373 strcat(buffer, " ");
1374 tagged = TRUE;
1375 } else
1376#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1377 snprintf(tmp_buf, sizeof(tmp_buf), "%s%lc", art_mark_width > wcwidth(sbuf.art_mark) ? " " : " ", sbuf.art_mark);
1378#else
1379 snprintf(tmp_buf, sizeof(tmp_buf), " %c", sbuf.art_mark);
1380#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1381 strcat(buffer, tmp_buf);
1382 break;
1383
1384 case 'M': /* message-id */
1385 len = MIN(grp_fmt.len_msgid, sizeof(tmp) - 1);
1386 strncpy(tmp, arts[j].refptr ? arts[j].refptr->txt : "", len);
1387 tmp[len] = '\0';
1388 strcat(buffer, tmp);
1389 if ((k = (int) (len - (size_t) strwidth(tmp))) > 0) {
1390 buf = buffer + strlen(buffer);
1391 for (; k > 0; --k)
1392 *buf++ = ' ';
1393 *buf = '\0';
1394 }
1395 break;
1396
1397 case 'n':
1398 strcat(buffer, tin_ltoa(i + 1, (int) grp_fmt.len_linenumber));
1399 break;
1400
1401 case 'R':
1402 n = ((curr_group->attribute->show_only_unread_arts) ? (sbuf.unread + sbuf.seen) : sbuf.total);
1403 if (n > 1)
1404 strcat(buffer, tin_ltoa(n, (int) grp_fmt.len_respcnt));
1405 else {
1406 buf = buffer + strlen(buffer);
1407 for (k = (int) grp_fmt.len_respcnt; k > 0; --k)
1408 *buf++ = ' ';
1409 *buf = '\0';
1410 }
1411 break;
1412
1413 case 'S': /* score */
1414 strcat(buffer, tin_ltoa(sbuf.score, (int) grp_fmt.len_score));
1415 break;
1416
1417 case 's': /* thread/subject */
1419
1420 if (sbuf.multipart_have > 1) /* We have a multipart msg so lets built our new header info. */
1421 build_multipart_header(arts_sub, (int) len, arts[j].subject, sbuf.multipart_compare_len, sbuf.multipart_have, sbuf.multipart_total);
1422 else
1423 STRCPY(arts_sub, arts[j].subject);
1424
1425#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1426 if ((wtmp = char2wchar_t(arts_sub)) != NULL) {
1427 wtmp2 = wcspart(wtmp, (int) len, TRUE);
1428 if (wcstombs(tmp, wtmp2, sizeof(tmp) - 1) != (size_t) -1)
1429 strcat(buffer, tmp);
1430
1431 free(wtmp);
1432 free(wtmp2);
1433 }
1434#else
1435 len_start = strwidth(buffer);
1436 strncat(buffer, arts_sub, len);
1437 fill = len - (strwidth(buffer) - len_start);
1438 gap = strlen(buffer);
1439 for (k = 0; k < fill; k++)
1440 buffer[gap + k] = ' ';
1441 buffer[gap + fill] = '\0';
1442#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1443 break;
1444
1445 default:
1446 break;
1447 }
1448 }
1449 /* protect display from non-displayable characters (e.g., form-feed) */
1450 convert_to_printable(buffer, FALSE);
1451
1452#ifndef USE_CURSES
1453 if (tinrc.strip_blanks)
1454 strcat(strip_line(buffer), cCRLF);
1455#endif /* !USE_CURSES */
1456
1457 WriteLine(INDEX2LNUM(i), buffer);
1458
1459#ifdef USE_CURSES
1460 free(buffer);
1461#endif /* USE_CURSES */
1462 if (!tagged && sbuf.art_mark == tinrc.art_marked_selected)
1464}
1465
1466
1467static void
1469 t_bool clear_title)
1470{
1471 char buf[LEN], tmp[LEN], flag;
1472 int i, art_cnt = 0, recent_art_cnt = 0, selected_art_cnt = 0, read_selected_art_cnt = 0, killed_art_cnt = 0;
1473
1474 for_each_art(i) {
1475 if (arts[i].thread == ART_EXPIRED)
1476 continue;
1477
1479 if (arts[i].status != ART_READ) {
1480 art_cnt++;
1481 if (tinrc.recent_time && ((time((time_t *) 0) - arts[i].date) < (tinrc.recent_time * DAY)))
1482 recent_art_cnt++;
1483 }
1484 if (arts[i].killed == ART_KILLED_UNREAD)
1485 killed_art_cnt++;
1486 } else {
1487 art_cnt++;
1488 if (tinrc.recent_time && ((time((time_t *) 0) - arts[i].date) < (tinrc.recent_time * DAY)))
1489 recent_art_cnt++;
1490
1491 if (arts[i].killed)
1492 killed_art_cnt++;
1493 }
1494 if (arts[i].selected) {
1495 if (arts[i].status != ART_READ)
1496 selected_art_cnt++;
1497 else
1498 read_selected_art_cnt++;
1499 }
1500 }
1501
1502 /*
1503 * build the group title
1504 */
1505 /* group name and thread count */
1506 snprintf(buf, sizeof(buf), "%s (%d%c",
1509
1510 /* article count */
1512 snprintf(tmp, sizeof(tmp), " %d/%d%"T_CHAR_FMT,
1515 else
1516 snprintf(tmp, sizeof(tmp), " %d%"T_CHAR_FMT,
1517 art_cnt,
1519 if (sizeof(buf) > strlen(buf) + strlen(tmp))
1520 strcat(buf, tmp);
1521
1522 /* selected articles */
1524 snprintf(tmp, sizeof(tmp), " %d%"T_CHAR_FMT,
1525 selected_art_cnt, tinrc.art_marked_selected);
1526 else
1527 snprintf(tmp, sizeof(tmp), " %d%"T_CHAR_FMT" %d%"T_CHAR_FMT,
1528 selected_art_cnt, tinrc.art_marked_selected,
1529 read_selected_art_cnt, tinrc.art_marked_read_selected);
1530 if (sizeof(buf) > strlen(buf) + strlen(tmp))
1531 strcat(buf, tmp);
1532
1533 /* recent articles */
1534 if (tinrc.recent_time) {
1535 snprintf(tmp, sizeof(tmp), " %d%"T_CHAR_FMT,
1536 recent_art_cnt, tinrc.art_marked_recent);
1537
1538 if (sizeof(buf) > strlen(buf) + strlen(tmp))
1539 strcat(buf, tmp);
1540 }
1541
1542 /* killed articles */
1543 snprintf(tmp, sizeof(tmp), " %d%"T_CHAR_FMT,
1544 killed_art_cnt, tinrc.art_marked_killed);
1545
1546 if (sizeof(buf) > strlen(buf) + strlen(tmp))
1547 strcat(buf, tmp);
1548
1549 /* group flag */
1550 if ((flag = group_flag(curr_group->moderated)) == ' ')
1551 snprintf(tmp, sizeof(tmp), ")");
1552 else
1553 snprintf(tmp, sizeof(tmp), ") %c", flag);
1554 if (sizeof(buf) > strlen(buf) + strlen(tmp))
1555 strcat(buf, tmp);
1556
1557 if (clear_title) {
1558 MoveCursor(0, 0);
1559 CleartoEOLN();
1560 }
1561 show_title(buf);
1562}
1563
1564
1565/*
1566 * Search for type SUBJ/AUTH in direction (TRUE = forwards)
1567 * Return 0 if all is done, or a >0 thread_depth to enter the thread menu
1568 */
1569static int
1572 t_bool repeat)
1573{
1574 int start, n;
1575
1576 if (grpmenu.curr < 0)
1577 return 0;
1578
1579 /*
1580 * Not intuitive to search current thread in fwd search
1581 */
1583 && grpmenu.curr < grpmenu.max - 1) ? prev_response((int) base[grpmenu.curr + 1]) : (int) base[grpmenu.curr];
1584
1585 if (start >= 0 && ((n = search(func, start, repeat)) != -1)) {
1587
1588 /*
1589 * If the search found something deeper in a thread(not the base art)
1590 * then enter the thread
1591 */
1592 if ((n = which_response(n)) != 0)
1593 return n;
1594
1596 }
1597 return 0;
1598}
1599
1600
1601/*
1602 * We don't directly invoke the pager, but pass through the thread menu
1603 * to keep navigation sane.
1604 * 'art' is the arts[art] we wish to read
1605 * ignore_unavail should be set if we wish to 'keep going' after 'article unavailable'
1606 * Return a -ve ret_code if we must exit the group menu on return
1607 */
1608static int
1610 int art,
1611 t_bool ignore_unavail)
1612{
1613 t_pagerinfo page;
1614
1615 page.art = art;
1616 page.ignore_unavail = CAST_BOOL(ignore_unavail);
1617
1618 return enter_thread(0, &page);
1619}
1620
1621
1622/*
1623 * Handle entry/exit with the thread menu
1624 * Return -ve ret_code if we must exit the group menu on return
1625 */
1626static int
1628 int depth,
1629 t_pagerinfo *page)
1630{
1631 int i, n;
1632
1633 if (grpmenu.curr < 0) {
1635 return 0;
1636 }
1637
1638 forever {
1639 switch (i = thread_page(curr_group, (int) base[grpmenu.curr], depth, page)) {
1640 case GRP_QUIT: /* 'Q'uit */
1641 case GRP_RETSELECT: /* Back to selection screen */
1642 return i;
1643 /* NOTREACHED */
1644 break;
1645
1646 case GRP_NEXT: /* 'c'atchup */
1648 move_down();
1649 return 0;
1650 /* NOTREACHED */
1651 break;
1652
1653 case GRP_NEXTUNREAD: /* 'C'atchup */
1654 if ((n = next_unread((int) base[grpmenu.curr])) >= 0) {
1655 if (page)
1656 page->art = n;
1657 if ((n = which_thread(n)) >= 0) {
1658 grpmenu.curr = n;
1659 depth = 0;
1660 break; /* Drop into next thread with unread */
1661 }
1662 }
1663 /* No more unread threads in this group, enter next group */
1664 grpmenu.curr = 0;
1665 return GRP_NEXTUNREAD;
1666 /* NOTREACHED */
1667 break;
1668
1669 case GRP_KILLED:
1670 grpmenu.curr = 0;
1671 /* FALLTHROUGH */
1672
1673 case GRP_EXIT:
1674 /* case GRP_GOTOTHREAD will never make it up this far */
1675 default: /* ie >= 0 Shouldn't happen any more? */
1678 return 0;
1679 /* NOTREACHED */
1680 break;
1681 }
1682 }
1683 /* NOTREACHED */
1684 return 0;
1685}
1686
1687
1688/*
1689 * Return a ret_code
1690 */
1691static int
1693 void)
1694{
1695 int n;
1696
1697 if ((n = ((grpmenu.curr < 0) ? -1 : next_unread((int) base[grpmenu.curr]))) < 0)
1698 return GRP_NEXTUNREAD; /* => Enter next unread group */
1699
1700 /* We still have unread arts in the current group ... */
1701 return enter_pager(n, TRUE);
1702}
1703
1704
1705/*
1706 * There are three ways this is called
1707 * catchup & return to group menu
1708 * catchup & go to next group with unread articles
1709 * group exit via left arrow if auto-catchup is set
1710 * Return a -ve ret_code if we're done with the group menu
1711 */
1712static int
1715{
1716 char buf[LEN];
1717 int pyn = 1;
1718
1720 return 0;
1721
1723
1724 if (!curr_group->newsrc.num_unread || (!TINRC_CONFIRM_ACTION) || (pyn = prompt_yn(buf, TRUE)) == 1)
1726
1727 switch (func) {
1728 case CATCHUP: /* 'c' */
1729 if (pyn == 1)
1730 return GRP_NEXT;
1731 break;
1732
1733 case CATCHUP_NEXT_UNREAD: /* 'C' */
1734 if (pyn == 1)
1735 return GRP_NEXTUNREAD;
1736 break;
1737
1738 case SPECIAL_CATCHUP_LEFT: /* <- group catchup on exit */
1739 switch (pyn) {
1740 case -1: /* ESCAPE - do nothing */
1741 break;
1742
1743 case 1: /* We caught up - advance group */
1744 return GRP_NEXT;
1745 /* NOTREACHED */
1746 break;
1747
1748 default: /* Just leave the group */
1749 return GRP_EXIT;
1750 /* NOTREACHED */
1751 break;
1752 }
1753 /* FALLTHROUGH */
1754 default: /* Should not be here */
1755 break;
1756 }
1757 return 0; /* Stay in this menu by default */
1758}
1759
1760
1761static t_bool
1763 void)
1764{
1765 char *p;
1766 t_bool ret = FALSE;
1767
1768 clear_message();
1769 if ((p = tin_getline(_(txt_enter_getart_limit), 2, NULL, 0, FALSE, HIST_OTHER)) != NULL) {
1770 tinrc.getart_limit = atoi(p);
1771 ret = TRUE;
1772 }
1773 clear_message();
1774 return ret;
1775}
1776
1777
1778/*
1779 * Redraw all necessary parts of the screen after FEED_MARK_(UN)READ
1780 * Move cursor to next unread item if needed
1781 *
1782 * Returns TRUE when no next unread art, FALSE otherwise
1783 */
1784t_bool
1786 int function,
1787 t_function feed_type,
1788 int respnum)
1789{
1790 int n;
1791
1793 switch (function) {
1794 case (FEED_MARK_READ):
1795 if (feed_type == FEED_THREAD || feed_type == FEED_ARTICLE)
1797 else
1799
1800 if ((n = next_unread(next_response(respnum))) == -1) {
1802 return TRUE;
1803 }
1804
1806 break;
1807
1808 case (FEED_MARK_UNREAD):
1809 if (feed_type == FEED_THREAD || feed_type == FEED_ARTICLE)
1811 else
1813
1815 break;
1816
1817 default:
1818 break;
1819 }
1820 return FALSE;
1821}
unsigned t_bool
Definition: bool.h:77
#define bool_not(b)
Definition: bool.h:81
#define TRUE
Definition: bool.h:74
#define FALSE
Definition: bool.h:70
static t_openartinfo * art
Definition: cook.c:78
#define DEBUG_NEWSRC
Definition: debug.h:50
constext txt_unread[]
Definition: lang.c:916
int this_resp
Definition: page.c:71
constext txt_enter_getart_limit[]
Definition: lang.c:174
@ HIST_OTHER
Definition: extern.h:1558
@ HIST_SELECT_PATTERN
Definition: extern.h:1572
t_function last_search
Definition: init.c:117
constext txt_bad_command[]
Definition: lang.c:112
constext txt_cannot_post[]
Definition: lang.c:130
constext txt_autoselecting_articles[]
Definition: lang.c:108
constext txt_info_all_parts_untagged[]
Definition: lang.c:550
constext txt_catchup_despite_tags[]
Definition: lang.c:139
int NOTESLINES
Definition: signal.c:111
t_openartinfo pgart
Definition: page.c:63
constext txt_quick_filter_kill[]
Definition: lang.c:758
int last_resp
Definition: page.c:70
constext txt_quick_filter_select[]
Definition: lang.c:759
constext txt_enter_next_unread_group[]
Definition: lang.c:178
int tin_errno
Definition: read.c:59
t_menu selmenu
Definition: select.c:84
constext txt_no_prev_group[]
Definition: lang.c:693
struct t_article * arts
Definition: memory.c:69
constext txt_thread_marked_as_selected[]
Definition: lang.c:893
constext txt_end_of_arts[]
Definition: lang.c:166
int art_mark_width
Definition: init.c:118
constext txt_select_pattern[]
Definition: lang.c:852
constext txt_no_last_message[]
Definition: lang.c:686
constext txt_select_art[]
Definition: lang.c:849
constext txt_index_page_com[]
Definition: lang.c:546
constext txt_prefix_untagged[]
Definition: lang.c:748
constext txt_quit_despite_tags[]
Definition: lang.c:762
constext txt_thread_marked_as_deselected[]
Definition: lang.c:892
constext txt_confirm_select_on_exit[]
Definition: lang.c:152
constext txt_all[]
Definition: lang.c:50
constext txt_info_add_kill[]
Definition: lang.c:547
int num_of_tagged_arts
Definition: tags.c:47
constext txt_mark_arts_read[]
Definition: lang.c:633
int filter_file_offset
Definition: filter.c:93
char filter_file[PATH_LEN]
Definition: init.c:89
constext txt_no_arts[]
Definition: lang.c:678
constext txt_reading_arts[]
Definition: lang.c:773
t_bool range_active
Definition: init.c:148
constext txt_info_no_previous_expression[]
Definition: lang.c:557
char cvers[LEN]
Definition: init.c:70
int signal_context
Definition: signal.c:105
constext txt_reading_article[]
Definition: lang.c:772
int mark_offset
Definition: screen.c:48
t_menu * currmenu
Definition: init.c:166
t_artnum * base
Definition: memory.c:65
constext txt_no_prev_search[]
Definition: lang.c:694
constext txt_marked_as_unread[]
Definition: lang.c:629
int cCOLS
Definition: curses.c:53
constext txt_thread_singular[]
Definition: lang.c:897
constext * txt_threading[]
Definition: lang.c:1276
constext txt_base_article_range[]
Definition: lang.c:115
constext txt_info_all_parts_tagged[]
Definition: lang.c:549
t_bool can_post
Definition: nntplib.c:32
constext txt_no_next_unread_art[]
Definition: lang.c:692
constext txt_no_prev_unread_art[]
Definition: lang.c:695
constext txt_select_thread[]
Definition: lang.c:853
constext txt_prefix_tagged[]
Definition: lang.c:747
constext txt_info_add_select[]
Definition: lang.c:548
constext txt_base_article[]
Definition: lang.c:114
struct t_config tinrc
Definition: init.c:192
unsigned short debug
Definition: debug.c:51
constext txt_no_more_groups[]
Definition: lang.c:690
struct t_screen * screen
Definition: screen.c:51
struct t_cmdlineopts cmdline
Definition: init.c:190
static void show_tagged_lines(void)
Definition: group.c:89
static void toggle_read_unread(t_bool force)
Definition: group.c:1065
static t_function group_right(void)
Definition: group.c:124
static int group_catchup(t_function func)
Definition: group.c:1713
static void draw_subject_arrow(void)
Definition: group.c:1035
t_menu grpmenu
Definition: group.c:83
static t_function group_left(void)
Definition: group.c:113
void show_group_page(void)
Definition: group.c:961
static void update_group_page(void)
Definition: group.c:990
static int enter_thread(int depth, t_pagerinfo *page)
Definition: group.c:1627
void pos_first_unread_thread(void)
Definition: group.c:1130
static int find_new_pos(long old_artnum, int cur_pos)
Definition: group.c:1112
static void build_sline(int i)
Definition: group.c:1237
static int tab_pressed(void)
Definition: group.c:1692
static struct t_fmt grp_fmt
Definition: group.c:56
static int enter_pager(int art, t_bool ignore_unavail)
Definition: group.c:1609
void clear_note_area(void)
Definition: group.c:1051
int group_page(struct t_group *group)
Definition: group.c:153
static int ret_code
Definition: group.c:86
void mark_screen(int screen_row, int screen_col, const char *value)
Definition: group.c:1147
static void build_multipart_header(char *dest, int maxlen, const char *src, int cmplen, int have, int total)
Definition: group.c:1206
struct t_group * curr_group
Definition: group.c:55
t_bool group_mark_postprocess(int function, t_function feed_type, int respnum)
Definition: group.c:1785
static int do_search(t_function func, t_bool repeat)
Definition: group.c:1570
static void show_group_title(t_bool clear_title)
Definition: group.c:1468
static t_bool prompt_getart_limit(void)
Definition: group.c:1762
t_function global_mouse_action(t_function(*left_action)(void), t_function(*right_action)(void))
Definition: global.c:321
#define MAXKEYLEN
Definition: keymap.h:136
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
@ GROUP_TAG
Definition: keymap.h:252
@ GROUP_SAVE
Definition: keymap.h:248
@ GROUP_MAIL
Definition: keymap.h:237
@ GLOBAL_SCROLL_UP
Definition: keymap.h:214
@ GROUP_DO_AUTOSELECT
Definition: keymap.h:234
@ GROUP_TOGGLE_READ_UNREAD
Definition: keymap.h:255
@ DIGIT_7
Definition: keymap.h:157
@ GLOBAL_SHELL_ESCAPE
Definition: keymap.h:223
@ GROUP_TAG_PARTS
Definition: keymap.h:253
@ GROUP_MARK_UNSELECTED_ARTICLES_READ
Definition: keymap.h:239
@ GROUP_TOGGLE_GET_ARTICLES_LIMIT
Definition: keymap.h:254
@ DIGIT_3
Definition: keymap.h:153
@ GLOBAL_PAGE_UP
Definition: keymap.h:201
@ GROUP_UNDO_SELECTIONS
Definition: keymap.h:259
@ GLOBAL_SET_RANGE
Definition: keymap.h:221
@ GROUP_PREVIOUS_GROUP
Definition: keymap.h:243
@ GROUP_CANCEL
Definition: keymap.h:233
@ GROUP_NEXT_UNREAD_ARTICLE
Definition: keymap.h:241
@ GROUP_SELECT_THREAD
Definition: keymap.h:250
@ GROUP_TOGGLE_SUBJECT_DISPLAY
Definition: keymap.h:256
@ FEED_ARTICLE
Definition: keymap.h:176
@ DIGIT_6
Definition: keymap.h:156
@ GLOBAL_PIPE
Definition: keymap.h:202
@ GLOBAL_POST
Definition: keymap.h:203
@ GLOBAL_SEARCH_SUBJECT_FORWARD
Definition: keymap.h:220
@ GLOBAL_LINE_DOWN
Definition: keymap.h:194
@ GLOBAL_SCROLL_DOWN
Definition: keymap.h:213
@ GROUP_NEXT_UNREAD_ARTICLE_OR_GROUP
Definition: keymap.h:242
@ GLOBAL_HELP
Definition: keymap.h:191
@ GLOBAL_LOOKUP_MESSAGEID
Definition: keymap.h:196
@ GLOBAL_QUICK_FILTER_SELECT
Definition: keymap.h:209
@ GROUP_MARK_THREAD_READ
Definition: keymap.h:238
@ GROUP_NEXT_GROUP
Definition: keymap.h:240
@ DIGIT_2
Definition: keymap.h:152
@ GLOBAL_PRINT
Definition: keymap.h:206
@ GLOBAL_SEARCH_SUBJECT_BACKWARD
Definition: keymap.h:219
@ MARK_FEED_UNREAD
Definition: keymap.h:264
@ FEED_RANGE
Definition: keymap.h:180
@ GROUP_AUTOSAVE
Definition: keymap.h:232
@ GLOBAL_TOGGLE_INVERSE_VIDEO
Definition: keymap.h:230
@ GLOBAL_TOGGLE_HELP_DISPLAY
Definition: keymap.h:228
@ GLOBAL_VERSION
Definition: keymap.h:231
@ MARK_FEED_READ
Definition: keymap.h:263
@ DIGIT_9
Definition: keymap.h:159
@ FEED_THREAD
Definition: keymap.h:177
@ NOT_ASSIGNED
Definition: keymap.h:149
@ GLOBAL_POSTPONED
Definition: keymap.h:204
@ GLOBAL_SEARCH_AUTHOR_BACKWARD
Definition: keymap.h:217
@ GLOBAL_PAGE_DOWN
Definition: keymap.h:200
@ SPECIAL_CATCHUP_LEFT
Definition: keymap.h:167
@ GROUP_TOGGLE_THREADING
Definition: keymap.h:258
@ GLOBAL_EDIT_FILTER
Definition: keymap.h:189
@ GROUP_REVERSE_SELECTIONS
Definition: keymap.h:247
@ GLOBAL_ABORT
Definition: keymap.h:186
@ GLOBAL_SEARCH_REPEAT
Definition: keymap.h:216
@ GLOBAL_SEARCH_AUTHOR_FORWARD
Definition: keymap.h:218
@ GLOBAL_QUIT
Definition: keymap.h:210
@ GROUP_REPOST
Definition: keymap.h:246
@ GLOBAL_FIRST_PAGE
Definition: keymap.h:190
@ GLOBAL_DISPLAY_POST_HISTORY
Definition: keymap.h:188
@ GLOBAL_REDRAW_SCREEN
Definition: keymap.h:212
@ DIGIT_8
Definition: keymap.h:158
@ GLOBAL_TOGGLE_INFO_LAST_LINE
Definition: keymap.h:229
@ GLOBAL_LAST_PAGE
Definition: keymap.h:192
@ DIGIT_1
Definition: keymap.h:151
@ GROUP_UNTAG
Definition: keymap.h:260
@ GLOBAL_LINE_UP
Definition: keymap.h:195
@ GROUP_TOGGLE_SELECT_THREAD
Definition: keymap.h:257
@ GLOBAL_SEARCH_BODY
Definition: keymap.h:215
@ DIGIT_4
Definition: keymap.h:154
@ GROUP_LIST_THREAD
Definition: keymap.h:236
@ GROUP_GOTO
Definition: keymap.h:235
@ GLOBAL_OPTION_MENU
Definition: keymap.h:199
@ GLOBAL_MENU_FILTER_SELECT
Definition: keymap.h:198
@ GROUP_PREVIOUS_UNREAD_ARTICLE
Definition: keymap.h:244
@ DIGIT_5
Definition: keymap.h:155
@ GLOBAL_QUIT_TIN
Definition: keymap.h:211
@ CATCHUP_NEXT_UNREAD
Definition: keymap.h:170
@ MARK_ARTICLE_UNREAD
Definition: keymap.h:261
@ GROUP_SELECT_PATTERN
Definition: keymap.h:249
@ GLOBAL_MENU_FILTER_KILL
Definition: keymap.h:197
@ GROUP_READ_BASENOTE
Definition: keymap.h:245
@ MARK_THREAD_UNREAD
Definition: keymap.h:262
@ GLOBAL_QUICK_FILTER_KILL
Definition: keymap.h:208
@ CATCHUP
Definition: keymap.h:169
@ GLOBAL_BUGREPORT
Definition: keymap.h:187
@ GLOBAL_LAST_VIEWED
Definition: keymap.h:193
@ GROUP_SELECT_THREAD_IF_UNREAD_SELECTED
Definition: keymap.h:251
struct keylist group_keys
Definition: keymap.c:67
char func_to_key(t_function func, const struct keylist keys)
Definition: keymap.c:125
enum defined_functions t_function
Definition: keymap.h:375
#define PrintFuncKey(buf, func, keys)
Definition: keymap.h:445
static char buf[16]
Definition: langinfo.c:50
void scroll_down(void)
Definition: global.c:252
void move_to_item(int n)
Definition: global.c:227
void grp_mark_read(struct t_group *group, struct t_article *art)
Definition: newsrc.c:724
void page_up(void)
Definition: global.c:130
void prompt_item_num(int ch, const char *prompt)
Definition: global.c:200
void draw_arrow_mark(int line)
Definition: screen.c:352
t_bool pickup_postponed_articles(t_bool ask, t_bool all)
Definition: post.c:2904
void show_mini_help(int level)
Definition: help.c:798
void make_threads(struct t_group *group, t_bool rethread)
Definition: art.c:1229
void grp_del_mail_arts(struct t_group *group)
Definition: mail.c:604
t_bool filter_articles(struct t_group *group)
Definition: filter.c:1843
int choose_new_group(void)
Definition: select.c:1012
int tag_multipart(int arts_index)
Definition: tags.c:57
void find_base(struct t_group *group)
Definition: art.c:123
char * prompt_string_default(const char *prompt, char *def, const char *failtext, int history)
Definition: prompt.c:587
t_bool read_filter_file(const char *file)
Definition: filter.c:308
int find_artnum(t_artnum art)
Definition: art.c:3223
void show_help_page(const int level, const char *title)
Definition: help.c:734
int atoi(const char *s)
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
int get_initials(struct t_article *art, char *s, int maxsize)
Definition: misc.c:1993
size_t my_strftime(char *s, size_t maxsize, const char *format, struct tm *timeptr)
Definition: strftime.c:64
t_bool index_group(struct t_group *group)
Definition: art.c:396
t_bool set_range(int level, int min, int max, int curr)
Definition: tags.c:214
void error_message(unsigned int sdelay, const char *fmt,...)
Definition: screen.c:224
void art_mark(struct t_group *group, struct t_article *art, int flag)
Definition: newsrc.c:1611
void parse_format_string(const char *fmtstr, struct t_fmt *fmt)
Definition: string.c:1437
int which_response(int n)
Definition: thread.c:1099
void get_author(t_bool thread, struct t_article *art, char *str, size_t len)
Definition: misc.c:1011
char * strip_line(char *line)
Definition: misc.c:3644
void ClearScreen(void)
Definition: curses.c:410
void do_shell_escape(void)
Definition: misc.c:547
void set_xclick_on(void)
Definition: curses.c:691
void scroll_up(void)
Definition: global.c:278
void config_page(const char *grpname, enum context level)
Definition: options_menu.c:939
t_bool filter_menu(t_function type, struct t_group *group, struct t_article *art)
Definition: filter.c:1061
char group_flag(char ch)
Definition: active.c:1247
void info_message(const char *fmt,...)
Definition: screen.c:102
void toggle_inverse_video(void)
Definition: misc.c:1050
int prev_unread(int n)
Definition: thread.c:1393
int feed_articles(int function, int level, t_function type, struct t_group *group, int respnum)
Definition: feed.c:566
char * convert_to_printable(char *buf, t_bool keep_tab)
Definition: charset.c:394
void show_inverse_video_status(void)
Definition: misc.c:1065
int prompt_msgid(void)
Definition: prompt.c:621
t_bool match_regex(const char *string, char *pattern, struct regex_cache *cache, t_bool icase)
Definition: regex.c:59
void toggle_mini_help(int level)
Definition: help.c:1078
int stat_thread(int n, struct t_art_stat *sbuf)
Definition: thread.c:1192
void draw_mark_selected(int i)
Definition: misc.c:4179
int new_responses(int thread)
Definition: thread.c:1045
int prev_response(int n)
Definition: thread.c:1321
t_bool invoke_editor(const char *filename, int lineno, struct t_group *group)
Definition: misc.c:377
void MoveCursor(int row, int col)
Definition: curses.c:441
void art_close(t_openartinfo *artinfo)
Definition: rfc2046.c:1623
void untag_article(long art)
Definition: tags.c:159
t_bool untag_all_articles(void)
Definition: tags.c:179
t_bool post_hist_page(void)
Definition: post.c:519
void do_auto_select_arts(void)
Definition: tags.c:382
void page_down(void)
Definition: global.c:155
void move_up(void)
Definition: global.c:81
void set_xclick_off(void)
Definition: curses.c:703
void move_down(void)
Definition: global.c:110
void clear_message(void)
Definition: screen.c:283
int next_response(int n)
Definition: thread.c:1280
int line_is_tagged(int n)
Definition: tags.c:115
int search_body(struct t_group *group, int current_art, t_bool repeat)
Definition: search.c:722
int which_thread(int n)
Definition: thread.c:1073
int strwidth(const char *str)
Definition: string.c:1050
void set_first_screen_item(void)
Definition: global.c:61
void end_of_list(void)
Definition: global.c:191
void wait_message(unsigned int sdelay, const char *fmt,...)
Definition: screen.c:133
void unfilter_articles(struct t_group *group)
Definition: filter.c:1818
t_bool post_article(const char *groupname)
Definition: post.c:2994
void stow_cursor(void)
Definition: screen.c:59
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:1566
int search(t_function func, int current_art, t_bool repeat)
Definition: search.c:564
t_bool cancel_article(struct t_group *group, struct t_article *art, int respnum)
Definition: post.c:4222
t_bool compile_regex(const char *regex, struct regex_cache *cache, int options)
Definition: regex.c:111
void CleartoEOS(void)
Definition: curses.c:470
void undo_auto_select_arts(void)
Definition: tags.c:409
void show_title(const char *title)
Definition: screen.c:457
void top_of_list(void)
Definition: global.c:182
int next_unread(int n)
Definition: thread.c:1363
int thread_page(struct t_group *group, int respnum, int thread_depth, t_pagerinfo *page)
Definition: thread.c:446
int prompt_yn(const char *prompt, t_bool default_answer)
Definition: prompt.c:165
void CleartoEOLN(void)
Definition: curses.c:458
char * fmt_string(const char *fmt,...)
Definition: string.c:1386
void undo_selections(void)
Definition: tags.c:433
char * tin_ltoa(t_artnum value, int digits)
Definition: string.c:80
void bug_report(void)
Definition: global.c:430
t_bool quick_filter(t_function type, struct t_group *group, struct t_article *art)
Definition: filter.c:1496
void(* func)(SIG_ARGS)
Definition: signal.c:176
pcre_extra * extra
Definition: tin.h:1963
pcre * re
Definition: tin.h:1962
int multipart_total
Definition: tin.h:2003
int score
Definition: tin.h:2002
int selected_unread
Definition: tin.h:1999
time_t time
Definition: tin.h:2006
char art_mark
Definition: tin.h:1991
int killed
Definition: tin.h:2001
int unread
Definition: tin.h:1994
int total
Definition: tin.h:1993
int multipart_compare_len
Definition: tin.h:2005
int seen
Definition: tin.h:1995
int multipart_have
Definition: tin.h:2004
Definition: tin.h:1533
char * subject
Definition: tin.h:1535
int thread
Definition: tin.h:1548
t_bool inrange
Definition: tin.h:1556
t_bool keep_in_base
Definition: tin.h:1558
t_artnum artnum
Definition: tin.h:1534
t_bool selected
Definition: tin.h:1555
int tagged
Definition: tin.h:1547
char * group_format
Definition: tin.h:1617
unsigned thread_articles
Definition: tin.h:1677
unsigned group_catchup_on_exit
Definition: tin.h:1660
unsigned auto_list_thread
Definition: tin.h:1656
char * mailing_list
Definition: tin.h:1626
unsigned auto_select
Definition: tin.h:1657
unsigned mark_ignore_tags
Definition: tin.h:1663
unsigned show_author
Definition: tin.h:1680
unsigned pos_first_unread
Definition: tin.h:1665
unsigned show_only_unread_arts
Definition: tin.h:1674
unsigned int args
Definition: tin.h:1503
int getart_limit
Definition: tin.h:1499
t_bool strip_blanks
Definition: tinrc.h:249
t_bool draw_arrow
Definition: tinrc.h:223
char art_marked_selected
Definition: tinrc.h:73
char art_marked_recent
Definition: tinrc.h:74
char art_marked_unread
Definition: tinrc.h:75
char art_marked_read
Definition: tinrc.h:76
char art_marked_killed
Definition: tinrc.h:77
int wildcard
Definition: tinrc.h:167
char art_marked_read_selected
Definition: tinrc.h:78
int recent_time
Definition: tinrc.h:148
char default_select_pattern[LEN]
Definition: tinrc.h:103
t_bool info_in_last_line
Definition: tinrc.h:226
int getart_limit
Definition: tinrc.h:147
Definition: tin.h:1853
size_t len_msgid
Definition: tin.h:1866
size_t len_from
Definition: tin.h:1859
size_t len_linenumber
Definition: tin.h:1864
size_t len_linecnt
Definition: tin.h:1865
size_t len_respcnt
Definition: tin.h:1867
size_t len_initials
Definition: tin.h:1863
char str[1024]
Definition: tin.h:1854
size_t len_score
Definition: tin.h:1868
size_t len_subj
Definition: tin.h:1869
size_t mark_offset
Definition: tin.h:1872
size_t len_date_max
Definition: tin.h:1857
char date_str[1024]
Definition: tin.h:1855
Definition: tin.h:1816
char moderated
Definition: tin.h:1821
t_bool read_during_session
Definition: tin.h:1827
struct t_attribute * attribute
Definition: tin.h:1834
char * name
Definition: tin.h:1817
struct t_newsrc newsrc
Definition: tin.h:1833
Definition: tin.h:2055
int curr
Definition: tin.h:2056
void(* draw_arrow)(void)
Definition: tin.h:2060
int first
Definition: tin.h:2058
int max
Definition: tin.h:2057
t_artnum num_unread
Definition: tin.h:1806
int art
Definition: tin.h:2069
t_bool ignore_unavail
Definition: tin.h:2070
char * col
Definition: tin.h:1974
#define my_flush()
Definition: tcurses.h:177
#define cCRLF
Definition: tcurses.h:156
#define WriteLine(row, buffer)
Definition: tcurses.h:180
#define my_fputs(str, stream)
Definition: tcurses.h:159
#define my_retouch()
Definition: tcurses.h:179
#define TINRC_CONFIRM_ACTION
Definition: tin.h:958
#define STRCMPEQ(s1, s2)
Definition: tin.h:822
#define LEN
Definition: tin.h:860
long t_artnum
Definition: tin.h:229
#define THREAD_NONE
Definition: tin.h:1139
@ cGroup
Definition: tin.h:107
#define ART_KILLED_UNREAD
Definition: tin.h:1355
#define FEED_PIPE
Definition: tin.h:1127
#define STRCPY(dst, src)
Definition: tin.h:820
#define MIN(a, b)
Definition: tin.h:811
#define FEED_AUTOSAVE
Definition: tin.h:1130
#define THREAD_MAX
Definition: tin.h:1146
#define GROUP_LEVEL
Definition: tin.h:1113
#define for_each_art(x)
Definition: tin.h:2260
#define FEED_SAVE
Definition: tin.h:1129
#define CAST_BOOL(value)
Definition: tin.h:1588
#define DAY
Definition: tin.h:870
#define INDEX2LNUM(i)
Definition: tin.h:1020
#define TINRC_CONFIRM_SELECT
Definition: tin.h:960
#define FEED_PRINT
Definition: tin.h:1128
#define my_malloc(size)
Definition: tin.h:2245
#define HAS_FOLLOWUPS(i)
Definition: tin.h:1040
#define FreeIfNeeded(p)
Definition: tin.h:2252
#define INDEX2SNUM(i)
Definition: tin.h:1022
#define FEED_REPOST
Definition: tin.h:1131
#define SHOW_FROM_NONE
Definition: tin.h:1153
#define ART_ABORT
Definition: tin.h:1360
#define REGEX_FMT
Definition: tin.h:1027
#define _(Text)
Definition: tin.h:94
#define forever
Definition: tin.h:816
#define CMDLINE_GETART_LIMIT
Definition: tin.h:1102
#define for_each_art_in_thread(x, y)
Definition: tin.h:2261
#define FEED_MARK_UNREAD
Definition: tin.h:1133
#define snprintf
Definition: tin.h:2464
#define FreeAndNull(p)
Definition: tin.h:2253
#define T_ARTNUM_CONST(v)
Definition: tin.h:232
#define ART_EXPIRED
Definition: tin.h:1335
#define ART_WILL_RETURN
Definition: tin.h:1347
#define UNREAD_GROUP(i)
Definition: tin.h:1059
#define HEADER_LEN
Definition: tin.h:863
#define INDEX_TOP
Definition: tin.h:1019
#define CAST_BITS(value, bits)
Definition: tin.h:1589
#define FEED_MAIL
Definition: tin.h:1126
#define ART_READ
Definition: tin.h:1345
#define T_CHAR_FMT
Definition: tin.h:884
#define FEED_MARK_READ
Definition: tin.h:1132
@ GRP_EXIT
Definition: tin.h:1294
@ GRP_NEXTUNREAD
Definition: tin.h:1287
@ GRP_NEXT
Definition: tin.h:1288
@ GRP_RETSELECT
Definition: tin.h:1285
@ GRP_QUIT
Definition: tin.h:1286
@ GRP_KILLED
Definition: tin.h:1291
@ GRP_ENTER
Definition: tin.h:1293
#define assert(p)
Definition: tin.h:1320
#define ART_UNAVAILABLE
Definition: tin.h:1348
#define SHOW_FROM_BOTH
Definition: tin.h:1156