1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: help.c 1032 2008-04-11 00:30:04Z hubert@u.washington.edu $";
3 #endif
4 
5 /*
6  * ========================================================================
7  * Copyright 2013-2021 Eduardo Chappa
8  * Copyright 2006-2008 University of Washington
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *     http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * ========================================================================
17  */
18 
19 #include "headers.h"
20 #include "help.h"
21 #include "keymenu.h"
22 #include "status.h"
23 #include "mailview.h"
24 #include "mailindx.h"
25 #include "mailcmd.h"
26 #include "reply.h"
27 #include "signal.h"
28 #include "radio.h"
29 #include "send.h"
30 #include "../pith/state.h"
31 #include "../pith/conf.h"
32 #include "../pith/filter.h"
33 #include "../pith/msgno.h"
34 #include "../pith/pipe.h"
35 #include "../pith/util.h"
36 #include "../pith/detoken.h"
37 #include "../pith/list.h"
38 #include "../pith/margin.h"
39 
40 
41 typedef struct _help_scroll {
42     unsigned	keys_formatted:1;	/* Has full keymenu been formatted? */
43     char      **help_source;		/* Source of displayed help text */
44 } HELP_SCROLL_S;
45 
46 
47 static struct {
48     unsigned   crlf:1;
49     char     **line,
50 	      *offset;
51 } g_h_text;
52 
53 
54 typedef struct _help_print_state {
55     int	  page;
56     char *title;
57     int   title_len;
58 } HPRT_S;
59 
60 static HPRT_S *g_hprt;
61 
62 
63 static char att_cur_msg[] = "\
64          Reporting a bug...\n\
65 \n\
66   If you think that the \"current\" message may be related to the bug you\n\
67   are reporting you may include it as an attachment.  If you want to\n\
68   include a message but you aren't sure if it is the current message,\n\
69   cancel this bug report, go to the folder index, place the cursor on\n\
70   the message you wish to include, then return to the main menu and run\n\
71   the bug report command again.  Answer \"Y\" when asked the question\n\
72   \"Attach current message to report?\"\n\
73 \n\
74   This bug report will also automatically include your pine\n\
75   configuration file, which is helpful when investigating the problem.";
76 
77 
78 #define	GRIPE_OPT_CONF	0x01
79 #define	GRIPE_OPT_MSG	0x02
80 #define	GRIPE_OPT_LOCAL	0x04
81 #define	GRIPE_OPT_KEYS	0x08
82 
83 
84 /*
85  * Internal prototypes
86  */
87 int	 helper_internal(HelpType, char *, char *, int);
88 int	 help_processor(int, MSGNO_S *, SCROLL_S *);
89 void	 help_keymenu_tweek(SCROLL_S *, int);
90 void     print_all_help(void);
91 void	 print_help_page_title(char *, size_t, HPRT_S *);
92 int	 print_help_page_break(long, char *, LT_INS_S **, void *);
93 int	 help_bogus_input(UCS);
94 int	 gripe_newbody(struct pine *, BODY **, long, int);
95 ADDRESS *gripe_token_addr(char *);
96 char	*gripe_id(char *);
97 void	 att_cur_drawer(void);
98 int	 journal_processor(int, MSGNO_S *, SCROLL_S *);
99 int	 help_popup(SCROLL_S *, int);
100 #ifdef	_WINDOWS
101 int	 help_subsection_popup(SCROLL_S *, int);
102 #endif
103 
104 
105 
106 /*----------------------------------------------------------------------
107      Get the help text in the proper format and call scroller
108 
109     Args: text   -- The help text to display (from pine.help --> helptext.c)
110           title  -- The title of the help text
111 
112   Result: format text and call scroller
113 
114   The pages array contains the line number of the start of the pages in
115 the text. Page 1 is in the 0th element of the array.
116 The list is ended with a page line number of -1. Line number 0 is also
117 the first line in the text.
118   -----*/
119 int
helper_internal(HelpType text,char * frag,char * title,int flags)120 helper_internal(HelpType text, char *frag, char *title, int flags)
121 {
122     char	  **shown_text, **external_text = NULL, *help_text = NULL, **rv;
123     int		    cmd = MC_NONE, is_external;
124     long	    offset = 0L;
125     char	   *error = NULL, tmp_title[MAX_SCREEN_COLS + 1];
126     STORE_S	   *store;
127     HANDLE_S	   *handles = NULL, *htmp;
128     HELP_SCROLL_S   hscroll;
129     gf_io_t	    pc;
130 
131     dprint((1, "\n\n    ---- HELPER ----\n"));
132 
133     /* assumption here is that HelpType is char **  */
134     shown_text = text;
135     is_external = 0;
136 
137     if(shown_text && *shown_text && !struncmp(*shown_text, "x-alpine-http:", 14)){
138 	int status;
139 	HTTPSTREAM *stream = http_open(*shown_text + 14);
140 	if(stream) help_text = http_get(stream, NULL);
141 	status = stream->status ? stream->status->code : -1;
142 	if(stream) http_close(stream);
143 	if(status != HTTP_OK){
144 	    shown_text = NO_HELP;
145 	    if(help_text) fs_give((void **) &help_text);
146 	    return MC_FINISH;
147 	}
148 	else{
149 	    is_external = 1;
150 	    if(help_text == NULL) external_text = NO_HELP;
151 	    else{
152 		char *s, *t;
153 		int nlines;
154 
155 		for(nlines = 0, s = help_text; s != NULL; nlines++){
156 		   s = strchr(s, '\n');
157 		   if(s != NULL) s++;
158 		}
159 		rv = external_text = fs_get((nlines + 1)*sizeof(char *));
160 		for(s = help_text; s != NULL; s = t){
161 		   t = strchr(s, '\n');
162 		   if(t != NULL) *t++ = '\0';
163 		   *rv++ = cpystr(s);
164 		}
165 		*rv = NULL;
166 	    }
167 	}
168 
169     }
170 
171     if(F_ON(F_BLANK_KEYMENU,ps_global)){
172 	FOOTER_ROWS(ps_global) = 3;
173 	clearfooter(ps_global);
174 	ps_global->mangled_screen = 1;
175     }
176 
177     if(flags & HLPD_NEWWIN){
178  	fix_windsize(ps_global);
179 	init_sigwinch();
180     }
181 
182     /*
183      * At this point, shown_text is a charstarstar with html
184      * Turn it into a charstar with digested html
185      */
186     do{
187 	init_helper_getc(is_external ? external_text : shown_text);
188 	init_handles(&handles);
189 
190 	memset(&hscroll, 0, sizeof(HELP_SCROLL_S));
191 	hscroll.help_source = is_external ? external_text : shown_text;
192 	if((store = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){
193 	    gf_set_so_writec(&pc, store);
194 	    gf_filter_init();
195 
196 	    if(!struncmp(hscroll.help_source[0], "<html>", 6) || is_external)
197 	      gf_link_filter(gf_html2plain,
198 			     gf_html2plain_opt("x-alpine-help:",
199 					       ps_global->ttyo->screen_cols,
200 					       non_messageview_margin(),
201 					       &handles, NULL, GFHP_LOCAL_HANDLES));
202 	    else
203 	      gf_link_filter(gf_wrap, gf_wrap_filter_opt(
204 						  ps_global->ttyo->screen_cols,
205 						  ps_global->ttyo->screen_cols,
206 						  NULL, 0, GFW_HANDLES | GFW_SOFTHYPHEN));
207 
208 	    error = gf_pipe(helper_getc, pc);
209 
210 	    gf_clear_so_writec(store);
211 
212 	    if(!error){
213 		SCROLL_S	sargs;
214 		struct key_menu km;
215 		struct key	keys[24];
216 
217 		for(htmp = handles; htmp; htmp = htmp->next)
218 		  if(htmp->type == URL
219 		     && htmp->h.url.path
220 		     && (htmp->h.url.path[0] == 'x'
221 			 || htmp->h.url.path[0] == '#'))
222 		    htmp->force_display = 1;
223 
224 		/* This is mostly here to get the curses variables
225 		 * for line and column in sync with where the
226 		 * cursor is on the screen. This gets warped when
227 		 * the composer is called because it does it's own
228 		 * stuff
229 		 */
230 		ClearScreen();
231 
232 		memset(&sargs, 0, sizeof(SCROLL_S));
233 		sargs.text.text	   = so_text(store);
234 		sargs.text.src	   = CharStar;
235 		sargs.text.desc	   = _("help text");
236 		if((sargs.text.handles = handles) != NULL)
237 		  while(sargs.text.handles->type == URL
238 			&& !sargs.text.handles->h.url.path
239 			&& sargs.text.handles->next)
240 		    sargs.text.handles = sargs.text.handles->next;
241 
242 		if(!(sargs.bar.title = title)){
243 		    if(!struncmp(hscroll.help_source[0], "<html>", 6) || is_external){
244 			char *p;
245 			int   i;
246 
247 			/* if we're looking at html, look for a <title>
248 			 * in the <head>... */
249 			for(i = 1;
250 			    hscroll.help_source[0][i]
251 			      && struncmp(hscroll.help_source[i], "</head>", 7);
252 			    i++)
253 			  if(!struncmp(hscroll.help_source[i], "<title>", 7)){
254 			      strncpy(tmp_20k_buf, &hscroll.help_source[i][7], SIZEOF_20KBUF);
255 			      tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
256 			      if((p = strchr(tmp_20k_buf, '<')) != NULL)
257 				*p = '\0';
258 
259 			      snprintf(sargs.bar.title = tmp_title, sizeof(tmp_title),
260 				      "%s -- %.*s", _("HELP"),
261 				      ps_global->ttyo->screen_cols-10,
262 				      strsquish(tmp_20k_buf +  500, SIZEOF_20KBUF,
263 					_(tmp_20k_buf),
264 					ps_global->ttyo->screen_cols / 3));
265 			      tmp_title[sizeof(tmp_title)-1] = '\0';
266 			      break;
267 			  }
268 		    }
269 
270 		    if(!sargs.bar.title)
271 		      sargs.bar.title = _("HELP TEXT");
272 		}
273 
274 		sargs.bar.style	   = TextPercent;
275 		sargs.proc.tool	   = help_processor;
276 		sargs.proc.data.p  = (void *) &hscroll;
277 		sargs.resize_exit  = 1;
278 		sargs.help.text	   = h_special_help_nav;
279 		sargs.help.title   = _("HELP FOR HELP TEXT");
280 		sargs.keys.menu	   = &km;
281 		km		   = help_keymenu;
282 		km.keys		   = keys;
283 		memcpy(&keys[0], help_keymenu.keys,
284 		       (help_keymenu.how_many * 12) * sizeof(struct key));
285 		setbitmap(sargs.keys.bitmap);
286 		if(flags & HLPD_FROMHELP){
287 		    km.keys[HLP_EXIT_KEY].name	     = "P";
288 		    km.keys[HLP_EXIT_KEY].label	     = _("Prev Help");
289 		    km.keys[HLP_EXIT_KEY].bind.cmd   = MC_FINISH;
290 		    km.keys[HLP_EXIT_KEY].bind.ch[0] = 'p';
291 
292 		    km.keys[HLP_SUBEXIT_KEY].name	= "E";
293 		    km.keys[HLP_SUBEXIT_KEY].label	= _("Exit Help");
294 		    km.keys[HLP_SUBEXIT_KEY].bind.cmd   = MC_EXIT;
295 		    km.keys[HLP_SUBEXIT_KEY].bind.ch[0] = 'e';
296 		}
297 		else if(text == h_special_help_nav){
298 		    km.keys[HLP_EXIT_KEY].name	     = "P";
299 		    km.keys[HLP_EXIT_KEY].label	     = _("Prev Help");
300 		    km.keys[HLP_EXIT_KEY].bind.cmd   = MC_FINISH;
301 		    km.keys[HLP_EXIT_KEY].bind.ch[0] = 'p';
302 
303 		    clrbitn(HLP_MAIN_KEY, sargs.keys.bitmap);
304 		    clrbitn(HLP_SUBEXIT_KEY, sargs.keys.bitmap);
305 		}
306 		else{
307 		    km.keys[HLP_EXIT_KEY].name	     = "E";
308 		    km.keys[HLP_EXIT_KEY].label	     = _("Exit Help");
309 		    km.keys[HLP_EXIT_KEY].bind.cmd   = MC_EXIT;
310 		    km.keys[HLP_EXIT_KEY].bind.ch[0] = 'e';
311 
312 		    km.keys[HLP_SUBEXIT_KEY].name	= "?";
313 		    /* TRANSLATORS: this is the label of a command where
314 		       the user is asking for Help about the Help command */
315 		    km.keys[HLP_SUBEXIT_KEY].label	= _("Help Help");
316 		    km.keys[HLP_SUBEXIT_KEY].bind.cmd   = MC_HELP;
317 		    km.keys[HLP_SUBEXIT_KEY].bind.ch[0] = '?';
318 		}
319 
320 		if(flags & HLPD_SIMPLE){
321 		    clrbitn(HLP_MAIN_KEY, sargs.keys.bitmap);
322 		}
323 		else
324 		  sargs.bogus_input = help_bogus_input;
325 
326 		if(handles){
327 		    sargs.keys.each_cmd = help_keymenu_tweek;
328 		    hscroll.keys_formatted = 0;
329 		}
330 		else{
331 		    clrbitn(HLP_VIEW_HANDLE, sargs.keys.bitmap);
332 		    clrbitn(HLP_PREV_HANDLE, sargs.keys.bitmap);
333 		    clrbitn(HLP_NEXT_HANDLE, sargs.keys.bitmap);
334 		}
335 
336 		if(text != main_menu_tx
337 		   && text != h_mainhelp_pinehelp)
338 		  clrbitn(HLP_ALL_KEY, sargs.keys.bitmap);
339 
340 		if(frag){
341 		    sargs.start.on	 = Fragment;
342 		    sargs.start.loc.frag = frag;
343 		    frag		 = NULL; /* ignore next time */
344 		}
345 		else if(offset){
346 		    sargs.start.on	   = Offset;
347 		    sargs.start.loc.offset = offset;
348 		}
349 		else
350 		  sargs.start.on = FirstPage;
351 
352 #ifdef	_WINDOWS
353 		sargs.mouse.popup = (flags & HLPD_FROMHELP)
354 				      ? help_subsection_popup : help_popup;
355 #endif
356 
357 		cmd = scrolltool(&sargs);
358 
359 		offset = sargs.start.loc.offset;
360 
361 		if(F_ON(F_BLANK_KEYMENU,ps_global))
362 		  FOOTER_ROWS(ps_global) = 1;
363 
364 		ClearScreen();
365 	    }
366 
367 	    so_give(&store);
368 	}
369 
370 	free_handles(&handles);
371     }
372     while(cmd == MC_RESIZE);
373 
374     if(external_text != NULL){
375       for(rv = external_text; *rv != NULL; *rv++)
376 	fs_give((void **) &*rv);
377       fs_give((void **) external_text);
378     }
379     if(help_text) fs_give((void **) &help_text);
380     return(cmd);
381 }
382 
383 
384 /*
385  * helper -- compatibility function around newer helper_internal
386  */
387 int
helper(HelpType text,char * title,int flags)388 helper(HelpType text, char *title, int flags)
389 {
390     return(helper_internal(text, NULL, title, flags));
391 }
392 
393 
394 void
init_helper_getc(char ** help_txt)395 init_helper_getc(char **help_txt)
396 {
397     g_h_text.crlf   = 0;
398     g_h_text.line   = help_txt;
399     g_h_text.offset = *g_h_text.line;
400     if(g_h_text.offset && g_h_text.offset[0])
401       g_h_text.offset = _(g_h_text.offset);
402 }
403 
404 
405 int
helper_getc(char * c)406 helper_getc(char *c)
407 {
408     if(g_h_text.crlf){
409 	*c = '\012';
410 	g_h_text.crlf = 0;
411 	return(1);
412     }
413     else if(g_h_text.offset && *g_h_text.line){
414 	if(!(*c = *g_h_text.offset++)){
415 	    g_h_text.offset = *++g_h_text.line;
416 	    if(g_h_text.offset && g_h_text.offset[0])
417 	      g_h_text.offset = _(g_h_text.offset);
418 
419 	    *c = '\015';
420 	    g_h_text.crlf = 1;
421 	}
422 
423 	return(1);
424     }
425 
426     return(0);
427 }
428 
429 
430 int
help_processor(int cmd,MSGNO_S * msgmap,SCROLL_S * sparms)431 help_processor(int cmd, MSGNO_S *msgmap, SCROLL_S *sparms)
432 {
433     int rv = 0;
434     char message[64];
435     struct help_texts *t;
436 
437     switch(cmd){
438 	/*----------- Print all the help ------------*/
439       case MC_PRINTALL :
440 	print_all_help();
441 	break;
442 
443       case MC_PRINTMSG :
444 	snprintf(message, sizeof(message), "%s", STYLE_NAME(sparms));
445 	message[sizeof(message)-1] = '\0';
446 	if(open_printer(message) == 0){
447 	    print_help(((HELP_SCROLL_S *)sparms->proc.data.p)->help_source);
448 	    close_printer();
449 	}
450 
451 	break;
452 
453       case MC_EXPORT: /* reuse old definition, so as not to patch pine.h */
454 	{char help_name[40];
455 	 help_name[0] = '\0';
456 	 for(t = h_texts; t->help_text != NO_HELP; t++)
457 	   if(t->help_text == ((HELP_SCROLL_S *)sparms->proc.data.p)->help_source){
458 	     strncpy(help_name, t->tag, sizeof(help_name)-1);
459 	     help_name[sizeof(help_name)-1] = '\0';
460 	     break;
461 	   }
462 	 if(help_name[0])
463 	   q_status_message1(SM_ORDER, 0, 2,
464 		"Internal Name: x-alpine-help:%s", help_name);
465 	 else
466 	   q_status_message(SM_ORDER|SM_DING, 1, 2,
467 		"Can not find link for text help");
468 	}
469 	break;
470 
471       case MC_FINISH :
472 	rv = 1;
473 	break;
474 
475       default :
476 	alpine_panic("Unhandled case");
477     }
478 
479     return(rv);
480 }
481 
482 
483 void
help_keymenu_tweek(SCROLL_S * sparms,int handle_hidden)484 help_keymenu_tweek(SCROLL_S *sparms, int handle_hidden)
485 {
486     if(handle_hidden){
487 	sparms->keys.menu->keys[HLP_VIEW_HANDLE].name  = "";
488 	sparms->keys.menu->keys[HLP_VIEW_HANDLE].label = "";
489     }
490     else{
491 	if(!((HELP_SCROLL_S *)sparms->proc.data.p)->keys_formatted){
492 	    /* If label's always been blank, force reformatting */
493 	    mark_keymenu_dirty();
494 	    sparms->keys.menu->width = 0;
495 	    ((HELP_SCROLL_S *)sparms->proc.data.p)->keys_formatted = 1;
496 	}
497 
498 	sparms->keys.menu->keys[HLP_VIEW_HANDLE].name  = "V";
499 	sparms->keys.menu->keys[HLP_VIEW_HANDLE].label = "[" N_("View Link") "]";
500     }
501 }
502 
503 
504 /*
505  * print_help - send the raw array of lines to printer
506  */
507 void
print_help(char ** text)508 print_help(char **text)
509 {
510     char   *error, buf[256];
511     HPRT_S  help_data;
512 
513     init_helper_getc(text);
514 
515     memset(g_hprt = &help_data, 0, sizeof(HPRT_S));
516 
517     help_data.page = 1;
518 
519     gf_filter_init();
520 
521     if(!struncmp(text[0], "<html>", 6)){
522 	int   i;
523 	char *p;
524 
525 	gf_link_filter(gf_html2plain,
526 		       gf_html2plain_opt(NULL,80,non_messageview_margin(),
527 					 NULL,NULL,GFHP_STRIPPED));
528 	for(i = 1; i <= 5 && text[i]; i++)
529 	  if(!struncmp(text[i], "<title>", 7)
530 	     && (p = srchstr(text[i] + 7, "</title>"))
531 	     && p - text[i] > 7){
532 	      help_data.title	  = text[i] + 7;
533 	      help_data.title_len = p - help_data.title;
534 	      break;
535 	  }
536     }
537     else
538       gf_link_filter(gf_wrap, gf_wrap_filter_opt(80, 80, NULL, 0, GFW_NONE));
539 
540     gf_link_filter(gf_line_test,
541 		   gf_line_test_opt(print_help_page_break, NULL));
542     gf_link_filter(gf_nvtnl_local, NULL);
543 
544     print_help_page_title(buf, sizeof(buf), &help_data);
545     print_text(buf);
546     print_text(NEWLINE);		/* terminate it */
547     print_text(NEWLINE);		/* and write two blank links */
548     print_text(NEWLINE);
549 
550     if((error = gf_pipe(helper_getc, print_char)) != NULL)
551       q_status_message1(SM_ORDER | SM_DING, 3, 3, _("Printing Error: %s"), error);
552 
553     print_char(ctrl('L'));		/* new page. */
554 }
555 
556 
557 void
print_all_help(void)558 print_all_help(void)
559 {
560     struct help_texts *t;
561     char **h;
562     int we_turned_on = 0;
563 
564     if(open_printer(_("all 150+ pages of help text")) == 0) {
565 	we_turned_on = intr_handling_on();
566 	for(t = h_texts; (h = t->help_text) != NO_HELP; t++) {
567 	    if(ps_global->intr_pending){
568 		q_status_message(SM_ORDER, 3, 3,
569 				 _("Print of all help cancelled"));
570 		break;
571 	    }
572 
573 	    print_help(h);
574         }
575 
576 	if(we_turned_on)
577 	  intr_handling_off();
578 
579         close_printer();
580     }
581 }
582 
583 
584 /*
585  * print_help_page_title --
586  */
587 void
print_help_page_title(char * buf,size_t buflen,HPRT_S * hprt)588 print_help_page_title(char *buf, size_t buflen, HPRT_S *hprt)
589 {
590     snprintf(buf, buflen, "  Alpine Help%s%.*s%*s%d",
591 	    hprt->title_len ? ": " : " Text",
592 	    MIN(55, hprt->title_len), hprt->title_len ? hprt->title : "",
593 	    59 - (hprt->title_len ? MIN(55, hprt->title_len) : 5),
594 	    "Page ", hprt->page);
595     buf[buflen-1] = '\0';
596 }
597 
598 
599 /*
600  * print_help_page_break -- insert page breaks and such for printed
601  *			    help text
602  */
603 int
print_help_page_break(long int linenum,char * line,LT_INS_S ** ins,void * local)604 print_help_page_break(long int linenum, char *line, LT_INS_S **ins, void *local)
605 {
606     char buf[256];
607 
608     if(((linenum + (g_hprt->page * 3)) % 62) == 0){
609 	g_hprt->page++;			/* start on new page */
610 	buf[0] = ctrl('L');
611 	print_help_page_title(buf + 1, sizeof(buf)-1, g_hprt);
612 	strncat(buf, "\015\012\015\012\015\012", sizeof(buf)-strlen(buf)-1);
613 	buf[sizeof(buf)-1] = '\0';
614 	ins = gf_line_test_new_ins(ins, line, buf, strlen(buf));
615     }
616 
617     return(0);
618 }
619 
620 
621 /*
622  * help_bogus_input - used by scrolltool to complain about
623  *		      invalid user input.
624  */
625 int
help_bogus_input(UCS ch)626 help_bogus_input(UCS ch)
627 {
628     bogus_command(ch, NULL);
629     return(0);
630 }
631 
632 
633 int
url_local_helper(char * url)634 url_local_helper(char *url)
635 {
636     if((!struncmp(url, "x-alpine-help:", 14) && *(url += 14))
637 	|| (!struncmp(url, "x-pine-help:", 12) && *(url += 12))){
638 	char		   *frag;
639 	HelpType	    newhelp;
640 
641 	/* internal fragment reference? */
642 	if((frag = strchr(url, '#')) != NULL){
643 	    size_t len;
644 
645 	    if((len = frag - url) != 0){
646 		newhelp = help_name2section(url, len);
647 	    }
648 	    else{
649 		url_local_fragment(url);
650 		return(1);
651 	    }
652 	}
653 	else
654 	  newhelp = help_name2section(url, strlen(url));
655 
656 
657 	if(newhelp != NO_HELP){
658 	    int rv;
659 
660 	    rv = helper_internal(newhelp, frag, _("HELP SUB-SECTION"),
661 				 HLPD_NEWWIN | HLPD_SIMPLE | HLPD_FROMHELP);
662 	    ps_global->mangled_screen = 1;
663 	    return((rv == MC_EXIT) ? 2 : 1);
664 	}
665     }
666 
667     q_status_message1(SM_ORDER | SM_DING, 0, 3,
668 		      _("Unrecognized Internal help: \"%s\""), url);
669     return(0);
670 }
671 
672 
673 int
url_local_config(char * url)674 url_local_config(char *url)
675 {
676     if(!struncmp(url, "x-alpine-config:", 16)){
677 	char **config;
678 	int    rv = MC_NONE;
679 
680 	config = get_supported_options();
681 	if(config){
682 	    /* TRANSLATORS: Help for configuration */
683 	    rv = helper_internal(config, NULL, _("HELP CONFIG"),
684 				 HLPD_NEWWIN | HLPD_SIMPLE | HLPD_FROMHELP);
685 	    free_list_array(&config);
686 	}
687 
688 	ps_global->mangled_screen = 1;
689 	return((rv == MC_EXIT) ? 2 : 1);
690     }
691 
692     q_status_message1(SM_ORDER | SM_DING, 0, 3,
693 		      _("Unrecognized Internal help: \"%s\""), url);
694     return(0);
695 }
696 
697 
698 /*----------------------------------------------------------------------
699      Review latest status messages
700   -----*/
701 void
review_messages(void)702 review_messages(void)
703 {
704     SCROLL_S	    sargs;
705     STORE_S        *in_store = NULL, *out_store = NULL;
706     gf_io_t         gc, pc;
707     int             jo, lo, hi, donejo, donelo, donehi;
708     RMCat           rmcat;
709     int             cmd, timestamps=0, show_level=-1;
710     char            debugkeylabel[20];
711     /* TRANSLATORS: command label asking pine to include time stamps in output */
712     char            timestampkeylabel[] = N_("Timestamps");
713     /* TRANSLATORS: do not include time stamps in output */
714     char           *notimestampkeylabel = N_("NoTimestamps");
715 
716     if((rmjofirst < 0 && rmlofirst < 0 && rmhifirst < 0)
717        || rmjofirst >= RMJLEN || rmjolast >= RMJLEN
718        || rmlofirst >= RMLLEN || rmlolast >= RMLLEN
719        || rmhifirst >= RMHLEN || rmhilast >= RMHLEN
720        || (rmjofirst >= 0 && rmjolast < 0)
721        || (rmlofirst >= 0 && rmlolast < 0)
722        || (rmhifirst >= 0 && rmhilast < 0))
723       return;
724 
725     do{
726 
727 	if(!(in_store = so_get(CharStar, NULL, EDIT_ACCESS)) ||
728 	   !(out_store = so_get(CharStar, NULL, EDIT_ACCESS))){
729 	    if(in_store)
730 	      so_give(&in_store);
731 
732 	    q_status_message(SM_ORDER | SM_DING, 3, 4,
733 			     _("Failed allocating memory"));
734 	    return;
735 	}
736 
737 	add_review_message(_("Turning off new messages while reviewing"), 0);
738 	rm_not_right_now = 1;
739 
740 	donejo = donehi = donelo = 0;
741 	jo = rmjofirst;
742 	if(jo < 0)
743 	  donejo = 1;
744 
745 	lo = rmlofirst;
746 	if(lo < 0)
747 	  donelo = 1;
748 
749 	hi = rmhifirst;
750 	if(hi < 0)
751 	  donehi = 1;
752 
753 	while(!(donejo && donelo && donehi)){
754 	    REV_MSG_S *pjo, *plo, *phi, *p;
755 
756 	    if(!donejo)
757 	      pjo = &rmjoarray[jo];
758 	    else
759 	      pjo = NULL;
760 
761 	    if(!donelo)
762 	      plo = &rmloarray[lo];
763 	    else
764 	      plo = NULL;
765 
766 	    if(!donehi)
767 	      phi = &rmhiarray[hi];
768 	    else
769 	      phi = NULL;
770 
771 	    if(pjo && (!plo || pjo->seq <= plo->seq)
772 	       && (!phi || pjo->seq <= phi->seq))
773 	      rmcat = Jo;
774 	    else if(plo && (!phi || plo->seq <= phi->seq))
775 	      rmcat = Lo;
776 	    else if(phi)
777 	      rmcat = Hi;
778 	    else
779 	      rmcat = No;
780 
781 	    switch(rmcat){
782 	      case Jo:
783 		p = pjo;
784 		if(jo == rmjofirst && (((rmjolast + 1) % RMJLEN) == rmjofirst))
785 		  so_puts(in_store,
786 	_("**** Journal entries prior to this point have been trimmed. ****\n"));
787 		break;
788 
789 	      case Lo:
790 		p = plo;
791 		if(show_level >= 0 &&
792 		   lo == rmlofirst && (((rmlolast + 1) % RMLLEN) == rmlofirst))
793 		  so_puts(in_store,
794 	_("**** Debug 0-4 entries prior to this point have been trimmed. ****\n"));
795 		break;
796 
797 	      case Hi:
798 		p = phi;
799 		if(show_level >= 5 &&
800 		   hi == rmhifirst && (((rmhilast + 1) % RMHLEN) == rmhifirst))
801 		  so_puts(in_store,
802 	_("**** Debug 5-9 entries prior to this point have been trimmed. ****\n"));
803 		break;
804 
805 	      default:
806 		p = NULL;
807 		break;
808 	    }
809 
810 	    if(p){
811 		if(p->level <= show_level){
812 		    if(timestamps && p->timestamp && p->timestamp[0]){
813 			so_puts(in_store, p->timestamp);
814 			so_puts(in_store, ": ");
815 		    }
816 
817 		    if(p->message && p->message[0]){
818 			if(p->continuation)
819 			  so_puts(in_store, ">");
820 
821 			so_puts(in_store, p->message);
822 			so_puts(in_store, "\n");
823 		    }
824 		}
825 	    }
826 
827 	    switch(rmcat){
828 	      case Jo:
829 		if(jo == rmjolast)
830 		  donejo++;
831 		else
832 		  jo = (jo + 1) % RMJLEN;
833 
834 		break;
835 
836 	      case Lo:
837 		if(lo == rmlolast)
838 		  donelo++;
839 		else
840 		  lo = (lo + 1) % RMLLEN;
841 
842 		break;
843 
844 	      case Hi:
845 		if(hi == rmhilast)
846 		  donehi++;
847 		else
848 		  hi = (hi + 1) % RMHLEN;
849 
850 		break;
851 
852 	      default:
853 		donejo++;
854 		donelo++;
855 		donehi++;
856 		break;
857 	    }
858 	}
859 
860 
861 	so_seek(in_store, 0L, 0);
862 	gf_filter_init();
863 	gf_link_filter(gf_wrap,
864 		       gf_wrap_filter_opt(ps_global->ttyo->screen_cols - 4,
865 					  ps_global->ttyo->screen_cols,
866 					  NULL, show_level < 0 ? 2 : 0, GFW_NONE));
867 	gf_set_so_readc(&gc, in_store);
868 	gf_set_so_writec(&pc, out_store);
869 	gf_pipe(gc, pc);
870 	gf_clear_so_writec(out_store);
871 	gf_clear_so_readc(in_store);
872 
873 	memset(&sargs, 0, sizeof(SCROLL_S));
874 	sargs.text.text     = so_text(out_store);
875 	sargs.text.src      = CharStar;
876 	sargs.text.desc     = _("journal");
877 	sargs.keys.menu     = &rev_msg_keymenu;
878 	sargs.proc.tool     = journal_processor;
879 	sargs.start.on      = LastPage;
880 	sargs.resize_exit   = 1;
881 	sargs.proc.data.p   = (void *)&show_level;
882 	setbitmap(sargs.keys.bitmap);
883 
884 #ifdef DEBUG
885 #ifdef DEBUGJOURNAL
886 	sargs.jump_is_debug = 1;
887 	/* TRANSLATORS: these are some screen titles */
888 	sargs.help.title    = _("HELP FOR DEBUG JOURNAL");
889 	sargs.help.text     = h_debugjournal;
890 	sargs.bar.title     = _("REVIEW DEBUGGING");
891 #else	/* !DEBUGJOURNAL */
892 	clrbitn(DEBUG_KEY, sargs.keys.bitmap);
893 	sargs.help.title    = _("HELP FOR JOURNAL");
894 	sargs.help.text     = h_journal;
895 	sargs.bar.title     = _("REVIEW RECENT MESSAGES");
896 #endif	/* !DEBUGJOURNAL */
897 #else	/* !DEBUG */
898 	clrbitn(DEBUG_KEY, sargs.keys.bitmap);
899 	clrbitn(TIMESTAMP_KEY, sargs.keys.bitmap);
900 	sargs.help.title    = _("HELP FOR JOURNAL");
901 	sargs.help.text     = h_journal;
902 	sargs.bar.title     = _("REVIEW RECENT MESSAGES");
903 #endif	/* !DEBUG */
904 
905 	if(timestamps)
906 	  rev_msg_keys[TIMESTAMP_KEY].label = notimestampkeylabel;
907 	else
908 	  rev_msg_keys[TIMESTAMP_KEY].label = timestampkeylabel;
909 
910 	if(show_level >= 0)
911 	  /* TRANSLATORS: shows what numeric level Debug output is displayed at */
912 	  snprintf(debugkeylabel, sizeof(debugkeylabel), _("Debug (%d)"), show_level);
913 	else
914 	  /* TRANSLATORS: include debug output in journal */
915 	  strncpy(debugkeylabel, _("DebugView"), sizeof(debugkeylabel));
916 
917 	debugkeylabel[sizeof(debugkeylabel)-1] = '\0';
918 
919 	rev_msg_keys[DEBUG_KEY].label = debugkeylabel;
920 	KS_OSDATASET(&rev_msg_keys[DEBUG_KEY], KS_NONE);
921 
922 	if((cmd = scrolltool(&sargs)) == MC_TOGGLE)
923 	  timestamps = !timestamps;
924 
925 	so_give(&in_store);
926 	so_give(&out_store);
927 
928     }while(cmd != MC_EXIT);
929 
930     rm_not_right_now = 0;
931     add_review_message("Done reviewing", 0);
932 }
933 
934 
935 int
journal_processor(int cmd,MSGNO_S * msgmap,SCROLL_S * sparms)936 journal_processor(int cmd, MSGNO_S *msgmap, SCROLL_S *sparms)
937 {
938     switch(cmd){
939       case MC_TOGGLE:		/* turn timestamps on or off */
940         break;
941 
942       default:
943         alpine_panic("Unexpected command in journal_processor");
944 	break;
945     }
946 
947     return(1);
948 }
949 
950 
951 /*
952  * standard type of storage object used for body parts...
953  */
954 #ifdef	DOS
955 #define		  PART_SO_TYPE	TmpFileStar
956 #else
957 #define		  PART_SO_TYPE	CharStar
958 #endif
959 
960 
961 int
gripe_gripe_to(url)962 gripe_gripe_to(url)
963     char *url;
964 {
965     char      *composer_title, *url_copy, *optstr, *p;
966     int	       opts = 0;
967     BODY      *body = NULL;
968     ENVELOPE  *outgoing = NULL;
969     REPLY_S    fake_reply;
970     PINEFIELD *pf = NULL;
971     long       msgno = mn_m2raw(ps_global->msgmap,
972 				mn_get_cur(ps_global->msgmap));
973 
974     url_copy = cpystr(url + strlen("x-alpine-gripe:"));
975     if((optstr = strchr(url_copy, '?')) != NULL)
976       *optstr++ = '\0';
977 
978     outgoing		 = mail_newenvelope();
979     outgoing->message_id = generate_message_id(NULL);
980 
981     if((outgoing->to = gripe_token_addr(url_copy)) != NULL){
982 	composer_title = _("COMPOSE TO LOCAL SUPPORT");
983 	dprint((1,
984 		   "\n\n   -- Send to local support(%s@%s) --\n",
985 		   outgoing->to->mailbox ? outgoing->to->mailbox : "NULL",
986 		   outgoing->to->host ? outgoing->to->host : "NULL"));
987     }
988     else{			/* must be global */
989 	composer_title = _("REQUEST FOR ASSISTANCE");
990 	rfc822_parse_adrlist(&outgoing->to, url_copy, ps_global->maildomain);
991     }
992 
993     /*
994      * Sniff thru options
995      */
996     while(optstr){
997 	if((p = strchr(optstr, '?')) != NULL)	/* tie off list item */
998 	  *p++ = '\0';
999 
1000 	if(!strucmp(optstr, "config"))
1001 	  opts |= GRIPE_OPT_CONF;
1002 	else if(!strucmp(optstr, "curmsg"))
1003 	  opts |= GRIPE_OPT_MSG;
1004 	else if(!strucmp(optstr, "local"))
1005 	  opts |= GRIPE_OPT_LOCAL;
1006 	else if(!strucmp(optstr, "keys"))
1007 	  opts |= GRIPE_OPT_KEYS;
1008 
1009 	optstr = p;
1010     }
1011 
1012     /* build body and hand off to composer... */
1013     if(gripe_newbody(ps_global, &body, msgno, opts) == 0){
1014 	pf = (PINEFIELD *) fs_get(sizeof(PINEFIELD));
1015 	memset(pf, 0, sizeof(PINEFIELD));
1016 	pf->name		   = cpystr("X-Generated-Via");
1017 	pf->type		   = FreeText;
1018 	pf->textbuf		   = gripe_id("Alpine Bug Report screen");
1019 	memset((void *)&fake_reply, 0, sizeof(fake_reply));
1020 	fake_reply.pseudo	   = 1;
1021 	fake_reply.data.pico_flags = P_HEADEND;
1022 	pine_send(outgoing, &body, composer_title, NULL, NULL,
1023 		  &fake_reply, NULL, NULL, pf, PS_STICKY_TO);
1024     }
1025 
1026     ps_global->mangled_screen = 1;
1027     mail_free_envelope(&outgoing);
1028 
1029     if(body)
1030       pine_free_body(&body);
1031 
1032     fs_give((void **) &url_copy);
1033 
1034     return(10);
1035 }
1036 
1037 
1038 int
gripe_newbody(ps,body,msgno,flags)1039 gripe_newbody(ps, body, msgno, flags)
1040     struct pine *ps;
1041     BODY       **body;
1042     long         msgno;
1043     int          flags;
1044 {
1045     BODY        *pb;
1046     PART       **pp;
1047     STORE_S	*store;
1048     gf_io_t      pc;
1049     static char *err = "Problem creating space for message text.";
1050     int          i;
1051     char         tmp[MAILTMPLEN], *p;
1052 
1053     if((store = so_get(PicoText, NULL, EDIT_ACCESS)) != NULL){
1054 	*body = mail_newbody();
1055 
1056 	if((p = detoken(NULL, NULL, 2, 0, 1, NULL, NULL)) != NULL){
1057 	    if(*p)
1058 	      so_puts(store, p);
1059 
1060 	    fs_give((void **) &p);
1061 	}
1062     }
1063     else{
1064 	q_status_message(SM_ORDER | SM_DING, 3, 4, err);
1065 	return(-1);
1066     }
1067 
1068     if(flags){
1069 	/*---- Might have multiple parts ----*/
1070 	(*body)->type			= TYPEMULTIPART;
1071 	/*---- The TEXT part/body ----*/
1072 	(*body)->nested.part            = mail_newbody_part();
1073 	(*body)->nested.part->body.type = TYPETEXT;
1074 	(*body)->nested.part->body.contents.text.data = (void *) store;
1075 
1076 	/*---- create object, and write current config into it ----*/
1077 	pp = &((*body)->nested.part->next);
1078 
1079 	if(flags & GRIPE_OPT_CONF){
1080 	    *pp			     = mail_newbody_part();
1081 	    pb			     = &((*pp)->body);
1082 	    pp			     = &((*pp)->next);
1083 	    pb->type		     = TYPETEXT;
1084 	    pb->id		     = generate_message_id(NULL);
1085 	    pb->description	     = cpystr("Alpine Configuration Data");
1086 	    pb->parameter	     = mail_newbody_parameter();
1087 	    pb->parameter->attribute = cpystr("name");
1088 	    pb->parameter->value     = cpystr("config.txt");
1089 
1090 	    if((store = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){
1091 		extern char datestamp[], hoststamp[];
1092 
1093 		pb->contents.text.data = (void *) store;
1094 		gf_set_so_writec(&pc, store);
1095 		gf_puts("Alpine built ", pc);
1096 		gf_puts(datestamp, pc);
1097 		gf_puts(" on host: ", pc);
1098 		gf_puts(hoststamp, pc);
1099 		gf_puts("\n", pc);
1100 
1101 #ifdef DEBUG
1102 		dump_pine_struct(ps, pc);
1103 		dump_config(ps, pc, 0);
1104 #endif /* DEBUG */
1105 
1106 		pb->size.bytes = strlen((char *) so_text(store));
1107 		gf_clear_so_writec(store);
1108 	    }
1109 	    else{
1110 		q_status_message(SM_ORDER | SM_DING, 3, 4, err);
1111 		return(-1);
1112 	    }
1113 	}
1114 
1115 	if(flags & GRIPE_OPT_KEYS){
1116 	    *pp			     = mail_newbody_part();
1117 	    pb			     = &((*pp)->body);
1118 	    pp			     = &((*pp)->next);
1119 	    pb->type		     = TYPETEXT;
1120 	    pb->id		     = generate_message_id(NULL);
1121 	    pb->description	     = cpystr("Recent User Input");
1122 	    pb->parameter	      = mail_newbody_parameter();
1123 	    pb->parameter->attribute  = cpystr("name");
1124 	    pb->parameter->value      = cpystr("uinput.txt");
1125 
1126 	    if((store = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){
1127 		pb->contents.text.data = (void *) store;
1128 
1129 		so_puts(store, "User's most recent input:\n");
1130 
1131 		/* dump last n keystrokes */
1132 		so_puts(store, "========== Latest keystrokes ==========\n");
1133 		while((i = key_playback(0)) != -1){
1134 		    snprintf(tmp, sizeof(tmp), "\t%s\t(0x%x)\n", pretty_command(i), i);
1135 		    tmp[sizeof(tmp)-1] = '\0';
1136 		    so_puts(store, tmp);
1137 		}
1138 
1139 		pb->size.bytes = strlen((char *) so_text(store));
1140 	    }
1141 	    else{
1142 		q_status_message(SM_ORDER | SM_DING, 3, 4, err);
1143 		return(-1);
1144 	    }
1145 	}
1146 
1147 	/* check for local debugging info? */
1148 	if((flags & GRIPE_OPT_LOCAL)
1149 	   && ps_global->VAR_BUGS_EXTRAS
1150 	   && can_access(ps_global->VAR_BUGS_EXTRAS, EXECUTE_ACCESS) == 0){
1151 	    char *error		      = NULL;
1152 
1153 	    *pp			      = mail_newbody_part();
1154 	    pb			      = &((*pp)->body);
1155 	    pp			      = &((*pp)->next);
1156 	    pb->type		      = TYPETEXT;
1157 	    pb->id		      = generate_message_id(NULL);
1158 	    pb->description	      = cpystr("Local Configuration Data");
1159 	    pb->parameter	      = mail_newbody_parameter();
1160 	    pb->parameter->attribute  = cpystr("name");
1161 	    pb->parameter->value      = cpystr("lconfig.txt");
1162 
1163 	    if((store = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){
1164 		PIPE_S  *syspipe;
1165 		gf_io_t  gc;
1166 
1167 		pb->contents.text.data = (void *) store;
1168 		gf_set_so_writec(&pc, store);
1169 		if((syspipe = open_system_pipe(ps_global->VAR_BUGS_EXTRAS,
1170 					 NULL, NULL,
1171 					 PIPE_READ | PIPE_STDERR | PIPE_USER,
1172 					 0, pipe_callback, pipe_report_error)) != NULL){
1173 		    gf_set_readc(&gc, (void *)syspipe, 0, PipeStar, 0);
1174 		    gf_filter_init();
1175 		    error = gf_pipe(gc, pc);
1176 		    (void) close_system_pipe(&syspipe, NULL, pipe_callback);
1177 		}
1178 		else
1179 		  error = "executing config collector";
1180 
1181 		gf_clear_so_writec(store);
1182 	    }
1183 
1184 	    if(error){
1185 		q_status_message1(SM_ORDER | SM_DING, 3, 4,
1186 				  "Problem %s", error);
1187 		return(-1);
1188 	    }
1189 	    else			/* fixup attachment's size */
1190 	      pb->size.bytes = strlen((char *) so_text(store));
1191 	}
1192 
1193 	if((flags & GRIPE_OPT_MSG) && mn_get_total(ps->msgmap) > 0L){
1194 	    int ch = 0;
1195 
1196 	    ps->redrawer = att_cur_drawer;
1197 	    att_cur_drawer();
1198 
1199 	    if((ch = one_try_want_to("Attach current message to report",
1200 				     'y','x',NO_HELP,
1201 				     WT_FLUSH_IN|WT_SEQ_SENSITIVE)) == 'y'){
1202 		*pp		      = mail_newbody_part();
1203 		pb		      = &((*pp)->body);
1204 		pp		      = &((*pp)->next);
1205 		pb->type	      = TYPEMESSAGE;
1206 		pb->id		      = generate_message_id(NULL);
1207 		snprintf(tmp, sizeof(tmp), "Problem Message (%ld of %ld)",
1208 			mn_get_cur(ps->msgmap), mn_get_total(ps->msgmap));
1209 		tmp[sizeof(tmp)-1] = '\0';
1210 		pb->description	      = cpystr(tmp);
1211 
1212 		/*---- Package each message in a storage object ----*/
1213 		if((store = so_get(PART_SO_TYPE, NULL, EDIT_ACCESS)) != NULL){
1214 		    pb->contents.text.data = (void *) store;
1215 		}
1216 		else{
1217 		    q_status_message(SM_ORDER | SM_DING, 3, 4, err);
1218 		    return(-1);
1219 		}
1220 
1221 		/* write the header */
1222 		if((p = mail_fetch_header(ps->mail_stream, msgno, NIL, NIL,
1223 					  NIL, FT_PEEK)) && *p)
1224 		  so_puts(store, p);
1225 		else
1226 		  return(-1);
1227 
1228 		pb->size.bytes = strlen(p);
1229 		so_puts(store, "\015\012");
1230 
1231 		if((p = pine_mail_fetch_text(ps->mail_stream,
1232 					     msgno, NULL, NULL, NIL))
1233 		   &&  *p)
1234 		  so_puts(store, p);
1235 		else
1236 		  return(-1);
1237 
1238 		pb->size.bytes += strlen(p);
1239 	    }
1240 	    else if(ch == 'x'){
1241 		q_status_message(SM_ORDER, 0, 3, "Bug report cancelled.");
1242 		return(-1);
1243 	    }
1244 	}
1245     }
1246     else{
1247 	/*---- Only one part! ----*/
1248 	(*body)->type = TYPETEXT;
1249 	(*body)->contents.text.data = (void *) store;
1250     }
1251 
1252     return(0);
1253 }
1254 
1255 
1256 ADDRESS *
gripe_token_addr(token)1257 gripe_token_addr(token)
1258     char *token;
1259 {
1260     char    *p;
1261     ADDRESS *a = NULL;
1262 
1263     if(token && *token++ == '_'){
1264 	if(!strcmp(token, "LOCAL_ADDRESS_")){
1265 	    p = (ps_global->VAR_LOCAL_ADDRESS
1266 		 && ps_global->VAR_LOCAL_ADDRESS[0])
1267 		    ? ps_global->VAR_LOCAL_ADDRESS
1268 		    : "postmaster";
1269 	    a = rfc822_parse_mailbox(&p, ps_global->maildomain);
1270 	    a->personal = cpystr((ps_global->VAR_LOCAL_FULLNAME
1271 				  && ps_global->VAR_LOCAL_FULLNAME[0])
1272 				    ? ps_global->VAR_LOCAL_FULLNAME
1273 				    : "Place to report Alpine Bugs");
1274 	}
1275 	else if(!strcmp(token, "BUGS_ADDRESS_")){
1276 	    p = (ps_global->VAR_BUGS_ADDRESS
1277 		 && ps_global->VAR_BUGS_ADDRESS[0])
1278 		    ? ps_global->VAR_BUGS_ADDRESS : "postmaster";
1279 	    a = rfc822_parse_mailbox(&p, ps_global->maildomain);
1280 	    a->personal = cpystr((ps_global->VAR_BUGS_FULLNAME
1281 				  && ps_global->VAR_BUGS_FULLNAME[0])
1282 				    ? ps_global->VAR_BUGS_FULLNAME
1283 				    : "Place to report Alpine Bugs");
1284 	}
1285     }
1286 
1287     return(a);
1288 }
1289 
1290 
1291 char *
gripe_id(key)1292 gripe_id(key)
1293     char *key;
1294 {
1295     int i,j,k,l;
1296 
1297     /*
1298      * Build our contribution to the subject; part constant string
1299      * and random 4 character alpha numeric string.
1300      */
1301     i = (int)(random() % 36L);
1302     j = (int)(random() % 36L);
1303     k = (int)(random() % 36L);
1304     l = (int)(random() % 36L);
1305     tmp_20k_buf[0] = '\0';
1306     snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s (ID %c%c%d%c%c)", key,
1307 	    (i < 10) ? '0' + i : 'A' + (i - 10),
1308 	    (j < 10) ? '0' + j : 'A' + (j - 10),
1309 	    (int)(random() % 10L),
1310 	    (k < 10) ? '0' + k : 'A' + (k - 10),
1311 	    (l < 10) ? '0' + l : 'A' + (l - 10));
1312     tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1313     return(cpystr(tmp_20k_buf));
1314 }
1315 
1316 
1317 /*
1318  * Used by gripe_tool.
1319  */
1320 void
att_cur_drawer(void)1321 att_cur_drawer(void)
1322 {
1323     int	       i, dline, j;
1324     char       buf[256+1];
1325 
1326     /* blat helpful message to screen */
1327     ClearBody();
1328     j = 0;
1329     for(dline = 2;
1330 	dline < ps_global->ttyo->screen_rows - FOOTER_ROWS(ps_global);
1331 	dline++){
1332 	for(i = 0; i < 256 && att_cur_msg[j] && att_cur_msg[j] != '\n'; i++)
1333 	  buf[i] = att_cur_msg[j++];
1334 
1335 	buf[i] = '\0';
1336 	if(att_cur_msg[j])
1337 	  j++;
1338 	else if(!i)
1339 	  break;
1340 
1341         PutLine0(dline, 1, buf);
1342     }
1343 }
1344 
1345 
1346 #ifdef	_WINDOWS
1347 
1348 /*
1349  *
1350  */
1351 char *
pcpine_help(HelpType section)1352 pcpine_help(HelpType section)
1353 {
1354     char    **help_lines, *help_text = NULL;
1355     STORE_S  *store;
1356     gf_io_t   pc;
1357 
1358     /* assumption here is that HelpType is char **  */
1359     help_lines = section;
1360     if (help_lines != NULL){
1361 	init_helper_getc(help_lines);
1362 	if(store = so_get(CharStar, NULL, EDIT_ACCESS)){
1363 	    gf_set_so_writec(&pc, store);
1364 	    gf_filter_init();
1365 
1366 	    gf_link_filter(gf_local_nvtnl, NULL);
1367 
1368 	    gf_link_filter(gf_html2plain,
1369 			   gf_html2plain_opt(NULL,
1370 					     ps_global->ttyo->screen_cols,
1371 					     non_messageview_margin(), NULL, NULL, GFHP_STRIPPED));
1372 
1373 	    if(!gf_pipe(helper_getc, pc)){
1374 		help_text  = (char *) store->txt;
1375 		store->txt = (void *) NULL;
1376 	    }
1377 
1378 	    gf_clear_so_writec(store);
1379 	    so_give(&store);
1380 	}
1381     }
1382 
1383     return(help_text);
1384 }
1385 
1386 
1387 /*
1388  *
1389  */
1390 int
help_popup(SCROLL_S * sparms,int in_handle)1391 help_popup(SCROLL_S *sparms, int in_handle)
1392 {
1393     MPopup hp_menu[10];
1394     int	   i = -1;
1395 
1396     if(in_handle){
1397 	hp_menu[++i].type	= tQueue;
1398 	hp_menu[i].label.style	= lNormal;
1399 	hp_menu[i].label.string = "View Help Section";
1400 	hp_menu[i].data.val	= 'V';
1401     }
1402 
1403     hp_menu[++i].type	    = tQueue;
1404     hp_menu[i].label.style  = lNormal;
1405     hp_menu[i].label.string = "Exit Help";
1406     hp_menu[i].data.val	    = 'E';
1407 
1408     hp_menu[++i].type = tTail;
1409 
1410     mswin_popup(hp_menu);
1411 
1412     return(0);
1413 }
1414 
1415 
1416 /*
1417  *
1418  */
1419 int
help_subsection_popup(SCROLL_S * sparms,int in_handle)1420 help_subsection_popup(SCROLL_S *sparms, int in_handle)
1421 {
1422     MPopup hp_menu[10];
1423     int	   i = -1;
1424 
1425     if(in_handle){
1426 	hp_menu[++i].type	= tQueue;
1427 	hp_menu[i].label.style  = lNormal;
1428 	hp_menu[i].label.string = "View Help Section";
1429 	hp_menu[i].data.val	= 'V';
1430     }
1431 
1432     hp_menu[++i].type	    = tQueue;
1433     hp_menu[i].label.style  = lNormal;
1434     hp_menu[i].label.string = "Previous Help Section";
1435     hp_menu[i].data.val	    = 'P';
1436 
1437     hp_menu[++i].type	    = tQueue;
1438     hp_menu[i].label.style  = lNormal;
1439     hp_menu[i].label.string = "Exit Help";
1440     hp_menu[i].data.val	    = 'E';
1441 
1442     hp_menu[++i].type = tTail;
1443 
1444     if(mswin_popup(hp_menu) == (in_handle ? 1 : 0))
1445       /*(void) helper_internal()*/;
1446 
1447     return(0);
1448 }
1449 
1450 #endif /* _WINDOWS */
1451