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