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)  

page.c
Go to the documentation of this file.
1 /*
2  * Project : tin - a Usenet reader
3  * Module : page.c
4  * Author : I. Lea & R. Skrenta
5  * Created : 1991-04-01
6  * Updated : 2019-07-10
7  * Notes :
8  *
9  * Copyright (c) 1991-2020 Iain Lea <iain@bricbrac.de>, Rich Skrenta <skrenta@pbm.com>
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  *
16  * 1. Redistributions of source code must retain the above copyright notice,
17  * this list of conditions and the following disclaimer.
18  *
19  * 2. Redistributions in binary form must reproduce the above copyright
20  * notice, this list of conditions and the following disclaimer in the
21  * documentation and/or other materials provided with the distribution.
22  *
23  * 3. Neither the name of the copyright holder nor the names of its
24  * contributors may be used to endorse or promote products derived from
25  * this software without specific prior written permission.
26  *
27  * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 
41 #ifndef TIN_H
42 # include "tin.h"
43 #endif /* !TIN_H */
44 #ifndef TCURSES_H
45 # include "tcurses.h"
46 #endif /* !TCURSES_H */
47 
48 
49 /*
50  * PAGE_HEADER is the size in lines of the article page header
51  * ARTLINES is the number of lines available to display actual article text.
52  */
53 #define PAGE_HEADER 4
54 #define ARTLINES (NOTESLINES - (PAGE_HEADER - INDEX_TOP))
55 
56 int curr_line; /* current line in art (indexed from 0) */
57 static FILE *note_fp; /* active stream (raw or cooked) */
58 static int artlines; /* active # of lines in pager */
59 static t_lineinfo *artline; /* active 'lineinfo' data */
60 
61 static t_url *url_list;
62 
63 t_openartinfo pgart = /* Global context of article open in the pager */
64  {
65  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, FALSE, NULL},
66  FALSE, 0,
67  NULL, NULL, NULL, NULL,
68  };
69 
70 int last_resp; /* previous & current article # in arts[] for '-' command */
72 
73 size_t tabwidth = 8;
74 
75 static struct t_header *note_h = &pgart.hdr; /* Easy access to article headers */
76 
77 static FILE *info_file;
78 static const char *info_title;
79 static int curr_info_line;
80 static int hide_uue; /* set when uuencoded sections are 'hidden' */
81 static int num_info_lines;
82 static int reveal_ctrl_l_lines; /* number of lines (from top) with de-activated ^L */
83 static int rotate; /* 0=normal, 13=rot13 decode */
84 static int scroll_region_top; /* first screen line for displayed message */
85 static int search_line; /* Line to commence next search from */
86 static t_lineinfo *infoline = (t_lineinfo *) 0;
87 
88 static t_bool show_all_headers; /* all headers <-> headers in news_headers_to[_not]_display */
89 static t_bool show_raw_article; /* CTRL-H raw <-> cooked article */
90 static t_bool reveal_ctrl_l; /* set when ^L hiding is off */
91 
92 /*
93  * Local prototypes
94  */
95 static int build_url_list(void);
96 static int load_article(int new_respnum, struct t_group *group);
97 static int prompt_response(int ch, int curr_respnum);
98 static int scroll_page(int dir);
99 static t_bool deactivate_next_ctrl_l(void);
100 static t_bool activate_last_ctrl_l(void);
101 static t_bool process_url(int n);
102 static t_bool url_page(void);
103 static t_function page_left(void);
104 static t_function page_right(void);
105 static t_function page_mouse_action(t_function (*left_action) (void), t_function (*right_action) (void));
106 static t_function url_left(void);
107 static t_function url_right(void);
108 static void build_url_line(int i);
109 static void draw_page_header(const char *group);
110 static void draw_url_arrow(void);
111 static void free_url_list(void);
112 static void preprocess_info_message(FILE *info_fh);
113 static void print_message_page(FILE *file, t_lineinfo *messageline, size_t messagelines, size_t base_line, size_t begin, size_t end, int help_level);
114 static void process_search(int *lcurr_line, size_t message_lines, size_t screen_lines, int help_level);
115 static void show_url_page(void);
116 static void invoke_metamail(FILE *fp);
117 
119 
120 #ifdef XFACE_ABLE
121 # define XFACE_SHOW() if (tinrc.use_slrnface) \
122  slrnface_show_xface()
123 # define XFACE_CLEAR() if (tinrc.use_slrnface) \
124  slrnface_clear_xface()
125 # define XFACE_SUPPRESS() if (tinrc.use_slrnface) \
126  slrnface_suppress_xface()
127 #else
128 # define XFACE_SHOW() /*nothing*/
129 # define XFACE_CLEAR() /*nothing*/
130 # define XFACE_SUPPRESS() /*nothing*/
131 #endif /* XFACE_ABLE */
132 
133 /*
134  * Scroll visible article part of display down (+ve) or up (-ve)
135  * according to 'dir' (KEYMAP_UP or KEYMAP_DOWN) and tinrc.scroll_lines
136  * >= 1 line count
137  * 0 full page scroll
138  * -1 full page but retain last line of prev page when scrolling
139  * down. Obviously only applies when scrolling down.
140  * -2 half page scroll
141  * Return the offset we scrolled by so that redrawing can be done
142  */
143 static int
145  int dir)
146 {
147  int i;
148 
149  if (tinrc.scroll_lines >= 1)
150  i = tinrc.scroll_lines;
151  else {
153  switch (tinrc.scroll_lines) {
154  case 0:
155  break;
156 
157  case -1:
158  i--;
159  break;
160 
161  case -2:
162  i >>= 1;
163  break;
164  }
165  }
166 
167  if (dir == KEYMAP_UP)
168  i = -i;
169 
170 #ifdef USE_CURSES
171  scrollok(stdscr, TRUE);
172 #endif /* USE_CURSES */
174  ScrollScreen(i);
176 #ifdef USE_CURSES
177  scrollok(stdscr, FALSE);
178 #endif /* USE_CURSES */
179 
180  return i;
181 }
182 
183 
184 /*
185  * Map keypad codes to standard keyboard characters
186  */
187 static t_function
189  void)
190 {
191  return GLOBAL_QUIT;
192 }
193 
194 
195 static t_function
197  void)
198 {
199  return PAGE_NEXT_UNREAD;
200 }
201 
202 
203 static t_function
205  t_function (*left_action) (void),
206  t_function (*right_action) (void))
207 {
208  t_function func = NOT_ASSIGNED;
209 
210  switch (xmouse) {
211  case MOUSE_BUTTON_1:
212  if (xrow < PAGE_HEADER || xrow >= cLINES - 1)
213  func = GLOBAL_PAGE_DOWN;
214  else
215  func = right_action();
216  break;
217 
218  case MOUSE_BUTTON_2:
219  if (xrow < PAGE_HEADER || xrow >= cLINES - 1)
220  func = GLOBAL_PAGE_UP;
221  else
222  func = left_action();
223  break;
224 
225  case MOUSE_BUTTON_3:
226  func = SPECIAL_MOUSE_TOGGLE;
227  break;
228 
229  default:
230  break;
231  }
232  return func;
233 }
234 
235 
236 /*
237  * Make hidden part of article after ^L visible.
238  * Returns:
239  * FALSE no ^L found, no changes
240  * TRUE ^L found and displayed page must be updated
241  * (draw_page must be called)
242  */
243 static t_bool
245  void)
246 {
247  int i;
248  int end = curr_line + ARTLINES;
249 
250  if (reveal_ctrl_l)
251  return FALSE;
252  if (end > artlines)
253  end = artlines;
254  for (i = reveal_ctrl_l_lines + 1; i < end; i++)
255  if (artline[i].flags & C_CTRLL) {
257  return TRUE;
258  }
259  reveal_ctrl_l_lines = end - 1;
260  return FALSE;
261 }
262 
263 
264 /*
265  * Re-hide revealed part of article after last ^L
266  * that is currently displayed.
267  * Returns:
268  * FALSE no ^L found, no changes
269  * TRUE ^L found and displayed page must be updated
270  * (draw_page must be called)
271  */
272 static t_bool
274  void)
275 {
276  int i;
277 
278  if (reveal_ctrl_l)
279  return FALSE;
280  for (i = reveal_ctrl_l_lines; i >= curr_line; i--)
281  if (artline[i].flags & C_CTRLL) {
282  reveal_ctrl_l_lines = i - 1;
283  return TRUE;
284  }
286  return FALSE;
287 }
288 
289 
290 /*
291  * The main routine for viewing articles
292  * Returns:
293  * >=0 normal exit - return a new base[] note
294  * <0 indicates some unusual condition. See GRP_* in tin.h
295  * GRP_QUIT User is doing a 'Q'
296  * GRP_RETSELECT Back to selection level due to 'T' command
297  * GRP_ARTUNAVAIL We didn't make it into the art
298  * don't bother fixing the screen up
299  * GRP_ARTABORT User 'q'uit load of article
300  * GRP_GOTOTHREAD To thread menu due to 'l' command
301  * GRP_NEXT Catchup with 'c'
302  * GRP_NEXTUNREAD " " 'C'
303  */
304 int
306  struct t_group *group,
307  int start_respnum, /* index into arts[] */
308  int *threadnum) /* to allow movement in thread mode */
309 {
310  char buf[LEN];
311  char key[MAXKEYLEN];
312  int i, j, n = 0;
313  int art_type = GROUP_TYPE_NEWS;
314  int hide_uue_tmp;
315  t_artnum old_artnum = T_ARTNUM_CONST(0);
316  t_bool mouse_click_on = TRUE;
317  t_bool repeat_search;
318  t_function func;
319 
320  if (group->attribute->mailing_list != NULL)
321  art_type = GROUP_TYPE_MAIL;
322 
323  /*
324  * Peek to see if the pager started due to a body search
325  * Stop load_article() changing context again
326  */
327  if (srch_lineno != -1)
328  this_resp = start_respnum;
329 
330  if ((i = load_article(start_respnum, group)) < 0)
331  return i;
332 
333  if (srch_lineno != -1)
335 
336  forever {
338  func = last_search;
339  repeat_search = TRUE;
340  } else
341  repeat_search = FALSE;
342 
343  switch (func) {
344  case GLOBAL_ABORT: /* Abort */
345  break;
346 
347  case DIGIT_1:
348  case DIGIT_2:
349  case DIGIT_3:
350  case DIGIT_4:
351  case DIGIT_5:
352  case DIGIT_6:
353  case DIGIT_7:
354  case DIGIT_8:
355  case DIGIT_9:
358  else {
359  if ((n = prompt_response(func_to_key(func, page_keys), this_resp)) != -1) {
360  XFACE_CLEAR();
361  if ((i = load_article(n, group)) < 0)
362  return i;
363  }
364  }
365  break;
366 
367 #ifndef NO_SHELL_ESCAPE
368  case GLOBAL_SHELL_ESCAPE:
369  XFACE_CLEAR();
370  shell_escape();
371  draw_page(group->name, 0);
372  break;
373 #endif /* !NO_SHELL_ESCAPE */
374 
376  if (mouse_click_on)
377  set_xclick_off();
378  else
379  set_xclick_on();
380  mouse_click_on = bool_not(mouse_click_on);
381  break;
382 
383  case GLOBAL_PAGE_UP:
384  if (activate_last_ctrl_l())
385  draw_page(group->name, 0);
386  else {
387  if (curr_line == 0)
389  else {
390  curr_line -= ((tinrc.scroll_lines == -2) ? ARTLINES / 2 : ARTLINES);
391  draw_page(group->name, 0);
392  }
393  }
394  break;
395 
396  case GLOBAL_PAGE_DOWN: /* page down or next response */
397  case PAGE_NEXT_UNREAD:
399  draw_page(group->name, 0);
400  else {
401  if (curr_line + ARTLINES >= artlines) { /* End is already on screen */
402  switch (func) {
403  case PAGE_NEXT_UNREAD: /* <TAB> */
404  goto page_goto_next_unread;
405 
406  case GLOBAL_PAGE_DOWN:
408  goto page_goto_next_unread;
409  break;
410 
411  default: /* to keep gcc quiet */
412  break;
413  }
415  } else {
417  goto page_goto_next_unread;
418 
419  curr_line += ((tinrc.scroll_lines == -2) ? ARTLINES / 2 : ARTLINES);
420 
421  if (tinrc.scroll_lines == -1) /* formerly show_last_line_prev_page */
422  curr_line--;
423  draw_page(group->name, 0);
424  }
425  }
426  break;
427 
428 page_goto_next_unread:
429  XFACE_CLEAR();
430  if ((n = next_unread(next_response(this_resp))) == -1)
431  return (which_thread(this_resp));
432  if ((i = load_article(n, group)) < 0)
433  return i;
434  break;
435 
436  case GLOBAL_FIRST_PAGE: /* beginning of article */
437  if (reveal_ctrl_l_lines > -1 || curr_line != 0) {
438  reveal_ctrl_l_lines = -1;
439  curr_line = 0;
440  draw_page(group->name, 0);
441  }
442  break;
443 
444  case GLOBAL_LAST_PAGE: /* end of article */
447  /* Display a full last page for neatness */
449  draw_page(group->name, 0);
450  }
451  break;
452 
453  case GLOBAL_LINE_UP:
454  if (activate_last_ctrl_l())
455  draw_page(group->name, 0);
456  else {
457  if (curr_line == 0) {
459  break;
460  }
461 
462  i = scroll_page(KEYMAP_UP);
463  curr_line += i;
464  draw_page(group->name, i);
465  }
466  break;
467 
468  case GLOBAL_LINE_DOWN:
470  draw_page(group->name, 0);
471  else {
472  if (curr_line + ARTLINES >= artlines) {
474  break;
475  }
476 
478  curr_line += i;
479  draw_page(group->name, i);
480  }
481  break;
482 
483  case GLOBAL_LAST_VIEWED: /* show last viewed article */
484  if (last_resp < 0 || (which_thread(last_resp) == -1)) {
486  break;
487  }
488  if ((i = load_article(last_resp, group)) < 0) {
489  XFACE_CLEAR();
490  return i;
491  }
492  break;
493 
494  case GLOBAL_LOOKUP_MESSAGEID: /* Goto article by Message-ID */
495  if ((n = prompt_msgid()) != ART_UNAVAILABLE) {
496  if ((i = load_article(n, group)) < 0) {
497  XFACE_CLEAR();
498  return i;
499  }
500  }
501  break;
502 
503  case PAGE_GOTO_PARENT: /* Goto parent of this article */
504  {
506 
507  if (parent == NULL) {
509  break;
510  }
511 
512  if (parent->article == ART_UNAVAILABLE) {
514  break;
515  }
516 
519  break;
520  }
521 
522  if ((i = load_article(parent->article, group)) < 0) {
523  XFACE_CLEAR();
524  return i;
525  }
526 
527  break;
528  }
529 
530  case GLOBAL_PIPE: /* pipe article/thread/tagged arts to command */
531  XFACE_SUPPRESS();
533  XFACE_SHOW();
534  break;
535 
536  case PAGE_MAIL: /* mail article/thread/tagged articles to somebody */
537  XFACE_SUPPRESS();
539  XFACE_SHOW();
540  break;
541 
542 #ifndef DISABLE_PRINTING
543  case GLOBAL_PRINT: /* output art/thread/tagged arts to printer */
544  XFACE_SUPPRESS();
546  XFACE_SHOW();
547  break;
548 #endif /* !DISABLE_PRINTING */
549 
550  case PAGE_REPOST: /* repost current article */
551  if (can_post) {
552  XFACE_SUPPRESS();
554  XFACE_SHOW();
555  } else
557  break;
558 
559  case PAGE_SAVE: /* save article/thread/tagged articles */
560  XFACE_SUPPRESS();
562  XFACE_SHOW();
563  break;
564 
565  case PAGE_AUTOSAVE: /* Auto-save articles without prompting */
566  if (grpmenu.curr >= 0) {
567  XFACE_SUPPRESS();
569  XFACE_SHOW();
570  }
571  break;
572 
575  break;
576 
577  case GLOBAL_SEARCH_SUBJECT_FORWARD: /* search in article */
580  break;
581 
584  draw_page(group->name, 0);
585  }
587  break;
588 
589  case GLOBAL_SEARCH_BODY: /* article body search */
590  if ((n = search_body(group, this_resp, repeat_search)) != -1) {
591  this_resp = n; /* Stop load_article() changing context again */
592  if ((i = load_article(n, group)) < 0) {
593  XFACE_CLEAR();
594  return i;
595  }
597  }
598  break;
599 
600  case PAGE_TOP_THREAD: /* first article in current thread */
601  if (arts[this_resp].prev >= 0) {
602  if ((n = which_thread(this_resp)) >= 0 && base[n] != this_resp) {
603  assert(n < grpmenu.max);
604  if ((i = load_article(base[n], group)) < 0) {
605  XFACE_CLEAR();
606  return i;
607  }
608  }
609  }
610  break;
611 
612  case PAGE_BOTTOM_THREAD: /* last article in current thread */
613  for (i = this_resp; i >= 0; i = arts[i].thread)
614  n = i;
615 
616  if (n != this_resp) {
617  if ((i = load_article(n, group)) < 0) {
618  XFACE_CLEAR();
619  return i;
620  }
621  }
622  break;
623 
624  case PAGE_NEXT_THREAD: /* start of next thread */
625  XFACE_CLEAR();
626  if ((n = next_thread(this_resp)) == -1)
627  return (which_thread(this_resp));
628  if ((i = load_article(n, group)) < 0)
629  return i;
630  break;
631 
632 #ifdef HAVE_PGP_GPG
633  case PAGE_PGP_CHECK_ARTICLE:
634  XFACE_SUPPRESS();
635  if (pgp_check_article(&pgart))
636  draw_page(group->name, 0);
637  XFACE_SHOW();
638  break;
639 #endif /* HAVE_PGP_GPG */
640 
641  case PAGE_TOGGLE_HEADERS: /* toggle display of all headers */
642  XFACE_CLEAR();
644  resize_article(TRUE, &pgart); /* Also recooks it.. */
645  curr_line = 0;
646  draw_page(group->name, 0);
647  break;
648 
649  case PAGE_TOGGLE_RAW: /* toggle display of whole 'raw' article */
650  XFACE_CLEAR();
651  toggle_raw(group);
652  break;
653 
654  case PAGE_TOGGLE_TEX2ISO: /* toggle german TeX to ISO latin1 style conversion */
655  if (((group->attribute->tex2iso_conv) = !(group->attribute->tex2iso_conv)))
657  else
658  pgart.tex2iso = FALSE;
659 
660  resize_article(TRUE, &pgart); /* Also recooks it.. */
661  draw_page(group->name, 0);
663  break;
664 
665  case PAGE_TOGGLE_TABS: /* toggle tab stops 8 vs 4 */
666  tabwidth = (tabwidth == 8) ? 4 : 8;
667  resize_article(TRUE, &pgart); /* Also recooks it.. */
668  draw_page(group->name, 0);
670  break;
671 
672  case PAGE_TOGGLE_UUE: /* toggle display of uuencoded sections */
673  hide_uue = (hide_uue + 1) % (UUE_ALL + 1);
674  resize_article(TRUE, &pgart); /* Also recooks it.. */
675  /*
676  * If we hid uue and are off the end of the article, reposition to
677  * show last page for neatness
678  */
679  if (hide_uue && curr_line + ARTLINES > artlines)
681  draw_page(group->name, 0);
682  /* TODO: info_message()? */
683  break;
684 
685  case PAGE_REVEAL: /* toggle hiding after ^L */
687  if (!reveal_ctrl_l) { /* switched back to active ^L's */
688  reveal_ctrl_l_lines = -1;
689  curr_line = 0;
690  } else
692  draw_page(group->name, 0);
693  /* TODO: info_message()? */
694  break;
695 
696  case GLOBAL_QUICK_FILTER_SELECT: /* quickly auto-select article */
697  case GLOBAL_QUICK_FILTER_KILL: /* quickly kill article */
698  if (quick_filter(func, group, &arts[this_resp])) {
699  old_artnum = arts[this_resp].artnum;
700  unfilter_articles(group);
701  filter_articles(group);
702  make_threads(group, FALSE);
703  if ((n = find_artnum(old_artnum)) == -1 || which_thread(n) == -1) /* We have lost the thread */
704  return GRP_KILLED;
705  this_resp = n;
706  draw_page(group->name, 0);
708  }
709  break;
710 
711  case GLOBAL_MENU_FILTER_SELECT: /* auto-select article menu */
712  case GLOBAL_MENU_FILTER_KILL: /* kill article menu */
713  XFACE_CLEAR();
714  if (filter_menu(func, group, &arts[this_resp])) {
715  old_artnum = arts[this_resp].artnum;
716  unfilter_articles(group);
717  filter_articles(group);
718  make_threads(group, FALSE);
719  if ((n = find_artnum(old_artnum)) == -1 || which_thread(n) == -1) /* We have lost the thread */
720  return GRP_KILLED;
721  this_resp = n;
722  }
723  draw_page(group->name, 0);
724  break;
725 
726  case GLOBAL_EDIT_FILTER:
727  XFACE_CLEAR();
729  old_artnum = arts[this_resp].artnum;
730  unfilter_articles(group);
732  filter_articles(group);
733  make_threads(group, FALSE);
734  if ((n = find_artnum(old_artnum)) == -1 || which_thread(n) == -1) /* We have lost the thread */
735  return GRP_KILLED;
736  this_resp = n;
737  }
738  draw_page(group->name, 0);
739  break;
740 
741  case GLOBAL_REDRAW_SCREEN: /* redraw current page of article */
742  my_retouch();
743  draw_page(group->name, 0);
744  break;
745 
746  case PAGE_TOGGLE_ROT13: /* toggle rot-13 mode */
747  rotate = rotate ? 0 : 13;
748  draw_page(group->name, 0);
750  break;
751 
752  case GLOBAL_SEARCH_AUTHOR_FORWARD: /* author search forward */
753  case GLOBAL_SEARCH_AUTHOR_BACKWARD: /* author search backward */
754  if ((n = search(func, this_resp, repeat_search)) < 0)
755  break;
756  if ((i = load_article(n, group)) < 0) {
757  XFACE_CLEAR();
758  return i;
759  }
760  break;
761 
762  case CATCHUP: /* catchup - mark read, goto next */
763  case CATCHUP_NEXT_UNREAD: /* goto next unread */
764  if (group->attribute->thread_articles == THREAD_NONE)
766  else
768  if ((!TINRC_CONFIRM_ACTION) || prompt_yn(buf, TRUE) == 1) {
770  XFACE_CLEAR();
771  return (func == CATCHUP_NEXT_UNREAD) ? GRP_NEXTUNREAD : GRP_NEXT;
772  }
773  break;
774 
775  case MARK_THREAD_UNREAD:
777  if (group->attribute->thread_articles != THREAD_NONE)
779  else
781  break;
782 
783  case PAGE_CANCEL: /* cancel an article */
784  if (can_post || art_type != GROUP_TYPE_NEWS) {
785  XFACE_SUPPRESS();
786  if (cancel_article(group, &arts[this_resp], this_resp))
787  draw_page(group->name, 0);
788  XFACE_SHOW();
789  } else
791  break;
792 
793  case PAGE_EDIT_ARTICLE: /* edit an article (mailgroup only) */
794  XFACE_SUPPRESS();
795  if (art_edit(group, &arts[this_resp]))
796  draw_page(group->name, 0);
797  XFACE_SHOW();
798  break;
799 
800  case PAGE_FOLLOWUP_QUOTE: /* post a followup to this article */
802  case PAGE_FOLLOWUP:
803  if (!can_post && art_type == GROUP_TYPE_NEWS) {
805  break;
806  }
807  XFACE_CLEAR();
808  (void) post_response(group->name, this_resp,
811  draw_page(group->name, 0);
812  break;
813 
814  case GLOBAL_HELP: /* help */
815  XFACE_CLEAR();
817  draw_page(group->name, 0);
818  break;
819 
820  case GLOBAL_TOGGLE_HELP_DISPLAY: /* toggle mini help menu */
822  draw_page(group->name, 0);
823  break;
824 
825  case GLOBAL_QUIT: /* return to index page */
826 return_to_index:
827  XFACE_CLEAR();
828  i = which_thread(this_resp);
829  if (threadnum)
830  *threadnum = which_response(this_resp);
831 
832  return i;
833 
834  case GLOBAL_TOGGLE_INVERSE_VIDEO: /* toggle inverse video */
836  draw_page(group->name, 0);
838  break;
839 
840 #ifdef HAVE_COLOR
841  case GLOBAL_TOGGLE_COLOR: /* toggle color */
842  if (toggle_color()) {
843  draw_page(group->name, 0);
844  show_color_status();
845  }
846  break;
847 #endif /* HAVE_COLOR */
848 
849  case PAGE_LIST_THREAD: /* -> thread page that this article is in */
850  XFACE_CLEAR();
852  return GRP_GOTOTHREAD;
853 
854  case GLOBAL_OPTION_MENU: /* option menu */
855  XFACE_CLEAR();
856  old_artnum = arts[this_resp].artnum;
858  if ((this_resp = find_artnum(old_artnum)) == -1 || which_thread(this_resp) == -1) { /* We have lost the thread */
860  return GRP_EXIT;
861  }
863  draw_page(group->name, 0);
864  break;
865 
866  case PAGE_NEXT_ARTICLE: /* skip to next article */
867  XFACE_CLEAR();
868  if ((n = next_response(this_resp)) == -1)
869  return (which_thread(this_resp));
870 
871  if ((i = load_article(n, group)) < 0)
872  return i;
873  break;
874 
875  case PAGE_MARK_THREAD_READ: /* mark rest of thread as read */
876  thd_mark_read(group, this_resp);
877  if ((n = next_unread(next_response(this_resp))) == -1)
878  goto return_to_index;
879  if ((i = load_article(n, group)) < 0) {
880  XFACE_CLEAR();
881  return i;
882  }
883  break;
884 
885  case PAGE_NEXT_UNREAD_ARTICLE: /* next unread article */
886  goto page_goto_next_unread;
887 
888  case PAGE_PREVIOUS_ARTICLE: /* previous article */
889  XFACE_CLEAR();
890  if ((n = prev_response(this_resp)) == -1)
891  return this_resp;
892 
893  if ((i = load_article(n, group)) < 0)
894  return i;
895  break;
896 
897  case PAGE_PREVIOUS_UNREAD_ARTICLE: /* previous unread article */
898  if ((n = prev_unread(prev_response(this_resp))) == -1)
900  else {
901  if ((i = load_article(n, group)) < 0) {
902  XFACE_CLEAR();
903  return i;
904  }
905  }
906  break;
907 
908  case GLOBAL_QUIT_TIN: /* quit */
909  XFACE_CLEAR();
910  return GRP_QUIT;
911 
912  case PAGE_REPLY_QUOTE: /* reply to author through mail */
914  case PAGE_REPLY:
915  XFACE_CLEAR();
917  draw_page(group->name, 0);
918  break;
919 
920  case PAGE_TAG: /* tag/untag article for saving */
922  break;
923 
924  case PAGE_GROUP_SELECT: /* return to group selection page */
925 #if 0
926  /* Hasn't been used since tin 1.1 PL4 */
927  if (filter_state == FILTERING) {
928  filter_articles(group);
929  make_threads(group, FALSE);
930  }
931 #endif /* 0 */
932  XFACE_CLEAR();
933  return GRP_RETSELECT;
934 
935  case GLOBAL_VERSION:
937  break;
938 
939  case GLOBAL_POST: /* post a basenote */
940  XFACE_SUPPRESS();
941  if (post_article(group->name))
942  draw_page(group->name, 0);
943  XFACE_SHOW();
944  break;
945 
946  case GLOBAL_POSTPONED: /* post postponed article */
947  if (can_post || art_type != GROUP_TYPE_NEWS) {
948  XFACE_SUPPRESS();
950  draw_page(group->name, 0);
951  XFACE_SHOW();
952  } else
954  break;
955 
956  case GLOBAL_DISPLAY_POST_HISTORY: /* display messages posted by user */
957  XFACE_SUPPRESS();
958  if (user_posted_messages())
959  draw_page(group->name, 0);
960  XFACE_SHOW();
961  break;
962 
963  case MARK_ARTICLE_UNREAD: /* mark article as unread(to return) */
966  break;
967 
968  case PAGE_SKIP_INCLUDED_TEXT: /* skip included text */
969  for (i = j = curr_line; i < artlines; i++) {
970  if (artline[i].flags & (C_QUOTE1 | C_QUOTE2 | C_QUOTE3)) {
971  j = i;
972  break;
973  }
974  }
975 
976  for (; j < artlines; j++) {
977  if (!(artline[j].flags & (C_QUOTE1 | C_QUOTE2 | C_QUOTE3)))
978  break;
979  }
980 
981  if (j != curr_line) {
982  curr_line = j;
983  draw_page(group->name, 0);
984  }
985  break;
986 
987  case GLOBAL_TOGGLE_INFO_LAST_LINE: /* this is _not_ correct, we do not toggle status here */
988  info_message("%s", arts[this_resp].subject);
989  break;
990 
993  draw_page(group->name, 0);
995  break;
996 
998  XFACE_SUPPRESS();
999  hide_uue_tmp = hide_uue;
1000  hide_uue = UUE_NO;
1003  hide_uue = hide_uue_tmp;
1005  draw_page(group->name, 0);
1006  XFACE_SHOW();
1007  break;
1008 
1009  case PAGE_VIEW_URL:
1010  if (!show_raw_article) { /* cooked mode? */
1011  t_bool success;
1012 
1013  XFACE_SUPPRESS();
1014  resize_article(FALSE, &pgart); /* unbreak long lines */
1015  success = url_page();
1016  resize_article(TRUE, &pgart); /* rebreak long lines */
1017  draw_page(group->name, 0);
1018  if (!success)
1020  XFACE_SHOW();
1021  }
1022  break;
1023 
1024  default:
1026  }
1027  }
1028  /* NOTREACHED */
1029  return GRP_ARTUNAVAIL;
1030 }
1031 
1032 
1033 static void
1035  FILE *file,
1036  t_lineinfo *messageline,
1037  size_t messagelines,
1038  size_t base_line,
1039  size_t begin,
1040  size_t end,
1041  int help_level)
1042 {
1043  char *line;
1044  char *p;
1045  int bytes;
1046  size_t i = begin;
1047  t_lineinfo *curr;
1048 
1049  for (; i < end; i++) {
1050  if (base_line + i >= messagelines) /* ran out of message */
1051  break;
1052 
1053  curr = &messageline[base_line + i];
1054 
1055  if (fseek(file, curr->offset, SEEK_SET) != 0)
1056  break;
1057 
1058  if ((line = tin_fgets(file, FALSE)) == NULL)
1059  break; /* ran out of message */
1060 
1061  if ((help_level == INFO_PAGER) && (strwidth(line) >= cCOLS - 1))
1062 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1063  {
1064  char *tmp, *f, *t;
1065 
1066  f = tmp = strunc(line, cCOLS - 1);
1067  t = line;
1068  while (*f)
1069  *t++ = *f++;
1070  *t = '\0';
1071  free(tmp);
1072  }
1073 #else
1074  line[cCOLS - 1] = '\0';
1075 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1076 
1077  /*
1078  * use the offsets gained while doing line wrapping to
1079  * determine the correct position to truncate the line
1080  */
1081  if ((help_level != INFO_PAGER) && (base_line + i < messagelines - 1)) { /* not last line of message */
1082  bytes = (curr + 1)->offset - curr->offset;
1083  line[bytes] = '\0';
1084  }
1085 
1086  /*
1087  * rotN encoding on body and sig data only
1088  */
1089  if ((rotate != 0) && ((curr->flags & (C_BODY | C_SIG)) || show_raw_article)) {
1090  for (p = line; *p; p++) {
1091  if (*p >= 'A' && *p <= 'Z')
1092  *p = (*p - 'A' + rotate) % 26 + 'A';
1093  else if (*p >= 'a' && *p <= 'z')
1094  *p = (*p - 'a' + rotate) % 26 + 'a';
1095  }
1096  }
1097 
1098  strip_line(line);
1099 
1100 #ifndef USE_CURSES
1101  snprintf(screen[i + scroll_region_top].col, cCOLS, "%s" cCRLF, line);
1102 #endif /* !USE_CURSES */
1103 
1104  MoveCursor(i + scroll_region_top, 0);
1105  draw_pager_line(line, curr->flags, show_raw_article);
1106 
1107  /*
1108  * Highlight URL's and mail addresses
1109  */
1110  if (tinrc.url_highlight) {
1111  if (curr->flags & C_URL)
1112 #ifdef HAVE_COLOR
1113  highlight_regexes(i + scroll_region_top, &url_regex, use_color ? tinrc.col_urls : -1);
1114 #else
1116 #endif /* HAVE_COLOR */
1117 
1118  if (curr->flags & C_MAIL)
1119 #ifdef HAVE_COLOR
1120  highlight_regexes(i + scroll_region_top, &mail_regex, use_color ? tinrc.col_urls : -1);
1121 #else
1123 #endif /* HAVE_COLOR */
1124 
1125  if (curr->flags & C_NEWS)
1126 #ifdef HAVE_COLOR
1127  highlight_regexes(i + scroll_region_top, &news_regex, use_color ? tinrc.col_urls : -1);
1128 #else
1130 #endif /* HAVE_COLOR */
1131  }
1132 
1133  /*
1134  * Highlight /slashes/, *stars*, _underscores_ and -strokes-
1135  */
1136  if (word_highlight && (curr->flags & C_BODY) && !(curr->flags & C_CTRLL)) {
1137 #ifdef HAVE_COLOR
1138  highlight_regexes(i + scroll_region_top, &slashes_regex, use_color ? tinrc.col_markslash : tinrc.mono_markslash);
1139  highlight_regexes(i + scroll_region_top, &stars_regex, use_color ? tinrc.col_markstar : tinrc.mono_markstar);
1141  highlight_regexes(i + scroll_region_top, &strokes_regex, use_color ? tinrc.col_markstroke : tinrc.mono_markstroke);
1142 #else
1147 #endif /* HAVE_COLOR */
1148  }
1149 
1150  /* Blank the screen after a ^L (only occurs when showing cooked) */
1151  if (!reveal_ctrl_l && (curr->flags & C_CTRLL) && (int) (base_line + i) > reveal_ctrl_l_lines) {
1152  CleartoEOS();
1153  break;
1154  }
1155  }
1156 
1157 #ifdef HAVE_COLOR
1158  fcol(tinrc.col_text);
1159 #endif /* HAVE_COLOR */
1160 
1161  show_mini_help(help_level);
1162 }
1163 
1164 
1165 /*
1166  * Redraw the current page, curr_line will be the first line displayed
1167  * Everything that calls draw_page() just sets curr_line, this function must
1168  * ensure it is set to something sane
1169  * If part is !=0, then only draw the first (-ve) or last (+ve) few lines
1170  */
1171 void
1173  const char *group,
1174  int part)
1175 {
1176  int start, end; /* 1st, last line to draw */
1177 
1179 
1180  /*
1181  * Can't do partial draw if term can't scroll properly
1182  */
1183  if (part && !have_linescroll)
1184  part = 0;
1185 
1186  /*
1187  * Ensure curr_line is in bounds
1188  */
1189  if (curr_line < 0)
1190  curr_line = 0; /* Oops - off the top */
1191  else {
1192  if (curr_line > artlines)
1193  curr_line = artlines; /* Oops - off the end */
1194  }
1195 
1196  search_line = curr_line; /* Reset search to start from top of display */
1197 
1199 
1200  /* Down-scroll, only redraw bottom 'part' lines of screen */
1201  if ((start = (part > 0) ? ARTLINES - part : 0) < 0)
1202  start = 0;
1203 
1204  /* Up-scroll, only redraw the top 'part' lines of screen */
1205  if ((end = (part < 0) ? -part : ARTLINES) > ARTLINES)
1206  end = ARTLINES;
1207 
1208  /*
1209  * ncurses doesn't clear the scroll area when you scroll by more than the
1210  * window size - force full redraw
1211  */
1212  if ((end - start >= ARTLINES) || (part == 0)) {
1213  ClearScreen();
1214  draw_page_header(group);
1215  } else
1216  MoveCursor(0, 0);
1217 
1219 
1220  /*
1221  * Print an appropriate footer
1222  */
1223  if (curr_line + ARTLINES >= artlines) {
1224  char buf[LEN], *buf2;
1225  int len;
1226 
1227  STRCPY(buf, (arts[this_resp].thread != -1) ? _(txt_next_resp) : _(txt_last_resp));
1228  buf2 = strunc(buf, cCOLS - 1);
1229  len = strwidth(buf2);
1230  clear_message();
1231  MoveCursor(cLINES, cCOLS - len - (1 + BLANK_PAGE_COLS));
1232 #ifdef HAVE_COLOR
1233  fcol(tinrc.col_normal);
1234 #endif /* HAVE_COLOR */
1235  StartInverse();
1236  my_fputs(buf2, stdout);
1237  EndInverse();
1238  my_flush();
1239  free(buf2);
1240  } else
1242 
1243 #ifdef XFACE_ABLE
1244  if (tinrc.use_slrnface && !show_raw_article)
1245  slrnface_display_xface(note_h->xface);
1246 #endif /* XFACE_ABLE */
1247 
1248  stow_cursor();
1249 }
1250 
1251 
1252 /*
1253  * Start external metamail program
1254  */
1255 static void
1257  FILE *fp)
1258 {
1259  char *ptr = tinrc.metamail_prog;
1260  char buf[LEN];
1261  long offset;
1262  FILE *mime_fp;
1263 #ifdef DONT_HAVE_PIPING
1264  char mimefile[PATH_LEN];
1265  int fd_mime;
1266 #endif /* DONT_HAVE_PIPING */
1267 
1268  if ((*ptr == '\0') || (!strcmp(ptr, INTERNAL_CMD)) || (getenv("NOMETAMAIL") != NULL))
1269  return;
1270 
1271  if ((offset = ftell(fp)) == -1) {
1273  return;
1274  }
1275 
1276  EndWin();
1277  Raw(FALSE);
1278 
1279 #ifdef DONT_HAVE_PIPING
1280  if ((fd_mime = my_tmpfile(mimefile, sizeof(mimefile) - 1, homedir)) == -1) {
1282  return;
1283  }
1284  if ((mime_fp = fdopen(fd_mime, "w")))
1285 #else
1286  if ((mime_fp = popen(ptr, "w")))
1287 #endif /* DONT_HAVE_PIPING */
1288  {
1289  rewind(fp);
1290  while (fgets(buf, (int) sizeof(buf), fp) != NULL)
1291  fputs(buf, mime_fp);
1292 
1293  fflush(mime_fp);
1294  /* This is needed if we are viewing the raw art */
1295  fseek(fp, offset, SEEK_SET); /* goto old position */
1296 
1297 #ifdef DONT_HAVE_PIPING
1298  snprintf(buf, sizeof(buf) -1, "%s %s", tinrc.metamail_prog, mimefile);
1299  invoke_cmd(buf);
1300  fclose(mime_fp);
1301  unlink(mimefile);
1302 #else
1303  pclose(mime_fp);
1304 #endif /* DONT_HAVE_PIPING */
1305  } else
1307 
1308 #ifdef USE_CURSES
1309  Raw(TRUE);
1310  InitWin();
1311 #endif /* USE_CURSES */
1312  prompt_continue();
1313 #ifndef USE_CURSES
1314  Raw(TRUE);
1315  InitWin();
1316 #endif /* !USE_CURSES */
1317 }
1318 
1319 
1320 /*
1321  * PAGE_HEADER defines the size in lines of this header
1322  */
1323 static void
1325  const char *group)
1326 {
1327  char *buf, *tmp;
1328  int i;
1329  int whichresp, x_resp;
1330  int len, right_len, center_pos, cur_pos;
1331  size_t line_len;
1332 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1333  wchar_t *fmt_resp, *fmt_thread, *wtmp, *wtmp2, *wbuf;
1334 #else
1335  char *tmp2;
1336 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1337 
1338  whichresp = which_response(this_resp);
1340 
1341  line_len = LEN + 1;
1342  buf = my_malloc(line_len);
1343 
1344  if (!my_strftime(buf, line_len, curr_group->attribute->date_format, localtime(&arts[this_resp].date))) {
1345  strncpy(buf, BlankIfNull(note_h->date), line_len);
1346  buf[line_len - 1] = '\0';
1347  }
1348 
1349 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1350  /* convert to wide-char format strings */
1351  fmt_thread = char2wchar_t(_(txt_thread_x_of_n));
1352  fmt_resp = char2wchar_t(_(txt_art_x_of_n));
1353 
1354  /*
1355  * determine the needed space for the text at the right hand margin
1356  * the formatting info (%4s) needs 3 positions but we need 4 positions
1357  * on the screen for each counter.
1358  */
1359  if (fmt_thread && fmt_resp)
1360  right_len = MAX((wcswidth(fmt_thread, wcslen(fmt_thread)) - 6 + 8), (wcswidth(fmt_resp, wcslen(fmt_resp)) - 6 + 8));
1361  else if (fmt_thread)
1362  right_len = wcswidth(fmt_thread, wcslen(fmt_thread)) - 6 + 8;
1363  else if (fmt_resp)
1364  right_len = wcswidth(fmt_resp, wcslen(fmt_resp)) - 6 + 8;
1365  else
1366  right_len = 0;
1367  FreeIfNeeded(fmt_thread);
1368  FreeIfNeeded(fmt_resp);
1369 
1370  /*
1371  * limit right_len to cCOLS / 3
1372  */
1373  if (right_len > cCOLS / 3 + 1)
1374  right_len = cCOLS / 3 + 1;
1375 
1376  /*
1377  * first line
1378  */
1379  cur_pos = 0;
1380 
1381 # ifdef HAVE_COLOR
1382  fcol(tinrc.col_head);
1383 # endif /* HAVE_COLOR */
1384 
1385  /* date */
1386  if ((wtmp = char2wchar_t(buf)) != NULL) {
1387  my_fputws(wtmp, stdout);
1388  cur_pos += wcswidth(wtmp, wcslen(wtmp));
1389  free(wtmp);
1390  }
1391 
1392  /*
1393  * determine max len for centered group name
1394  * allow one space before and after group name
1395  */
1396  len = cCOLS - 2 * MAX(cur_pos, right_len) - 3;
1397 
1398  /* group name */
1399  if ((wtmp = char2wchar_t(group)) != NULL) {
1400  /* wconvert_to_printable(wtmp, FALSE); */
1402  wtmp2 = abbr_wcsgroupname(wtmp, len);
1403  else
1404  wtmp2 = wstrunc(wtmp, len);
1405 
1406  if ((i = wcswidth(wtmp2, wcslen(wtmp2))) < len)
1407  len = i;
1408 
1409  center_pos = (cCOLS - len) / 2;
1410 
1411  /* pad out to left */
1412  for (; cur_pos < center_pos; cur_pos++)
1413  my_fputc(' ', stdout);
1414 
1415  my_fputws(wtmp2, stdout);
1416  cur_pos += wcswidth(wtmp2, wcslen(wtmp2));
1417  free(wtmp2);
1418  free(wtmp);
1419  }
1420 
1421  /* pad out to right */
1422  for (; cur_pos < cCOLS - right_len - 1; cur_pos++)
1423  my_fputc(' ', stdout);
1424 
1425  /* thread info */
1426  /* can't eval tin_ltoa() more than once in a statement due to statics */
1427  strcpy(buf, tin_ltoa(which_thread(this_resp) + 1, 4));
1428  tmp = strunc(_(txt_thread_x_of_n), cCOLS / 3 - 1);
1429  my_printf(tmp, buf, tin_ltoa(grpmenu.max, 4));
1430  free(tmp);
1431 
1432  my_fputs(cCRLF, stdout);
1433 
1434 # if 0
1435  /* display a ruler for layout checking purposes */
1436  my_fputs("....|....3....|....2....|....1....|....0....|....1....|....2....|....3....|....\n", stdout);
1437 # endif /* 0 */
1438 
1439  /*
1440  * second line
1441  */
1442  cur_pos = 0;
1443 
1444 # ifdef HAVE_COLOR
1445  fcol(tinrc.col_head);
1446 # endif /* HAVE_COLOR */
1447 
1448  /* line count */
1449  if (arts[this_resp].line_count < 0)
1450  strcpy(buf, "?");
1451  else
1452  snprintf(buf, line_len, "%-4d", arts[this_resp].line_count);
1453 
1454  {
1455  wchar_t *fmt;
1456 
1457  if ((wtmp = char2wchar_t(_(txt_lines))) != NULL) {
1458  int tex_space = pgart.tex2iso ? 5 : 0;
1459 
1460  fmt = wstrunc(wtmp, cCOLS / 3 - 1 - tex_space);
1461  wtmp = my_realloc(wtmp, sizeof(wchar_t) * line_len);
1462  swprintf(wtmp, line_len, fmt, buf);
1463  my_fputws(wtmp, stdout);
1464  cur_pos += wcswidth(wtmp, wcslen(wtmp));
1465  free(fmt);
1466  free(wtmp);
1467  }
1468  }
1469 
1470 # ifdef HAVE_COLOR
1471  fcol(tinrc.col_subject);
1472 # endif /* HAVE_COLOR */
1473 
1474  /* tex2iso */
1475  if (pgart.tex2iso) {
1476  if ((wtmp = char2wchar_t(_(txt_tex))) != NULL) {
1477  wtmp2 = wstrunc(wtmp, 5);
1478  my_fputws(wtmp2, stdout);
1479  cur_pos += wcswidth(wtmp2, wcslen(wtmp2));
1480  free(wtmp);
1481  free(wtmp2);
1482  }
1483  }
1484 
1485  /* subject */
1486  /*
1487  * TODO: why do we fall back to arts[this_resp].subject if !note_h->subj?
1488  * if !note_h->subj then the article just has no subject, no matter
1489  * what the overview says.
1490  */
1491  strncpy(buf, (note_h->subj ? note_h->subj : arts[this_resp].subject), line_len);
1492  buf[line_len - 1] = '\0';
1493  if ((wtmp = char2wchar_t(buf)) != NULL) {
1494  wbuf = wexpand_tab(wtmp, tabwidth);
1495  wtmp2 = wstrunc(wbuf, cCOLS - 2 * right_len - 3);
1496  center_pos = (cCOLS - wcswidth(wtmp2, wcslen(wtmp2))) / 2;
1497 
1498  /* pad out to left */
1499  for (; cur_pos < center_pos; cur_pos++)
1500  my_fputc(' ', stdout);
1501 
1502  StartInverse();
1503  my_fputws(wtmp2, stdout);
1504  EndInverse();
1505  cur_pos += wcswidth(wtmp2, wcslen(wtmp2));
1506  free(wtmp2);
1507  free(wtmp);
1508  free(wbuf);
1509  }
1510 
1511 # ifdef HAVE_COLOR
1512  fcol(tinrc.col_response);
1513 # endif /* HAVE_COLOR */
1514 
1515  /* pad out to right */
1516  for (; cur_pos < cCOLS - right_len - 1; cur_pos++)
1517  my_fputc(' ', stdout);
1518 
1519  if (whichresp) {
1520  tmp = strunc(_(txt_art_x_of_n), cCOLS / 3 - 1);
1521  my_printf(tmp, whichresp + 1, x_resp + 1);
1522  free(tmp);
1523  } else {
1524  /* TODO: ngettext */
1525  if (!x_resp) {
1526  tmp = strunc(_(txt_no_responses), cCOLS / 3 - 1);
1527  my_printf("%s", tmp);
1528  } else if (x_resp == 1) {
1529  tmp = strunc(_(txt_1_resp), cCOLS / 3 - 1);
1530  my_printf("%s", tmp);
1531  } else {
1532  tmp = strunc(_(txt_x_resp), cCOLS / 3 - 1);
1533  my_printf(tmp, x_resp);
1534  }
1535  free(tmp);
1536  }
1537  my_fputs(cCRLF, stdout);
1538 
1539  /*
1540  * third line
1541  */
1542  cur_pos = 0;
1543 
1544 # ifdef HAVE_COLOR
1545  fcol(tinrc.col_from);
1546 # endif /* HAVE_COLOR */
1547  /* from */
1548  /*
1549  * TODO: don't use arts[this_resp].name/arts[this_resp].from
1550  * split up note_h->from and use that instead as it might
1551  * be different _if_ the overviews are broken
1552  */
1553  {
1554  char *p = idna_decode(arts[this_resp].from);
1555 
1556  if (arts[this_resp].name)
1557  snprintf(buf, line_len, "%s <%s>", arts[this_resp].name, p);
1558  else {
1559  strncpy(buf, p, line_len);
1560  buf[line_len - 1] = '\0';
1561  }
1562  free(p);
1563  }
1564 
1565  if ((wtmp = char2wchar_t(buf)) != NULL) {
1566  wtmp2 = wstrunc(wtmp, cCOLS - 1);
1567  my_fputws(wtmp2, stdout);
1568  cur_pos += wcswidth(wtmp2, wcslen(wtmp2));
1569  free(wtmp2);
1570  free(wtmp);
1571  }
1572 
1573  /*
1574  * Organization
1575  *
1576  * TODO: IDNA decoding, see also comment in
1577  * cook.c:cook_article()
1578  */
1579  if (note_h->org) {
1580  snprintf(buf, line_len, _(txt_at_s), note_h->org);
1581 
1582  if ((wtmp = char2wchar_t(buf)) != NULL) {
1583  wbuf = wexpand_tab(wtmp, tabwidth);
1584  wtmp2 = wstrunc(wbuf, cCOLS - cur_pos - 1);
1585 
1586  i = cCOLS - wcswidth(wtmp2, wcslen(wtmp2)) - 1;
1587  for (; cur_pos < i; cur_pos++)
1588  my_fputc(' ', stdout);
1589 
1590  my_fputws(wtmp2, stdout);
1591  free(wtmp2);
1592  free(wtmp);
1593  free(wbuf);
1594  }
1595  }
1596 
1597  my_fputs(cCRLF, stdout);
1598  my_fputs(cCRLF, stdout);
1599 
1600 #else /* !MULTIBYTE_ABLE || NO_LOCALE */
1601  /*
1602  * determine the needed space for the text at the right hand margin
1603  * the formatting info (%4s) needs 3 positions but we need 4 positions
1604  * on the screen for each counter
1605  */
1606  right_len = MAX((strlen(_(txt_thread_x_of_n)) - 6 + 8), (strlen(_(txt_art_x_of_n)) - 6 + 8));
1607 
1608  /*
1609  * first line
1610  */
1611  cur_pos = 0;
1612 
1613 # ifdef HAVE_COLOR
1614  fcol(tinrc.col_head);
1615 # endif /* HAVE_COLOR */
1616 
1617  /* date */
1618  my_fputs(buf, stdout);
1619  cur_pos += strlen(buf);
1620 
1621  /*
1622  * determine max len for centered group name
1623  * allow one space before and after group name
1624  */
1625  len = cCOLS - 2 * MAX(cur_pos, right_len) - 3;
1626 
1627  /* group name */
1629  tmp = abbr_groupname(group, len);
1630  else
1631  tmp = strunc(group, len);
1632 
1633  if ((i = strlen(tmp)) < len)
1634  len = i;
1635 
1636  center_pos = (cCOLS - len) / 2;
1637 
1638  /* pad out to left */
1639  for (; cur_pos < center_pos; cur_pos++)
1640  my_fputc(' ', stdout);
1641 
1642  my_fputs(tmp, stdout);
1643  cur_pos += strlen(tmp);
1644  free(tmp);
1645 
1646  /* pad out to right */
1647  for (; cur_pos < cCOLS - right_len - 1; cur_pos++)
1648  my_fputc(' ', stdout);
1649 
1650  /* thread info */
1651  /* can't eval tin_ltoa() more than once in a statement due to statics */
1652  strcpy(buf, tin_ltoa(which_thread(this_resp) + 1, 4));
1654 
1655  my_fputs(cCRLF, stdout);
1656 
1657 # if 0
1658  /* display a ruler for layout checking purposes */
1659  my_fputs("....|....3....|....2....|....1....|....0....|....1....|....2....|....3....|....\n", stdout);
1660 # endif /* 0 */
1661 
1662  /*
1663  * second line
1664  */
1665  cur_pos = 0;
1666 
1667 # ifdef HAVE_COLOR
1668  fcol(tinrc.col_head);
1669 # endif /* HAVE_COLOR */
1670 
1671  /* line count */
1672  /* an accurate line count will appear in the footer anymay */
1673  if (arts[this_resp].line_count < 0)
1674  strcpy(buf, "?");
1675  else
1676  snprintf(buf, line_len, "%-4d", arts[this_resp].line_count);
1677 
1678  tmp = my_malloc(line_len);
1679  snprintf(tmp, line_len, _(txt_lines), buf);
1680  my_fputs(tmp, stdout);
1681  cur_pos += strlen(tmp);
1682  free(tmp);
1683 
1684 # ifdef HAVE_COLOR
1685  fcol(tinrc.col_subject);
1686 # endif /* HAVE_COLOR */
1687 
1688  /* tex2iso */
1689  if (pgart.tex2iso) {
1690  my_fputs(_(txt_tex), stdout);
1691  cur_pos += strlen(_(txt_tex));
1692  }
1693 
1694  /* subject */
1695  /*
1696  * TODO: why do we fall back to arts[this_resp].subject if !note_h->subj?
1697  * if !note_h->subj then the article just has no subject, no matter
1698  * what the overview says.
1699  */
1700  strncpy(buf, (note_h->subj ? note_h->subj : arts[this_resp].subject), line_len);
1701  buf[line_len - 1] = '\0';
1702 
1703  tmp2 = expand_tab(buf, tabwidth);
1704  tmp = strunc(tmp2, cCOLS - 2 * right_len - 3);
1705 
1706  center_pos = (cCOLS - strlen(tmp)) / 2;
1707 
1708  /* pad out to left */
1709  for (; cur_pos < center_pos; cur_pos++)
1710  my_fputc(' ', stdout);
1711 
1712  StartInverse();
1713  my_fputs(tmp, stdout);
1714  EndInverse();
1715  cur_pos += strlen(tmp);
1716  free(tmp);
1717  free(tmp2);
1718 
1719 # ifdef HAVE_COLOR
1720  fcol(tinrc.col_response);
1721 # endif /* HAVE_COLOR */
1722 
1723  /* pad out to right */
1724  for (; cur_pos < cCOLS - right_len - 1; cur_pos++)
1725  my_fputc(' ', stdout);
1726 
1727  if (whichresp)
1728  my_printf(_(txt_art_x_of_n), whichresp + 1, x_resp + 1);
1729  else {
1730  /* TODO: ngettext */
1731  if (!x_resp)
1732  my_printf("%s", _(txt_no_responses));
1733  else if (x_resp == 1)
1734  my_printf("%s", _(txt_1_resp));
1735  else
1736  my_printf(_(txt_x_resp), x_resp);
1737  }
1738  my_fputs(cCRLF, stdout);
1739 
1740  /*
1741  * third line
1742  */
1743  cur_pos = 0;
1744 
1745 # ifdef HAVE_COLOR
1746  fcol(tinrc.col_from);
1747 # endif /* HAVE_COLOR */
1748  /* from */
1749  /*
1750  * TODO: don't use arts[this_resp].name/arts[this_resp].from
1751  * split up note_h->from and use that instead as it might
1752  * be different _if_ the overviews are broken
1753  */
1754  if (arts[this_resp].name)
1755  snprintf(buf, line_len, "%s <%s>", arts[this_resp].name, arts[this_resp].from);
1756  else {
1757  strncpy(buf, arts[this_resp].from, line_len);
1758  buf[line_len - 1] = '\0';
1759  }
1760 
1761  tmp = strunc(buf, cCOLS - 1);
1762  my_fputs(tmp, stdout);
1763  cur_pos += strlen(tmp);
1764  free(tmp);
1765 
1766  if (note_h->org && cCOLS - cur_pos - 1 >= (int) strlen(_(txt_at_s)) - 2 + 3) {
1767  /* we have enough space to print at least " at ..." */
1768  snprintf(buf, line_len, _(txt_at_s), note_h->org);
1769 
1770  tmp2 = expand_tab(buf, tabwidth);
1771  tmp = strunc(tmp2, cCOLS - cur_pos - 1);
1772  len = cCOLS - (int) strlen(tmp) - 1;
1773  for (; cur_pos < len; cur_pos++)
1774  my_fputc(' ', stdout);
1775  my_fputs(tmp, stdout);
1776  free(tmp);
1777  free(tmp2);
1778  }
1779 
1780  my_fputs(cCRLF, stdout);
1781  my_fputs(cCRLF, stdout);
1782 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1783  free(buf);
1784 
1785 #ifdef HAVE_COLOR
1786  fcol(tinrc.col_normal);
1787 #endif /* HAVE_COLOR */
1788 }
1789 
1790 
1791 /*
1792  * Change the pager article context to arts[new_respnum]
1793  * Return GRP_ARTUNAVAIL if article could not be opened
1794  * or GRP_ARTABORT if load of article was interrupted
1795  * or 0 on success
1796  */
1797 static int
1799  int new_respnum,
1800  struct t_group *group)
1801 {
1802  static t_bool art_closed = FALSE;
1803 
1804 #ifdef DEBUG
1805  if (debug & DEBUG_MISC)
1806  fprintf(stderr, "load_art %s(new=%d, curr=%d)\n", (new_respnum == this_resp && !art_closed) ? "ALREADY OPEN!" : "", new_respnum, this_resp);
1807 #endif /* DEBUG */
1808 
1809  if (new_respnum != this_resp || art_closed) {
1810  int ret;
1811 
1812  art_close(&pgart); /* close previously opened art in pager */
1813  ret = art_open(TRUE, &arts[new_respnum], group, &pgart, TRUE, _(txt_reading_article));
1814 
1815  switch (ret) {
1816  case ART_UNAVAILABLE:
1817  art_mark(group, &arts[new_respnum], ART_READ);
1818  /* prevent retagging as unread in unfilter_articles() */
1819  if (arts[new_respnum].killed == ART_KILLED_UNREAD)
1820  arts[new_respnum].killed = ART_KILLED;
1821  art_closed = TRUE;
1823  return GRP_ARTUNAVAIL;
1824 
1825  case ART_ABORT:
1826  art_close(&pgart);
1827  art_closed = TRUE;
1828  return GRP_ARTABORT; /* special retcode to stop redrawing screen */
1829 
1830  default: /* Normal case */
1831 #if 0 /* Very useful debugging tool */
1832  if (prompt_yn("Fake art unavailable? ", FALSE) == 1) {
1833  art_close(&pgart);
1834  art_mark(group, &arts[new_respnum], ART_READ);
1835  art_closed = TRUE;
1836  return GRP_ARTUNAVAIL;
1837  }
1838 #endif /* 0 */
1839  if (art_closed)
1840  art_closed = FALSE;
1841  if (new_respnum != this_resp) {
1842  /*
1843  * Remember current & previous articles for '-' command
1844  */
1845  last_resp = this_resp;
1846  this_resp = new_respnum; /* Set new art globally */
1847  }
1848  break;
1849  }
1850  } else if (show_all_headers) {
1851  /*
1852  * article is already opened with show_all_headers ON
1853  * -> re-cook it
1854  */
1857  }
1858 
1859  art_mark(group, &arts[this_resp], ART_READ);
1860 
1861  /*
1862  * Change status if art was unread before killing to
1863  * prevent retagging as unread in unfilter_articles()
1864  */
1865  if (arts[this_resp].killed == ART_KILLED_UNREAD)
1867 
1868  if (pgart.cooked == NULL) { /* harmony corruption */
1870  return GRP_ARTUNAVAIL;
1871  }
1872 
1873  /*
1874  * Setup to start viewing cooked version
1875  */
1878  curr_line = 0;
1879  note_fp = pgart.cooked;
1880  artline = pgart.cookl;
1882  search_line = 0;
1883  /*
1884  * Reset offsets only if not invoked during 'body search' (srch_lineno != -1)
1885  * otherwise the found string will not be highlighted
1886  */
1887  if (srch_lineno == -1)
1889  rotate = 0; /* normal mode, not rot13 */
1890  reveal_ctrl_l = FALSE;
1891  reveal_ctrl_l_lines = -1; /* all ^L's active */
1893 
1894  draw_page(group->name, 0);
1895 
1896  /*
1897  * Automatically invoke attachment viewing if requested
1898  */
1899  if (!note_h->mime || IS_PLAINTEXT(note_h->ext)) /* Text only article */
1900  return 0;
1901 
1902  if (*tinrc.metamail_prog == '\0' || getenv("NOMETAMAIL") != NULL) /* Viewer turned off */
1903  return 0;
1904 
1905  if (group->attribute->ask_for_metamail) {
1906  if (prompt_yn(_(txt_use_mime), TRUE) != 1)
1907  return 0;
1908  }
1909 
1910  XFACE_SUPPRESS();
1911  if (strcmp(tinrc.metamail_prog, INTERNAL_CMD) == 0) /* Use internal viewer */
1913  else
1915  XFACE_SHOW();
1916  return 0;
1917 }
1918 
1919 
1920 static int
1922  int ch,
1923  int curr_respnum)
1924 {
1925  int i, num;
1926 
1927  clear_message();
1928 
1929  if ((num = (prompt_num(ch, _(txt_select_art)) - 1)) == -1) {
1930  clear_message();
1931  return -1;
1932  }
1933 
1934  if ((i = which_thread(curr_respnum)) >= 0)
1935  return find_response(i, num);
1936  else
1937  return -1;
1938 }
1939 
1940 
1941 /*
1942  * Reposition within message as needed, highlight searched string
1943  * This is tied quite closely to the information stored by
1944  * get_search_vectors()
1945  */
1946 static void
1948  int *lcurr_line,
1949  size_t message_lines,
1950  size_t screen_lines,
1951  int help_level)
1952 {
1953  int i, start, end;
1954 
1955  if ((i = get_search_vectors(&start, &end)) == -1)
1956  return;
1957 
1958  /*
1959  * Is matching line off the current view?
1960  * Reposition within article if needed, try to get matched line
1961  * in the middle of the screen
1962  */
1963  if (i < *lcurr_line || i >= (int) (*lcurr_line + screen_lines)) {
1964  *lcurr_line = i - (screen_lines / 2);
1965  if (*lcurr_line + screen_lines > message_lines) /* off the end */
1966  *lcurr_line = message_lines - screen_lines;
1967  /* else pos. is just fine */
1968  }
1969 
1970  switch (help_level) {
1971  case PAGE_LEVEL:
1972  draw_page(curr_group->name, 0);
1973  break;
1974 
1975  case INFO_PAGER:
1976  display_info_page(0);
1977  break;
1978 
1979  default:
1980  break;
1981  }
1982  search_line = i; /* draw_page() resets this to 0 */
1983 
1984  /*
1985  * Highlight found string
1986  */
1987  highlight_string(i - *lcurr_line + scroll_region_top, start, end - start);
1988 }
1989 
1990 
1991 /*
1992  * Implement ^H toggle between cooked and raw views of article
1993  */
1994 void
1996  struct t_group *group)
1997 {
1998  if (show_raw_article) {
1999  artline = pgart.cookl;
2001  note_fp = pgart.cooked;
2002  } else {
2003  static int j; /* Needed on successive invocations */
2004  int chunk = note_h->ext->line_count;
2005 
2006  /*
2007  * We do this on the fly, since most of the time it won't be used
2008  */
2009  if (!pgart.rawl) { /* Already done this for this article? */
2010  char *line;
2011  char *p;
2012  long offset;
2013 
2014  j = 0;
2015  rewind(pgart.raw);
2016  pgart.rawl = my_malloc(sizeof(t_lineinfo) * chunk);
2017  offset = ftell(pgart.raw);
2018 
2019  while ((line = tin_fgets(pgart.raw, FALSE)) != NULL) {
2020  int space;
2021 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
2022  int num_bytes;
2023  wchar_t wc;
2024 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
2025 
2026  pgart.rawl[j].offset = offset;
2027  pgart.rawl[j].flags = 0;
2028  j++;
2029  if (j >= chunk) {
2030  chunk += 50;
2031  pgart.rawl = my_realloc(pgart.rawl, sizeof(t_lineinfo) * chunk);
2032  }
2033 
2034  p = line;
2035  while (*p) {
2036  space = cCOLS - 1;
2037 
2038  while ((space > 0) && *p) {
2039 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
2040  num_bytes = mbtowc(&wc, p, MB_CUR_MAX);
2041  if (num_bytes != -1 && iswprint(wc)) {
2042  if ((space -= wcwidth(wc)) < 0)
2043  break;
2044  p += num_bytes;
2045  offset += num_bytes;
2046  }
2047 #else
2048  if (my_isprint((unsigned char) *p)) {
2049  space--;
2050  p++;
2051  offset++;
2052  }
2053 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
2054  else if (IS_LOCAL_CHARSET("Big5") && (unsigned char) *p >= 0xa1 && (unsigned char) *p <= 0xfe && *(p + 1)) {
2055  /*
2056  * Big5: ASCII chars are handled by the normal code
2057  * check only for 2-byte chars
2058  * TODO: should we also check if the second byte is
2059  * also valid?
2060  */
2061  p += 2;
2062  offset += 2;
2063  space--;
2064  } else {
2065  /*
2066  * the current character can't be displayed print it as
2067  * an octal value (needs 4 columns) see also
2068  * color.c:draw_pager_line()
2069  */
2070  if ((space -= 4) < 0)
2071  break;
2072  offset++;
2073  p++;
2074  }
2075  }
2076  /*
2077  * if we reached the end of the line we don't need to
2078  * remember anything
2079  */
2080  if (*p) {
2081  pgart.rawl[j].offset = offset;
2082  pgart.rawl[j].flags = 0;
2083  if (++j >= chunk) {
2084  chunk += 50;
2085  pgart.rawl = my_realloc(pgart.rawl, sizeof(t_lineinfo) * chunk);
2086  }
2087  }
2088  }
2089 
2090  /*
2091  * only use ftell's return value here because we didn't
2092  * take the \n into account above.
2093  */
2094  offset = ftell(pgart.raw);
2095  }
2096 
2097  pgart.rawl = my_realloc(pgart.rawl, sizeof(t_lineinfo) * j);
2098  }
2099  artline = pgart.rawl;
2100  artlines = j;
2101  note_fp = pgart.raw;
2102  }
2103  curr_line = 0;
2105  draw_page(group ? group->name : "", 0);
2106 }
2107 
2108 
2109 /*
2110  * Re-cook an article
2111  */
2112 void
2114  t_bool wrap_lines,
2115  t_openartinfo *artinfo)
2116 {
2117  free(artinfo->cookl);
2118  if (artinfo->cooked)
2119  fclose(artinfo->cooked);
2120 
2121  if (!cook_article(wrap_lines, artinfo, hide_uue, show_all_headers))
2123 
2125  artline = pgart.cookl;
2127  note_fp = pgart.cooked;
2128 }
2129 
2130 
2131 /*
2132  * Infopager: simply page files
2133  */
2134 void
2136  FILE *info_fh,
2137  const char *title,
2138  t_bool wrap_at_ends)
2139 {
2140  int offset;
2141  t_function func;
2142 
2143  search_line = 0;
2145  info_file = info_fh;
2146  info_title = title;
2147  curr_info_line = 0;
2148  preprocess_info_message(info_fh);
2149  if (!info_fh)
2150  return;
2151  set_xclick_off();
2152  display_info_page(0);
2153 
2154  forever {
2156  case GLOBAL_ABORT: /* common arrow keys */
2157  break;
2158 
2159  case GLOBAL_LINE_UP:
2160  if (num_info_lines <= NOTESLINES) {
2162  break;
2163  }
2164  if (curr_info_line == 0) {
2165  if (!wrap_at_ends) {
2167  break;
2168  }
2170  display_info_page(0);
2171  break;
2172  }
2176  break;
2177 
2178  case GLOBAL_LINE_DOWN:
2179  if (num_info_lines <= NOTESLINES) {
2181  break;
2182  }
2184  if (!wrap_at_ends) {
2186  break;
2187  }
2188  curr_info_line = 0;
2189  display_info_page(0);
2190  break;
2191  }
2195  break;
2196 
2197  case GLOBAL_PAGE_DOWN:
2198  if (num_info_lines <= NOTESLINES) {
2200  break;
2201  }
2202  if (curr_info_line + NOTESLINES >= num_info_lines) { /* End is already on screen */
2203  if (!wrap_at_ends) {
2205  break;
2206  }
2207  curr_info_line = 0;
2208  display_info_page(0);
2209  break;
2210  }
2211  curr_info_line += ((tinrc.scroll_lines == -2) ? NOTESLINES / 2 : NOTESLINES);
2212  display_info_page(0);
2213  break;
2214 
2215  case GLOBAL_PAGE_UP:
2216  if (num_info_lines <= NOTESLINES) {
2218  break;
2219  }
2220  if (curr_info_line == 0) {
2221  if (!wrap_at_ends) {
2223  break;
2224  }
2226  display_info_page(0);
2227  break;
2228  }
2229  curr_info_line -= ((tinrc.scroll_lines == -2) ? NOTESLINES / 2 : NOTESLINES);
2230  display_info_page(0);
2231  break;
2232 
2233  case GLOBAL_FIRST_PAGE:
2234  if (curr_info_line) {
2235  curr_info_line = 0;
2236  display_info_page(0);
2237  }
2238  break;
2239 
2240  case GLOBAL_LAST_PAGE:
2242  /* Display a full last page for neatness */
2244  display_info_page(0);
2245  }
2246  break;
2247 
2250  display_info_page(0);
2251  break;
2252 
2255  case GLOBAL_SEARCH_REPEAT:
2257  break;
2258 
2260  break;
2261 
2263  break;
2264 
2265  case GLOBAL_QUIT: /* quit */
2266  ClearScreen();
2267  return;
2268 
2269  default:
2270  break;
2271  }
2272  }
2273 }
2274 
2275 
2276 /*
2277  * Redraw the current page, curr_info_line will be the first line displayed
2278  * If part is !=0, then only draw the first (-ve) or last (+ve) few lines
2279  */
2280 void
2282  int part)
2283 {
2284  int start, end; /* 1st, last line to draw */
2285 
2287 
2288  /*
2289  * Can't do partial draw if term can't scroll properly
2290  */
2291  if (part && !have_linescroll)
2292  part = 0;
2293 
2294  if (curr_info_line < 0)
2295  curr_info_line = 0;
2298 
2300 
2301  /* Down-scroll, only redraw bottom 'part' lines of screen */
2302  if ((start = (part > 0) ? NOTESLINES - part : 0) < 0)
2303  start = 0;
2304 
2305  /* Up-scroll, only redraw the top 'part' lines of screen */
2306  if ((end = (part < 0) ? -part : NOTESLINES) > NOTESLINES)
2307  end = NOTESLINES;
2308 
2309  /* Print title */
2310  if ((end - start >= NOTESLINES) || (part == 0)) {
2311  ClearScreen();
2313  }
2314 
2316 
2317  /* print footer */
2319  stow_cursor();
2320 }
2321 
2322 
2323 static void
2325  FILE *info_fh)
2326 {
2327  int chunk = 50;
2328 
2330  if (!info_fh)
2331  return;
2332 
2333  rewind(info_fh);
2334  infoline = my_malloc(sizeof(t_lineinfo) * chunk);
2335  num_info_lines = 0;
2336 
2337  do {
2338  infoline[num_info_lines].offset = ftell(info_fh);
2340  num_info_lines++;
2341  if (num_info_lines >= chunk) {
2342  chunk += 50;
2343  infoline = my_realloc(infoline, sizeof(t_lineinfo) * chunk);
2344  }
2345  } while (tin_fgets(info_fh, FALSE) != NULL);
2346 
2347  num_info_lines--;
2349 }
2350 
2351 
2352 /*
2353  * URL menu
2354  */
2355 static t_function
2357  void)
2358 {
2359  return GLOBAL_QUIT;
2360 }
2361 
2362 
2363 static t_function
2365  void)
2366 {
2367  return URL_SELECT;
2368 }
2369 
2370 
2371 static void
2373  void)
2374 {
2375  int i;
2376 
2377  signal_context = cURL;
2378  currmenu = &urlmenu;
2379  mark_offset = 0;
2380 
2381  if (urlmenu.curr < 0)
2382  urlmenu.curr = 0;
2383 
2384  ClearScreen();
2387 
2388  for (i = urlmenu.first; i < urlmenu.first + NOTESLINES && i < urlmenu.max; ++i)
2389  build_url_line(i);
2390 
2392 
2393  draw_url_arrow();
2394 }
2395 
2396 
2397 static t_bool
2399  void)
2400 {
2401  char key[MAXKEYLEN];
2402  t_function func;
2403  t_menu *oldmenu = NULL;
2404 
2405  if (currmenu)
2406  oldmenu = currmenu;
2407  urlmenu.curr = 0;
2409  if (urlmenu.max == 0)
2410  return FALSE;
2411 
2412  clear_note_area();
2413  show_url_page();
2414  set_xclick_off();
2415 
2416  forever {
2417  switch ((func = handle_keypad(url_left, url_right, NULL, url_keys))) {
2418  case GLOBAL_QUIT:
2419  free_url_list();
2420  if (oldmenu)
2421  currmenu = oldmenu;
2422  return TRUE;
2423 
2424  case DIGIT_1:
2425  case DIGIT_2:
2426  case DIGIT_3:
2427  case DIGIT_4:
2428  case DIGIT_5:
2429  case DIGIT_6:
2430  case DIGIT_7:
2431  case DIGIT_8:
2432  case DIGIT_9:
2433  if (urlmenu.max)
2435  break;
2436 
2437 #ifndef NO_SHELL_ESCAPE
2438  case GLOBAL_SHELL_ESCAPE:
2439  do_shell_escape();
2440  break;
2441 #endif /* !NO_SHELL_ESCAPE */
2442 
2443  case GLOBAL_HELP:
2445  show_url_page();
2446  break;
2447 
2448  case GLOBAL_FIRST_PAGE:
2449  top_of_list();
2450  break;
2451 
2452  case GLOBAL_LAST_PAGE:
2453  end_of_list();
2454  break;
2455 
2456  case GLOBAL_REDRAW_SCREEN:
2457  my_retouch();
2458  show_url_page();
2459  break;
2460 
2461  case GLOBAL_LINE_DOWN:
2462  move_down();
2463  break;
2464 
2465  case GLOBAL_LINE_UP:
2466  move_up();
2467  break;
2468 
2469  case GLOBAL_PAGE_DOWN:
2470  page_down();
2471  break;
2472 
2473  case GLOBAL_PAGE_UP:
2474  page_up();
2475  break;
2476 
2477  case GLOBAL_SCROLL_DOWN:
2478  scroll_down();
2479  break;
2480 
2481  case GLOBAL_SCROLL_UP:
2482  scroll_up();
2483  break;
2484 
2487  show_url_page();
2488  break;
2489 
2492  show_url_page();
2493  break;
2494 
2495  case URL_SELECT:
2496  if (urlmenu.max) {
2497  if (process_url(urlmenu.curr))
2498  show_url_page();
2499  else
2500  draw_url_arrow();
2501  }
2502  break;
2503 
2506  case GLOBAL_SEARCH_REPEAT:
2509  else if (urlmenu.max) {
2510  int new_pos, old_pos = urlmenu.curr;
2511 
2513  if (new_pos != old_pos)
2514  move_to_item(new_pos);
2515  }
2516  break;
2517 
2518  default:
2520  break;
2521  }
2522  }
2523 }
2524 
2525 
2526 static void
2528  void)
2529 {
2531  if (tinrc.info_in_last_line) {
2532  t_url *lptr;
2533 
2534  lptr = find_url(urlmenu.curr);
2535  info_message("%s", lptr->url);
2536  } else if (urlmenu.curr == urlmenu.max - 1)
2538 }
2539 
2540 
2541 t_url *
2543  int n)
2544 {
2545  t_url *lptr;
2546 
2547  lptr = url_list;
2548  while (n-- > 0 && lptr->next)
2549  lptr = lptr->next;
2550 
2551  return lptr;
2552 }
2553 
2554 
2555 static void
2557  int i)
2558 {
2559  char *sptr;
2560  int len = cCOLS - 9;
2561  t_url *lptr;
2562 
2563 #ifdef USE_CURSES
2564  /*
2565  * Allocate line buffer
2566  * make it the same size like in !USE_CURSES case to simplify some code
2567  */
2568  sptr = my_malloc(cCOLS + 2);
2569 #else
2570  sptr = screen[INDEX2SNUM(i)].col;
2571 #endif /* USE_CURSES */
2572 
2573  lptr = find_url(i);
2574  snprintf(sptr, cCOLS, " %s %-*.*s%s", tin_ltoa(i + 1, 4), len, len, lptr->url, cCRLF);
2575  WriteLine(INDEX2LNUM(i), sptr);
2576 
2577 #ifdef USE_CURSES
2578  free(sptr);
2579 #endif /* USE_CURSES */
2580 }
2581 
2582 
2583 static t_bool
2585  int n)
2586 {
2587  char *url, *url_esc;
2588  size_t len;
2589  t_url *lptr;
2590 
2591  lptr = find_url(n);
2592  len = strlen(lptr->url) << 1; /* double size; room for editing URL */
2593  url = my_malloc(len + 1);
2594  if (prompt_default_string("URL:", url, len, lptr->url, HIST_URL)) {
2595  if (!*url) { /* Don't try and open nothing */
2596  free(url);
2597  return FALSE;
2598  }
2599  wait_message(2, _(txt_url_open), url);
2600  url_esc = escape_shell_meta(url, no_quote);
2601  len = strlen(url_esc) + strlen(tinrc.url_handler) + 2;
2602  url = my_realloc(url, len);
2603  snprintf(url, len, "%s %s", tinrc.url_handler, url_esc);
2604  invoke_cmd(url);
2605  free(url);
2606  cursoroff();
2607  return TRUE;
2608  }
2609  free(url);
2610  return FALSE;
2611 }
2612 
2613 
2614 static int
2616  void)
2617 {
2618  char *ptr;
2619  int i, count = 0;
2620  int offsets[6];
2621  int offsets_size = ARRAY_SIZE(offsets);
2622  t_url *lptr = NULL;
2623 
2624  for (i = 0; i < artlines; ++i) {
2625  if (!(artline[i].flags & (C_URL | C_NEWS | C_MAIL)))
2626  continue;
2627 
2628  /*
2629  * Line contains a URL, so read it in
2630  */
2631  if (fseek(pgart.cooked, artline[i].offset, SEEK_SET) == -1) /* skip on error */
2632  continue;
2633  if ((ptr = tin_fgets(pgart.cooked, FALSE)) == NULL)
2634  continue;
2635 
2636  /*
2637  * Step through, finding URL's
2638  */
2639  forever {
2640  /* any matches left? */
2641  if (pcre_exec(url_regex.re, url_regex.extra, ptr, strlen(ptr), 0, 0, offsets, offsets_size) == PCRE_ERROR_NOMATCH)
2642  if (pcre_exec(mail_regex.re, mail_regex.extra, ptr, strlen(ptr), 0, 0, offsets, offsets_size) == PCRE_ERROR_NOMATCH)
2643  if (pcre_exec(news_regex.re, news_regex.extra, ptr, strlen(ptr), 0, 0, offsets, offsets_size) == PCRE_ERROR_NOMATCH)
2644  break;
2645 
2646  *(ptr + offsets[1]) = '\0';
2647 
2648  if (!lptr)
2649  lptr = url_list = my_malloc(sizeof(t_url));
2650  else {
2651  lptr->next = my_malloc(sizeof(t_url));
2652  lptr = lptr->next;
2653  }
2654  lptr->url = my_strdup(ptr + offsets[0]);
2655  lptr->next = NULL;
2656  ++count;
2657 
2658  ptr += offsets[1] + 1;
2659  }
2660  }
2661  return count;
2662 }
2663 
2664 
2665 static void
2667  void)
2668 {
2669  t_url *p, *q;
2670 
2671  for (p = url_list; p != NULL; p = q) {
2672  q = p->next;
2673  free(p->url);
2674  free(p);
2675  }
2676  url_list = NULL;
2677 }
name
const char * name
Definition: signal.c:117
MOUSE_BUTTON_3
#define MOUSE_BUTTON_3
Definition: tin.h:2111
get_search_vectors
int get_search_vectors(int *start, int *end)
Definition: search.c:753
t_config::hide_uue
int hide_uue
Definition: tinrc.h:138
PAGE_SKIP_INCLUDED_TEXT
@ PAGE_SKIP_INCLUDED_TEXT
Definition: keymap.h:292
next_thread
int next_thread(int n)
Definition: thread.c:1228
t_header::date
char * date
Definition: rfc2046.h:132
abbr_groupname
char * abbr_groupname(const char *grpname, size_t len)
Definition: string.c:990
txt_lines
constext txt_lines[]
Definition: lang.c:599
stars_regex
struct regex_cache stars_regex
cURL
@ cURL
Definition: tin.h:107
url_list
static t_url * url_list
Definition: page.c:61
txt_x_resp
constext txt_x_resp[]
Definition: lang.c:986
make_threads
void make_threads(struct t_group *group, t_bool rethread)
Definition: art.c:1194
txt_command_failed
constext txt_command_failed[]
Definition: lang.c:150
txt_mark_art_read
constext txt_mark_art_read[]
Definition: lang.c:625
txt_art_parent_killed
constext txt_art_parent_killed[]
Definition: lang.c:64
PAGE_TAG
@ PAGE_TAG
Definition: keymap.h:293
find_artnum
int find_artnum(t_artnum art)
Definition: art.c:3192
PAGE_REPOST
@ PAGE_REPOST
Definition: keymap.h:290
DEBUG_MISC
#define DEBUG_MISC
Definition: debug.h:54
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
FEED_PIPE
#define FEED_PIPE
Definition: tin.h:1115
PAGE_NEXT_UNREAD_ARTICLE
@ PAGE_NEXT_UNREAD_ARTICLE
Definition: keymap.h:280
PAGE_REPLY_QUOTE
@ PAGE_REPLY_QUOTE
Definition: keymap.h:288
my_realloc
#define my_realloc(ptr, size)
Definition: tin.h:2198
INDEX_TOP
#define INDEX_TOP
Definition: tin.h:1008
txt_cook_article_failed_exiting
constext txt_cook_article_failed_exiting[]
Definition: lang.c:156
PAGE_FOLLOWUP_QUOTE_HEADERS
@ PAGE_FOLLOWUP_QUOTE_HEADERS
Definition: keymap.h:271
url_regex
struct regex_cache url_regex
UUE_ALL
#define UUE_ALL
Definition: tin.h:1239
invoke_editor
t_bool invoke_editor(const char *filename, int lineno, struct t_group *group)
Definition: misc.c:372
my_tmpfile
int my_tmpfile(char *filename, size_t name_size, const char *base_dir)
Definition: my_tmpfile.c:57
GLOBAL_SEARCH_AUTHOR_FORWARD
@ GLOBAL_SEARCH_AUTHOR_FORWARD
Definition: keymap.h:218
hide_uue
static int hide_uue
Definition: page.c:80
txt_no_prev_search
constext txt_no_prev_search[]
Definition: lang.c:683
reveal_ctrl_l
static t_bool reveal_ctrl_l
Definition: page.c:90
txt_info_add_kill
constext txt_info_add_kill[]
Definition: lang.c:539
my_strdup
char * my_strdup(const char *str)
Definition: string.c:133
center_line
void center_line(int line, t_bool inverse, const char *str)
Definition: screen.c:258
txt_cannot_post
constext txt_cannot_post[]
Definition: lang.c:130
C_URL
#define C_URL
Definition: rfc2046.h:163
t_group
Definition: tin.h:1772
MARK_ARTICLE_UNREAD
@ MARK_ARTICLE_UNREAD
Definition: keymap.h:261
CATCHUP
@ CATCHUP
Definition: keymap.h:169
DIGIT_8
@ DIGIT_8
Definition: keymap.h:158
page_left
static t_function page_left(void)
Definition: page.c:188
GLOBAL_TOGGLE_INFO_LAST_LINE
@ GLOBAL_TOGGLE_INFO_LAST_LINE
Definition: keymap.h:229
GLOBAL_DISPLAY_POST_HISTORY
@ GLOBAL_DISPLAY_POST_HISTORY
Definition: keymap.h:188
reveal_ctrl_l_lines
static int reveal_ctrl_l_lines
Definition: page.c:82
tag_article
t_bool tag_article(int art)
Definition: tags.c:277
pcre_exec
int pcre_exec(const pcre *, const pcre_extra *, const char *, int, int, int, int *, int)
Definition: pcre_exec.c:3690
expand_tab
char * expand_tab(char *str, size_t tab_width)
Definition: string.c:623
PAGE_NEXT_THREAD
@ PAGE_NEXT_THREAD
Definition: keymap.h:278
curr_info_line
static int curr_info_line
Definition: page.c:79
cLINES
int cLINES
Definition: curses.c:52
infoline
static t_lineinfo * infoline
Definition: page.c:86
PAGE_EDIT_ARTICLE
@ PAGE_EDIT_ARTICLE
Definition: keymap.h:268
txt_bad_command
constext txt_bad_command[]
Definition: lang.c:112
txt_toggled_rot13
constext txt_toggled_rot13[]
Definition: lang.c:888
PAGE_SAVE
@ PAGE_SAVE
Definition: keymap.h:291
txt_toggled_high
constext txt_toggled_high[]
Definition: lang.c:887
GLOBAL_SEARCH_SUBJECT_FORWARD
@ GLOBAL_SEARCH_SUBJECT_FORWARD
Definition: keymap.h:220
GRP_ARTUNAVAIL
@ GRP_ARTUNAVAIL
Definition: tin.h:1264
URL_SELECT
@ URL_SELECT
Definition: keymap.h:371
GROUP_TYPE_NEWS
#define GROUP_TYPE_NEWS
Definition: tin.h:1059
art_mark
void art_mark(struct t_group *group, struct t_article *art, int flag)
Definition: newsrc.c:1571
t_msgid
Definition: tin.h:1486
activate_last_ctrl_l
static t_bool activate_last_ctrl_l(void)
Definition: page.c:273
GOTO_NEXT_UNREAD_PGDN
#define GOTO_NEXT_UNREAD_PGDN
Definition: tin.h:963
t_attribute::ask_for_metamail
unsigned ask_for_metamail
Definition: tin.h:1606
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
openartinfo
Definition: rfc2046.h:183
find_url
t_url * find_url(int n)
Definition: page.c:2542
txt_art_x_of_n
constext txt_art_x_of_n[]
Definition: lang.c:71
PAGE_VIEW_URL
@ PAGE_VIEW_URL
Definition: keymap.h:303
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
lineinfo::flags
int flags
Definition: rfc2046.h:176
my_flush
#define my_flush()
Definition: tcurses.h:171
ClearScreen
void ClearScreen(void)
Definition: curses.c:410
GLOBAL_LOOKUP_MESSAGEID
@ GLOBAL_LOOKUP_MESSAGEID
Definition: keymap.h:196
GLOBAL_OPTION_MENU
@ GLOBAL_OPTION_MENU
Definition: keymap.h:199
KILL_NOTHREAD
#define KILL_NOTHREAD
Definition: tin.h:1207
PAGE_MARK_THREAD_READ
@ PAGE_MARK_THREAD_READ
Definition: keymap.h:276
scroll_up
void scroll_up(void)
Definition: global.c:278
cCRLF
#define cCRLF
Definition: tcurses.h:150
t_attribute::tex2iso_conv
unsigned tex2iso_conv
Definition: tin.h:1656
grpmenu
t_menu grpmenu
Definition: group.c:83
underscores_regex
struct regex_cache underscores_regex
PAGE_REPLY_QUOTE_HEADERS
@ PAGE_REPLY_QUOTE_HEADERS
Definition: keymap.h:289
tabwidth
size_t tabwidth
Definition: page.c:73
cPage
@ cPage
Definition: tin.h:107
thd_mark_unread
void thd_mark_unread(struct t_group *group, long thread)
Definition: newsrc.c:772
t_config::goto_next_unread
int goto_next_unread
Definition: tinrc.h:137
PAGE_FOLLOWUP
@ PAGE_FOLLOWUP
Definition: keymap.h:269
SPECIAL_MOUSE_TOGGLE
@ SPECIAL_MOUSE_TOGGLE
Definition: keymap.h:168
DIGIT_3
@ DIGIT_3
Definition: keymap.h:153
tinrc
struct t_config tinrc
Definition: init.c:191
perror_message
void perror_message(const char *fmt,...)
Definition: screen.c:220
txt_end_of_page
constext txt_end_of_page[]
Definition: lang.c:169
wait_message
void wait_message(unsigned int sdelay, const char *fmt,...)
Definition: screen.c:133
FEED_SAVE
#define FEED_SAVE
Definition: tin.h:1117
FreeAndNull
#define FreeAndNull(p)
Definition: tin.h:2204
curr_group
struct t_group * curr_group
Definition: group.c:55
scroll_region_top
static int scroll_region_top
Definition: page.c:84
invoke_metamail
static void invoke_metamail(FILE *fp)
Definition: page.c:1256
GOTO_NEXT_UNREAD_TAB
#define GOTO_NEXT_UNREAD_TAB
Definition: tin.h:964
display_info_page
void display_info_page(int part)
Definition: page.c:2281
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
lineinfo
Definition: rfc2046.h:173
print_message_page
static void print_message_page(FILE *file, t_lineinfo *messageline, size_t messagelines, size_t base_line, size_t begin, size_t end, int help_level)
Definition: page.c:1034
CATCHUP_NEXT_UNREAD
@ CATCHUP_NEXT_UNREAD
Definition: keymap.h:170
C_NEWS
#define C_NEWS
Definition: rfc2046.h:165
regex_cache::extra
pcre_extra * extra
Definition: tin.h:1919
search
int search(t_function func, int current_art, t_bool repeat)
Definition: search.c:551
GLOBAL_POSTPONED
@ GLOBAL_POSTPONED
Definition: keymap.h:204
XFACE_CLEAR
#define XFACE_CLEAR()
Definition: page.c:129
process_search
static void process_search(int *lcurr_line, size_t message_lines, size_t screen_lines, int help_level)
Definition: page.c:1947
GLOBAL_SCROLL_DOWN
@ GLOBAL_SCROLL_DOWN
Definition: keymap.h:213
txt_last_resp
constext txt_last_resp[]
Definition: lang.c:598
txt_thread_x_of_n
constext txt_thread_x_of_n[]
Definition: lang.c:885
INFO_PAGER
#define INFO_PAGER
Definition: tin.h:1105
openartinfo::cooked_lines
int cooked_lines
Definition: rfc2046.h:187
GROUP_TYPE_MAIL
#define GROUP_TYPE_MAIL
Definition: tin.h:1058
my_fputc
#define my_fputc(ch, stream)
Definition: tcurses.h:152
PAGE_TOGGLE_UUE
@ PAGE_TOGGLE_UUE
Definition: keymap.h:300
prompt_response
static int prompt_response(int ch, int curr_respnum)
Definition: page.c:1921
pickup_postponed_articles
t_bool pickup_postponed_articles(t_bool ask, t_bool all)
Definition: post.c:2462
PAGE_FOLLOWUP_QUOTE
@ PAGE_FOLLOWUP_QUOTE
Definition: keymap.h:270
TINRC_CONFIRM_ACTION
#define TINRC_CONFIRM_ACTION
Definition: tin.h:947
SetScrollRegion
void SetScrollRegion(int topline, int bottomline)
Definition: curses.c:490
which_response
int which_response(int n)
Definition: thread.c:1029
info_keys
struct keylist info_keys
Definition: keymap.c:68
prompt_item_num
void prompt_item_num(int ch, const char *prompt)
Definition: global.c:200
URL_LEVEL
#define URL_LEVEL
Definition: tin.h:1110
HIST_URL
@ HIST_URL
Definition: extern.h:1557
MoveCursor
void MoveCursor(int row, int col)
Definition: curses.c:441
GRP_NEXTUNREAD
@ GRP_NEXTUNREAD
Definition: tin.h:1262
deactivate_next_ctrl_l
static t_bool deactivate_next_ctrl_l(void)
Definition: page.c:244
tcurses.h
PAGE_VIEW_ATTACHMENTS
@ PAGE_VIEW_ATTACHMENTS
Definition: keymap.h:302
clear_note_area
void clear_note_area(void)
Definition: group.c:988
invoke_cmd
t_bool invoke_cmd(const char *nam)
Definition: misc.c:793
t_article::killed
unsigned int killed
Definition: tin.h:1530
end
static char * end
Definition: plp_snprintf.c:205
GLOBAL_SCROLL_UP
@ GLOBAL_SCROLL_UP
Definition: keymap.h:214
build_url_line
static void build_url_line(int i)
Definition: page.c:2556
t_menu::max
int max
Definition: tin.h:2007
load_article
static int load_article(int new_respnum, struct t_group *group)
Definition: page.c:1798
info_message
void info_message(const char *fmt,...)
Definition: screen.c:102
info_file
static FILE * info_file
Definition: page.c:77
openartinfo::tex2iso
t_bool tex2iso
Definition: rfc2046.h:186
tin.h
tin_done
void tin_done(int ret, const char *fmt,...)
Definition: misc.c:557
GLOBAL_LAST_PAGE
@ GLOBAL_LAST_PAGE
Definition: keymap.h:192
urllist
Definition: tin.h:2062
urllist::next
struct urllist * next
Definition: tin.h:2064
no_quote
@ no_quote
Definition: tin.h:1245
t_header::org
char * org
Definition: rfc2046.h:134
MAX
#define MAX(a, b)
Definition: tin.h:802
num_of_responses
int num_of_responses(int n)
Definition: thread.c:1054
read_filter_file
t_bool read_filter_file(const char *file)
Definition: filter.c:308
prompt_msgid
int prompt_msgid(void)
Definition: prompt.c:592
PAGE_HEADER
#define PAGE_HEADER
Definition: page.c:53
reset_srch_offsets
void reset_srch_offsets(void)
Definition: search.c:771
txt_use_mime
constext txt_use_mime[]
Definition: lang.c:915
last_resp
int last_resp
Definition: page.c:70
is_art_tex_encoded
t_bool is_art_tex_encoded(FILE *fp)
Definition: charset.c:343
DIGIT_4
@ DIGIT_4
Definition: keymap.h:154
t_msgid::parent
struct t_msgid * parent
Definition: tin.h:1488
GRP_EXIT
@ GRP_EXIT
Definition: tin.h:1269
can_post
t_bool can_post
Definition: nntplib.c:32
FEED_PRINT
#define FEED_PRINT
Definition: tin.h:1116
prev_response
int prev_response(int n)
Definition: thread.c:1247
openartinfo::cooked
FILE * cooked
Definition: rfc2046.h:189
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
show_raw_article
static t_bool show_raw_article
Definition: page.c:89
prompt_default_string
t_bool prompt_default_string(const char *prompt, char *buf, int buf_len, char *default_prompt, int which_hist)
Definition: prompt.c:108
PATH_LEN
#define PATH_LEN
Definition: tin.h:837
page_mouse_action
static t_function page_mouse_action(t_function(*left_action)(void), t_function(*right_action)(void))
Definition: page.c:204
EndInverse
void EndInverse(void)
Definition: curses.c:564
t_header::xface
char * xface
Definition: rfc2046.h:144
PAGE_REVEAL
@ PAGE_REVEAL
Definition: keymap.h:286
GLOBAL_TOGGLE_HELP_DISPLAY
@ GLOBAL_TOGGLE_HELP_DISPLAY
Definition: keymap.h:228
strunc
char * strunc(const char *message, int len)
Definition: string.c:1069
cInfopager
@ cInfopager
Definition: tin.h:107
tin_progname
char * tin_progname
Definition: init.c:105
txt_url_menu_com
constext txt_url_menu_com[]
Definition: lang.c:911
page_up
void page_up(void)
Definition: global.c:130
filter_file
char filter_file[PATH_LEN]
Definition: init.c:89
t_config::mono_markstroke
int mono_markstroke
Definition: tinrc.h:192
txt_toggled_tex2iso
constext txt_toggled_tex2iso[]
Definition: lang.c:889
forever
#define forever
Definition: tin.h:810
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
tin_fgets
char * tin_fgets(FILE *fp, t_bool header)
Definition: read.c:320
srch_lineno
int srch_lineno
Definition: search.c:59
Raw
void Raw(int state)
Definition: curses.c:624
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
part::line_count
int line_count
Definition: rfc2046.h:104
find_response
int find_response(int i, int n)
Definition: thread.c:1268
preprocess_info_message
static void preprocess_info_message(FILE *info_fh)
Definition: page.c:2324
rotate
static int rotate
Definition: page.c:83
attachment_page
void attachment_page(t_openartinfo *art)
Definition: save.c:1592
C_QUOTE3
#define C_QUOTE3
Definition: rfc2046.h:161
part
Definition: rfc2046.h:92
PAGE_NEXT_ARTICLE
@ PAGE_NEXT_ARTICLE
Definition: keymap.h:277
FEED_REPOST
#define FEED_REPOST
Definition: tin.h:1119
txt_begin_of_art
constext txt_begin_of_art[]
Definition: lang.c:117
quick_filter
t_bool quick_filter(t_function type, struct t_group *group, struct t_article *art)
Definition: filter.c:1489
escape_shell_meta
char * escape_shell_meta(const char *source, int quote_area)
Definition: misc.c:1727
txt_art_parent_unavail
constext txt_art_parent_unavail[]
Definition: lang.c:65
strwidth
int strwidth(const char *str)
Definition: string.c:1043
txt_url_done
constext txt_url_done[]
Definition: lang.c:914
IS_PLAINTEXT
#define IS_PLAINTEXT(x)
Definition: tin.h:1025
search_article
int search_article(t_bool forward, t_bool repeat, int start_line, int lines, t_lineinfo *line, int reveal_ctrl_l_lines, FILE *fp)
Definition: search.c:591
post_response
int post_response(const char *groupname, int respnum, t_bool copy_text, t_bool with_headers, t_bool raw_data)
Definition: post.c:2874
mark_offset
int mark_offset
Definition: screen.c:48
homedir
char homedir[PATH_LEN]
Definition: init.c:78
ART_ABORT
#define ART_ABORT
Definition: tin.h:1335
strokes_regex
struct regex_cache strokes_regex
Definition: init.c:184
GLOBAL_VERSION
@ GLOBAL_VERSION
Definition: keymap.h:231
PAGE_TOGGLE_HEADERS
@ PAGE_TOGGLE_HEADERS
Definition: keymap.h:294
C_BODY
#define C_BODY
Definition: rfc2046.h:153
GLOBAL_EDIT_FILTER
@ GLOBAL_EDIT_FILTER
Definition: keymap.h:189
draw_arrow_mark
void draw_arrow_mark(int line)
Definition: screen.c:300
t_header::subj
char * subj
Definition: rfc2046.h:133
GLOBAL_QUICK_FILTER_KILL
@ GLOBAL_QUICK_FILTER_KILL
Definition: keymap.h:208
openartinfo::rawl
t_lineinfo * rawl
Definition: rfc2046.h:190
WriteLine
#define WriteLine(row, buffer)
Definition: tcurses.h:174
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
C_CTRLL
#define C_CTRLL
Definition: rfc2046.h:166
GRP_GOTOTHREAD
@ GRP_GOTOTHREAD
Definition: tin.h:1267
toggle_mini_help
void toggle_mini_help(int level)
Definition: help.c:1020
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
page_right
static t_function page_right(void)
Definition: page.c:196
t_config::mono_markdash
int mono_markdash
Definition: tinrc.h:189
t_config::kill_level
int kill_level
Definition: tinrc.h:139
ART_READ
#define ART_READ
Definition: tin.h:1320
txt_enter_next_unread_art
constext txt_enter_next_unread_art[]
Definition: lang.c:176
PAGE_PREVIOUS_ARTICLE
@ PAGE_PREVIOUS_ARTICLE
Definition: keymap.h:284
GLOBAL_MENU_FILTER_SELECT
@ GLOBAL_MENU_FILTER_SELECT
Definition: keymap.h:198
artlines
static int artlines
Definition: page.c:58
my_isprint
int my_isprint(int c)
Definition: misc.c:986
t_config::info_in_last_line
t_bool info_in_last_line
Definition: tinrc.h:215
GRP_ARTABORT
@ GRP_ARTABORT
Definition: tin.h:1265
shell_escape
void shell_escape(void)
Definition: misc.c:491
buf
static char buf[16]
Definition: langinfo.c:50
txt_no_prev_unread_art
constext txt_no_prev_unread_art[]
Definition: lang.c:684
url_left
static t_function url_left(void)
Definition: page.c:2356
GLOBAL_PRINT
@ GLOBAL_PRINT
Definition: keymap.h:206
GLOBAL_PIPE
@ GLOBAL_PIPE
Definition: keymap.h:202
ARRAY_SIZE
#define ARRAY_SIZE(array)
Definition: tin.h:2201
num_info_lines
static int num_info_lines
Definition: page.c:81
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
txt_art_unavailable
constext txt_art_unavailable[]
Definition: lang.c:69
config_page
void config_page(const char *grpname, enum context level)
Definition: options_menu.c:921
FEED_MAIL
#define FEED_MAIL
Definition: tin.h:1114
GLOBAL_LAST_VIEWED
@ GLOBAL_LAST_VIEWED
Definition: keymap.h:193
openartinfo::cookl
t_lineinfo * cookl
Definition: rfc2046.h:191
info_title
static const char * info_title
Definition: page.c:78
assert
#define assert(p)
Definition: tin.h:1295
pos_first_unread_thread
void pos_first_unread_thread(void)
Definition: group.c:1067
GLOBAL_LINE_UP
@ GLOBAL_LINE_UP
Definition: keymap.h:195
MOUSE_BUTTON_2
#define MOUSE_BUTTON_2
Definition: tin.h:2110
show_all_headers
static t_bool show_all_headers
Definition: page.c:88
mail_to_author
int mail_to_author(const char *group, int respnum, t_bool copy_text, t_bool with_headers, t_bool raw_data)
Definition: post.c:3553
offset
static int offset
Definition: read.c:62
GRP_KILLED
@ GRP_KILLED
Definition: tin.h:1266
top_of_list
void top_of_list(void)
Definition: global.c:182
stow_cursor
void stow_cursor(void)
Definition: screen.c:59
GLOBAL_SEARCH_SUBJECT_BACKWARD
@ GLOBAL_SEARCH_SUBJECT_BACKWARD
Definition: keymap.h:219
show_page
int show_page(struct t_group *group, int start_respnum, int *threadnum)
Definition: page.c:305
news_regex
struct regex_cache news_regex
draw_page_header
static void draw_page_header(const char *group)
Definition: page.c:1324
THREAD_NONE
#define THREAD_NONE
Definition: tin.h:1127
url_keys
struct keylist url_keys
Definition: keymap.c:90
DIGIT_9
@ DIGIT_9
Definition: keymap.h:159
cCOLS
int cCOLS
Definition: curses.c:53
LEN
#define LEN
Definition: tin.h:854
pgart
t_openartinfo pgart
Definition: page.c:63
T_ARTNUM_CONST
#define T_ARTNUM_CONST(v)
Definition: tin.h:229
GLOBAL_SEARCH_AUTHOR_BACKWARD
@ GLOBAL_SEARCH_AUTHOR_BACKWARD
Definition: keymap.h:217
urlmenu
static t_menu urlmenu
Definition: page.c:118
t_function
enum defined_functions t_function
Definition: keymap.h:373
process_url
static t_bool process_url(int n)
Definition: page.c:2584
toggle_inverse_video
void toggle_inverse_video(void)
Definition: misc.c:1058
toggle_raw
void toggle_raw(struct t_group *group)
Definition: page.c:1995
filter_menu
t_bool filter_menu(t_function type, struct t_group *group, struct t_article *art)
Definition: filter.c:1054
PAGE_TOP_THREAD
@ PAGE_TOP_THREAD
Definition: keymap.h:301
currmenu
t_menu * currmenu
Definition: init.c:165
t_article::artnum
t_artnum artnum
Definition: tin.h:1511
which_thread
int which_thread(int n)
Definition: thread.c:1003
cursoroff
void cursoroff(void)
Definition: curses.c:721
txt_begin_of_page
constext txt_begin_of_page[]
Definition: lang.c:118
t_config::url_highlight
t_bool url_highlight
Definition: tinrc.h:194
GLOBAL_FIRST_PAGE
@ GLOBAL_FIRST_PAGE
Definition: keymap.h:190
ART_KILLED
#define ART_KILLED
Definition: tin.h:1329
free_url_list
static void free_url_list(void)
Definition: page.c:2666
txt_url_menu
constext txt_url_menu[]
Definition: lang.c:910
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
txt_end_of_art
constext txt_end_of_art[]
Definition: lang.c:165
GRP_NEXT
@ GRP_NEXT
Definition: tin.h:1263
draw_pager_line
void draw_pager_line(const char *str, int flags, t_bool raw_data)
Definition: color.c:245
INTERNAL_CMD
#define INTERNAL_CMD
Definition: tin.h:571
set_xclick_off
void set_xclick_off(void)
Definition: curses.c:703
EXIT_FAILURE
#define EXIT_FAILURE
Definition: tin.h:1277
search_line
static int search_line
Definition: page.c:85
regex_cache::re
pcre * re
Definition: tin.h:1918
build_url_list
static int build_url_list(void)
Definition: page.c:2615
idna_decode
char * idna_decode(char *in)
Definition: misc.c:3758
highlight_string
void highlight_string(int row, int col, int size)
Definition: curses.c:733
my_fputs
#define my_fputs(str, stream)
Definition: tcurses.h:153
func_to_key
char func_to_key(t_function func, const struct keylist keys)
Definition: keymap.c:124
my_retouch
#define my_retouch()
Definition: tcurses.h:173
C_MAIL
#define C_MAIL
Definition: rfc2046.h:164
txt_no_last_message
constext txt_no_last_message[]
Definition: lang.c:675
decode_save_mime
void decode_save_mime(t_openartinfo *art, t_bool postproc)
Definition: save.c:1495
ART_WILL_RETURN
#define ART_WILL_RETURN
Definition: tin.h:1322
info_pager
void info_pager(FILE *info_fh, const char *title, t_bool wrap_at_ends)
Definition: page.c:2135
EndWin
void EndWin(void)
Definition: curses.c:368
BlankIfNull
#define BlankIfNull(p)
Definition: tin.h:2206
t_article::refptr
struct t_msgid * refptr
Definition: tin.h:1522
PAGE_GOTO_PARENT
@ PAGE_GOTO_PARENT
Definition: keymap.h:272
unfilter_articles
void unfilter_articles(struct t_group *group)
Definition: filter.c:1811
SEEK_SET
#define SEEK_SET
Definition: tin.h:2441
bool_not
#define bool_not(b)
Definition: bool.h:81
t_config::metamail_prog
char metamail_prog[PATH_LEN]
Definition: tinrc.h:97
t_header
Definition: rfc2046.h:126
filter_articles
t_bool filter_articles(struct t_group *group)
Definition: filter.c:1836
PAGE_TOGGLE_HIGHLIGHTING
@ PAGE_TOGGLE_HIGHLIGHTING
Definition: keymap.h:295
PAGE_LEVEL
#define PAGE_LEVEL
Definition: tin.h:1104
slashes_regex
struct regex_cache slashes_regex
my_printf
#define my_printf
Definition: tcurses.h:169
txt_1_resp
constext txt_1_resp[]
Definition: lang.c:45
scroll_down
void scroll_down(void)
Definition: global.c:252
MAXKEYLEN
#define MAXKEYLEN
Definition: keymap.h:136
PCRE_ERROR_NOMATCH
#define PCRE_ERROR_NOMATCH
Definition: pcre.h:125
note_fp
static FILE * note_fp
Definition: page.c:57
PAGE_BOTTOM_THREAD
@ PAGE_BOTTOM_THREAD
Definition: keymap.h:266
t_menu::curr
int curr
Definition: tin.h:2006
t_config::mono_markslash
int mono_markslash
Definition: tinrc.h:191
INDEX2LNUM
#define INDEX2LNUM(i)
Definition: tin.h:1009
t_group::name
char * name
Definition: tin.h:1773
txt_toggled_tabwidth
constext txt_toggled_tabwidth[]
Definition: lang.c:890
url_page
static t_bool url_page(void)
Definition: page.c:2398
InitWin
void InitWin(void)
Definition: curses.c:355
PAGE_PREVIOUS_UNREAD_ARTICLE
@ PAGE_PREVIOUS_UNREAD_ARTICLE
Definition: keymap.h:285
XFACE_SHOW
#define XFACE_SHOW()
Definition: page.c:128
UUE_NO
#define UUE_NO
Definition: tin.h:1237
C_QUOTE1
#define C_QUOTE1
Definition: rfc2046.h:159
txt_article_upper
constext txt_article_upper[]
Definition: lang.c:76
t_screen::col
char * col
Definition: tin.h:1930
GLOBAL_MENU_FILTER_KILL
@ GLOBAL_MENU_FILTER_KILL
Definition: keymap.h:197
C_SIG
#define C_SIG
Definition: rfc2046.h:154
C_QUOTE2
#define C_QUOTE2
Definition: rfc2046.h:160
cancel_article
t_bool cancel_article(struct t_group *group, struct t_article *art, int respnum)
Definition: post.c:3770
page_keys
struct keylist page_keys
Definition: keymap.c:70
txt_info_add_select
constext txt_info_add_select[]
Definition: lang.c:540
draw_page
void draw_page(const char *group, int part)
Definition: page.c:1172
FALSE
#define FALSE
Definition: bool.h:70
STRCPY
#define STRCPY(dst, src)
Definition: tin.h:814
FEED_AUTOSAVE
#define FEED_AUTOSAVE
Definition: tin.h:1118
PAGE_TOGGLE_TEX2ISO
@ PAGE_TOGGLE_TEX2ISO
Definition: keymap.h:299
PAGE_TOGGLE_TABS
@ PAGE_TOGGLE_TABS
Definition: keymap.h:298
prompt_num
int prompt_num(int ch, const char *prompt)
Definition: prompt.c:65
t_config::mono_markstar
int mono_markstar
Definition: tinrc.h:190
debug
unsigned short debug
Definition: debug.c:51
CleartoEOS
void CleartoEOS(void)
Definition: curses.c:470
GLOBAL_QUIT_TIN
@ GLOBAL_QUIT_TIN
Definition: keymap.h:211
GLOBAL_PAGE_UP
@ GLOBAL_PAGE_UP
Definition: keymap.h:201
ARTLINES
#define ARTLINES
Definition: page.c:54
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
art_edit
t_bool art_edit(struct t_group *group, struct t_article *article)
Definition: mail.c:640
txt_art_parent_none
constext txt_art_parent_none[]
Definition: lang.c:63
txt_enter_next_thread
constext txt_enter_next_thread[]
Definition: lang.c:175
txt_end_of_urls
constext txt_end_of_urls[]
Definition: lang.c:172
t_attribute::date_format
char * date_format
Definition: tin.h:1571
snprintf
#define snprintf
Definition: tin.h:2417
show_url_page
static void show_url_page(void)
Definition: page.c:2372
next_response
int next_response(int n)
Definition: thread.c:1206
GLOBAL_SEARCH_REPEAT
@ GLOBAL_SEARCH_REPEAT
Definition: keymap.h:216
move_to_item
void move_to_item(int n)
Definition: global.c:227
PAGE_TOGGLE_RAW
@ PAGE_TOGGLE_RAW
Definition: keymap.h:296
DIGIT_2
@ DIGIT_2
Definition: keymap.h:152
txt_next_resp
constext txt_next_resp[]
Definition: lang.c:665
openartinfo::raw
FILE * raw
Definition: rfc2046.h:188
xmouse
int xmouse
Definition: init.c:122
openartinfo::hdr
struct t_header hdr
Definition: rfc2046.h:185
t_artnum
long t_artnum
Definition: tin.h:226
url_right
static t_function url_right(void)
Definition: page.c:2364
GRP_QUIT
@ GRP_QUIT
Definition: tin.h:1261
txt_tex
constext txt_tex[]
Definition: lang.c:859
t_group::attribute
struct t_attribute * attribute
Definition: tin.h:1790
t_config::url_handler
char url_handler[LEN]
Definition: tinrc.h:128
t_header::mime
t_bool mime
Definition: rfc2046.h:145
GLOBAL_HELP
@ GLOBAL_HELP
Definition: keymap.h:191
word_highlight
t_bool word_highlight
Definition: init.c:154
t_menu::first
int first
Definition: tin.h:2008
PAGE_CANCEL
@ PAGE_CANCEL
Definition: keymap.h:267
draw_url_arrow
static void draw_url_arrow(void)
Definition: page.c:2527
GLOBAL_ABORT
@ GLOBAL_ABORT
Definition: keymap.h:186
StartInverse
void StartInverse(void)
Definition: curses.c:540
mail_regex
struct regex_cache mail_regex
txt_url_select
constext txt_url_select[]
Definition: lang.c:913
txt_at_s
constext txt_at_s[]
Definition: lang.c:78
GLOBAL_QUICK_FILTER_SELECT
@ GLOBAL_QUICK_FILTER_SELECT
Definition: keymap.h:209
GRP_RETSELECT
@ GRP_RETSELECT
Definition: tin.h:1260
art_close
void art_close(t_openartinfo *artinfo)
Definition: rfc2046.c:1604
move_up
void move_up(void)
Definition: global.c:81
DIGIT_6
@ DIGIT_6
Definition: keymap.h:156
ScrollScreen
void ScrollScreen(int lines_to_scroll)
Definition: curses.c:509
this_resp
int this_resp
Definition: page.c:71
fixup_thread
void fixup_thread(int respnum, t_bool redraw)
Definition: thread.c:950
ART_KILLED_UNREAD
#define ART_KILLED_UNREAD
Definition: tin.h:1330
IS_LOCAL_CHARSET
#define IS_LOCAL_CHARSET(c)
Definition: tin.h:776
t_attribute::thread_articles
unsigned thread_articles
Definition: tin.h:1631
PAGE_NEXT_UNREAD
@ PAGE_NEXT_UNREAD
Definition: keymap.h:279
PAGE_LIST_THREAD
@ PAGE_LIST_THREAD
Definition: keymap.h:274
cook_article
t_bool cook_article(t_bool wrap_lines, t_openartinfo *artinfo, int hide_uue, t_bool show_all_headers)
Definition: cook.c:828
next_unread
int next_unread(int n)
Definition: thread.c:1289
t_config::scroll_lines
int scroll_lines
Definition: tinrc.h:144
artline
static t_lineinfo * artline
Definition: page.c:59
MOUSE_BUTTON_1
#define MOUSE_BUTTON_1
Definition: tin.h:2109
t_bool
unsigned t_bool
Definition: bool.h:77
draw_percent_mark
void draw_percent_mark(long cur_num, long max_num)
Definition: misc.c:837
resize_article
void resize_article(t_bool wrap_lines, t_openartinfo *artinfo)
Definition: page.c:2113
txt_select_art
constext txt_select_art[]
Definition: lang.c:836
curr_line
int curr_line
Definition: page.c:56
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
PAGE_REPLY
@ PAGE_REPLY
Definition: keymap.h:287
GLOBAL_REDRAW_SCREEN
@ GLOBAL_REDRAW_SCREEN
Definition: keymap.h:212
urllist::url
char * url
Definition: tin.h:2063
GLOBAL_TOGGLE_INVERSE_VIDEO
@ GLOBAL_TOGGLE_INVERSE_VIDEO
Definition: keymap.h:230
txt_art_pager_com
constext txt_art_pager_com[]
Definition: lang.c:62
show_inverse_video_status
void show_inverse_video_status(void)
Definition: misc.c:1073
arts
struct t_article * arts
Definition: memory.c:69
prompt_continue
void prompt_continue(void)
Definition: prompt.c:774
BLANK_PAGE_COLS
#define BLANK_PAGE_COLS
Definition: tin.h:939
my_strftime
size_t my_strftime(char *s, size_t maxsize, const char *format, struct tm *timeptr)
Definition: strftime.c:64
PAGE_MAIL
@ PAGE_MAIL
Definition: keymap.h:275
txt_marked_as_unread
constext txt_marked_as_unread[]
Definition: lang.c:620
GLOBAL_SEARCH_BODY
@ GLOBAL_SEARCH_BODY
Definition: keymap.h:215
scroll_page
static int scroll_page(int dir)
Definition: page.c:144
t_config::abbreviate_groupname
t_bool abbreviate_groupname
Definition: tinrc.h:199
PAGE_GROUP_SELECT
@ PAGE_GROUP_SELECT
Definition: keymap.h:273
t_header::ext
t_part * ext
Definition: rfc2046.h:146
have_linescroll
t_bool have_linescroll
Definition: curses.c:57
generic_search
int generic_search(t_bool forward, t_bool repeat, int current, int last, int level)
Definition: search.c:196
DIGIT_1
@ DIGIT_1
Definition: keymap.h:151
GLOBAL_QUIT
@ GLOBAL_QUIT
Definition: keymap.h:210
PAGE_AUTOSAVE
@ PAGE_AUTOSAVE
Definition: keymap.h:265
unlink
#define unlink(file)
Definition: tin.h:384
XFACE_SUPPRESS
#define XFACE_SUPPRESS()
Definition: page.c:130
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
KEYMAP_UP
#define KEYMAP_UP
Definition: tin.h:1066
cvers
char cvers[LEN]
Definition: init.c:70
NOTESLINES
int NOTESLINES
Definition: signal.c:111
do_shell_escape
void do_shell_escape(void)
Definition: misc.c:542
txt_url_open
constext txt_url_open[]
Definition: lang.c:912
INDEX2SNUM
#define INDEX2SNUM(i)
Definition: tin.h:1011
prev_unread
int prev_unread(int n)
Definition: thread.c:1319
lineinfo::offset
long offset
Definition: rfc2046.h:175
PAGE_TOGGLE_ROT13
@ PAGE_TOGGLE_ROT13
Definition: keymap.h:297
highlight_regexes
void highlight_regexes(int row, struct regex_cache *regex, int color)
Definition: regex.c:148
NOT_ASSIGNED
@ NOT_ASSIGNED
Definition: keymap.h:149
page_down
void page_down(void)
Definition: global.c:155
clear_message
void clear_message(void)
Definition: screen.c:243
KEYMAP_DOWN
#define KEYMAP_DOWN
Definition: tin.h:1067
txt_onoff
constext * txt_onoff[]
Definition: lang.c:1257
HAS_FOLLOWUPS
#define HAS_FOLLOWUPS(i)
Definition: tin.h:1029
note_h
static struct t_header * note_h
Definition: page.c:75
my_malloc
#define my_malloc(size)
Definition: tin.h:2196
user_posted_messages
t_bool user_posted_messages(void)
Definition: post.c:466
set_first_screen_item
void set_first_screen_item(void)
Definition: global.c:61