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)  

thread.c
Go to the documentation of this file.
1 /*
2  * Project : tin - a Usenet reader
3  * Module : thread.c
4  * Author : I. Lea
5  * Created : 1991-04-01
6  * Updated : 2017-03-28
7  * Notes :
8  *
9  * Copyright (c) 1991-2020 Iain Lea <iain@bricbrac.de>
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 #define IS_EXPIRED(a) ((a)->article == ART_UNAVAILABLE || arts[(a)->article].thread == ART_EXPIRED)
50 
51 int thread_basenote = 0; /* Index in base[] of basenote */
52 static int thread_respnum = 0; /* Index in arts[] of basenote ie base[thread_basenote] */
53 static struct t_fmt thrd_fmt;
55 
56 /*
57  * Local prototypes
58  */
59 static char get_art_mark(struct t_article *art);
60 static int enter_pager(int art, t_bool ignore_unavail, int level);
61 static int thread_catchup(t_function func, struct t_group *group);
62 static int thread_tab_pressed(void);
63 static t_bool find_unexpired(struct t_msgid *ptr);
64 static t_bool has_sibling(struct t_msgid *ptr);
65 static t_function thread_left(void);
66 static t_function thread_right(void);
67 static void build_tline(int l, struct t_article *art);
68 static void draw_thread_arrow(void);
69 static void draw_thread_item(int item);
70 static void make_prefix(struct t_msgid *art, char *prefix, int maxlen);
71 static void show_thread_page(void);
72 static void update_thread_page(void);
73 
74 
75 /*
76  * thdmenu.curr Current screen cursor position in thread
77  * thdmenu.max Essentially = # threaded arts in current thread
78  * thdmenu.first Response # at top of screen
79  */
81 
82 /* TODO: find a better solution */
83 static int ret_code = 0; /* Set to < 0 when it is time to leave this menu */
84 
85 /*
86  * returns the mark which should be used for this article
87  */
88 static char
90  struct t_article *art)
91 {
92  if (art->inrange) {
94  } else if (art->status == ART_UNREAD) {
95  return (art->selected ? tinrc.art_marked_selected : (tinrc.recent_time && ((time((time_t *) 0) - art->date) < (tinrc.recent_time * DAY))) ? tinrc.art_marked_recent : tinrc.art_marked_unread);
96  } else if (art->status == ART_WILL_RETURN) {
97  return tinrc.art_marked_return;
98  } else if (art->killed && tinrc.kill_level != KILL_NOTHREAD) {
99  return tinrc.art_marked_killed;
100  } else {
101  if (/* tinrc.kill_level != KILL_UNREAD && */ art->score >= tinrc.score_select)
102  return tinrc.art_marked_read_selected; /* read hot chil^H^H^H^H article */
103  else
104  return tinrc.art_marked_read;
105  }
106 }
107 
108 
109 /*
110  * Build one line of the thread page display. Looks long winded, but
111  * there are a lot of variables in the format for the output
112  *
113  * WARNING: some other code expects to find the article mark (ART_MARK_READ,
114  * ART_MARK_SELECTED, etc) at mark_offset from beginning of the line.
115  * So, if you change the format used in this routine, be sure to check that
116  * the value of mark_offset is still correct.
117  * Yes, this is somewhat kludgy.
118  */
119 static void
121  int l,
122  struct t_article *art)
123 {
124  char mark = '\0';
125  int gap, fill, i;
126  size_t len, len_start, len_end;
127  struct t_msgid *ptr;
128  char *buffer, *buf;
129  char *fmt = thrd_fmt.str;
130  char tmp[LEN];
131 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
132  wchar_t *wtmp, *wtmp2;
133 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
134 
135 #ifdef USE_CURSES
136  /*
137  * Allocate line buffer
138  * make it the same size like in !USE_CURSES case to simplify some code
139  */
140 # if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
141  buffer = my_malloc(cCOLS * MB_CUR_MAX + 2);
142 # else
143  buffer = my_malloc(cCOLS + 2);
144 # endif /* MULTIBYTE_ABLE && !NO_LOCALE */
145 #else
146  buffer = screen[INDEX2SNUM(l)].col;
147 #endif /* USE_CURSES */
148 
149  buffer[0] = '\0';
150 
151  if (tinrc.draw_arrow)
152  strcat(buffer, " ");
153 
154  for (; *fmt; fmt++) {
155  if (*fmt != '%') {
156  strncat(buffer, fmt, 1);
157  continue;
158  }
159  switch (*++fmt) {
160  case '\0':
161  break;
162 
163  case '%':
164  strncat(buffer, fmt, 1);
165  break;
166 
167  case 'D': /* date */
168  buf = my_malloc(LEN);
169  if (my_strftime(buf, LEN - 1, thrd_fmt.date_str, localtime(&art->date))) {
170 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
171  if ((wtmp = char2wchar_t(buf)) != NULL) {
172  wtmp2 = wcspart(wtmp, thrd_fmt.len_date_max, TRUE);
173  if (wcstombs(tmp, wtmp2, sizeof(tmp) - 1) != (size_t) -1)
174  strcat(buffer, tmp);
175 
176  free(wtmp);
177  free(wtmp2);
178  }
179 #else
180  strncat(buffer, buf, thrd_fmt.len_date_max);
181 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
182  }
183  free(buf);
184  break;
185 
186  case 'F': /* from */
187 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
188  get_author(TRUE, art, tmp, sizeof(tmp) - 1);
189 
190  if ((wtmp = char2wchar_t(tmp)) != NULL) {
191  wtmp2 = wcspart(wtmp, thrd_fmt.len_from, TRUE);
192  if (wcstombs(tmp, wtmp2, sizeof(tmp) - 1) != (size_t) -1)
193  strcat(buffer, tmp);
194 
195  free(wtmp);
196  free(wtmp2);
197  }
198 #else
200  len_start = strwidth(buffer);
202  fill = thrd_fmt.len_from - (strwidth(buffer) - len_start);
203  gap = strlen(buffer);
204  for (i = 0; i < fill; i++)
205  buffer[gap + i] = ' ';
206  buffer[gap + fill] = '\0';
207  }
208 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
209  break;
210 
211  case 'I': /* initials */
212  len = MIN(thrd_fmt.len_initials, sizeof(tmp) - 1);
213  get_initials(art, tmp, len);
214  strcat(buffer, tmp);
215  if ((i = len - strwidth(tmp)) > 0) {
216  buf = buffer + strlen(buffer);
217  for (; i > 0; --i)
218  *buf++ = ' ';
219  *buf = '\0';
220  }
221  break;
222 
223  case 'L': /* lines */
224  if (art->line_count != -1)
225  strcat(buffer, tin_ltoa(art->line_count, thrd_fmt.len_linecnt));
226  else {
227  buf = buffer + strlen(buffer);
228  for (i = thrd_fmt.len_linecnt; i > 1; --i)
229  *buf++ = ' ';
230  *buf++ = '?';
231  *buf = '\0';
232  }
233  break;
234 
235  case 'm': /* article flags, tag number, or whatever */
236  if (!thrd_fmt.mark_offset)
238  if (art->tagged) {
239  strcat(buffer, tin_ltoa(art->tagged, 3));
240  mark = '\0';
241  } else {
242  strcat(buffer, " ");
243  mark = get_art_mark(art);
244  buffer[strlen(buffer) - 1] = mark; /* insert mark */
245  }
246  break;
247 
248  case 'M': /* message-id */
249  len = MIN(thrd_fmt.len_msgid, sizeof(tmp) - 1);
250  strncpy(tmp, art->refptr ? art->refptr->txt : "", len);
251  tmp[len] = '\0';
252  strcat(buffer, tmp);
253  if ((i = len - strwidth(tmp)) > 0) {
254  buf = buffer + strlen(buffer);
255  for (; i > 0; --i)
256  *buf++ = ' ';
257  *buf = '\0';
258  }
259  break;
260 
261  case 'n':
262  strcat(buffer, tin_ltoa(l + 1, thrd_fmt.len_linenumber));
263  break;
264 
265  case 'S': /* score */
266  strcat(buffer, tin_ltoa(art->score, thrd_fmt.len_score));
267  break;
268 
269  case 'T': /* thread/subject */
271  len_start = strwidth(buffer);
272 
274  case THREAD_REFS:
275  case THREAD_BOTH:
276  /*
277  * Mutt-like thread tree. by sjpark@sparcs.kaist.ac.kr
278  * Insert tree-structure strings "`->", "+->", ...
279  */
280 
281  if (art->refptr) {
282  make_prefix(art->refptr, buffer + strlen(buffer), len);
283 
284  len_end = strwidth(buffer);
285 
286  /*
287  * Copy in the subject up to where the author (if any) starts
288  */
289  gap = len - (len_end - len_start);
290 
291  /*
292  * Mutt-like thread tree. by sjpark@sparcs.kaist.ac.kr
293  * Hide subject if same as parent's.
294  */
295  if (gap > 0) {
296  for (ptr = art->refptr->parent; ptr && IS_EXPIRED(ptr); ptr = ptr->parent)
297  ;
298  if (!(ptr && arts[ptr->article].subject == art->subject))
299 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
300  {
301  if ((wtmp = char2wchar_t(art->subject)) != NULL) {
302  wtmp2 = wcspart(wtmp, gap, TRUE);
303  if (wcstombs(tmp, wtmp2, sizeof(tmp) - 1) != (size_t) -1)
304  strcat(buffer, tmp);
305 
306  free(wtmp);
307  free(wtmp2);
308  }
309  }
310 #else
311  {
312  strncat(buffer, art->subject, gap);
313  }
314  buffer[len_end + gap] = '\0'; /* Just in case */
315 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
316  }
317  }
318  break;
319 
320  case THREAD_NONE:
321  case THREAD_SUBJ:
322  case THREAD_MULTI:
323  case THREAD_PERC:
324  len_end = strwidth(buffer);
325  gap = len - (len_end - len_start);
326  if (gap > 0) {
327 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
328  {
329  if ((wtmp = char2wchar_t(art->subject)) != NULL) {
330  wtmp2 = wcspart(wtmp, gap, TRUE);
331  if (wcstombs(tmp, wtmp2, sizeof(tmp) - 1) != (size_t) -1)
332  strcat(buffer, tmp);
333 
334  free(wtmp);
335  free(wtmp2);
336  }
337  }
338 #else
339  {
340  strncat(buffer, art->subject, gap);
341  }
342  buffer[len_end + gap] = '\0'; /* Just in case */
343 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
344  }
345  break;
346 
347  default:
348  break;
349  }
350 
351  /* pad out */
352  fill = len - (strwidth(buffer) - len_start);
353  gap = strlen(buffer);
354  for (i = 0; i < fill; i++)
355  buffer[gap + i] = ' ';
356  buffer[gap + fill] = '\0';
357  break;
358 
359  default:
360  break;
361  }
362  }
363  /* protect display from non-displayable characters (e.g., form-feed) */
365 
366 #ifndef USE_CURSES
367  if (tinrc.strip_blanks)
368  strcat(strip_line(buffer), cCRLF);
369 #endif /* !USE_CURSES */
370 
372 
373 #ifdef USE_CURSES
374  free(buffer);
375 #endif /* USE_CURSES */
376 
377  if (mark == tinrc.art_marked_selected)
379 }
380 
381 
382 static void
384  int item)
385 {
387 }
388 
389 
390 static t_function
392  void)
393 {
395  return SPECIAL_CATCHUP_LEFT; /* ie, not via 'c' or 'C' */
396  else
397  return GLOBAL_QUIT;
398 }
399 
400 
401 static t_function
403  void)
404 {
405  return THREAD_READ_ARTICLE;
406 }
407 
408 
409 /*
410  * Show current thread.
411  * If threaded on Subject: show
412  * <respnum> <name>
413  * If threaded on References: or Archive-name: show
414  * <respnum> <subject> <name>
415  * Return values:
416  * GRP_RETSELECT Return to selection screen
417  * GRP_QUIT 'Q'uit all the way out
418  * GRP_NEXT Catchup goto next group
419  * GRP_NEXTUNREAD Catchup enter next unread thread
420  * GRP_KILLED Thread was killed at art level?
421  * GRP_EXIT Return to group menu
422  */
423 int
425  struct t_group *group,
426  int respnum, /* base[] article of thread to view */
427  int thread_depth, /* initial depth in thread */
428  t_pagerinfo *page) /* !NULL if we must go direct to the pager */
429 {
430  char key[MAXKEYLEN];
431  char mark[] = { '\0', '\0' };
432  int i, n;
433  t_artnum old_artnum = T_ARTNUM_CONST(0);
434  t_bool repeat_search;
435  t_function func;
436 
437  thread_respnum = respnum; /* Bodge to make this variable global */
438 
439  if ((n = which_thread(thread_respnum)) >= 0)
440  thread_basenote = n;
441  if ((thdmenu.max = num_of_responses(thread_basenote) + 1) <= 0) {
443  return GRP_EXIT;
444  }
445 
446  /*
447  * Set the cursor to the last response unless pos_first_unread is on
448  * or an explicit thread_depth has been specified
449  */
451  /* reset the first item on screen to 0 */
452  thdmenu.first = 0;
453 
454  if (thread_depth)
455  thdmenu.curr = thread_depth;
456  else {
457  if (group->attribute->pos_first_unread) {
459  for (n = 0, i = (int) base[thread_basenote]; i >= 0; i = arts[i].thread, n++) {
460  if (arts[i].status == ART_UNREAD || arts[i].status == ART_WILL_RETURN) {
461  if (arts[i].thread == ART_EXPIRED)
462  art_mark(group, &arts[i], ART_READ);
463  else
464  thdmenu.curr = n;
465  break;
466  }
467  }
468  }
469  }
470  }
471 
472  if (thdmenu.curr < 0)
473  thdmenu.curr = 0;
474 
475  /*
476  * See if we're on a direct call from the group menu to the pager
477  */
478  if (page) {
479  if ((ret_code = enter_pager(page->art, page->ignore_unavail, GROUP_LEVEL)) != 0)
480  return ret_code;
481  /* else fall through to stay in thread level */
482  }
483 
484  /* Now we know where the cursor is, actually put something on the screen */
486 
487  /* reset ret_code */
488  ret_code = 0;
489  while (ret_code >= 0) {
490  set_xclick_on();
492  func = last_search;
493  repeat_search = TRUE;
494  } else
495  repeat_search = FALSE;
496 
497  switch (func) {
498  case GLOBAL_ABORT: /* Abort */
499  break;
500 
501  case DIGIT_1:
502  case DIGIT_2:
503  case DIGIT_3:
504  case DIGIT_4:
505  case DIGIT_5:
506  case DIGIT_6:
507  case DIGIT_7:
508  case DIGIT_8:
509  case DIGIT_9:
510  if (thdmenu.max == 1)
512  else
514  break;
515 
516 #ifndef NO_SHELL_ESCAPE
517  case GLOBAL_SHELL_ESCAPE:
518  do_shell_escape();
519  break;
520 #endif /* !NO_SHELL_ESCAPE */
521 
522  case GLOBAL_FIRST_PAGE: /* show first page of articles */
523  top_of_list();
524  break;
525 
526  case GLOBAL_LAST_PAGE: /* show last page of articles */
527  end_of_list();
528  break;
529 
530  case GLOBAL_LAST_VIEWED: /* show last viewed article */
531  if (this_resp < 0 || (which_thread(this_resp) == -1)) {
533  break;
534  }
536  break;
537 
538  case GLOBAL_SET_RANGE: /* set range */
539  if (set_range(THREAD_LEVEL, 1, thdmenu.max, thdmenu.curr + 1)) {
540  range_active = TRUE;
542  }
543  break;
544 
545  case GLOBAL_PIPE: /* pipe article(s) to command */
546  if (thread_basenote >= 0)
548  break;
549 
550 #ifndef DISABLE_PRINTING
551  case GLOBAL_PRINT: /* print article(s) */
552  if (thread_basenote >= 0)
554  break;
555 #endif /* !DISABLE_PRINTING */
556 
557  case THREAD_MAIL: /* mail article(s) to somebody */
558  if (thread_basenote >= 0)
560  break;
561 
562  case THREAD_SAVE: /* save articles with prompting */
563  if (thread_basenote >= 0)
565  break;
566 
567  case THREAD_AUTOSAVE: /* Auto-save articles without prompting */
568  if (thread_basenote >= 0)
570  break;
571 
572  case MARK_FEED_READ: /* mark selected articles as read */
573  if (thread_basenote >= 0)
575  break;
576 
577  case MARK_FEED_UNREAD: /* mark selected articles as unread */
578  if (thread_basenote >= 0)
580  break;
581 
585  if (filter_menu(func, group, &arts[n])) {
586  old_artnum = arts[n].artnum;
587  unfilter_articles(group);
588  filter_articles(group);
589  make_threads(group, FALSE);
590  if ((n = find_artnum(old_artnum)) == -1 || which_thread(n) == -1) { /* We have lost the thread */
592  break;
593  }
594  fixup_thread(n, TRUE);
595  }
597  break;
598 
599  case GLOBAL_EDIT_FILTER:
602  unfilter_articles(group);
604  filter_articles(group);
605  make_threads(group, FALSE);
606  if ((n = find_artnum(old_artnum)) == -1 || which_thread(n) == -1) { /* We have lost the thread */
608  break;
609  }
610  fixup_thread(n, TRUE);
611  }
613  break;
614 
615  case THREAD_READ_ARTICLE: /* read current article within thread */
617  break;
618 
621  break;
622 
623  case THREAD_CANCEL: /* cancel current article */
624  if (can_post || group->attribute->mailing_list != NULL) {
625  int ret;
626 
628  ret = art_open(TRUE, &arts[n], group, &pgart, TRUE, _(txt_reading_article));
629  if (ret != ART_UNAVAILABLE && ret != ART_ABORT && cancel_article(group, &arts[n], n))
631  art_close(&pgart);
632  } else
634  break;
635 
636  case GLOBAL_POST: /* post a basenote */
637  if (post_article(group->name))
639  break;
640 
641  case GLOBAL_REDRAW_SCREEN: /* redraw screen */
642  my_retouch();
643  set_xclick_off();
645  break;
646 
647  case GLOBAL_LINE_DOWN:
648  move_down();
649  break;
650 
651  case GLOBAL_LINE_UP:
652  move_up();
653  break;
654 
655  case GLOBAL_PAGE_UP:
656  page_up();
657  break;
658 
659  case GLOBAL_PAGE_DOWN:
660  page_down();
661  break;
662 
663  case GLOBAL_SCROLL_DOWN:
664  scroll_down();
665  break;
666 
667  case GLOBAL_SCROLL_UP:
668  scroll_up();
669  break;
670 
671  case SPECIAL_CATCHUP_LEFT: /* come here when exiting thread via <- */
672  case CATCHUP: /* catchup thread, move to next one */
673  case CATCHUP_NEXT_UNREAD: /* -> next with unread arts */
674  ret_code = thread_catchup(func, group);
675  break;
676 
677  case THREAD_MARK_ARTICLE_READ: /* mark current article/range/tagged articles as read */
678  case MARK_ARTICLE_UNREAD: /* or unread */
679  if (thread_basenote >= 0) {
680  t_function function, type;
681 
684  if (feed_articles(function, THREAD_LEVEL, type, group, find_response(thread_basenote, thdmenu.curr)) == 1)
685  ret_code = GRP_EXIT;
686  }
687  break;
688 
689  case THREAD_TOGGLE_SUBJECT_DISPLAY: /* toggle display of subject & subj/author */
690  if (show_subject) {
694  }
695  break;
696 
697  case GLOBAL_OPTION_MENU:
699  old_artnum = arts[n].artnum;
701  if ((n = find_artnum(old_artnum)) == -1 || which_thread(n) == -1) { /* We have lost the thread */
703  ret_code = GRP_EXIT;
704  } else {
705  fixup_thread(n, FALSE);
708  }
709  break;
710 
711  case GLOBAL_HELP: /* help */
714  break;
715 
717  if ((n = prompt_msgid()) != ART_UNAVAILABLE)
719  break;
720 
723  break;
724 
725  case GLOBAL_SEARCH_BODY: /* search article body */
726  if ((n = search_body(group, find_response(thread_basenote, thdmenu.curr), repeat_search)) != -1) {
727  fixup_thread(n, FALSE);
729  }
730  break;
731 
732  case GLOBAL_SEARCH_AUTHOR_FORWARD: /* author search */
734  case GLOBAL_SEARCH_SUBJECT_FORWARD: /* subject search */
736  if ((n = search(func, find_response(thread_basenote, thdmenu.curr), repeat_search)) != -1)
737  fixup_thread(n, TRUE);
738  break;
739 
740  case GLOBAL_TOGGLE_HELP_DISPLAY: /* toggle mini help menu */
743  break;
744 
745  case GLOBAL_TOGGLE_INVERSE_VIDEO: /* toggle inverse video */
749  break;
750 
751 #ifdef HAVE_COLOR
752  case GLOBAL_TOGGLE_COLOR: /* toggle color */
753  if (toggle_color()) {
755  show_color_status();
756  }
757  break;
758 #endif /* HAVE_COLOR */
759 
760  case GLOBAL_QUIT: /* return to previous level */
761  ret_code = GRP_EXIT;
762  break;
763 
764  case GLOBAL_QUIT_TIN: /* quit */
765  ret_code = GRP_QUIT;
766  break;
767 
768  case THREAD_TAG: /* tag/untag article */
769  /* Find index of current article */
770  if ((n = find_response(thread_basenote, thdmenu.curr)) < 0)
771  break;
772  else {
773  t_bool tagged;
774 
775  if ((tagged = tag_article(n)))
776  mark_screen(thdmenu.curr, mark_offset - 2, tin_ltoa((&arts[n])->tagged, 3));
777  else
778  update_thread_page(); /* Must update whole page */
779 
780  /* Automatically advance to next art if not at end of thread */
781  if (thdmenu.curr + 1 < thdmenu.max)
782  move_down();
783  else
785 
787  }
788  break;
789 
790  case GLOBAL_BUGREPORT:
791  bug_report();
792  break;
793 
794  case THREAD_UNTAG: /* untag all articles */
795  if (grpmenu.curr >= 0 && untag_all_articles())
797  break;
798 
799  case GLOBAL_VERSION: /* version */
801  break;
802 
803  case MARK_THREAD_UNREAD: /* mark thread as unread */
807  break;
808 
809  case THREAD_SELECT_ARTICLE: /* mark article as selected */
810  case THREAD_TOGGLE_ARTICLE_SELECTION: /* toggle article as selected */
811  if ((n = find_response(thread_basenote, thdmenu.curr)) < 0)
812  break;
813  arts[n].selected = (!(func == THREAD_TOGGLE_ARTICLE_SELECTION && arts[n].selected)); /* TODO: optimise? */
814 /* update_thread_page(); */
815  mark[0] = get_art_mark(&arts[n]);
817  if (thdmenu.curr + 1 < thdmenu.max)
818  move_down();
819  else
821  break;
822 
823  case THREAD_REVERSE_SELECTIONS: /* reverse selections */
825  arts[i].selected = bool_not(arts[i].selected);
827  break;
828 
829  case THREAD_UNDO_SELECTIONS: /* undo selections */
831  arts[i].selected = FALSE;
833  break;
834 
835  case GLOBAL_POSTPONED: /* post postponed article */
836  if (can_post) {
839  } else
841  break;
842 
843  case GLOBAL_DISPLAY_POST_HISTORY: /* display messages posted by user */
844  if (user_posted_messages())
846  break;
847 
848  case GLOBAL_TOGGLE_INFO_LAST_LINE: /* display subject in last line */
851  break;
852 
853  default:
855  }
856  } /* ret_code >= 0 */
857 
858  set_xclick_off();
859  clear_note_area();
860 
861  return ret_code;
862 }
863 
864 
865 static void
867  void)
868 {
869  char *title;
870  int i, art;
871 
873  currmenu = &thdmenu;
875 
876  ClearScreen();
878 
880  mark_offset = 0;
881 
882  if (!show_subject)
884 
885  if (show_subject)
887  else
888  title = fmt_string(_(txt_stp_thread), cCOLS - 23, arts[thread_respnum].subject);
889  show_title(title);
890  free(title);
891 
893  for (i = thdmenu.first; i < thdmenu.first + NOTESLINES && i < thdmenu.max; ++i) {
894  build_tline(i, &arts[art]);
895  if ((art = next_response(art)) < 0)
896  break;
897  }
898 
901 }
902 
903 
904 static void
906  void)
907 {
908  char mark[] = { '\0', '\0' };
909  int i, the_index;
910 
912  assert(thdmenu.first != 0 || the_index == thread_respnum);
913 
914  for (i = thdmenu.first; i < thdmenu.first + NOTESLINES && i < thdmenu.max; ++i) {
915  if ((&arts[the_index])->tagged)
916  mark_screen(i, mark_offset - 2, tin_ltoa((&arts[the_index])->tagged, 3));
917  else {
918  mark[0] = get_art_mark(&arts[the_index]);
919  mark_screen(i, mark_offset - 2, " "); /* clear space used by tag numbering */
920  mark_screen(i, mark_offset, mark);
921  if (mark[0] == tinrc.art_marked_selected)
923  }
924  if ((the_index = next_response(the_index)) == -1)
925  break;
926  }
927 
929 }
930 
931 
932 static void
934  void)
935 {
937 
940  else if (thdmenu.curr == thdmenu.max - 1)
942 }
943 
944 
945 /*
946  * Fix all the internal pointers if the current thread/response has
947  * changed.
948  */
949 void
951  int respnum,
952  t_bool redraw)
953 {
954  int basenote = which_thread(respnum);
955  int old_thread_basenote = thread_basenote;
956 
957  if (basenote >= 0) {
958  thread_basenote = basenote;
961  grpmenu.curr = basenote;
962  if (redraw && basenote != old_thread_basenote)
964  }
965 
966  if (redraw)
967  move_to_item(which_response(respnum)); /* Redraw screen etc.. */
968 }
969 
970 
971 /*
972  * Return the number of unread articles there are within a thread
973  */
974 int
976  int thread)
977 {
978  int i;
979  int sum = 0;
980 
981  for_each_art_in_thread(i, thread) {
982  if (arts[i].status != ART_READ)
983  sum++;
984  }
985 
986  return sum;
987 }
988 
989 
990 /*
991  * Which base note (an index into base[]) does a respnum (an index into
992  * arts[]) correspond to?
993  *
994  * In other words, base[] points to an entry in arts[] which is the head of
995  * a thread, linked with arts[].thread. For any q: arts[q], find i such that
996  * base[i]->arts[n]->arts[o]->...->arts[q]
997  *
998  * Note that which_thread() can return -1 if in show_read_only mode and the
999  * article of interest has been read as well as all other articles in the
1000  * thread, thus resulting in no base[] entry for it.
1001  */
1002 int
1004  int n)
1005 {
1006  int i, j;
1007 
1008  /* Move to top of thread */
1009  for (i = n; arts[i].prev >= 0; i = arts[i].prev)
1010  ;
1011  /* Find in base[] */
1012  for (j = 0; j < grpmenu.max; j++) {
1013  if (base[j] == i)
1014  return j;
1015  }
1016 
1017 #ifdef DEBUG
1018  if (debug & (DEBUG_FILTER | DEBUG_REFS))
1020 #endif /* DEBUG */
1021  return -1;
1022 }
1023 
1024 
1025 /*
1026  * Find how deep in its' thread arts[n] is. Start counting at zero
1027  */
1028 int
1030  int n)
1031 {
1032  int i, j;
1033  int num = 0;
1034 
1035  if ((i = which_thread(n)) == -1)
1036  return 0;
1037 
1038  for_each_art_in_thread(j, i) {
1039  if (j == n)
1040  break;
1041  else
1042  num++;
1043  }
1044 
1045  return num;
1046 }
1047 
1048 
1049 /*
1050  * Given an index into base[], find the number of responses for
1051  * that basenote
1052  */
1053 int
1055  int n)
1056 {
1057  int i;
1058  int oldi = -3;
1059  int sum = 0;
1060 
1061  assert(n < grpmenu.max && n >= 0);
1062 
1063  for_each_art_in_thread(i, n) {
1064  assert(i != ART_EXPIRED);
1065  assert(i != oldi);
1066  oldi = i;
1067  sum++;
1068  }
1069 
1070  return sum - 1;
1071 }
1072 
1073 
1074 /*
1075  * Calculating the score of a thread has been extracted from stat_thread()
1076  * because we need it also in art.c to sort base[].
1077  * get_score_of_thread expects the number of the first article of a thread.
1078  */
1079 int
1081  int n)
1082 {
1083  int i;
1084  int j = 0;
1085  int score = 0;
1086 
1087  for (i = n; i >= 0; i = arts[i].thread) {
1088  /*
1089  * TODO: do we want to take the score of read articles into account?
1090  */
1091  if (arts[i].status != ART_READ || arts[i].killed == ART_KILLED_UNREAD /* || tinrc.kill_level == KILL_THREAD */) {
1093  /* we use the maximum article score for the complete thread */
1094  if ((arts[i].score > score) && (arts[i].score > 0))
1095  score = arts[i].score;
1096  else {
1097  if ((arts[i].score < score) && (score <= 0))
1098  score = arts[i].score;
1099  }
1100  } else { /* tinrc.thread_score >= THREAD_SCORE_SUM */
1101  /* sum scores of unread arts and count num. arts */
1102  score += arts[i].score;
1103  j++;
1104  }
1105  }
1106  }
1108  score /= j;
1109 
1110  return score;
1111 }
1112 
1113 
1114 /*
1115  * Given an index into base[], return relevant statistics
1116  */
1117 int
1119  int n,
1120  struct t_art_stat *sbuf) /* return value is always ignored */
1121 {
1122  int i;
1123  MultiPartInfo minfo = {0};
1124 
1125  sbuf->total = 0;
1126  sbuf->unread = 0;
1127  sbuf->seen = 0;
1128  sbuf->deleted = 0;
1129  sbuf->inrange = 0;
1130  sbuf->selected_total = 0;
1131  sbuf->selected_unread = 0;
1132  sbuf->selected_seen = 0;
1133  sbuf->killed = 0;
1134  sbuf->art_mark = tinrc.art_marked_read;
1135  sbuf->score = 0 /* -(SCORE_MAX) */;
1136  sbuf->time = 0;
1137  sbuf->multipart_compare_len = 0;
1138  sbuf->multipart_total = 0;
1139  sbuf->multipart_have = 0;
1140 
1141  for_each_art_in_thread(i, n) {
1142  ++sbuf->total;
1143  if (arts[i].inrange)
1144  ++sbuf->inrange;
1145 
1146  if (arts[i].delete_it)
1147  ++sbuf->deleted;
1148 
1149  if (arts[i].status == ART_UNREAD) {
1150  ++sbuf->unread;
1151 
1152  if (arts[i].date > sbuf->time)
1153  sbuf->time = arts[i].date;
1154  } else if (arts[i].status == ART_WILL_RETURN)
1155  ++sbuf->seen;
1156 
1157  if (arts[i].selected) {
1158  ++sbuf->selected_total;
1159  if (arts[i].status == ART_UNREAD)
1160  ++sbuf->selected_unread;
1161  else if (arts[i].status == ART_WILL_RETURN)
1162  ++sbuf->selected_seen;
1163  }
1164 
1165  if (arts[i].killed)
1166  ++sbuf->killed;
1167 
1168  if ((curr_group->attribute->thread_articles == THREAD_MULTI) && global_get_multipart_info(i, &minfo) && (minfo.total >= 1)) {
1170  sbuf->multipart_total = minfo.total;
1171  sbuf->multipart_have++;
1172  }
1173  }
1174 
1175  sbuf->score = get_score_of_thread((int) base[n]);
1176 
1177  if (sbuf->inrange)
1179  else if (sbuf->deleted)
1181  else if (sbuf->selected_unread)
1183  else if (sbuf->unread) {
1184  if (tinrc.recent_time && (time((time_t *) 0) - sbuf->time) < (tinrc.recent_time * DAY))
1186  else
1188  }
1189  else if (sbuf->seen)
1191  else if (sbuf->selected_total)
1193  else if (sbuf->killed == sbuf->total)
1195  else
1196  sbuf->art_mark = tinrc.art_marked_read;
1197  return sbuf->total;
1198 }
1199 
1200 
1201 /*
1202  * Find the next response to arts[n]. Go to the next basenote if there
1203  * are no more responses in this thread
1204  */
1205 int
1207  int n)
1208 {
1209  int i;
1210 
1211  if (arts[n].thread >= 0)
1212  return arts[n].thread;
1213 
1214  i = which_thread(n) + 1;
1215 
1216  if (i >= grpmenu.max)
1217  return -1;
1218 
1219  return (int) base[i];
1220 }
1221 
1222 
1223 /*
1224  * Given a respnum (index into arts[]), find the respnum of the
1225  * next basenote
1226  */
1227 int
1229  int n)
1230 {
1231  int i;
1232 
1233  i = which_thread(n) + 1;
1234  if (i >= grpmenu.max)
1235  return -1;
1236 
1237  return (int) base[i];
1238 }
1239 
1240 
1241 /*
1242  * Find the previous response. Go to the last response in the previous
1243  * thread if we go past the beginning of this thread.
1244  * Return -1 if we are at the start of the group
1245  */
1246 int
1248  int n)
1249 {
1250  int i;
1251 
1252  if (arts[n].prev >= 0)
1253  return arts[n].prev;
1254 
1255  i = which_thread(n) - 1;
1256 
1257  if (i < 0)
1258  return -1;
1259 
1260  return find_response(i, num_of_responses(i));
1261 }
1262 
1263 
1264 /*
1265  * return index in arts[] of the 'n'th response in thread base 'i'
1266  */
1267 int
1269  int i,
1270  int n)
1271 {
1272  int j;
1273 
1274  j = (int) base[i];
1275 
1276  while (n-- > 0 && arts[j].thread >= 0)
1277  j = arts[j].thread;
1278 
1279  return j;
1280 }
1281 
1282 
1283 /*
1284  * Find the next unread response to art[n] in this group. If no response is
1285  * found from current point to the end restart from beginning of articles.
1286  * If no more responses can be found, return -1
1287  */
1288 int
1290  int n)
1291 {
1292  int cur_base_art = n;
1293 
1294  while (n >= 0) {
1295  if (((arts[n].status == ART_UNREAD) || (arts[n].status == ART_WILL_RETURN)) && arts[n].thread != ART_EXPIRED)
1296  return n;
1297 
1298  n = next_response(n);
1299  }
1300 
1302  n = base[0];
1303  while (n != cur_base_art && n >= 0) {
1304  if (((arts[n].status == ART_UNREAD) || (arts[n].status == ART_WILL_RETURN)) && arts[n].thread != ART_EXPIRED)
1305  return n;
1306 
1307  n = next_response(n);
1308  }
1309  }
1310 
1311  return -1;
1312 }
1313 
1314 
1315 /*
1316  * Find the previous unread response in this thread
1317  */
1318 int
1320  int n)
1321 {
1322  while (n >= 0) {
1323  if (arts[n].status != ART_READ && arts[n].thread != ART_EXPIRED)
1324  return n;
1325 
1326  n = prev_response(n);
1327  }
1328 
1329  return -1;
1330 }
1331 
1332 
1333 static t_bool
1335  struct t_msgid *ptr)
1336 {
1337  return ptr && (!IS_EXPIRED(ptr) || find_unexpired(ptr->child) || find_unexpired(ptr->sibling));
1338 }
1339 
1340 
1341 static t_bool
1343  struct t_msgid *ptr)
1344 {
1345  do {
1346  if (find_unexpired(ptr->sibling))
1347  return TRUE;
1348  ptr = ptr->parent;
1349  } while (ptr && IS_EXPIRED(ptr));
1350  return FALSE;
1351 }
1352 
1353 
1354 /*
1355  * mutt-like subject according. by sjpark@sparcs.kaist.ac.kr
1356  * string in prefix will be overwritten up to length len prefix will always
1357  * be terminated with \0
1358  * make sure prefix is at least len+1 bytes long (to hold the terminating
1359  * null byte)
1360  */
1361 static void
1363  struct t_msgid *art,
1364  char *prefix,
1365  int maxlen)
1366 {
1367 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1368  char *result;
1369  wchar_t *buf, *buf2;
1370 #else
1371  char *buf;
1372 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1373  int prefix_ptr;
1374  int depth = 0;
1375  int depth_level = 0;
1376  struct t_msgid *ptr;
1377 
1378  for (ptr = art->parent; ptr; ptr = ptr->parent)
1379  depth += (!IS_EXPIRED(ptr) ? 1 : 0);
1380 
1381  if ((depth == 0) || (maxlen < 1)) {
1382  prefix[0] = '\0';
1383  return;
1384  }
1385 
1386  prefix_ptr = depth * 2 - 1;
1387 
1388  if (prefix_ptr > maxlen - 1 - !(maxlen % 2)) {
1389  int odd = ((maxlen % 2) ? 0 : 1);
1390 
1391  prefix_ptr -= maxlen - ++depth_level - 2 - odd;
1392 
1393  while (prefix_ptr > maxlen - 2 - odd) {
1394  if (depth_level < maxlen / 5)
1395  depth_level++;
1396  prefix_ptr -= maxlen - depth_level - 2 - odd;
1397  odd = (odd ? 0 : 1);
1398  }
1399  }
1400 
1401 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1402  buf = my_malloc(sizeof(wchar_t) * prefix_ptr + 3 * sizeof(wchar_t));
1403  buf[prefix_ptr + 2] = (wchar_t) '\0';
1404 #else
1405  buf = my_malloc(prefix_ptr + 3);
1406  buf[prefix_ptr + 2] = '\0';
1407 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1408  buf[prefix_ptr + 1] = TREE_ARROW;
1409  buf[prefix_ptr] = TREE_HORIZ;
1410  buf[--prefix_ptr] = (has_sibling(art) ? TREE_VERT_RIGHT : TREE_UP_RIGHT);
1411 
1412  for (ptr = art->parent; prefix_ptr > 1; ptr = ptr->parent) {
1413  if (IS_EXPIRED(ptr))
1414  continue;
1415  buf[--prefix_ptr] = TREE_BLANK;
1416  buf[--prefix_ptr] = (has_sibling(ptr) ? TREE_VERT : TREE_BLANK);
1417  }
1418 
1419  while (depth_level)
1420  buf[--depth_level] = TREE_ARROW_WRAP;
1421 
1422 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1423  buf2 = wcspart(buf, maxlen, FALSE);
1424  result = wchar_t2char(buf2);
1425  strcpy(prefix, result);
1426  free(buf);
1427  FreeIfNeeded(buf2);
1428  FreeIfNeeded(result);
1429 #else
1430  strncpy(prefix, buf, maxlen);
1431  prefix[maxlen] = '\0'; /* just in case strlen(buf) > maxlen */
1432  free(buf);
1433 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1434 }
1435 
1436 
1437 /*
1438  * There are 3 catchup methods:
1439  * When exiting thread via <-
1440  * Catchup thread, move to next one
1441  * Catchup thread and enter next one with unread arts
1442  * Return a suitable ret_code
1443  */
1444 static int
1446  t_function func,
1447  struct t_group *group)
1448 {
1449  char buf[LEN];
1450  int i, n;
1451  int pyn = 1;
1452 
1453  /* Find first unread art in this thread */
1455  for (i = n; i != -1; i = arts[i].thread) {
1456  if ((arts[i].status == ART_UNREAD) || (arts[i].status == ART_WILL_RETURN))
1457  break;
1458  }
1459 
1460  if (i != -1) { /* still unread arts in this thread */
1461  if (group->attribute->thread_articles == THREAD_NONE)
1463  else
1465  if ((!TINRC_CONFIRM_ACTION) || (pyn = prompt_yn(buf, TRUE)) == 1)
1467  }
1468 
1469  switch (func) {
1470  case CATCHUP: /* 'c' */
1471  if (pyn == 1)
1472  return GRP_NEXT;
1473  break;
1474 
1475  case CATCHUP_NEXT_UNREAD: /* 'C' */
1476  if (pyn == 1)
1477  return GRP_NEXTUNREAD;
1478  break;
1479 
1480  case SPECIAL_CATCHUP_LEFT: /* <- thread catchup on exit */
1481  switch (pyn) {
1482  case -1: /* ESC from prompt, stay in group */
1483  break;
1484 
1485  case 1: /* We caught up - advance group */
1486  return GRP_NEXT;
1487 
1488  default: /* Just leave the group */
1489  return GRP_EXIT;
1490  }
1491  /* FALLTHROUGH */
1492  default:
1493  break;
1494  }
1495  return 0; /* Default is to stay in current screen */
1496 }
1497 
1498 
1499 /*
1500  * This is the single entry point into the article pager
1501  * art
1502  * is the arts[art] we wish to read
1503  * ignore_unavail
1504  * should be set if we wish to keep going after article unavailable
1505  * level
1506  * is the menu from which we came. This should be only be GROUP or THREAD
1507  * it is used to set the return code to go back to the calling menu when
1508  * not explicitly set
1509  * Return:
1510  * <0 to quit to group menu
1511  * 0 to stay in thread menu
1512  * >0 after normal exit from pager to return to previous menu level
1513  */
1514 static int
1516  int art,
1517  t_bool ignore_unavail,
1518  int level)
1519 {
1520  int i;
1521 
1522 again:
1523  switch ((i = show_page(curr_group, art, &thdmenu.curr))) {
1524  /* These exit to previous menu level */
1525  case GRP_QUIT: /* 'Q' all the way out */
1526  case GRP_EXIT: /* back to group menu */
1527  case GRP_RETSELECT: /* 'T' back to select menu */
1528  case GRP_NEXT: /* 'c' Move to next thread on group menu */
1529  case GRP_NEXTUNREAD: /* 'C' */
1530  case GRP_KILLED: /* article/thread was killed at page level */
1531  break;
1532 
1533  case GRP_ARTABORT: /* user 'q'uit load of article */
1534  /* break forces return to group menu */
1535  if (level == GROUP_LEVEL)
1536  break;
1537  /* else stay on thread menu */
1538  show_thread_page();
1539  return 0;
1540 
1541  /* Keeps us in thread menu */
1542  case GRP_ARTUNAVAIL:
1543  if (ignore_unavail && (art = next_unread(art)) != -1)
1544  goto again;
1545  else if (level == GROUP_LEVEL)
1546  return GRP_ARTABORT;
1547  /* back to thread menu */
1548  show_thread_page();
1549  return 0;
1550 
1551  case GRP_GOTOTHREAD: /* 'l' from pager */
1552  show_thread_page();
1554  return 0;
1555 
1556  default: /* >=0 normal exit, new basenote */
1558 
1559  if (currmenu != &grpmenu) /* group menu will redraw itself */
1560  currmenu->redraw();
1561 
1562  return 1; /* Must return any +ve integer */
1563  }
1564  return i;
1565 }
1566 
1567 
1568 /*
1569  * Find index in arts[] of next unread article _IN_THIS_THREAD_
1570  * Page it or return GRP_NEXTUNREAD if thread is all read
1571  * (to tell group menu to skip to next thread)
1572  */
1573 static int
1575  void)
1576 {
1577  int i, n;
1578 
1579  /*
1580  * Find current position in thread
1581  */
1583 
1584  /*
1585  * Find and display next unread
1586  */
1587  for (i = n; i != -1; i = arts[i].thread) {
1588  if ((arts[i].status == ART_UNREAD) || (arts[i].status == ART_WILL_RETURN))
1589  return (enter_pager(i, TRUE, THREAD_LEVEL));
1590  }
1591 
1592  /*
1593  * We ran out of thread, tell group.c to enter the next with unread
1594  */
1595  return GRP_NEXTUNREAD;
1596 }
1597 
1598 
1599 /*
1600  * Redraw all necessary parts of the screen after FEED_MARK_(UN)READ
1601  * Move cursor to next unread item if needed
1602  *
1603  * Returns TRUE when no next unread art, FALSE otherwise
1604  */
1605 t_bool
1607  int function,
1608  t_function feed_type,
1609  int respnum)
1610 {
1611  char mark[] = { '\0', '\0' };
1612  int n;
1613 
1614  switch (function) {
1615  case (FEED_MARK_READ):
1616  if (feed_type == FEED_ARTICLE) {
1617  mark[0] = get_art_mark(&arts[respnum]);
1619  } else
1620  show_thread_page();
1621 
1622  if ((n = next_unread(respnum)) == -1) /* no more unread articles */
1623  return TRUE;
1624  else
1625  fixup_thread(n, TRUE); /* We may be in the next thread now */
1626  break;
1627 
1628  case (FEED_MARK_UNREAD):
1629  if (feed_type == FEED_ARTICLE) {
1630  mark[0] = get_art_mark(&arts[respnum]);
1633  } else
1634  show_thread_page();
1635  break;
1636 
1637  default:
1638  break;
1639  }
1640  return FALSE;
1641 }
t_attribute::wrap_on_next_unread
unsigned wrap_on_next_unread
Definition: tin.h:1647
t_article
Definition: tin.h:1510
t_config::score_select
int score_select
Definition: tinrc.h:159
t_attribute::thread_catchup_on_exit
unsigned thread_catchup_on_exit
Definition: tin.h:1632
THREAD_TOGGLE_SUBJECT_DISPLAY
@ THREAD_TOGGLE_SUBJECT_DISPLAY
Definition: keymap.h:368
t_config::recent_time
int recent_time
Definition: tinrc.h:136
t_config::art_marked_killed
char art_marked_killed
Definition: tinrc.h:66
TREE_HORIZ
#define TREE_HORIZ
Definition: tin.h:930
has_sibling
static t_bool has_sibling(struct t_msgid *ptr)
Definition: thread.c:1342
make_threads
void make_threads(struct t_group *group, t_bool rethread)
Definition: art.c:1194
txt_mark_art_read
constext txt_mark_art_read[]
Definition: lang.c:625
find_artnum
int find_artnum(t_artnum art)
Definition: art.c:3192
THREAD_REVERSE_SELECTIONS
@ THREAD_REVERSE_SELECTIONS
Definition: keymap.h:363
t_art_stat::deleted
int deleted
Definition: tin.h:1946
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
GLOBAL_SHELL_ESCAPE
@ GLOBAL_SHELL_ESCAPE
Definition: keymap.h:223
txt_reading_article
constext txt_reading_article[]
Definition: lang.c:759
txt_prefix_tagged
constext txt_prefix_tagged[]
Definition: lang.c:732
FEED_PIPE
#define FEED_PIPE
Definition: tin.h:1115
t_fmt::len_msgid
size_t len_msgid
Definition: tin.h:1822
THREAD_LEVEL
#define THREAD_LEVEL
Definition: tin.h:1103
INDEX_TOP
#define INDEX_TOP
Definition: tin.h:1008
show_thread_page
static void show_thread_page(void)
Definition: thread.c:866
next_response
int next_response(int n)
Definition: thread.c:1206
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_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
THREAD_READ_ARTICLE
@ THREAD_READ_ARTICLE
Definition: keymap.h:362
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
t_art_stat::selected_seen
int selected_seen
Definition: tin.h:1950
DIGIT_8
@ DIGIT_8
Definition: keymap.h:158
enter_pager
static int enter_pager(int art, t_bool ignore_unavail, int level)
Definition: thread.c:1515
bug_report
void bug_report(void)
Definition: global.c:430
prefix
static const char * prefix[]
Definition: pcregrep.c:219
GLOBAL_TOGGLE_INFO_LAST_LINE
@ GLOBAL_TOGGLE_INFO_LAST_LINE
Definition: keymap.h:229
MultiPartInfo::subject_compare_len
int subject_compare_len
Definition: tin.h:1995
GLOBAL_DISPLAY_POST_HISTORY
@ GLOBAL_DISPLAY_POST_HISTORY
Definition: keymap.h:188
tag_article
t_bool tag_article(int art)
Definition: tags.c:277
t_fmt::date_str
char date_str[1024]
Definition: tin.h:1811
txt_bad_command
constext txt_bad_command[]
Definition: lang.c:112
GLOBAL_SEARCH_SUBJECT_FORWARD
@ GLOBAL_SEARCH_SUBJECT_FORWARD
Definition: keymap.h:220
GRP_ARTUNAVAIL
@ GRP_ARTUNAVAIL
Definition: tin.h:1264
show_title
void show_title(const char *title)
Definition: screen.c:405
THREAD_READ_NEXT_ARTICLE_OR_THREAD
@ THREAD_READ_NEXT_ARTICLE_OR_THREAD
Definition: keymap.h:361
art_mark
void art_mark(struct t_group *group, struct t_article *art, int flag)
Definition: newsrc.c:1571
make_prefix
static void make_prefix(struct t_msgid *art, char *prefix, int maxlen)
Definition: thread.c:1362
t_msgid
Definition: tin.h:1486
t_article::prev
int prev
Definition: tin.h:1527
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
THREAD_TAG
@ THREAD_TAG
Definition: keymap.h:366
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
ClearScreen
void ClearScreen(void)
Definition: curses.c:410
get_art_mark
static char get_art_mark(struct t_article *art)
Definition: thread.c:89
GLOBAL_LOOKUP_MESSAGEID
@ GLOBAL_LOOKUP_MESSAGEID
Definition: keymap.h:196
GLOBAL_OPTION_MENU
@ GLOBAL_OPTION_MENU
Definition: keymap.h:199
KILL_NOTHREAD
#define KILL_NOTHREAD
Definition: tin.h:1207
THREAD_SCORE_MAX
#define THREAD_SCORE_MAX
Definition: tin.h:1149
scroll_up
void scroll_up(void)
Definition: global.c:278
cCRLF
#define cCRLF
Definition: tcurses.h:150
grpmenu
t_menu grpmenu
Definition: group.c:83
for_each_art_in_thread
#define for_each_art_in_thread(x, y)
Definition: tin.h:2212
thread_keys
struct keylist thread_keys
Definition: keymap.c:89
thd_mark_unread
void thd_mark_unread(struct t_group *group, long thread)
Definition: newsrc.c:772
prev_unread
int prev_unread(int n)
Definition: thread.c:1319
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
cThread
@ cThread
Definition: tin.h:107
tinrc
struct t_config tinrc
Definition: init.c:191
FEED_SAVE
#define FEED_SAVE
Definition: tin.h:1117
curr_group
struct t_group * curr_group
Definition: group.c:55
filter_file_offset
int filter_file_offset
Definition: filter.c:93
signal_context
int signal_context
Definition: signal.c:105
ART_UNAVAILABLE
#define ART_UNAVAILABLE
Definition: tin.h:1323
next_unread
int next_unread(int n)
Definition: thread.c:1289
CATCHUP_NEXT_UNREAD
@ CATCHUP_NEXT_UNREAD
Definition: keymap.h:170
thread_right
static t_function thread_right(void)
Definition: thread.c:402
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
txt_stp_list_thread
constext txt_stp_list_thread[]
Definition: lang.c:846
GLOBAL_SCROLL_DOWN
@ GLOBAL_SCROLL_DOWN
Definition: keymap.h:213
fmt_string
char * fmt_string(const char *fmt,...)
Definition: string.c:1379
thread_mark_postprocess
t_bool thread_mark_postprocess(int function, t_function feed_type, int respnum)
Definition: thread.c:1606
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
DAY
#define DAY
Definition: tin.h:864
prompt_item_num
void prompt_item_num(int ch, const char *prompt)
Definition: global.c:200
t_config::art_marked_selected
char art_marked_selected
Definition: tinrc.h:62
t_msgid::sibling
struct t_msgid * sibling
Definition: tin.h:1489
GRP_NEXTUNREAD
@ GRP_NEXTUNREAD
Definition: tin.h:1262
tcurses.h
clear_note_area
void clear_note_area(void)
Definition: group.c:988
GLOBAL_SCROLL_UP
@ GLOBAL_SCROLL_UP
Definition: keymap.h:214
t_config::art_marked_read
char art_marked_read
Definition: tinrc.h:65
t_menu::max
int max
Definition: tin.h:2007
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
GLOBAL_LAST_PAGE
@ GLOBAL_LAST_PAGE
Definition: keymap.h:192
t_art_stat::killed
int killed
Definition: tin.h:1951
thread_left
static t_function thread_left(void)
Definition: thread.c:391
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
global_get_multipart_info
int global_get_multipart_info(int aindex, MultiPartInfo *setme)
Definition: art.c:982
prompt_msgid
int prompt_msgid(void)
Definition: prompt.c:592
txt_article_singular
constext txt_article_singular[]
Definition: lang.c:75
which_thread
int which_thread(int n)
Definition: thread.c:1003
DIGIT_4
@ DIGIT_4
Definition: keymap.h:154
t_msgid::parent
struct t_msgid * parent
Definition: tin.h:1488
SHOW_FROM_NONE
#define SHOW_FROM_NONE
Definition: tin.h:1141
can_post
t_bool can_post
Definition: nntplib.c:32
GRP_EXIT
@ GRP_EXIT
Definition: tin.h:1269
build_tline
static void build_tline(int l, struct t_article *art)
Definition: thread.c:120
FEED_PRINT
#define FEED_PRINT
Definition: tin.h:1116
thdmenu
static t_menu thdmenu
Definition: thread.c:80
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
txt_thread_upper
constext txt_thread_upper[]
Definition: lang.c:877
t_fmt
Definition: tin.h:1809
thread_page
int thread_page(struct t_group *group, int respnum, int thread_depth, t_pagerinfo *page)
Definition: thread.c:424
txt_cannot_find_base_art
constext txt_cannot_find_base_art[]
t_art_stat
Definition: tin.h:1941
SPECIAL_CATCHUP_LEFT
@ SPECIAL_CATCHUP_LEFT
Definition: keymap.h:167
new_responses
int new_responses(int thread)
Definition: thread.c:975
GLOBAL_TOGGLE_HELP_DISPLAY
@ GLOBAL_TOGGLE_HELP_DISPLAY
Definition: keymap.h:228
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
t_msgid::article
int article
Definition: tin.h:1491
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
ART_EXPIRED
#define ART_EXPIRED
Definition: tin.h:1310
thrd_fmt
static struct t_fmt thrd_fmt
Definition: thread.c:53
strwidth
int strwidth(const char *str)
Definition: string.c:1043
txt_no_resps_in_thread
constext txt_no_resps_in_thread[]
Definition: lang.c:686
t_attribute::thread_format
char * thread_format
Definition: tin.h:1570
t_art_stat::art_mark
char art_mark
Definition: tin.h:1942
t_fmt::len_from
size_t len_from
Definition: tin.h:1815
mark_offset
int mark_offset
Definition: screen.c:48
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
ART_ABORT
#define ART_ABORT
Definition: tin.h:1335
GLOBAL_VERSION
@ GLOBAL_VERSION
Definition: keymap.h:231
GLOBAL_EDIT_FILTER
@ GLOBAL_EDIT_FILTER
Definition: keymap.h:189
draw_arrow_mark
void draw_arrow_mark(int line)
Definition: screen.c:300
t_article::archive
struct t_archive * archive
Definition: tin.h:1524
t_fmt::len_initials
size_t len_initials
Definition: tin.h:1819
WriteLine
#define WriteLine(row, buffer)
Definition: tcurses.h:174
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
GRP_GOTOTHREAD
@ GRP_GOTOTHREAD
Definition: tin.h:1267
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
t_config::kill_level
int kill_level
Definition: tinrc.h:139
t_fmt::str
char str[1024]
Definition: tin.h:1810
ART_READ
#define ART_READ
Definition: tin.h:1320
txt_enter_next_unread_art
constext txt_enter_next_unread_art[]
Definition: lang.c:176
GLOBAL_MENU_FILTER_SELECT
@ GLOBAL_MENU_FILTER_SELECT
Definition: keymap.h:198
MultiPartInfo::total
int total
Definition: tin.h:1997
t_config::info_in_last_line
t_bool info_in_last_line
Definition: tinrc.h:215
GRP_ARTABORT
@ GRP_ARTABORT
Definition: tin.h:1265
buf
static char buf[16]
Definition: langinfo.c:50
TREE_VERT
#define TREE_VERT
Definition: tin.h:932
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
THREAD_TOGGLE_ARTICLE_SELECTION
@ THREAD_TOGGLE_ARTICLE_SELECTION
Definition: keymap.h:367
GLOBAL_PIPE
@ GLOBAL_PIPE
Definition: keymap.h:202
t_config::art_marked_deleted
char art_marked_deleted
Definition: tinrc.h:59
show_subject
t_bool show_subject
Definition: thread.c:54
t_menu
Definition: tin.h:2005
GLOBAL_LINE_DOWN
@ GLOBAL_LINE_DOWN
Definition: keymap.h:194
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
post_article
t_bool post_article(const char *groupname)
Definition: post.c:2554
config_page
void config_page(const char *grpname, enum context level)
Definition: options_menu.c:921
DEBUG_REFS
#define DEBUG_REFS
Definition: debug.h:51
FEED_MAIL
#define FEED_MAIL
Definition: tin.h:1114
GLOBAL_LAST_VIEWED
@ GLOBAL_LAST_VIEWED
Definition: keymap.h:193
t_art_stat::selected_total
int selected_total
Definition: tin.h:1948
t_config::art_marked_return
char art_marked_return
Definition: tinrc.h:61
FEED_RANGE
@ FEED_RANGE
Definition: keymap.h:180
assert
#define assert(p)
Definition: tin.h:1295
TREE_VERT_RIGHT
#define TREE_VERT_RIGHT
Definition: tin.h:933
pos_first_unread_thread
void pos_first_unread_thread(void)
Definition: group.c:1067
GLOBAL_LINE_UP
@ GLOBAL_LINE_UP
Definition: keymap.h:195
t_config::art_marked_read_selected
char art_marked_read_selected
Definition: tinrc.h:67
draw_thread_arrow
static void draw_thread_arrow(void)
Definition: thread.c:933
GRP_KILLED
@ GRP_KILLED
Definition: tin.h:1266
top_of_list
void top_of_list(void)
Definition: global.c:182
t_fmt::len_subj
size_t len_subj
Definition: tin.h:1825
num_of_responses
int num_of_responses(int n)
Definition: thread.c:1054
GLOBAL_SEARCH_SUBJECT_BACKWARD
@ GLOBAL_SEARCH_SUBJECT_BACKWARD
Definition: keymap.h:219
MultiPartInfo
Definition: tin.h:1993
THREAD_NONE
#define THREAD_NONE
Definition: tin.h:1127
DIGIT_9
@ DIGIT_9
Definition: keymap.h:159
cCOLS
int cCOLS
Definition: curses.c:53
LEN
#define LEN
Definition: tin.h:854
t_article::status
unsigned int status
Definition: tin.h:1529
T_ARTNUM_CONST
#define T_ARTNUM_CONST(v)
Definition: tin.h:229
GLOBAL_SEARCH_AUTHOR_BACKWARD
@ GLOBAL_SEARCH_AUTHOR_BACKWARD
Definition: keymap.h:217
thread_basenote
int thread_basenote
Definition: thread.c:51
t_function
enum defined_functions t_function
Definition: keymap.h:373
t_config::thread_score
int thread_score
Definition: tinrc.h:154
which_response
int which_response(int n)
Definition: thread.c:1029
txt_stp_thread
constext txt_stp_thread[]
Definition: lang.c:847
toggle_inverse_video
void toggle_inverse_video(void)
Definition: misc.c:1058
filter_menu
t_bool filter_menu(t_function type, struct t_group *group, struct t_article *art)
Definition: filter.c:1054
thread_tab_pressed
static int thread_tab_pressed(void)
Definition: thread.c:1574
currmenu
t_menu * currmenu
Definition: init.c:165
t_article::artnum
t_artnum artnum
Definition: tin.h:1511
find_response
int find_response(int i, int n)
Definition: thread.c:1268
GLOBAL_FIRST_PAGE
@ GLOBAL_FIRST_PAGE
Definition: keymap.h:190
THREAD_SELECT_ARTICLE
@ THREAD_SELECT_ARTICLE
Definition: keymap.h:365
GLOBAL_POST
@ GLOBAL_POST
Definition: keymap.h:203
t_article::thread
int thread
Definition: tin.h:1526
txt_mark_thread_read
constext txt_mark_thread_read[]
Definition: lang.c:627
t_article::subject
char * subject
Definition: tin.h:1512
GRP_NEXT
@ GRP_NEXT
Definition: tin.h:1263
t_menu::redraw
void(* redraw)(void)
Definition: tin.h:2009
set_xclick_off
void set_xclick_off(void)
Definition: curses.c:703
untag_all_articles
t_bool untag_all_articles(void)
Definition: tags.c:318
FEED_MARK_UNREAD
#define FEED_MARK_UNREAD
Definition: tin.h:1121
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
TREE_ARROW_WRAP
#define TREE_ARROW_WRAP
Definition: tin.h:928
ART_WILL_RETURN
#define ART_WILL_RETURN
Definition: tin.h:1322
unfilter_articles
void unfilter_articles(struct t_group *group)
Definition: filter.c:1811
ret_code
static int ret_code
Definition: thread.c:83
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
thread_catchup
static int thread_catchup(t_function func, struct t_group *group)
Definition: thread.c:1445
t_config::art_marked_recent
char art_marked_recent
Definition: tinrc.h:63
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
THREAD_MARK_ARTICLE_READ
@ THREAD_MARK_ARTICLE_READ
Definition: keymap.h:360
txt_end_of_thread
constext txt_end_of_thread[]
Definition: lang.c:171
t_menu::curr
int curr
Definition: tin.h:2006
show_page
int show_page(struct t_group *group, int start_respnum, int *threadnum)
Definition: page.c:305
t_msgid::child
struct t_msgid * child
Definition: tin.h:1490
INDEX2LNUM
#define INDEX2LNUM(i)
Definition: tin.h:1009
t_group::name
char * name
Definition: tin.h:1773
t_attribute::mark_ignore_tags
unsigned mark_ignore_tags
Definition: tin.h:1616
t_article::score
int score
Definition: tin.h:1528
THREAD_SAVE
@ THREAD_SAVE
Definition: keymap.h:364
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
TREE_BLANK
#define TREE_BLANK
Definition: tin.h:929
t_art_stat::time
time_t time
Definition: tin.h:1956
GLOBAL_SET_RANGE
@ GLOBAL_SET_RANGE
Definition: keymap.h:221
cancel_article
t_bool cancel_article(struct t_group *group, struct t_article *art, int respnum)
Definition: post.c:3770
next_thread
int next_thread(int n)
Definition: thread.c:1228
prev_response
int prev_response(int n)
Definition: thread.c:1247
THREAD_CANCEL
@ THREAD_CANCEL
Definition: keymap.h:358
FALSE
#define FALSE
Definition: bool.h:70
FEED_AUTOSAVE
#define FEED_AUTOSAVE
Definition: tin.h:1118
num_of_tagged_arts
int num_of_tagged_arts
Definition: tags.c:50
debug
unsigned short debug
Definition: debug.c:51
THREAD_BOTH
#define THREAD_BOTH
Definition: tin.h:1130
GLOBAL_QUIT_TIN
@ GLOBAL_QUIT_TIN
Definition: keymap.h:211
GLOBAL_PAGE_UP
@ GLOBAL_PAGE_UP
Definition: keymap.h:201
stat_thread
int stat_thread(int n, struct t_art_stat *sbuf)
Definition: thread.c:1118
THREAD_UNDO_SELECTIONS
@ THREAD_UNDO_SELECTIONS
Definition: keymap.h:369
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
txt_enter_next_thread
constext txt_enter_next_thread[]
Definition: lang.c:175
ART_UNREAD
#define ART_UNREAD
Definition: tin.h:1321
THREAD_SCORE_WEIGHT
#define THREAD_SCORE_WEIGHT
Definition: tin.h:1151
FEED_MARK_READ
#define FEED_MARK_READ
Definition: tin.h:1120
THREAD_MAIL
@ THREAD_MAIL
Definition: keymap.h:359
t_art_stat::inrange
int inrange
Definition: tin.h:1947
draw_mark_selected
void draw_mark_selected(int i)
Definition: misc.c:4123
snprintf
#define snprintf
Definition: tin.h:2417
GLOBAL_SEARCH_REPEAT
@ GLOBAL_SEARCH_REPEAT
Definition: keymap.h:216
t_pagerinfo
Definition: tin.h:2018
fixup_thread
void fixup_thread(int respnum, t_bool redraw)
Definition: thread.c:950
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
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
thread_respnum
static int thread_respnum
Definition: thread.c:52
t_group::attribute
struct t_attribute * attribute
Definition: tin.h:1790
GLOBAL_HELP
@ GLOBAL_HELP
Definition: keymap.h:191
t_menu::first
int first
Definition: tin.h:2008
GLOBAL_ABORT
@ GLOBAL_ABORT
Definition: keymap.h:186
update_thread_page
static void update_thread_page(void)
Definition: thread.c:905
t_config::art_marked_inrange
char art_marked_inrange
Definition: tinrc.h:60
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
THREAD_PERC
#define THREAD_PERC
Definition: tin.h:1132
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
t_art_stat::total
int total
Definition: tin.h:1943
t_attribute::thread_articles
unsigned thread_articles
Definition: tin.h:1631
TREE_UP_RIGHT
#define TREE_UP_RIGHT
Definition: tin.h:931
txt_thread_com
constext txt_thread_com[]
Definition: lang.c:878
THREAD_AUTOSAVE
@ THREAD_AUTOSAVE
Definition: keymap.h:357
mark_screen
void mark_screen(int screen_row, int screen_col, const char *value)
Definition: group.c:1084
THREAD_SUBJ
#define THREAD_SUBJ
Definition: tin.h:1128
t_bool
unsigned t_bool
Definition: bool.h:77
FEED_ARTICLE
@ FEED_ARTICLE
Definition: keymap.h:176
txt_select_art
constext txt_select_art[]
Definition: lang.c:836
printascii
char * printascii(char *buf, int ch)
Definition: keymap.c:271
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
GLOBAL_REDRAW_SCREEN
@ GLOBAL_REDRAW_SCREEN
Definition: keymap.h:212
IS_EXPIRED
#define IS_EXPIRED(a)
Definition: thread.c:49
GLOBAL_TOGGLE_INVERSE_VIDEO
@ GLOBAL_TOGGLE_INVERSE_VIDEO
Definition: keymap.h:230
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
TREE_ARROW
#define TREE_ARROW
Definition: tin.h:927
my_strftime
size_t my_strftime(char *s, size_t maxsize, const char *format, struct tm *timeptr)
Definition: strftime.c:64
find_unexpired
static t_bool find_unexpired(struct t_msgid *ptr)
Definition: thread.c:1334
txt_marked_as_unread
constext txt_marked_as_unread[]
Definition: lang.c:620
GLOBAL_SEARCH_BODY
@ GLOBAL_SEARCH_BODY
Definition: keymap.h:215
get_score_of_thread
int get_score_of_thread(int n)
Definition: thread.c:1080
DEBUG_FILTER
#define DEBUG_FILTER
Definition: debug.h:49
DIGIT_1
@ DIGIT_1
Definition: keymap.h:151
GLOBAL_QUIT
@ GLOBAL_QUIT
Definition: keymap.h:210
thd_mark_read
void thd_mark_read(struct t_group *group, long thread)
Definition: newsrc.c:755
txt_no_responses
constext txt_no_responses[]
Definition: lang.c:685
THREAD_REFS
#define THREAD_REFS
Definition: tin.h:1129
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
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
t_art_stat::selected_unread
int selected_unread
Definition: tin.h:1949
t_config::draw_arrow
t_bool draw_arrow
Definition: tinrc.h:212
t_article::date
time_t date
Definition: tin.h:1516
THREAD_UNTAG
@ THREAD_UNTAG
Definition: keymap.h:370
THREAD_MULTI
#define THREAD_MULTI
Definition: tin.h:1131
my_malloc
#define my_malloc(size)
Definition: tin.h:2196
draw_thread_item
static void draw_thread_item(int item)
Definition: thread.c:383
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