diff options
author | Eduardo Chappa <echappa@gmx.com> | 2013-02-03 00:59:38 -0700 |
---|---|---|
committer | Eduardo Chappa <echappa@gmx.com> | 2013-02-03 00:59:38 -0700 |
commit | 094ca96844842928810f14844413109fc6cdd890 (patch) | |
tree | e60efbb980f38ba9308ccb4fb2b77b87bbc115f3 /alpine/help.c | |
download | alpine-094ca96844842928810f14844413109fc6cdd890.tar.xz |
Initial Alpine Version
Diffstat (limited to 'alpine/help.c')
-rw-r--r-- | alpine/help.c | 1408 |
1 files changed, 1408 insertions, 0 deletions
diff --git a/alpine/help.c b/alpine/help.c new file mode 100644 index 00000000..b291defd --- /dev/null +++ b/alpine/help.c @@ -0,0 +1,1408 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: help.c 1032 2008-04-11 00:30:04Z hubert@u.washington.edu $"; +#endif + +/* + * ======================================================================== + * Copyright 2006-2008 University of Washington + * Copyright 2013 Eduardo Chappa + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include "headers.h" +#include "help.h" +#include "keymenu.h" +#include "status.h" +#include "mailview.h" +#include "mailindx.h" +#include "mailcmd.h" +#include "reply.h" +#include "signal.h" +#include "radio.h" +#include "send.h" +#include "../pith/state.h" +#include "../pith/conf.h" +#include "../pith/filter.h" +#include "../pith/msgno.h" +#include "../pith/pipe.h" +#include "../pith/util.h" +#include "../pith/detoken.h" +#include "../pith/list.h" +#include "../pith/margin.h" + + +typedef struct _help_scroll { + unsigned keys_formatted:1; /* Has full keymenu been formatted? */ + char **help_source; /* Source of displayed help text */ +} HELP_SCROLL_S; + + +static struct { + unsigned crlf:1; + char **line, + *offset; +} g_h_text; + + +typedef struct _help_print_state { + int page; + char *title; + int title_len; +} HPRT_S; + +static HPRT_S *g_hprt; + + +static char att_cur_msg[] = "\ + Reporting a bug...\n\ +\n\ + If you think that the \"current\" message may be related to the bug you\n\ + are reporting you may include it as an attachment. If you want to\n\ + include a message but you aren't sure if it is the current message,\n\ + cancel this bug report, go to the folder index, place the cursor on\n\ + the message you wish to include, then return to the main menu and run\n\ + the bug report command again. Answer \"Y\" when asked the question\n\ + \"Attach current message to report?\"\n\ +\n\ + This bug report will also automatically include your pine\n\ + configuration file, which is helpful when investigating the problem."; + + +#define GRIPE_OPT_CONF 0x01 +#define GRIPE_OPT_MSG 0x02 +#define GRIPE_OPT_LOCAL 0x04 +#define GRIPE_OPT_KEYS 0x08 + + +/* + * Internal prototypes + */ +int helper_internal(HelpType, char *, char *, int); +int help_processor(int, MSGNO_S *, SCROLL_S *); +void help_keymenu_tweek(SCROLL_S *, int); +void print_all_help(void); +void print_help_page_title(char *, size_t, HPRT_S *); +int print_help_page_break(long, char *, LT_INS_S **, void *); +int help_bogus_input(UCS); +int gripe_newbody(struct pine *, BODY **, long, int); +ADDRESS *gripe_token_addr(char *); +char *gripe_id(char *); +void att_cur_drawer(void); +int journal_processor(int, MSGNO_S *, SCROLL_S *); +int help_popup(SCROLL_S *, int); +#ifdef _WINDOWS +int help_subsection_popup(SCROLL_S *, int); +#endif + + + +/*---------------------------------------------------------------------- + Get the help text in the proper format and call scroller + + Args: text -- The help text to display (from pine.help --> helptext.c) + title -- The title of the help text + + Result: format text and call scroller + + The pages array contains the line number of the start of the pages in +the text. Page 1 is in the 0th element of the array. +The list is ended with a page line number of -1. Line number 0 is also +the first line in the text. + -----*/ +int +helper_internal(HelpType text, char *frag, char *title, int flags) +{ + char **shown_text; + int cmd = MC_NONE; + long offset = 0L; + char *error = NULL, tmp_title[MAX_SCREEN_COLS + 1]; + STORE_S *store; + HANDLE_S *handles = NULL, *htmp; + HELP_SCROLL_S hscroll; + gf_io_t pc; + + dprint((1, "\n\n ---- HELPER ----\n")); + + /* assumption here is that HelpType is char ** */ + shown_text = text; + + if(F_ON(F_BLANK_KEYMENU,ps_global)){ + FOOTER_ROWS(ps_global) = 3; + clearfooter(ps_global); + ps_global->mangled_screen = 1; + } + + if(flags & HLPD_NEWWIN){ + fix_windsize(ps_global); + init_sigwinch(); + } + + /* + * At this point, shown_text is a charstarstar with html + * Turn it into a charstar with digested html + */ + do{ + init_helper_getc(shown_text); + init_handles(&handles); + + memset(&hscroll, 0, sizeof(HELP_SCROLL_S)); + hscroll.help_source = shown_text; + if((store = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){ + gf_set_so_writec(&pc, store); + gf_filter_init(); + + if(!struncmp(shown_text[0], "<html>", 6)) + gf_link_filter(gf_html2plain, + gf_html2plain_opt("x-alpine-help:", + ps_global->ttyo->screen_cols, + non_messageview_margin(), + &handles, NULL, GFHP_LOCAL_HANDLES)); + else + gf_link_filter(gf_wrap, gf_wrap_filter_opt( + ps_global->ttyo->screen_cols, + ps_global->ttyo->screen_cols, + NULL, 0, GFW_HANDLES | GFW_SOFTHYPHEN)); + + error = gf_pipe(helper_getc, pc); + + gf_clear_so_writec(store); + + if(!error){ + SCROLL_S sargs; + struct key_menu km; + struct key keys[24]; + + for(htmp = handles; htmp; htmp = htmp->next) + if(htmp->type == URL + && htmp->h.url.path + && (htmp->h.url.path[0] == 'x' + || htmp->h.url.path[0] == '#')) + htmp->force_display = 1; + + /* This is mostly here to get the curses variables + * for line and column in sync with where the + * cursor is on the screen. This gets warped when + * the composer is called because it does it's own + * stuff + */ + ClearScreen(); + + memset(&sargs, 0, sizeof(SCROLL_S)); + sargs.text.text = so_text(store); + sargs.text.src = CharStar; + sargs.text.desc = _("help text"); + if((sargs.text.handles = handles) != NULL) + while(sargs.text.handles->type == URL + && !sargs.text.handles->h.url.path + && sargs.text.handles->next) + sargs.text.handles = sargs.text.handles->next; + + if(!(sargs.bar.title = title)){ + if(!struncmp(shown_text[0], "<html>", 6)){ + char *p; + int i; + + /* if we're looking at html, look for a <title> + * in the <head>... */ + for(i = 1; + shown_text[i] + && struncmp(shown_text[i], "</head>", 7); + i++) + if(!struncmp(shown_text[i], "<title>", 7)){ + strncpy(tmp_20k_buf, &shown_text[i][7], SIZEOF_20KBUF); + tmp_20k_buf[SIZEOF_20KBUF-1] = '\0'; + if((p = strchr(tmp_20k_buf, '<')) != NULL) + *p = '\0'; + + snprintf(sargs.bar.title = tmp_title, sizeof(tmp_title), + "%s -- %.*s", _("HELP"), + ps_global->ttyo->screen_cols-10, + strsquish(tmp_20k_buf + 500, SIZEOF_20KBUF, + _(tmp_20k_buf), + ps_global->ttyo->screen_cols / 3)); + tmp_title[sizeof(tmp_title)-1] = '\0'; + break; + } + } + + if(!sargs.bar.title) + sargs.bar.title = _("HELP TEXT"); + } + + sargs.bar.style = TextPercent; + sargs.proc.tool = help_processor; + sargs.proc.data.p = (void *) &hscroll; + sargs.resize_exit = 1; + sargs.help.text = h_special_help_nav; + sargs.help.title = _("HELP FOR HELP TEXT"); + sargs.keys.menu = &km; + km = help_keymenu; + km.keys = keys; + memcpy(&keys[0], help_keymenu.keys, + (help_keymenu.how_many * 12) * sizeof(struct key)); + setbitmap(sargs.keys.bitmap); + if(flags & HLPD_FROMHELP){ + km.keys[HLP_EXIT_KEY].name = "P"; + km.keys[HLP_EXIT_KEY].label = _("Prev Help"); + km.keys[HLP_EXIT_KEY].bind.cmd = MC_FINISH; + km.keys[HLP_EXIT_KEY].bind.ch[0] = 'p'; + + km.keys[HLP_SUBEXIT_KEY].name = "E"; + km.keys[HLP_SUBEXIT_KEY].label = _("Exit Help"); + km.keys[HLP_SUBEXIT_KEY].bind.cmd = MC_EXIT; + km.keys[HLP_SUBEXIT_KEY].bind.ch[0] = 'e'; + } + else if(text == h_special_help_nav){ + km.keys[HLP_EXIT_KEY].name = "P"; + km.keys[HLP_EXIT_KEY].label = _("Prev Help"); + km.keys[HLP_EXIT_KEY].bind.cmd = MC_FINISH; + km.keys[HLP_EXIT_KEY].bind.ch[0] = 'p'; + + clrbitn(HLP_MAIN_KEY, sargs.keys.bitmap); + clrbitn(HLP_SUBEXIT_KEY, sargs.keys.bitmap); + } + else{ + km.keys[HLP_EXIT_KEY].name = "E"; + km.keys[HLP_EXIT_KEY].label = _("Exit Help"); + km.keys[HLP_EXIT_KEY].bind.cmd = MC_EXIT; + km.keys[HLP_EXIT_KEY].bind.ch[0] = 'e'; + + km.keys[HLP_SUBEXIT_KEY].name = "?"; + /* TRANSLATORS: this is the label of a command where + the user is asking for Help about the Help command */ + km.keys[HLP_SUBEXIT_KEY].label = _("Help Help"); + km.keys[HLP_SUBEXIT_KEY].bind.cmd = MC_HELP; + km.keys[HLP_SUBEXIT_KEY].bind.ch[0] = '?'; + } + + if(flags & HLPD_SIMPLE){ + clrbitn(HLP_MAIN_KEY, sargs.keys.bitmap); + } + else + sargs.bogus_input = help_bogus_input; + + if(handles){ + sargs.keys.each_cmd = help_keymenu_tweek; + hscroll.keys_formatted = 0; + } + else{ + clrbitn(HLP_VIEW_HANDLE, sargs.keys.bitmap); + clrbitn(HLP_PREV_HANDLE, sargs.keys.bitmap); + clrbitn(HLP_NEXT_HANDLE, sargs.keys.bitmap); + } + + if(text != main_menu_tx + && text != h_mainhelp_pinehelp) + clrbitn(HLP_ALL_KEY, sargs.keys.bitmap); + + if(frag){ + sargs.start.on = Fragment; + sargs.start.loc.frag = frag; + frag = NULL; /* ignore next time */ + } + else if(offset){ + sargs.start.on = Offset; + sargs.start.loc.offset = offset; + } + else + sargs.start.on = FirstPage; + +#ifdef _WINDOWS + sargs.mouse.popup = (flags & HLPD_FROMHELP) + ? help_subsection_popup : help_popup; +#endif + + cmd = scrolltool(&sargs); + + offset = sargs.start.loc.offset; + + if(F_ON(F_BLANK_KEYMENU,ps_global)) + FOOTER_ROWS(ps_global) = 1; + + ClearScreen(); + } + + so_give(&store); + } + + free_handles(&handles); + } + while(cmd == MC_RESIZE); + + return(cmd); +} + + +/* + * helper -- compatibility function around newer helper_internal + */ +int +helper(HelpType text, char *title, int flags) +{ + return(helper_internal(text, NULL, title, flags)); +} + + +void +init_helper_getc(char **help_txt) +{ + g_h_text.crlf = 0; + g_h_text.line = help_txt; + g_h_text.offset = *g_h_text.line; + if(g_h_text.offset && g_h_text.offset[0]) + g_h_text.offset = _(g_h_text.offset); +} + + +int +helper_getc(char *c) +{ + if(g_h_text.crlf){ + *c = '\012'; + g_h_text.crlf = 0; + return(1); + } + else if(g_h_text.offset && *g_h_text.line){ + if(!(*c = *g_h_text.offset++)){ + g_h_text.offset = *++g_h_text.line; + if(g_h_text.offset && g_h_text.offset[0]) + g_h_text.offset = _(g_h_text.offset); + + *c = '\015'; + g_h_text.crlf = 1; + } + + return(1); + } + + return(0); +} + + +int +help_processor(int cmd, MSGNO_S *msgmap, SCROLL_S *sparms) +{ + int rv = 0; + char message[64]; + struct help_texts *t; + + switch(cmd){ + /*----------- Print all the help ------------*/ + case MC_PRINTALL : + print_all_help(); + break; + + case MC_PRINTMSG : + snprintf(message, sizeof(message), "%s", STYLE_NAME(sparms)); + message[sizeof(message)-1] = '\0'; + if(open_printer(message) == 0){ + print_help(((HELP_SCROLL_S *)sparms->proc.data.p)->help_source); + close_printer(); + } + + break; + + case MC_EXPORT: /* reuse old definition, so as not to patch pine.h */ + {char help_name[40]; + help_name[0] = '\0'; + for(t = h_texts; t->help_text != NO_HELP; t++) + if(t->help_text == ((HELP_SCROLL_S *)sparms->proc.data.p)->help_source){ + strcpy(help_name,t->tag); + break; + } + if(help_name[0]) + q_status_message1(SM_ORDER, 0, 2, + "Internal Name: x-alpine-help:%s", help_name); + else + q_status_message(SM_ORDER|SM_DING, 1, 2, + "Can not find link for text help"); + } + break; + + case MC_FINISH : + rv = 1; + break; + + default : + panic("Unhandled case"); + } + + return(rv); +} + + +void +help_keymenu_tweek(SCROLL_S *sparms, int handle_hidden) +{ + if(handle_hidden){ + sparms->keys.menu->keys[HLP_VIEW_HANDLE].name = ""; + sparms->keys.menu->keys[HLP_VIEW_HANDLE].label = ""; + } + else{ + if(!((HELP_SCROLL_S *)sparms->proc.data.p)->keys_formatted){ + /* If label's always been blank, force reformatting */ + mark_keymenu_dirty(); + sparms->keys.menu->width = 0; + ((HELP_SCROLL_S *)sparms->proc.data.p)->keys_formatted = 1; + } + + sparms->keys.menu->keys[HLP_VIEW_HANDLE].name = "V"; + sparms->keys.menu->keys[HLP_VIEW_HANDLE].label = "[" N_("View Link") "]"; + } +} + + +/* + * print_help - send the raw array of lines to printer + */ +void +print_help(char **text) +{ + char *error, buf[256]; + HPRT_S help_data; + + init_helper_getc(text); + + memset(g_hprt = &help_data, 0, sizeof(HPRT_S)); + + help_data.page = 1; + + gf_filter_init(); + + if(!struncmp(text[0], "<html>", 6)){ + int i; + char *p; + + gf_link_filter(gf_html2plain, + gf_html2plain_opt(NULL,80,non_messageview_margin(), + NULL,NULL,GFHP_STRIPPED)); + for(i = 1; i <= 5 && text[i]; i++) + if(!struncmp(text[i], "<title>", 7) + && (p = srchstr(text[i] + 7, "</title>")) + && p - text[i] > 7){ + help_data.title = text[i] + 7; + help_data.title_len = p - help_data.title; + break; + } + } + else + gf_link_filter(gf_wrap, gf_wrap_filter_opt(80, 80, NULL, 0, GFW_NONE)); + + gf_link_filter(gf_line_test, + gf_line_test_opt(print_help_page_break, NULL)); + gf_link_filter(gf_nvtnl_local, NULL); + + print_help_page_title(buf, sizeof(buf), &help_data); + print_text(buf); + print_text(NEWLINE); /* terminate it */ + print_text(NEWLINE); /* and write two blank links */ + print_text(NEWLINE); + + if((error = gf_pipe(helper_getc, print_char)) != NULL) + q_status_message1(SM_ORDER | SM_DING, 3, 3, _("Printing Error: %s"), error); + + print_char(ctrl('L')); /* new page. */ +} + + +void +print_all_help(void) +{ + struct help_texts *t; + char **h; + int we_turned_on = 0; + + if(open_printer(_("all 150+ pages of help text")) == 0) { + we_turned_on = intr_handling_on(); + for(t = h_texts; (h = t->help_text) != NO_HELP; t++) { + if(ps_global->intr_pending){ + q_status_message(SM_ORDER, 3, 3, + _("Print of all help cancelled")); + break; + } + + print_help(h); + } + + if(we_turned_on) + intr_handling_off(); + + close_printer(); + } +} + + +/* + * print_help_page_title -- + */ +void +print_help_page_title(char *buf, size_t buflen, HPRT_S *hprt) +{ + snprintf(buf, buflen, " Alpine Help%s%.*s%*s%d", + hprt->title_len ? ": " : " Text", + MIN(55, hprt->title_len), hprt->title_len ? hprt->title : "", + 59 - (hprt->title_len ? MIN(55, hprt->title_len) : 5), + "Page ", hprt->page); + buf[buflen-1] = '\0'; +} + + +/* + * print_help_page_break -- insert page breaks and such for printed + * help text + */ +int +print_help_page_break(long int linenum, char *line, LT_INS_S **ins, void *local) +{ + char buf[256]; + + if(((linenum + (g_hprt->page * 3)) % 62) == 0){ + g_hprt->page++; /* start on new page */ + buf[0] = ctrl('L'); + print_help_page_title(buf + 1, sizeof(buf)-1, g_hprt); + strncat(buf, "\015\012\015\012\015\012", sizeof(buf)-strlen(buf)-1); + buf[sizeof(buf)-1] = '\0'; + ins = gf_line_test_new_ins(ins, line, buf, strlen(buf)); + } + + return(0); +} + + +/* + * help_bogus_input - used by scrolltool to complain about + * invalid user input. + */ +int +help_bogus_input(UCS ch) +{ + bogus_command(ch, NULL); + return(0); +} + + +int +url_local_helper(char *url) +{ + if((!struncmp(url, "x-alpine-help:", 14) && *(url += 14)) + || (!struncmp(url, "x-pine-help:", 12) && *(url += 12))){ + char *frag; + HelpType newhelp; + + /* internal fragment reference? */ + if((frag = strchr(url, '#')) != NULL){ + size_t len; + + if((len = frag - url) != 0){ + newhelp = help_name2section(url, len); + } + else{ + url_local_fragment(url); + return(1); + } + } + else + newhelp = help_name2section(url, strlen(url)); + + + if(newhelp != NO_HELP){ + int rv; + + rv = helper_internal(newhelp, frag, _("HELP SUB-SECTION"), + HLPD_NEWWIN | HLPD_SIMPLE | HLPD_FROMHELP); + ps_global->mangled_screen = 1; + return((rv == MC_EXIT) ? 2 : 1); + } + } + + q_status_message1(SM_ORDER | SM_DING, 0, 3, + _("Unrecognized Internal help: \"%s\""), url); + return(0); +} + + +int +url_local_config(char *url) +{ + if(!struncmp(url, "x-alpine-config:", 16)){ + char **config; + int rv; + + config = get_supported_options(); + if(config){ + /* TRANSLATORS: Help for configuration */ + rv = helper_internal(config, NULL, _("HELP CONFIG"), + HLPD_NEWWIN | HLPD_SIMPLE | HLPD_FROMHELP); + free_list_array(&config); + } + + ps_global->mangled_screen = 1; + return((rv == MC_EXIT) ? 2 : 1); + } + + q_status_message1(SM_ORDER | SM_DING, 0, 3, + _("Unrecognized Internal help: \"%s\""), url); + return(0); +} + + +/*---------------------------------------------------------------------- + Review latest status messages + -----*/ +void +review_messages(void) +{ + SCROLL_S sargs; + STORE_S *in_store = NULL, *out_store = NULL; + gf_io_t gc, pc; + int jo, lo, hi, donejo, donelo, donehi; + RMCat rmcat; + int cmd, timestamps=0, show_level=-1; + char debugkeylabel[20]; + /* TRANSLATORS: command label asking pine to include time stamps in output */ + char timestampkeylabel[] = N_("Timestamps"); + /* TRANSLATORS: do not include time stamps in output */ + char *notimestampkeylabel = N_("NoTimestamps"); + + if((rmjofirst < 0 && rmlofirst < 0 && rmhifirst < 0) + || rmjofirst >= RMJLEN || rmjolast >= RMJLEN + || rmlofirst >= RMLLEN || rmlolast >= RMLLEN + || rmhifirst >= RMHLEN || rmhilast >= RMHLEN + || (rmjofirst >= 0 && rmjolast < 0) + || (rmlofirst >= 0 && rmlolast < 0) + || (rmhifirst >= 0 && rmhilast < 0)) + return; + + do{ + + if(!(in_store = so_get(CharStar, NULL, EDIT_ACCESS)) || + !(out_store = so_get(CharStar, NULL, EDIT_ACCESS))){ + if(in_store) + so_give(&in_store); + + q_status_message(SM_ORDER | SM_DING, 3, 4, + _("Failed allocating memory")); + return; + } + + add_review_message(_("Turning off new messages while reviewing"), 0); + rm_not_right_now = 1; + + donejo = donehi = donelo = 0; + jo = rmjofirst; + if(jo < 0) + donejo = 1; + + lo = rmlofirst; + if(lo < 0) + donelo = 1; + + hi = rmhifirst; + if(hi < 0) + donehi = 1; + + while(!(donejo && donelo && donehi)){ + REV_MSG_S *pjo, *plo, *phi, *p; + + if(!donejo) + pjo = &rmjoarray[jo]; + else + pjo = NULL; + + if(!donelo) + plo = &rmloarray[lo]; + else + plo = NULL; + + if(!donehi) + phi = &rmhiarray[hi]; + else + phi = NULL; + + if(pjo && (!plo || pjo->seq <= plo->seq) + && (!phi || pjo->seq <= phi->seq)) + rmcat = Jo; + else if(plo && (!phi || plo->seq <= phi->seq)) + rmcat = Lo; + else if(phi) + rmcat = Hi; + else + rmcat = No; + + switch(rmcat){ + case Jo: + p = pjo; + if(jo == rmjofirst && (((rmjolast + 1) % RMJLEN) == rmjofirst)) + so_puts(in_store, + _("**** Journal entries prior to this point have been trimmed. ****\n")); + break; + + case Lo: + p = plo; + if(show_level >= 0 && + lo == rmlofirst && (((rmlolast + 1) % RMLLEN) == rmlofirst)) + so_puts(in_store, + _("**** Debug 0-4 entries prior to this point have been trimmed. ****\n")); + break; + + case Hi: + p = phi; + if(show_level >= 5 && + hi == rmhifirst && (((rmhilast + 1) % RMHLEN) == rmhifirst)) + so_puts(in_store, + _("**** Debug 5-9 entries prior to this point have been trimmed. ****\n")); + break; + + default: + p = NULL; + break; + } + + if(p){ + if(p->level <= show_level){ + if(timestamps && p->timestamp && p->timestamp[0]){ + so_puts(in_store, p->timestamp); + so_puts(in_store, ": "); + } + + if(p->message && p->message[0]){ + if(p->continuation) + so_puts(in_store, ">"); + + so_puts(in_store, p->message); + so_puts(in_store, "\n"); + } + } + } + + switch(rmcat){ + case Jo: + if(jo == rmjolast) + donejo++; + else + jo = (jo + 1) % RMJLEN; + + break; + + case Lo: + if(lo == rmlolast) + donelo++; + else + lo = (lo + 1) % RMLLEN; + + break; + + case Hi: + if(hi == rmhilast) + donehi++; + else + hi = (hi + 1) % RMHLEN; + + break; + + default: + donejo++; + donelo++; + donehi++; + break; + } + } + + + so_seek(in_store, 0L, 0); + gf_filter_init(); + gf_link_filter(gf_wrap, + gf_wrap_filter_opt(ps_global->ttyo->screen_cols - 4, + ps_global->ttyo->screen_cols, + NULL, show_level < 0 ? 2 : 0, GFW_NONE)); + gf_set_so_readc(&gc, in_store); + gf_set_so_writec(&pc, out_store); + gf_pipe(gc, pc); + gf_clear_so_writec(out_store); + gf_clear_so_readc(in_store); + + memset(&sargs, 0, sizeof(SCROLL_S)); + sargs.text.text = so_text(out_store); + sargs.text.src = CharStar; + sargs.text.desc = _("journal"); + sargs.keys.menu = &rev_msg_keymenu; + sargs.proc.tool = journal_processor; + sargs.start.on = LastPage; + sargs.resize_exit = 1; + sargs.proc.data.p = (void *)&show_level; + setbitmap(sargs.keys.bitmap); + +#ifdef DEBUG +#ifdef DEBUGJOURNAL + sargs.jump_is_debug = 1; + /* TRANSLATORS: these are some screen titles */ + sargs.help.title = _("HELP FOR DEBUG JOURNAL"); + sargs.help.text = h_debugjournal; + sargs.bar.title = _("REVIEW DEBUGGING"); +#else /* !DEBUGJOURNAL */ + clrbitn(DEBUG_KEY, sargs.keys.bitmap); + sargs.help.title = _("HELP FOR JOURNAL"); + sargs.help.text = h_journal; + sargs.bar.title = _("REVIEW RECENT MESSAGES"); +#endif /* !DEBUGJOURNAL */ +#else /* !DEBUG */ + clrbitn(DEBUG_KEY, sargs.keys.bitmap); + clrbitn(TIMESTAMP_KEY, sargs.keys.bitmap); + sargs.help.title = _("HELP FOR JOURNAL"); + sargs.help.text = h_journal; + sargs.bar.title = _("REVIEW RECENT MESSAGES"); +#endif /* !DEBUG */ + + if(timestamps) + rev_msg_keys[TIMESTAMP_KEY].label = notimestampkeylabel; + else + rev_msg_keys[TIMESTAMP_KEY].label = timestampkeylabel; + + if(show_level >= 0) + /* TRANSLATORS: shows what numeric level Debug output is displayed at */ + snprintf(debugkeylabel, sizeof(debugkeylabel), _("Debug (%d)"), show_level); + else + /* TRANSLATORS: include debug output in journal */ + strncpy(debugkeylabel, _("DebugView"), sizeof(debugkeylabel)); + + debugkeylabel[sizeof(debugkeylabel)-1] = '\0'; + + rev_msg_keys[DEBUG_KEY].label = debugkeylabel; + KS_OSDATASET(&rev_msg_keys[DEBUG_KEY], KS_NONE); + + if((cmd = scrolltool(&sargs)) == MC_TOGGLE) + timestamps = !timestamps; + + so_give(&in_store); + so_give(&out_store); + + }while(cmd != MC_EXIT); + + rm_not_right_now = 0; + add_review_message("Done reviewing", 0); +} + + +int +journal_processor(int cmd, MSGNO_S *msgmap, SCROLL_S *sparms) +{ + switch(cmd){ + case MC_TOGGLE: /* turn timestamps on or off */ + break; + + default: + panic("Unexpected command in journal_processor"); + break; + } + + return(1); +} + + +/* + * standard type of storage object used for body parts... + */ +#ifdef DOS +#define PART_SO_TYPE TmpFileStar +#else +#define PART_SO_TYPE CharStar +#endif + + +int +gripe_gripe_to(url) + char *url; +{ + char *composer_title, *url_copy, *optstr, *p; + int opts = 0; + BODY *body = NULL; + ENVELOPE *outgoing = NULL; + REPLY_S fake_reply; + PINEFIELD *pf = NULL; + long msgno = mn_m2raw(ps_global->msgmap, + mn_get_cur(ps_global->msgmap)); + + url_copy = cpystr(url + strlen("x-alpine-gripe:")); + if((optstr = strchr(url_copy, '?')) != NULL) + *optstr++ = '\0'; + + outgoing = mail_newenvelope(); + outgoing->message_id = generate_message_id(); + + if((outgoing->to = gripe_token_addr(url_copy)) != NULL){ + composer_title = _("COMPOSE TO LOCAL SUPPORT"); + dprint((1, + "\n\n -- Send to local support(%s@%s) --\n", + outgoing->to->mailbox ? outgoing->to->mailbox : "NULL", + outgoing->to->host ? outgoing->to->host : "NULL")); + } + else{ /* must be global */ + composer_title = _("REQUEST FOR ASSISTANCE"); + rfc822_parse_adrlist(&outgoing->to, url_copy, ps_global->maildomain); + } + + /* + * Sniff thru options + */ + while(optstr){ + if((p = strchr(optstr, '?')) != NULL) /* tie off list item */ + *p++ = '\0'; + + if(!strucmp(optstr, "config")) + opts |= GRIPE_OPT_CONF; + else if(!strucmp(optstr, "curmsg")) + opts |= GRIPE_OPT_MSG; + else if(!strucmp(optstr, "local")) + opts |= GRIPE_OPT_LOCAL; + else if(!strucmp(optstr, "keys")) + opts |= GRIPE_OPT_KEYS; + + optstr = p; + } + + /* build body and hand off to composer... */ + if(gripe_newbody(ps_global, &body, msgno, opts) == 0){ + pf = (PINEFIELD *) fs_get(sizeof(PINEFIELD)); + memset(pf, 0, sizeof(PINEFIELD)); + pf->name = cpystr("X-Generated-Via"); + pf->type = FreeText; + pf->textbuf = gripe_id("Alpine Bug Report screen"); + memset((void *)&fake_reply, 0, sizeof(fake_reply)); + fake_reply.pseudo = 1; + fake_reply.data.pico_flags = P_HEADEND; + pine_send(outgoing, &body, composer_title, NULL, NULL, + &fake_reply, NULL, NULL, pf, PS_STICKY_TO); + } + + ps_global->mangled_screen = 1; + mail_free_envelope(&outgoing); + + if(body) + pine_free_body(&body); + + fs_give((void **) &url_copy); + + return(10); +} + + +int +gripe_newbody(ps, body, msgno, flags) + struct pine *ps; + BODY **body; + long msgno; + int flags; +{ + BODY *pb; + PART **pp; + STORE_S *store; + gf_io_t pc; + static char *err = "Problem creating space for message text."; + int i; + char tmp[MAILTMPLEN], *p; + + if((store = so_get(PicoText, NULL, EDIT_ACCESS)) != NULL){ + *body = mail_newbody(); + + if((p = detoken(NULL, NULL, 2, 0, 1, NULL, NULL)) != NULL){ + if(*p) + so_puts(store, p); + + fs_give((void **) &p); + } + } + else{ + q_status_message(SM_ORDER | SM_DING, 3, 4, err); + return(-1); + } + + if(flags){ + /*---- Might have multiple parts ----*/ + (*body)->type = TYPEMULTIPART; + /*---- The TEXT part/body ----*/ + (*body)->nested.part = mail_newbody_part(); + (*body)->nested.part->body.type = TYPETEXT; + (*body)->nested.part->body.contents.text.data = (void *) store; + + /*---- create object, and write current config into it ----*/ + pp = &((*body)->nested.part->next); + + if(flags & GRIPE_OPT_CONF){ + *pp = mail_newbody_part(); + pb = &((*pp)->body); + pp = &((*pp)->next); + pb->type = TYPETEXT; + pb->id = generate_message_id(); + pb->description = cpystr("Alpine Configuration Data"); + pb->parameter = mail_newbody_parameter(); + pb->parameter->attribute = cpystr("name"); + pb->parameter->value = cpystr("config.txt"); + + if((store = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){ + extern char datestamp[], hoststamp[]; + + pb->contents.text.data = (void *) store; + gf_set_so_writec(&pc, store); + gf_puts("Alpine built ", pc); + gf_puts(datestamp, pc); + gf_puts(" on host: ", pc); + gf_puts(hoststamp, pc); + gf_puts("\n", pc); + +#ifdef DEBUG + dump_pine_struct(ps, pc); + dump_config(ps, pc, 0); +#endif /* DEBUG */ + + pb->size.bytes = strlen((char *) so_text(store)); + gf_clear_so_writec(store); + } + else{ + q_status_message(SM_ORDER | SM_DING, 3, 4, err); + return(-1); + } + } + + if(flags & GRIPE_OPT_KEYS){ + *pp = mail_newbody_part(); + pb = &((*pp)->body); + pp = &((*pp)->next); + pb->type = TYPETEXT; + pb->id = generate_message_id(); + pb->description = cpystr("Recent User Input"); + pb->parameter = mail_newbody_parameter(); + pb->parameter->attribute = cpystr("name"); + pb->parameter->value = cpystr("uinput.txt"); + + if((store = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){ + pb->contents.text.data = (void *) store; + + so_puts(store, "User's most recent input:\n"); + + /* dump last n keystrokes */ + so_puts(store, "========== Latest keystrokes ==========\n"); + while((i = key_playback(0)) != -1){ + snprintf(tmp, sizeof(tmp), "\t%s\t(0x%x)\n", pretty_command(i), i); + tmp[sizeof(tmp)-1] = '\0'; + so_puts(store, tmp); + } + + pb->size.bytes = strlen((char *) so_text(store)); + } + else{ + q_status_message(SM_ORDER | SM_DING, 3, 4, err); + return(-1); + } + } + + /* check for local debugging info? */ + if((flags & GRIPE_OPT_LOCAL) + && ps_global->VAR_BUGS_EXTRAS + && can_access(ps_global->VAR_BUGS_EXTRAS, EXECUTE_ACCESS) == 0){ + char *error = NULL; + + *pp = mail_newbody_part(); + pb = &((*pp)->body); + pp = &((*pp)->next); + pb->type = TYPETEXT; + pb->id = generate_message_id(); + pb->description = cpystr("Local Configuration Data"); + pb->parameter = mail_newbody_parameter(); + pb->parameter->attribute = cpystr("name"); + pb->parameter->value = cpystr("lconfig.txt"); + + if((store = so_get(CharStar, NULL, EDIT_ACCESS)) != NULL){ + PIPE_S *syspipe; + gf_io_t gc; + + pb->contents.text.data = (void *) store; + gf_set_so_writec(&pc, store); + if((syspipe = open_system_pipe(ps_global->VAR_BUGS_EXTRAS, + NULL, NULL, + PIPE_READ | PIPE_STDERR | PIPE_USER, + 0, pipe_callback, pipe_report_error)) != NULL){ + gf_set_readc(&gc, (void *)syspipe, 0, PipeStar, 0); + gf_filter_init(); + error = gf_pipe(gc, pc); + (void) close_system_pipe(&syspipe, NULL, pipe_callback); + } + else + error = "executing config collector"; + + gf_clear_so_writec(store); + } + + if(error){ + q_status_message1(SM_ORDER | SM_DING, 3, 4, + "Problem %s", error); + return(-1); + } + else /* fixup attachment's size */ + pb->size.bytes = strlen((char *) so_text(store)); + } + + if((flags & GRIPE_OPT_MSG) && mn_get_total(ps->msgmap) > 0L){ + int ch = 0; + + ps->redrawer = att_cur_drawer; + att_cur_drawer(); + + if((ch = one_try_want_to("Attach current message to report", + 'y','x',NO_HELP, + WT_FLUSH_IN|WT_SEQ_SENSITIVE)) == 'y'){ + *pp = mail_newbody_part(); + pb = &((*pp)->body); + pp = &((*pp)->next); + pb->type = TYPEMESSAGE; + pb->id = generate_message_id(); + snprintf(tmp, sizeof(tmp), "Problem Message (%ld of %ld)", + mn_get_cur(ps->msgmap), mn_get_total(ps->msgmap)); + tmp[sizeof(tmp)-1] = '\0'; + pb->description = cpystr(tmp); + + /*---- Package each message in a storage object ----*/ + if((store = so_get(PART_SO_TYPE, NULL, EDIT_ACCESS)) != NULL){ + pb->contents.text.data = (void *) store; + } + else{ + q_status_message(SM_ORDER | SM_DING, 3, 4, err); + return(-1); + } + + /* write the header */ + if((p = mail_fetch_header(ps->mail_stream, msgno, NIL, NIL, + NIL, FT_PEEK)) && *p) + so_puts(store, p); + else + return(-1); + + pb->size.bytes = strlen(p); + so_puts(store, "\015\012"); + + if((p = pine_mail_fetch_text(ps->mail_stream, + msgno, NULL, NULL, NIL)) + && *p) + so_puts(store, p); + else + return(-1); + + pb->size.bytes += strlen(p); + } + else if(ch == 'x'){ + q_status_message(SM_ORDER, 0, 3, "Bug report cancelled."); + return(-1); + } + } + } + else{ + /*---- Only one part! ----*/ + (*body)->type = TYPETEXT; + (*body)->contents.text.data = (void *) store; + } + + return(0); +} + + +ADDRESS * +gripe_token_addr(token) + char *token; +{ + char *p; + ADDRESS *a = NULL; + + if(token && *token++ == '_'){ + if(!strcmp(token, "LOCAL_ADDRESS_")){ + p = (ps_global->VAR_LOCAL_ADDRESS + && ps_global->VAR_LOCAL_ADDRESS[0]) + ? ps_global->VAR_LOCAL_ADDRESS + : "postmaster"; + a = rfc822_parse_mailbox(&p, ps_global->maildomain); + a->personal = cpystr((ps_global->VAR_LOCAL_FULLNAME + && ps_global->VAR_LOCAL_FULLNAME[0]) + ? ps_global->VAR_LOCAL_FULLNAME + : "Place to report Alpine Bugs"); + } + else if(!strcmp(token, "BUGS_ADDRESS_")){ + p = (ps_global->VAR_BUGS_ADDRESS + && ps_global->VAR_BUGS_ADDRESS[0]) + ? ps_global->VAR_BUGS_ADDRESS : "postmaster"; + a = rfc822_parse_mailbox(&p, ps_global->maildomain); + a->personal = cpystr((ps_global->VAR_BUGS_FULLNAME + && ps_global->VAR_BUGS_FULLNAME[0]) + ? ps_global->VAR_BUGS_FULLNAME + : "Place to report Alpine Bugs"); + } + } + + return(a); +} + + +char * +gripe_id(key) + char *key; +{ + int i,j,k,l; + + /* + * Build our contribution to the subject; part constant string + * and random 4 character alpha numeric string. + */ + i = (int)(random() % 36L); + j = (int)(random() % 36L); + k = (int)(random() % 36L); + l = (int)(random() % 36L); + tmp_20k_buf[0] = '\0'; + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s (ID %c%c%d%c%c)", key, + (i < 10) ? '0' + i : 'A' + (i - 10), + (j < 10) ? '0' + j : 'A' + (j - 10), + (int)(random() % 10L), + (k < 10) ? '0' + k : 'A' + (k - 10), + (l < 10) ? '0' + l : 'A' + (l - 10)); + tmp_20k_buf[SIZEOF_20KBUF-1] = '\0'; + return(cpystr(tmp_20k_buf)); +} + + +/* + * Used by gripe_tool. + */ +void +att_cur_drawer(void) +{ + int i, dline, j; + char buf[256+1]; + + /* blat helpful message to screen */ + ClearBody(); + j = 0; + for(dline = 2; + dline < ps_global->ttyo->screen_rows - FOOTER_ROWS(ps_global); + dline++){ + for(i = 0; i < 256 && att_cur_msg[j] && att_cur_msg[j] != '\n'; i++) + buf[i] = att_cur_msg[j++]; + + buf[i] = '\0'; + if(att_cur_msg[j]) + j++; + else if(!i) + break; + + PutLine0(dline, 1, buf); + } +} + + +#ifdef _WINDOWS + +/* + * + */ +char * +pcpine_help(HelpType section) +{ + char **help_lines, *help_text = NULL; + STORE_S *store; + gf_io_t pc; + + /* assumption here is that HelpType is char ** */ + help_lines = section; + if (help_lines != NULL){ + init_helper_getc(help_lines); + if(store = so_get(CharStar, NULL, EDIT_ACCESS)){ + gf_set_so_writec(&pc, store); + gf_filter_init(); + + gf_link_filter(gf_local_nvtnl, NULL); + + gf_link_filter(gf_html2plain, + gf_html2plain_opt(NULL, + ps_global->ttyo->screen_cols, + non_messageview_margin(), NULL, NULL, GFHP_STRIPPED)); + + if(!gf_pipe(helper_getc, pc)){ + help_text = (char *) store->txt; + store->txt = (void *) NULL; + } + + gf_clear_so_writec(store); + so_give(&store); + } + } + + return(help_text); +} + + +/* + * + */ +int +help_popup(SCROLL_S *sparms, int in_handle) +{ + MPopup hp_menu[10]; + int i = -1; + + if(in_handle){ + hp_menu[++i].type = tQueue; + hp_menu[i].label.style = lNormal; + hp_menu[i].label.string = "View Help Section"; + hp_menu[i].data.val = 'V'; + } + + hp_menu[++i].type = tQueue; + hp_menu[i].label.style = lNormal; + hp_menu[i].label.string = "Exit Help"; + hp_menu[i].data.val = 'E'; + + hp_menu[++i].type = tTail; + + mswin_popup(hp_menu); + + return(0); +} + + +/* + * + */ +int +help_subsection_popup(SCROLL_S *sparms, int in_handle) +{ + MPopup hp_menu[10]; + int i = -1; + + if(in_handle){ + hp_menu[++i].type = tQueue; + hp_menu[i].label.style = lNormal; + hp_menu[i].label.string = "View Help Section"; + hp_menu[i].data.val = 'V'; + } + + hp_menu[++i].type = tQueue; + hp_menu[i].label.style = lNormal; + hp_menu[i].label.string = "Previous Help Section"; + hp_menu[i].data.val = 'P'; + + hp_menu[++i].type = tQueue; + hp_menu[i].label.style = lNormal; + hp_menu[i].label.string = "Exit Help"; + hp_menu[i].data.val = 'E'; + + hp_menu[++i].type = tTail; + + if(mswin_popup(hp_menu) == (in_handle ? 1 : 0)) + /*(void) helper_internal()*/; + + return(0); +} + +#endif /* _WINDOWS */ |