/*---------------------------------------------------------------------- Close printer If we're piping to a spooler close down the pipe and wait for the process to finish. If we're sending to an attached printer send the escape sequence. Also let the user know the result of the print ----*/ void close_printer(void) { #ifndef _WINDOWS if(trailer){ if(*trailer) fputs(trailer, ps_global->print->fp); fs_give((void **)&trailer); } if(ps_global->print->fp == stdout) { if(ansi_off) fputs("\033[4i", stdout); else printf("%c", 20); /* aux off for wyse60 */ fflush(stdout); if(F_OFF(F_PRESERVE_START_STOP, ps_global)) xonxoff_proc(0); /* turn off XON/XOFF */ crlf_proc(0); /* turn off CF->LF xlantion */ } else { (void) close_system_pipe(&ps_global->print->pipe, NULL, pipe_callback); display_output_file(ps_global->print->result, "PRINT", NULL, 1); if(ps_global->print && ps_global->print->result) fs_give((void **) &ps_global->print->result); } #else /* _WINDOWS */ mswin_print_done(); #endif /* _WINDOWS */ if(ps_global->print) fs_give((void **) &ps_global->print); q_status_message(SM_ASYNC, 0, 3, "Print command completed"); display_message('x'); }
int optionally_enter(char *utf8string, int y_base, int x_base, int utf8string_size, char *utf8prompt, ESCKEY_S *escape_list, HelpType help, int *flags) { UCS *string = NULL, ucs; size_t string_size; UCS *s2; UCS *saved_original = NULL; char *candidate; UCS *kill_buffer = NULL; UCS *k, *kb; int field_pos; /* offset into array dline.vl */ int i, j, return_v, cols, prompt_width, too_thin, real_y_base, km_popped, passwd; char **help_text; long fkey_table[12]; struct key_menu *km; bitmap_t bitmap; COLOR_PAIR *lastc = NULL, *promptc = NULL; struct variable *vars = ps_global->vars; struct display_line dline; #ifdef _WINDOWS int cursor_shown; #endif dprint((5, "=== optionally_enter called ===\n")); dprint((9, "utf8string:\"%s\" y:%d x:%d length: %d append: %d\n", utf8string ? utf8string : "", x_base, y_base, utf8string_size, (flags && *flags & OE_APPEND_CURRENT))); dprint((9, "passwd:%d utf8prompt:\"%s\" label:\"%s\"\n", (flags && *flags & OE_PASSWD_NOAST) ? 10 : (flags && *flags & OE_PASSWD) ? 1 : 0, utf8prompt ? utf8prompt : "", (escape_list && escape_list[0].ch != -1 && escape_list[0].label) ? escape_list[0].label: "")); if(!ps_global->ttyo) return(pre_screen_config_opt_enter(utf8string, utf8string_size, utf8prompt, escape_list, help, flags)); #ifdef _WINDOWS if (mswin_usedialog ()) return(win_dialog_opt_enter(utf8string, utf8string_size, utf8prompt, escape_list, help, flags)); #endif /* * Utf8string comes in as UTF-8. We'll convert it to a UCS-4 array and operate on * that array, then convert it back before returning. Utf8string_size is the size * of the utf8string array but that doesn't help us much for the array we need to * operate on here. We'll just allocate a big array and then cut it off when * sending it back. * * This should come before the specialized calls above but those aren't * converted to use UCS-4 yet. */ string = utf8_to_ucs4_cpystr(utf8string); dline.vused = ucs4_strlen(string); string_size = (2 * MAX(utf8string_size,dline.vused) + 100); fs_resize((void **) &string, string_size * sizeof(UCS)); suspend_busy_cue(); cols = ps_global->ttyo->screen_cols; prompt_width = utf8_width(utf8prompt); too_thin = 0; km_popped = 0; if(y_base > 0) real_y_base = y_base; else{ real_y_base = y_base + ps_global->ttyo->screen_rows; real_y_base = MAX(real_y_base, 0); } flush_ordered_messages(); mark_status_dirty(); if(flags && *flags & OE_APPEND_CURRENT) /* save a copy in case of cancel */ saved_original = ucs4_cpystr(string); /* * build the function key mapping table, skipping predefined keys... */ memset(fkey_table, NO_OP_COMMAND, 12 * sizeof(long)); for(i = 0, j = 0; escape_list && escape_list[i].ch != -1 && i+j < 12; i++){ if(i+j == OE_HELP_KEY) j++; if(i+j == OE_CANCEL_KEY) j++; if(i+j == OE_ENTER_KEY) j++; fkey_table[i+j] = escape_list[i].ch; } /* assumption that HelpType is char ** */ help_text = help; if(help_text){ /*---- Show help text -----*/ int width = ps_global->ttyo->screen_cols - x_base; if(FOOTER_ROWS(ps_global) == 1){ km_popped++; FOOTER_ROWS(ps_global) = 3; clearfooter(ps_global); y_base = -3; real_y_base = y_base + ps_global->ttyo->screen_rows; } for(j = 0; j < 2 && help_text[j]; j++){ MoveCursor(real_y_base + 1 + j, x_base); CleartoEOLN(); if(width < utf8_width(help_text[j])){ char *tmp = cpystr(help_text[j]); (void) utf8_truncate(tmp, width); PutLine0(real_y_base + 1 + j, x_base, tmp); fs_give((void **) &tmp); } else PutLine0(real_y_base + 1 + j, x_base, help_text[j]); } } else{ clrbitmap(bitmap); clrbitmap((km = &oe_keymenu)->bitmap); /* force formatting */ if(!(flags && (*flags) & OE_DISALLOW_HELP)) setbitn(OE_HELP_KEY, bitmap); setbitn(OE_ENTER_KEY, bitmap); if(!(flags && (*flags) & OE_DISALLOW_CANCEL)) setbitn(OE_CANCEL_KEY, bitmap); setbitn(OE_CTRL_T_KEY, bitmap); /*---- Show the usual possible keys ----*/ for(i=0,j=0; escape_list && escape_list[i].ch != -1 && i+j < 12; i++){ if(i+j == OE_HELP_KEY) j++; if(i+j == OE_CANCEL_KEY) j++; if(i+j == OE_ENTER_KEY) j++; oe_keymenu.keys[i+j].label = escape_list[i].label; oe_keymenu.keys[i+j].name = escape_list[i].name; setbitn(i+j, bitmap); } for(i = i+j; i < 12; i++) if(!(i == OE_HELP_KEY || i == OE_ENTER_KEY || i == OE_CANCEL_KEY)) oe_keymenu.keys[i].name = NULL; draw_keymenu(km, bitmap, cols, 1-FOOTER_ROWS(ps_global), 0, FirstMenu); } if(pico_usingcolor() && VAR_PROMPT_FORE_COLOR && VAR_PROMPT_BACK_COLOR && pico_is_good_color(VAR_PROMPT_FORE_COLOR) && pico_is_good_color(VAR_PROMPT_BACK_COLOR)){ lastc = pico_get_cur_color(); if(lastc){ promptc = new_color_pair(VAR_PROMPT_FORE_COLOR, VAR_PROMPT_BACK_COLOR); (void)pico_set_colorp(promptc, PSC_NONE); } } else StartInverse(); /* * if display length isn't wide enough to support input, * shorten up the prompt... */ if((dline.dwid = cols - (x_base + prompt_width)) < MIN_OPT_ENT_WIDTH){ char *p; unsigned got_width; /* * Scoot prompt pointer forward at least (MIN_OPT_ENT_WIDTH - dline.dwid) screencells. */ p = utf8_count_forw_width(utf8prompt, MIN_OPT_ENT_WIDTH-dline.dwid, &got_width); if(got_width < MIN_OPT_ENT_WIDTH-dline.dwid) p = utf8_count_forw_width(utf8prompt, MIN_OPT_ENT_WIDTH+1-dline.dwid, &got_width); if(p){ prompt_width = utf8_width(p); dline.dwid = cols - (x_base + prompt_width); utf8prompt = p; } } /* * How many UCS-4 characters will we need to make up the width dwid? It could be * unlimited because of zero-width characters, I suppose, but realistically it * isn't going to be much more than dwid. */ dline.dlen = 2 * dline.dwid + 100; dline.dl = (UCS *) fs_get(dline.dlen * sizeof(UCS)); dline.olddl = (UCS *) fs_get(dline.dlen * sizeof(UCS)); memset(dline.dl, 0, dline.dlen * sizeof(UCS)); memset(dline.olddl, 0, dline.dlen * sizeof(UCS)); dline.movecursor = MoveCursor; dline.writechar = Writewchar; dline.row = real_y_base; dline.col = x_base + prompt_width; dline.vl = string; dline.vlen = --string_size; /* -1 for terminating zero */ dline.vbase = field_pos = 0; #ifdef _WINDOWS cursor_shown = mswin_showcaret(1); #endif PutLine0(real_y_base, x_base, utf8prompt); /* * If appending, position field_pos at end of input. */ if(flags && *flags & OE_APPEND_CURRENT) while(string[field_pos]) field_pos++; passwd = (flags && *flags & OE_PASSWD_NOAST) ? 10 : (flags && *flags & OE_PASSWD) ? 1 : 0; line_paint(field_pos, &dline, &passwd); /*---------------------------------------------------------------------- The main loop loops until someone sets the return_v. ----------------------------------------------------------------------*/ return_v = -10; while(return_v == -10) { #ifdef MOUSE mouse_in_content(KEY_MOUSE, -1, -1, 0x5, 0); register_mfunc(mouse_in_content, real_y_base, x_base + prompt_width, real_y_base, ps_global->ttyo->screen_cols); #endif #ifdef _WINDOWS mswin_allowpaste(MSWIN_PASTE_LINE); g_mc_row = real_y_base; g_mc_col = x_base + prompt_width; mswin_mousetrackcallback(pcpine_oe_cursor); #endif /* Timeout 10 min to keep imap mail stream alive */ ps_global->conceal_sensitive_debugging = passwd ? 1 : 0; ucs = read_char(600); ps_global->conceal_sensitive_debugging = 0; #ifdef MOUSE clear_mfunc(mouse_in_content); #endif #ifdef _WINDOWS mswin_allowpaste(MSWIN_PASTE_DISABLE); mswin_mousetrackcallback(NULL); #endif /* * Don't want to intercept all characters if typing in passwd. * We select an ad hoc set that we will catch and let the rest * through. We would have caught the set below in the big switch * but we skip the switch instead. Still catch things like ^K, * DELETE, ^C, RETURN. */ if(passwd) switch(ucs){ case ctrl('F'): case KEY_RIGHT: case ctrl('B'): case KEY_LEFT: case ctrl('U'): case ctrl('A'): case KEY_HOME: case ctrl('E'): case KEY_END: case TAB: goto ok_for_passwd; } if(too_thin && ucs != KEY_RESIZE && ucs != ctrl('Z') && ucs != ctrl('C')) goto bleep; switch(ucs){ /*--------------- KEY RIGHT ---------------*/ case ctrl('F'): case KEY_RIGHT: if(field_pos >= string_size || string[field_pos] == '\0') goto bleep; line_paint(++field_pos, &dline, &passwd); break; /*--------------- KEY LEFT ---------------*/ case ctrl('B'): case KEY_LEFT: if(field_pos <= 0) goto bleep; line_paint(--field_pos, &dline, &passwd); break; /*-------------------- WORD SKIP --------------------*/ case ctrl('@'): /* * Note: read_char *can* return NO_OP_COMMAND which is * the def'd with the same value as ^@ (NULL), BUT since * read_char has a big timeout (>25 secs) it won't. */ /* skip thru current word */ while(string[field_pos] && isalnum((unsigned char) string[field_pos])) field_pos++; /* skip thru current white space to next word */ while(string[field_pos] && !isalnum((unsigned char) string[field_pos])) field_pos++; line_paint(field_pos, &dline, &passwd); break; /*-------------------- RETURN --------------------*/ case PF4: if(F_OFF(F_USE_FK,ps_global)) goto bleep; case ctrl('J'): case ctrl('M'): return_v = 0; break; /*-------------------- Destructive backspace --------------------*/ case '\177': /* DEL */ case ctrl('H'): /* Try and do this with by telling the terminal to delete a a character. If that fails, then repaint the rest of the line, acheiving the same much less efficiently */ if(field_pos <= 0) goto bleep; field_pos--; /* drop thru to pull line back ... */ /*-------------------- Delete char --------------------*/ case ctrl('D'): case KEY_DEL: if(field_pos >= string_size || !string[field_pos]) goto bleep; dline.vused--; for(s2 = &string[field_pos]; *s2 != 0; s2++) *s2 = s2[1]; *s2 = 0; /* Copy last NULL */ line_paint(field_pos, &dline, &passwd); if(flags) /* record change if requested */ *flags |= OE_USER_MODIFIED; break; /*--------------- Kill line -----------------*/ case ctrl('K'): if(kill_buffer != NULL) fs_give((void **) &kill_buffer); if(field_pos != 0 || string[0]){ if(!passwd && F_ON(F_DEL_FROM_DOT, ps_global)) dline.vused -= ucs4_strlen(&string[i = field_pos]); else dline.vused = i = 0; kill_buffer = ucs4_cpystr(&string[field_pos = i]); string[field_pos] = '\0'; line_paint(field_pos, &dline, &passwd); if(flags) /* record change if requested */ *flags |= OE_USER_MODIFIED; } break; /*------------------- Undelete line --------------------*/ case ctrl('U'): if(kill_buffer == NULL) goto bleep; /* Make string so it will fit */ kb = ucs4_cpystr(kill_buffer); if(ucs4_strlen(kb) + ucs4_strlen(string) > string_size) kb[string_size - ucs4_strlen(string)] = '\0'; if(string[field_pos] == '\0') { /*--- adding to the end of the string ----*/ for(k = kb; *k; k++) string[field_pos++] = *k; string[field_pos] = '\0'; } else{ int shift; shift = ucs4_strlen(kb); /* shift field_pos ... end to right */ for(k = &string[field_pos] + ucs4_strlen(&string[field_pos]); k >= &string[field_pos]; k--) *(k+shift) = *k; for(k = kb; *k; k++) string[field_pos++] = *k; } if(*kb && flags) /* record change if requested */ *flags |= OE_USER_MODIFIED; dline.vused = ucs4_strlen(string); fs_give((void **) &kb); line_paint(field_pos, &dline, &passwd); break; /*-------------------- Interrupt --------------------*/ case ctrl('C'): /* ^C */ if(F_ON(F_USE_FK,ps_global) || (flags && ((*flags) & OE_DISALLOW_CANCEL))) goto bleep; goto cancel; case PF2: if(F_OFF(F_USE_FK,ps_global) || (flags && ((*flags) & OE_DISALLOW_CANCEL))) goto bleep; cancel: return_v = 1; if(saved_original){ for(i = 0; saved_original[i]; i++) string[i] = saved_original[i]; string[i] = 0; } break; case ctrl('A'): case KEY_HOME: /*-------------------- Start of line -------------*/ line_paint(field_pos = 0, &dline, &passwd); break; case ctrl('E'): case KEY_END: /*-------------------- End of line ---------------*/ line_paint(field_pos = dline.vused, &dline, &passwd); break; /*-------------------- Help --------------------*/ case ctrl('G') : case PF1: if(flags && ((*flags) & OE_DISALLOW_HELP)) goto bleep; else if(FOOTER_ROWS(ps_global) == 1 && km_popped == 0){ km_popped++; FOOTER_ROWS(ps_global) = 3; clearfooter(ps_global); if(lastc) (void)pico_set_colorp(lastc, PSC_NONE); else EndInverse(); draw_keymenu(km, bitmap, cols, 1-FOOTER_ROWS(ps_global), 0, FirstMenu); if(promptc) (void)pico_set_colorp(promptc, PSC_NONE); else StartInverse(); mark_keymenu_dirty(); y_base = -3; dline.row = real_y_base = y_base + ps_global->ttyo->screen_rows; PutLine0(real_y_base, x_base, utf8prompt); memset(dline.dl, 0, dline.dlen * sizeof(UCS)); memset(dline.olddl, 0, dline.dlen * sizeof(UCS)); line_paint(field_pos, &dline, &passwd); break; } if(FOOTER_ROWS(ps_global) > 1){ mark_keymenu_dirty(); return_v = 3; } else goto bleep; break; #ifdef MOUSE /* Mouse support untested in pine 5.00 */ case KEY_MOUSE : { MOUSEPRESS mp; int w; mouse_get_last (NULL, &mp); switch(mp.button){ case M_BUTTON_LEFT : /* position cursor */ mp.col -= dline.col; /* * We have to figure out which character is under the cursor. * This is complicated by the fact that characters may * be other than one cell wide. */ /* the -1 is for the '<' when text is offscreen left */ w = (dline.vbase > 0) ? mp.col-1 : mp.col; if(mp.col <= 0) field_pos = dline.vbase - 1; else{ if(dline.vused <= dline.vbase || ucs4_str_width_a_to_b(dline.vl,dline.vbase,dline.vused-1) <= w) field_pos = dline.vused; else{ /* * Find index of 1st character that causes the * width to be > w. */ for(i = 0; ucs4_str_width_a_to_b(dline.vl,dline.vbase,dline.vbase+i) <= w; i++) ; field_pos = dline.vbase + i; } } field_pos = MIN(MAX(field_pos, 0), dline.vused); /* just allow line_paint to choose vbase */ line_paint(field_pos, &dline, &passwd); break; case M_BUTTON_RIGHT : #ifdef _WINDOWS /* * Same as M_BUTTON_LEFT except we paste in text after * moving the cursor. */ mp.col -= dline.col; /* the -1 is for the '<' when text is offscreen left */ w = (dline.vbase > 0) ? mp.col-1 : mp.col; if(mp.col <= 0) field_pos = dline.vbase - 1; else{ if(dline.vused <= dline.vbase || ucs4_str_width_a_to_b(dline.vl,dline.vbase,dline.vused-1) <= w) field_pos = dline.vused; else{ /* * Find index of 1st character that causes the * width to be > w. */ for(i = 0; ucs4_str_width_a_to_b(dline.vl,dline.vbase,dline.vbase+i) <= w; i++) ; field_pos = dline.vbase + i; } } field_pos = MIN(MAX(field_pos, 0), dline.vused); line_paint(field_pos, &dline, &passwd); mswin_allowpaste(MSWIN_PASTE_LINE); mswin_paste_popup(); mswin_allowpaste(MSWIN_PASTE_DISABLE); break; #endif case M_BUTTON_MIDDLE : /* NO-OP for now */ default: /* just ignore */ break; } } break; #endif case NO_OP_IDLE: /* * Keep mail stream alive by checking for new mail. * If we're asking for a password in a login prompt * we don't want to check for new_mail because the * new mail check might be what got us here in the first * place (because of a filter trying to save a message). * If we need to wait for the user to come back then * the caller will just have to deal with the failure * to login. */ i = -1; if(!ps_global->no_newmail_check_from_optionally_enter) i = new_mail(0, 2, NM_DEFER_SORT); if(sp_expunge_count(ps_global->mail_stream) && flags && ((*flags) & OE_SEQ_SENSITIVE)) goto cancel; if(i < 0){ line_paint(field_pos, &dline, &passwd); break; /* no changes, get on with life */ } /* Else fall into redraw */ /*-------------------- Redraw --------------------*/ case ctrl('L'): /*---------------- re size ----------------*/ case KEY_RESIZE: dline.row = real_y_base = y_base > 0 ? y_base : y_base + ps_global->ttyo->screen_rows; if(lastc) (void)pico_set_colorp(lastc, PSC_NONE); else EndInverse(); ClearScreen(); redraw_titlebar(); if(ps_global->redrawer != (void (*)(void))NULL) (*ps_global->redrawer)(); redraw_keymenu(); if(promptc) (void)pico_set_colorp(promptc, PSC_NONE); else StartInverse(); PutLine0(real_y_base, x_base, utf8prompt); cols = ps_global->ttyo->screen_cols; too_thin = 0; if(cols < x_base + prompt_width + 4){ Writechar(BELL, 0); PutLine0(real_y_base, 0, "Screen's too thin. Ouch!"); too_thin = 1; } else{ dline.col = x_base + prompt_width; dline.dwid = cols - (x_base + prompt_width); dline.dlen = 2 * dline.dwid + 100; fs_resize((void **) &dline.dl, (size_t) dline.dlen * sizeof(UCS)); fs_resize((void **) &dline.olddl, (size_t) dline.dlen * sizeof(UCS)); memset(dline.dl, 0, dline.dlen * sizeof(UCS)); memset(dline.olddl, 0, dline.dlen * sizeof(UCS)); line_paint(field_pos, &dline, &passwd); } fflush(stdout); dprint((9, "optionally_enter RESIZE new_cols:%d too_thin: %d\n", cols, too_thin)); break; case PF3 : /* input to potentially remap */ case PF5 : case PF6 : case PF7 : case PF8 : case PF9 : case PF10 : case PF11 : case PF12 : if(F_ON(F_USE_FK,ps_global) && fkey_table[ucs - PF1] != NO_OP_COMMAND) ucs = fkey_table[ucs - PF1]; /* remap function key input */ default: if(escape_list){ /* in the escape key list? */ for(j=0; escape_list[j].ch != -1; j++){ if(escape_list[j].ch == ucs){ return_v = escape_list[j].rval; break; } } if(return_v != -10) break; } if(ucs < 0x80 && FILTER_THIS((unsigned char) ucs)){ bleep: putc(BELL, stdout); continue; } ok_for_passwd: /*--- Insert a character -----*/ if(dline.vused >= string_size) goto bleep; /*---- extending the length of the string ---*/ for(s2 = &string[++dline.vused]; s2 - string > field_pos; s2--) *s2 = *(s2-1); string[field_pos++] = ucs; line_paint(field_pos, &dline, &passwd); if(flags) /* record change if requested */ *flags |= OE_USER_MODIFIED; } /*---- End of switch on char ----*/ } #ifdef _WINDOWS if(!cursor_shown) mswin_showcaret(0); #endif if(dline.dl) fs_give((void **) &dline.dl); if(dline.olddl) fs_give((void **) &dline.olddl); if(saved_original) fs_give((void **) &saved_original); if(kill_buffer) fs_give((void **) &kill_buffer); /* * Change string back into UTF-8. */ candidate = ucs4_to_utf8_cpystr(string); if(string) fs_give((void **) &string); if(candidate){ strncpy(utf8string, candidate, utf8string_size); utf8string[utf8string_size-1] = '\0'; fs_give((void **) &candidate); } if (!(flags && (*flags) & OE_KEEP_TRAILING_SPACE)) removing_trailing_white_space(utf8string); if(lastc){ (void)pico_set_colorp(lastc, PSC_NONE); free_color_pair(&lastc); if(promptc) free_color_pair(&promptc); } else EndInverse(); MoveCursor(real_y_base, x_base); /* Move the cursor to show we're done */ fflush(stdout); resume_busy_cue(0); if(km_popped){ FOOTER_ROWS(ps_global) = 1; clearfooter(ps_global); ps_global->mangled_body = 1; } return(return_v); }
ESCKEY_S * construct_combined_esclist(ESCKEY_S *list1, ESCKEY_S *list2) { ESCKEY_S *list; int i, j=0, count; count = 2; /* for blank key and for OTHER key */ for(i=0; list1 && list1[i].ch != -1; i++) count++; for(i=0; list2 && list2[i].ch != -1; i++) count++; list = (ESCKEY_S *) fs_get((count + 1) * sizeof(*list)); memset(list, 0, (count + 1) * sizeof(*list)); list[j].ch = -2; /* leave blank */ list[j].rval = 0; list[j].name = NULL; list[j++].label = NULL; list[j].ch = 'o'; list[j].rval = OTHER_RETURN_VAL; list[j].name = "O"; list[j].label = N_("OTHER CMDS"); /* * Make sure that O for OTHER CMD or the return val for OTHER CMD * isn't used for something else. */ for(i=0; list1 && list1[i].ch != -1; i++){ if(list1[i].rval == list[j].rval) alpine_panic("1bad rval in d_r"); if(F_OFF(F_USE_FK,ps_global) && list1[i].ch == list[j].ch) alpine_panic("1bad ch in ccl"); } for(i=0; list2 && list2[i].ch != -1; i++){ if(list2[i].rval == list[j].rval) alpine_panic("2bad rval in d_r"); if(F_OFF(F_USE_FK,ps_global) && list2[i].ch == list[j].ch) alpine_panic("2bad ch in ccl"); } j++; /* the visible set */ for(i=0; list1 && list1[i].ch != -1; i++){ if(i >= KEYS_PER_LIST && list1[i].label[0] != '\0') alpine_panic("too many visible keys in ccl"); list[j++] = list1[i]; } /* the rest are invisible */ for(i=0; list2 && list2[i].ch != -1; i++){ list[j] = list2[i]; list[j].label = ""; list[j++].name = ""; } list[j].ch = -1; return(list); }
/*---------------------------------------------------------------------- Handle fetching and filtering a text message segment to be displayed by scrolltool or printed or exported or piped. Args: att -- segment to fetch msgno -- message number segment is a part of pc -- function to write characters from segment with style -- Indicates special handling for error messages flags -- Indicates special necessary handling Returns: 1 if errors encountered, 0 if everything went A-OK ----*/ int decode_text(ATTACH_S *att, long int msgno, gf_io_t pc, HANDLE_S **handlesp, DetachErrStyle style, int flags) { FILTLIST_S filters[14]; char *err, *charset; int filtcnt = 0, error_found = 0, column, wrapit; int is_in_sig = OUT_SIG_BLOCK; int is_flowed_msg = 0, add_me = 1, doraw = RAWSTRING; int is_delsp_yes = 0; int filt_only_c0 = 0; char *parmval; char *free_this = NULL; STORE_S *warn_so = NULL; DELQ_S dq; URL_HILITE_S uh; column = (flags & FM_DISPLAY) ? ps_global->ttyo->screen_cols : 80; if(!(flags & FM_DISPLAY)) flags |= FM_NOINDENT; wrapit = column; memset(filters, 0, sizeof(filters)); /* charset the body part is in */ charset = parameter_val(att->body->parameter, "charset"); /* determined if it's flowed, affects wrapping and quote coloring */ if(att->body->type == TYPETEXT && !strucmp(att->body->subtype, "plain") && (parmval = parameter_val(att->body->parameter, "format"))){ if(!strucmp(parmval, "flowed")) is_flowed_msg = 1; fs_give((void **) &parmval); if(is_flowed_msg){ if((parmval = parameter_val(att->body->parameter, "delsp")) != NULL){ if(!strucmp(parmval, "yes")) is_delsp_yes = 1; fs_give((void **) &parmval); } } } if(!ps_global->pass_ctrl_chars){ filters[filtcnt++].filter = gf_escape_filter; filters[filtcnt].filter = gf_control_filter; filt_only_c0 = 1; filters[filtcnt++].data = gf_control_filter_opt(&filt_only_c0); } if(flags & FM_DISPLAY) filters[filtcnt++].filter = gf_tag_filter; /* * if it's just plain old text, look for url's */ if(!(att->body->subtype && strucmp(att->body->subtype, "plain"))){ struct variable *vars = ps_global->vars; if((F_ON(F_VIEW_SEL_URL, ps_global) || F_ON(F_VIEW_SEL_URL_HOST, ps_global) || F_ON(F_SCAN_ADDR, ps_global)) && handlesp){ /* * The url_hilite filter really ought to come * after flowing, because flowing with the DelSp=yes parameter * can reassemble broken urls back into identifiable urls. * We add the preflow filter to do only the reassembly part * of the flowing so that we can spot the urls. * At this time (2005-03-29) we know that Apple Mail does * send mail like this sometimes. This filter removes the * sequence SP CRLF if that seems safe. */ if(ps_global->full_header != 2 && is_delsp_yes) filters[filtcnt++].filter = gf_preflow; filters[filtcnt].filter = gf_line_test; filters[filtcnt++].data = gf_line_test_opt(url_hilite, gf_url_hilite_opt(&uh,handlesp,0)); } if((flags & FM_DISPLAY) && !(flags & FM_NOCOLOR) && pico_usingcolor() && VAR_SPECIAL_TEXT_FORE_COLOR && VAR_SPECIAL_TEXT_BACK_COLOR){ filters[filtcnt].filter = gf_line_test; filters[filtcnt++].data = gf_line_test_opt(color_this_text, NULL); } /* * First, paint the signature. * Disclaimers noted below for coloring quotes apply here as well. */ if((flags & FM_DISPLAY) && !(flags & FM_NOCOLOR) && pico_usingcolor() && VAR_SIGNATURE_FORE_COLOR && VAR_SIGNATURE_BACK_COLOR){ filters[filtcnt].filter = gf_quote_test; filters[filtcnt++].data = gf_line_test_opt(color_signature, &is_in_sig); } /* * Gotta be careful with this. The color_a_quote filter adds color * to the beginning and end of the line. This will break some * line_test-style filters which come after it. For example, if they * are looking for something at the start of a line (like color_a_quote * itself). I guess we could fix that by ignoring tags at the * beginning of the line when doing the search. */ if((flags & FM_DISPLAY) && !(flags & FM_NOCOLOR) && pico_usingcolor() && VAR_QUOTE1_FORE_COLOR && VAR_QUOTE1_BACK_COLOR){ add_me = 0; filters[filtcnt].filter = gf_quote_test; filters[filtcnt++].data = gf_line_test_opt(color_a_quote, &is_flowed_msg); } } else if(!strucmp(att->body->subtype, "richtext")){ int plain_opt; plain_opt = !(flags&FM_DISPLAY); /* maybe strip everything! */ filters[filtcnt].filter = gf_rich2plain; filters[filtcnt++].data = gf_rich2plain_opt(&plain_opt); /* width to use for file or printer */ if(wrapit - 5 > 0) wrapit -= 5; } else if(!strucmp(att->body->subtype, "enriched")){ int plain_opt; plain_opt = !(flags&FM_DISPLAY); filters[filtcnt].filter = gf_enriched2plain; filters[filtcnt++].data = gf_enriched2plain_opt(&plain_opt); /* width to use for file or printer */ if(wrapit - 5 > 0) wrapit -= 5; } else if(!strucmp(att->body->subtype, "html") && ps_global->full_header < 2){ /*BUG: sniff the params for "version=2.0" ala draft-ietf-html-spec-01 */ int opts = 0; clear_html_risk(); if(flags & FM_DISPLAY){ gf_io_t warn_pc; if(handlesp){ /* pass on handles awareness */ opts |= GFHP_HANDLES; if(F_OFF(F_QUELL_HOST_AFTER_URL, ps_global) && !(flags & FM_HIDESERVER)) opts |= GFHP_SHOW_SERVER; } if(!(flags & FM_NOEDITORIAL)){ warn_so = so_get(CharStar, NULL, EDIT_ACCESS); gf_set_so_writec(&warn_pc, warn_so); format_editorial(HTML_WARNING, column, flags, handlesp, warn_pc); gf_clear_so_writec(warn_so); so_puts(warn_so, "\015\012"); so_writec('\0', warn_so); } } else opts |= GFHP_STRIPPED; /* don't embed anything! */ if(flags & FM_NOHTMLREL) opts |= GFHP_NO_RELATIVE; if(flags & FM_HTMLRELATED) opts |= GFHP_RELATED_CONTENT; if(flags & FM_HTML) opts |= GFHP_HTML; if(flags & FM_HTMLIMAGES) opts |= GFHP_HTML_IMAGES; wrapit = 0; /* wrap already handled! */ filters[filtcnt].filter = gf_html2plain; filters[filtcnt++].data = gf_html2plain_opt(NULL, column, (flags & (FM_NOINDENT | FM_HTML)) ? 0 : format_view_margin(), handlesp, set_html_risk, opts); if(warn_so){ filters[filtcnt].filter = gf_prepend_editorial; filters[filtcnt++].data = gf_prepend_editorial_opt(get_html_risk, (char *) so_text(warn_so)); } } if (add_me){ filters[filtcnt].filter = gf_quote_test; filters[filtcnt++].data = gf_line_test_opt(select_quote, &doraw); } /* * If the message is not flowed, we do the quote suppression before * the wrapping, because the wrapping does not preserve the quote * characters at the beginnings of the lines in that case. * Otherwise, we defer until after the wrapping. * * Also, this is a good place to do quote-replacement on nonflowed * messages because no other filters depend on the "> ". * Quote-replacement is easier in the flowed case and occurs * automatically in the flowed wrapping filter. */ if(!is_flowed_msg && ps_global->full_header == 0 && !(att->body->subtype && strucmp(att->body->subtype, "plain")) && (flags & FM_DISPLAY)){ if(ps_global->quote_suppression_threshold != 0){ memset(&dq, 0, sizeof(dq)); dq.lines = ps_global->quote_suppression_threshold; dq.is_flowed = is_flowed_msg; dq.indent_length = 0; /* indent didn't happen yet */ dq.saved_line = &free_this; dq.handlesp = handlesp; dq.do_color = (!(flags & FM_NOCOLOR) && pico_usingcolor()); filters[filtcnt].filter = gf_quote_test; filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq); } if(ps_global->VAR_QUOTE_REPLACE_STRING && F_ON(F_QUOTE_REPLACE_NOFLOW, ps_global)){ filters[filtcnt].filter = gf_line_test; filters[filtcnt++].data = gf_line_test_opt(replace_quotes, NULL); } } if(wrapit && !(flags & FM_NOWRAP)){ int wrapflags = (flags & FM_DISPLAY) ? (GFW_HANDLES|GFW_SOFTHYPHEN) : GFW_NONE; if(flags & FM_DISPLAY && !(flags & FM_NOCOLOR) && pico_usingcolor()) wrapflags |= GFW_USECOLOR; /* text/flowed (RFC 2646 + draft)? */ if(ps_global->full_header != 2 && is_flowed_msg){ wrapflags |= GFW_FLOWED; if(is_delsp_yes) wrapflags |= GFW_DELSP; } filters[filtcnt].filter = gf_wrap; filters[filtcnt++].data = gf_wrap_filter_opt(wrapit, column, (flags & FM_NOINDENT) ? 0 : format_view_margin(), 0, wrapflags); } /* * This has to come after wrapping has happened because the user tells * us how many quoted lines to display, and we want that number to be * the wrapped lines, not the pre-wrapped lines. We do it before the * wrapping if the message is not flowed, because the wrapping does not * preserve the quote characters at the beginnings of the lines in that * case. */ if(is_flowed_msg && ps_global->full_header == 0 && !(att->body->subtype && strucmp(att->body->subtype, "plain")) && (flags & FM_DISPLAY) && ps_global->quote_suppression_threshold != 0){ memset(&dq, 0, sizeof(dq)); dq.lines = ps_global->quote_suppression_threshold; dq.is_flowed = is_flowed_msg; dq.indent_length = (wrapit && !(flags & FM_NOWRAP) && !(flags & FM_NOINDENT)) ? format_view_margin()[0] : 0; dq.saved_line = &free_this; dq.handlesp = handlesp; dq.do_color = (!(flags & FM_NOCOLOR) && pico_usingcolor()); filters[filtcnt].filter = gf_quote_test; filters[filtcnt++].data = gf_line_test_opt(delete_quotes, &dq); } if(charset){ if(F_OFF(F_QUELL_CHARSET_WARNING, ps_global) && !(flags & FM_NOEDITORIAL)){ int rv = TRUE; CONV_TABLE *ct = NULL; /* * Need editorial if message charset is not ascii * and the display charset is not either the same * as the message charset or UTF-8. */ if(strucmp(charset, "us-ascii") && !((ps_global->display_charmap && !strucmp(charset, ps_global->display_charmap)) || !strucmp("UTF-8", ps_global->display_charmap))){ /* * This is probably overkill. We're just using this * conversion_table routine to get at the quality. */ if(ps_global->display_charmap) ct = conversion_table(charset, ps_global->display_charmap); rv = charset_editorial(charset, msgno, handlesp, flags, ct ? ct->quality : CV_NO_TRANSLATE_POSSIBLE, column, pc); } if(!rv) goto write_error; } fs_give((void **) &charset); } /* Format editorial comment about unknown encoding */ if(att->body->encoding > ENCQUOTEDPRINTABLE){ char buf[2048]; snprintf(buf, sizeof(buf), ENCODING_DISCLAIMER, body_encodings[att->body->encoding]); if(!(format_editorial(buf, column, flags, handlesp, pc) == NULL && gf_puts(NEWLINE, pc) && gf_puts(NEWLINE, pc))) goto write_error; } err = detach(ps_global->mail_stream, msgno, att->number, 0L, NULL, pc, filtcnt ? filters : NULL, 0); delete_unused_handles(handlesp); if(free_this) fs_give((void **) &free_this); if(warn_so) so_give(&warn_so); if(err) { error_found++; if(style == QStatus) { q_status_message1(SM_ORDER, 3, 4, "%.200s", err); } else if(style == InLine) { char buftmp[MAILTMPLEN]; snprintf(buftmp, sizeof(buftmp), "%s", att->body->description ? att->body->description : ""); snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s [Error: %s] %c%s%c%s%s", NEWLINE, err, att->body->description ? '\"' : ' ', att->body->description ? buftmp : "", att->body->description ? '\"' : ' ', NEWLINE, NEWLINE); if(!gf_puts(tmp_20k_buf, pc)) goto write_error; } } if(att->body->subtype && (!strucmp(att->body->subtype, "richtext") || !strucmp(att->body->subtype, "enriched")) && !(flags & FM_DISPLAY)){ if(!gf_puts(NEWLINE, pc) || !gf_puts(NEWLINE, pc)) goto write_error; } return(error_found); write_error: if(style == QStatus) q_status_message1(SM_ORDER, 3, 4, "Error writing message: %.200s", error_description(errno)); return(1); }
/* * Format editorial comment about charset mismatch */ int charset_editorial(char *charset, long int msgno, HANDLE_S **handlesp, int flags, int quality, int width, gf_io_t pc) { char *p, color[64], buf[2048]; int i, n; HANDLE_S *h = NULL; snprintf(buf, sizeof(buf), CHARSET_DISCLAIMER_1, charset ? charset : "US-ASCII"); p = &buf[strlen(buf)]; if(!(ps_global->display_charmap && strucmp(ps_global->display_charmap, "US-ASCII")) && handlesp && (flags & FM_DISPLAY) == FM_DISPLAY){ h = new_handle(handlesp); h->type = URL; h->h.url.path = cpystr("x-alpine-help:h_config_char_set"); /* * Because this filter comes after the delete_quotes filter, we need * to tell delete_quotes that this handle is used, so it won't * delete it. This is a dangerous thing. */ h->is_used = 1; if(!(flags & FM_NOCOLOR) && scroll_handle_start_color(color, sizeof(color), &n)){ for(i = 0; i < n; i++) if(p-buf < sizeof(buf)) *p++ = color[i]; } else if(F_OFF(F_SLCTBL_ITEM_NOBOLD, ps_global)){ if(p-buf+1 < sizeof(buf)){ *p++ = TAG_EMBED; *p++ = TAG_BOLDON; } } if(p-buf+1 < sizeof(buf)){ *p++ = TAG_EMBED; *p++ = TAG_HANDLE; } snprintf(p + 1, sizeof(buf)-(p+1-buf), "%d", h->key); if(p-buf < sizeof(buf)) *p = strlen(p + 1); p += (*p + 1); } sstrncpy(&p, CHARSET_DISCLAIMER_2, sizeof(buf)-(p-buf)); if(h){ /* in case it was the current selection */ if(p-buf+1 < sizeof(buf)){ *p++ = TAG_EMBED; *p++ = TAG_INVOFF; } if(scroll_handle_end_color(color, sizeof(color), &n, 0)){ for(i = 0; i < n; i++) if(p-buf < sizeof(buf)) *p++ = color[i]; } else{ if(p-buf+1 < sizeof(buf)){ *p++ = TAG_EMBED; *p++ = TAG_BOLDOFF; } } if(p-buf < sizeof(buf)) *p = '\0'; } snprintf(p, sizeof(buf)-(p-buf), CHARSET_DISCLAIMER_3, ps_global->display_charmap ? ps_global->display_charmap : "US-ASCII", (quality == CV_LOSES_SPECIAL_CHARS) ? "special " : ""); buf[sizeof(buf)-1] = '\0'; return(format_editorial(buf, width, flags, handlesp, pc) == NULL && gf_puts(NEWLINE, pc) && gf_puts(NEWLINE, pc)); }
/* * mc_cmd_bldr - construct a command string to execute * * If tmp_file is null, then the contents of the given MIME segment * is not provided. This is useful for building the "test=" string * as it doesn't operate on the segment's data. * * The return value is an alloc'd copy of the command to be executed. */ char * mc_cmd_bldr(char *controlstring, int type, char *subtype, BODY *body, char *tmp_file, char **err) { char *from, *to, *s, *parm; int prefixed = 0, used_tmp_file = 0; dprint((8, "- mc_cmd_bldr -\n")); for(from = controlstring, to = tmp_20k_buf; *from; ++from){ if(prefixed){ /* previous char was % */ prefixed = 0; switch(*from){ case '%': /* turned \% into this earlier */ if(to-tmp_20k_buf < SIZEOF_20KBUF) *to++ = '%'; break; case 's': /* insert tmp_file name in cmd */ if(tmp_file){ used_tmp_file = 1; sstrncpy(&to, tmp_file, SIZEOF_20KBUF-(to-tmp_20k_buf)); } else dprint((1, "mc_cmd_bldr: %%s in cmd but not supplied!\n")); break; case 't': /* insert MIME type/subtype */ /* quote to prevent funny business */ if(to-tmp_20k_buf < SIZEOF_20KBUF) *to++ = '\''; sstrncpy(&to, body_type_names(type), SIZEOF_20KBUF-(to-tmp_20k_buf)); if(to-tmp_20k_buf < SIZEOF_20KBUF) *to++ = '/'; sstrncpy(&to, subtype, SIZEOF_20KBUF-(to-tmp_20k_buf)); if(to-tmp_20k_buf < SIZEOF_20KBUF) *to++ = '\''; break; case '{': /* insert requested MIME param */ if(F_OFF(F_DO_MAILCAP_PARAM_SUBST, ps_global)){ int save; dprint((2, "mc_cmd_bldr: param subs %s\n", from ? from : "?")); if(err){ if((s = strindex(from, '}')) != NULL){ save = *++s; *s = '\0'; } snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Mailcap: see hidden feature %.200s (%%%.200s)", feature_list_name(F_DO_MAILCAP_PARAM_SUBST), from); *err = tmp_20k_buf; if(s) *s = save; } return(NULL); } s = strindex(from, '}'); if(!s){ q_status_message1(SM_ORDER, 0, 4, "Ignoring ill-formed parameter reference in mailcap file: %.200s", from); break; } *s = '\0'; ++from; /* from is the part inside the brackets now */ parm = parameter_val(body ? body->parameter : NULL, from); dprint((9, "mc_cmd_bldr: parameter %s = %s\n", from ? from : "?", parm ? parm : "(not found)")); /* * Quote parameter values for /bin/sh. * Put single quotes around the whole thing but every time * there is an actual single quote put it outside of the * single quotes with a backslash in front of it. So the * parameter value fred's car * turns into 'fred'\''s car' */ if(to-tmp_20k_buf < SIZEOF_20KBUF) *to++ = '\''; /* opening quote */ if(parm){ char *p; /* * Copy value, but quote single quotes for /bin/sh * Backslash quote is ignored inside single quotes so * have to put those outside of the single quotes. * (The parm+1000 nonsense is to protect against * malicious mail trying to overflow our buffer.) * * TCH - Change 2/8/1999 * Also quote the ` to prevent execution of arbitrary code */ for(p = parm; *p && p < parm+1000; p++){ if((*p == '\'') || (*p == '`')){ if(to-tmp_20k_buf+4 < SIZEOF_20KBUF){ *to++ = '\''; /* closing quote */ *to++ = '\\'; *to++ = *p; /* quoted character */ *to++ = '\''; /* opening quote */ } } else if(to-tmp_20k_buf < SIZEOF_20KBUF) *to++ = *p; } fs_give((void **) &parm); } if(to-tmp_20k_buf < SIZEOF_20KBUF) *to++ = '\''; /* closing quote for /bin/sh */ *s = '}'; /* restore */ from = s; break; /* * %n and %F are used by metamail to support otherwise * unrecognized multipart Content-Types. Pine does * not use these since we're only dealing with the individual * parts at this point. */ case 'n': case 'F': default: dprint((9, "Ignoring %s format code in mailcap file: %%%c\n", (*from == 'n' || *from == 'F') ? "unimplemented" : "unrecognized", *from)); break; } } else if(*from == '%') /* next char is special */ prefixed = 1; else if(to-tmp_20k_buf < SIZEOF_20KBUF) /* regular character, just copy */ *to++ = *from; } if(to-tmp_20k_buf < SIZEOF_20KBUF) *to = '\0'; tmp_20k_buf[SIZEOF_20KBUF-1] = '\0'; /* * file not specified, redirect to stdin */ if(!used_tmp_file && tmp_file) snprintf(to, SIZEOF_20KBUF-(to-tmp_20k_buf), MC_ADD_TMP, tmp_file); return(cpystr(tmp_20k_buf)); }
/*---------------------------------------------------------------------- Present pinerc data for manipulation Args: None Result: help edit certain pinerc fields. ---*/ void option_screen(struct pine *ps, int edit_exceptions) { char tmp[MAXPATH+1], *pval, **lval; int i, j, ln = 0, readonly_warning = 0; struct variable *vtmp; CONF_S *ctmpa = NULL, *ctmpb, *first_line = NULL; FEATURE_S *feature; PINERC_S *prc = NULL; SAVED_CONFIG_S *vsave; OPT_SCREEN_S screen; int expose_hidden_config, add_hidden_vars_title = 0; dprint((3, "-- option_screen --\n")); expose_hidden_config = F_ON(F_EXPOSE_HIDDEN_CONFIG, ps_global); treat_color_vars_as_text = expose_hidden_config; ew = edit_exceptions ? ps_global->ew_for_except_vars : Main; if(ps->restricted) readonly_warning = 1; else{ switch(ew){ case Main: prc = ps->prc; break; case Post: prc = ps->post_prc; break; default: break; } readonly_warning = prc ? prc->readonly : 1; if(prc && prc->quit_to_edit){ quit_to_edit_msg(prc); treat_color_vars_as_text = 0; return; } } ps->next_screen = SCREEN_FUN_NULL; mailcap_free(); /* free resources we won't be using for a while */ if(ps->fix_fixed_warning) offer_to_fix_pinerc(ps); /* * First, find longest variable name */ for(vtmp = ps->vars; vtmp->name; vtmp++){ if(exclude_config_var(ps, vtmp, expose_hidden_config)) continue; if((i = utf8_width(pretty_var_name(vtmp->name))) > ln) ln = i; } dprint((9, "initialize config list\n")); /* * Next, allocate and initialize config line list... */ for(vtmp = ps->vars; vtmp->name; vtmp++){ /* * INCOMING_FOLDERS is currently the first of the normally * hidden variables. Should probably invent a more robust way * to keep this up to date. */ if(expose_hidden_config && vtmp == &ps->vars[V_INCOMING_FOLDERS]) add_hidden_vars_title = 1; if(exclude_config_var(ps, vtmp, expose_hidden_config)) continue; if(add_hidden_vars_title){ add_hidden_vars_title = 0; new_confline(&ctmpa); /* Blank line */ ctmpa->flags |= CF_NOSELECT | CF_B_LINE; new_confline(&ctmpa)->var = NULL; ctmpa->help = NO_HELP; ctmpa->valoffset = 2; ctmpa->flags |= CF_NOSELECT; ctmpa->value = cpystr("--- [ Normally hidden configuration options ] ---"); new_confline(&ctmpa); /* Blank line */ ctmpa->flags |= CF_NOSELECT | CF_B_LINE; } if(vtmp->is_list) lval = LVAL(vtmp, ew); else pval = PVAL(vtmp, ew); new_confline(&ctmpa)->var = vtmp; if(!first_line) first_line = ctmpa; ctmpa->valoffset = ln + 3; if(vtmp->is_list) ctmpa->keymenu = &config_text_wshuf_keymenu; else ctmpa->keymenu = &config_text_keymenu; ctmpa->help = config_help(vtmp - ps->vars, 0); ctmpa->tool = text_tool; utf8_snprintf(tmp, sizeof(tmp), "%-*.100w =", ln, pretty_var_name(vtmp->name)); tmp[sizeof(tmp)-1] = '\0'; ctmpa->varname = cpystr(tmp); ctmpa->varnamep = ctmpb = ctmpa; ctmpa->flags |= CF_STARTITEM; if(vtmp == &ps->vars[V_FEATURE_LIST]){ /* special checkbox case */ char *this_sect, *new_sect; ctmpa->flags |= CF_NOSELECT; ctmpa->keymenu = &config_checkbox_keymenu; ctmpa->tool = NULL; /* put a nice delimiter before list */ new_confline(&ctmpa)->var = NULL; ctmpa->varnamep = ctmpb; ctmpa->keymenu = &config_checkbox_keymenu; ctmpa->help = NO_HELP; ctmpa->tool = checkbox_tool; ctmpa->valoffset = feature_indent(); ctmpa->flags |= CF_NOSELECT; ctmpa->value = cpystr("Set Feature Name"); new_confline(&ctmpa)->var = NULL; ctmpa->varnamep = ctmpb; ctmpa->keymenu = &config_checkbox_keymenu; ctmpa->help = NO_HELP; ctmpa->tool = checkbox_tool; ctmpa->valoffset = feature_indent(); ctmpa->flags |= CF_NOSELECT; ctmpa->value = cpystr("--- ----------------------"); for(i = 0, this_sect = NULL; (feature = feature_list(i)); i++) if((new_sect = feature_list_section(feature)) && (strcmp(new_sect, HIDDEN_PREF) != 0)){ if(this_sect != new_sect){ new_confline(&ctmpa)->var = NULL; ctmpa->varnamep = ctmpb; ctmpa->keymenu = &config_checkbox_keymenu; ctmpa->help = NO_HELP; ctmpa->tool = checkbox_tool; ctmpa->valoffset = 2; ctmpa->flags |= (CF_NOSELECT | CF_STARTITEM); snprintf(tmp, sizeof(tmp), "[ %s ]", this_sect = new_sect); tmp[sizeof(tmp)-1] = '\0'; ctmpa->value = cpystr(tmp); } new_confline(&ctmpa)->var = vtmp; ctmpa->varnamep = ctmpb; ctmpa->keymenu = &config_checkbox_keymenu; ctmpa->help = config_help(vtmp-ps->vars, feature->id); ctmpa->tool = checkbox_tool; ctmpa->valoffset = feature_indent(); ctmpa->varmem = i; ctmpa->value = pretty_value(ps, ctmpa); } } else if(standard_radio_var(ps, vtmp)){ standard_radio_setup(ps, &ctmpa, vtmp, NULL); } else if(vtmp == &ps->vars[V_SORT_KEY]){ /* radio case */ SortOrder def_sort; int def_sort_rev; ctmpa->flags |= CF_NOSELECT; ctmpa->keymenu = &config_radiobutton_keymenu; ctmpa->tool = NULL; /* put a nice delimiter before list */ new_confline(&ctmpa)->var = NULL; ctmpa->varnamep = ctmpb; ctmpa->keymenu = &config_radiobutton_keymenu; ctmpa->help = NO_HELP; ctmpa->tool = radiobutton_tool; ctmpa->valoffset = 12; ctmpa->flags |= CF_NOSELECT; ctmpa->value = cpystr("Set Sort Options"); new_confline(&ctmpa)->var = NULL; ctmpa->varnamep = ctmpb; ctmpa->keymenu = &config_radiobutton_keymenu; ctmpa->help = NO_HELP; ctmpa->tool = radiobutton_tool; ctmpa->valoffset = 12; ctmpa->flags |= CF_NOSELECT; ctmpa->value = cpystr("--- ----------------------"); decode_sort(pval, &def_sort, &def_sort_rev); for(j = 0; j < 2; j++){ for(i = 0; ps->sort_types[i] != EndofList; i++){ new_confline(&ctmpa)->var = vtmp; ctmpa->varnamep = ctmpb; ctmpa->keymenu = &config_radiobutton_keymenu; ctmpa->help = config_help(vtmp - ps->vars, 0); ctmpa->tool = radiobutton_tool; ctmpa->valoffset = 12; ctmpa->varmem = i + (j * EndofList); ctmpa->value = pretty_value(ps, ctmpa); } } } else if(vtmp == &ps->vars[V_USE_ONLY_DOMAIN_NAME]){ /* yesno case */ ctmpa->keymenu = &config_yesno_keymenu; ctmpa->tool = yesno_tool; ctmpa->value = pretty_value(ps, ctmpa); } else if(vtmp == &ps->vars[V_LITERAL_SIG]){ ctmpa->tool = litsig_text_tool; ctmpa->value = pretty_value(ps, ctmpa); } else if(vtmp == &ps->vars[V_INBOX_PATH]){ ctmpa->tool = inbox_path_text_tool; ctmpa->value = pretty_value(ps, ctmpa); } else if(vtmp == &ps->vars[V_POST_CHAR_SET] #ifndef _WINDOWS || vtmp == &ps->vars[V_CHAR_SET] || vtmp == &ps->vars[V_KEY_CHAR_SET] #endif /* !_WINDOWS */ || vtmp == &ps->vars[V_UNK_CHAR_SET]){ ctmpa->keymenu = &config_text_to_charsets_keymenu; ctmpa->tool = to_charsets_text_tool; ctmpa->value = pretty_value(ps, ctmpa); } else if(vtmp->is_list){ int (*t_tool)(struct pine *, int, CONF_S **, unsigned); struct key_menu *km; t_tool = NULL; km = NULL; if(vtmp == &ps->vars[V_INCCHECKLIST]){ t_tool = incoming_monitoring_list_tool; km = &config_text_keymenu; } else if(vtmp == &ps->vars[V_PERMLOCKED]){ t_tool = stayopen_list_tool; km = &config_text_wshufandfldr_keymenu; } if(lval){ for(i = 0; lval[i]; i++){ if(i) (void)new_confline(&ctmpa); ctmpa->var = vtmp; ctmpa->varmem = i; ctmpa->valoffset = ln + 3; ctmpa->value = pretty_value(ps, ctmpa); ctmpa->keymenu = km ? km : &config_text_wshuf_keymenu; ctmpa->help = config_help(vtmp - ps->vars, 0); ctmpa->tool = t_tool ? t_tool : text_tool; ctmpa->varnamep = ctmpb; } } else{ ctmpa->varmem = 0; ctmpa->value = pretty_value(ps, ctmpa); ctmpa->tool = t_tool ? t_tool : text_tool; ctmpa->keymenu = km ? km : &config_text_wshuf_keymenu; } } else{ if(vtmp == &ps->vars[V_FILLCOL] || vtmp == &ps->vars[V_SLEEP] || vtmp == &ps->vars[V_QUOTE_SUPPRESSION] || vtmp == &ps->vars[V_OVERLAP] || vtmp == &ps->vars[V_MAXREMSTREAM] || vtmp == &ps->vars[V_MARGIN] || vtmp == &ps->vars[V_DEADLETS] || vtmp == &ps->vars[V_NMW_WIDTH] || vtmp == &ps->vars[V_STATUS_MSG_DELAY] || vtmp == &ps->vars[V_ACTIVE_MSG_INTERVAL] || vtmp == &ps->vars[V_MAILCHECK] || vtmp == &ps->vars[V_MAILCHECKNONCURR] || vtmp == &ps->vars[V_MAILDROPCHECK] || vtmp == &ps->vars[V_NNTPRANGE] || vtmp == &ps->vars[V_TCPOPENTIMEO] || vtmp == &ps->vars[V_TCPREADWARNTIMEO] || vtmp == &ps->vars[V_TCPWRITEWARNTIMEO] || vtmp == &ps->vars[V_TCPQUERYTIMEO] || vtmp == &ps->vars[V_RSHOPENTIMEO] || vtmp == &ps->vars[V_SSHOPENTIMEO] || vtmp == &ps->vars[V_INCCHECKTIMEO] || vtmp == &ps->vars[V_INCCHECKINTERVAL] || vtmp == &ps->vars[V_INC2NDCHECKINTERVAL] || vtmp == &ps->vars[V_USERINPUTTIMEO] || vtmp == &ps->vars[V_REMOTE_ABOOK_VALIDITY] || vtmp == &ps->vars[V_REMOTE_ABOOK_HISTORY]) ctmpa->flags |= CF_NUMBER; ctmpa->value = pretty_value(ps, ctmpa); } } dprint((9, "add hidden features\n")); /* add the hidden features */ if(expose_hidden_config){ char *new_sect; new_confline(&ctmpa); /* Blank line */ ctmpa->flags |= CF_NOSELECT | CF_B_LINE; new_confline(&ctmpa)->var = NULL; ctmpa->help = NO_HELP; ctmpa->valoffset = 2; ctmpa->flags |= CF_NOSELECT; ctmpa->value = cpystr("--- [ Normally hidden configuration features ] ---"); new_confline(&ctmpa); /* Blank line */ ctmpa->flags |= CF_NOSELECT | CF_B_LINE; vtmp = &ps->vars[V_FEATURE_LIST]; ctmpa->flags |= CF_NOSELECT; ctmpa->keymenu = &config_checkbox_keymenu; ctmpa->tool = NULL; /* put a nice delimiter before list */ new_confline(&ctmpa)->var = NULL; ctmpa->varnamep = ctmpb; ctmpa->keymenu = &config_checkbox_keymenu; ctmpa->help = NO_HELP; ctmpa->tool = checkbox_tool; ctmpa->valoffset = feature_indent(); ctmpa->flags |= CF_NOSELECT; ctmpa->value = cpystr("Set Feature Name"); new_confline(&ctmpa)->var = NULL; ctmpa->varnamep = ctmpb; ctmpa->keymenu = &config_checkbox_keymenu; ctmpa->help = NO_HELP; ctmpa->tool = checkbox_tool; ctmpa->valoffset = feature_indent(); ctmpa->flags |= CF_NOSELECT; ctmpa->value = cpystr("--- ----------------------"); for(i = 0; (feature = feature_list(i)); i++) if((new_sect = feature_list_section(feature)) && (strcmp(new_sect, HIDDEN_PREF) == 0)){ new_confline(&ctmpa)->var = vtmp; ctmpa->varnamep = ctmpb; ctmpa->keymenu = &config_checkbox_keymenu; ctmpa->help = config_help(vtmp-ps->vars, feature->id); ctmpa->tool = checkbox_tool; ctmpa->valoffset = feature_indent(); ctmpa->varmem = i; ctmpa->value = pretty_value(ps, ctmpa); } } vsave = save_config_vars(ps, expose_hidden_config); first_line = first_sel_confline(first_line); memset(&screen, 0, sizeof(screen)); screen.ro_warning = readonly_warning; /* TRANSLATORS: Print something1 using something2. "configuration" is something1 */ switch(conf_scroll_screen(ps, &screen, first_line, edit_exceptions ? CONFIG_SCREEN_TITLE_EXC : CONFIG_SCREEN_TITLE, _("configuration"), 0)){ case 0: break; case 1: write_pinerc(ps, ew, WRP_NONE); break; case 10: revert_to_saved_config(ps, vsave, expose_hidden_config); if(prc) prc->outstanding_pinerc_changes = 0; break; default: q_status_message(SM_ORDER,7,10, "conf_scroll_screen bad ret, not supposed to happen"); break; } pval = PVAL(&ps->vars[V_SORT_KEY], ew); if(vsave[V_SORT_KEY].saved_user_val.p && pval && strcmp(vsave[V_SORT_KEY].saved_user_val.p, pval)){ if(!mn_get_mansort(ps_global->msgmap)){ clear_index_cache(ps_global->mail_stream, 0); reset_sort_order(SRT_VRB); } } treat_color_vars_as_text = 0; free_saved_config(ps, &vsave, expose_hidden_config); #ifdef _WINDOWS mswin_set_quit_confirm (F_OFF(F_QUIT_WO_CONFIRM, ps_global)); #endif }
/*---------------------------------------------------------------------- Suspend Pine. Reset tty and suspend. Suspend is finished when this returns Args: The pine structure Result: Execution suspended for a while. Screen will need redrawing after this is done. Instead of the usual handling of ^Z by catching a signal, we actually read the ^Z and then clean up the tty driver, then kill ourself to stop, and pick up where we left off when execution resumes. ----------------------------------------------------------------------*/ UCS do_suspend(void) { struct pine *pine = ps_global; time_t now; UCS retval; #if defined(DOS) || defined(OS2) int result, orig_cols, orig_rows; #else int isremote; #endif #ifdef DOS static char *shell = NULL; #define STD_SHELL "COMMAND.COM" #else #ifdef OS2 static char *shell = NULL; #define STD_SHELL "CMD.EXE" #endif #endif if(!have_job_control()) { bogus_command(ctrl('Z'), F_ON(F_USE_FK, pine) ? "F1" : "?"); return(NO_OP_COMMAND); } if(F_OFF(F_CAN_SUSPEND, pine)) { q_status_message(SM_ORDER | SM_DING, 3, 3, _("Alpine suspension not enabled - see help text")); return(NO_OP_COMMAND); } #ifdef _WINDOWS mswin_minimize(); return(NO_OP_COMMAND); #else isremote = (ps_global->mail_stream && ps_global->mail_stream->mailbox && (*ps_global->mail_stream->mailbox == '{' || (*ps_global->mail_stream->mailbox == '*' && *(ps_global->mail_stream->mailbox + 1) == '{'))); now = time((time_t *)0); dprint((1, "\n\n --- %s - SUSPEND ---- %s", isremote ? "REMOTE" : "LOCAL", ctime(&now))); ttyfix(0); #if defined(DOS) || defined(OS2) suspend_notice("exit"); if (!shell) { char *p; if (!((shell = getenv("SHELL")) || (shell = getenv("COMSPEC")))) shell = STD_SHELL; shell = cpystr(shell); /* copy in free storage */ for(p = shell; (p = strchr(p, '/')); p++) *p = '\\'; } result = system(shell); #else if(F_ON(F_SUSPEND_SPAWNS, ps_global)) { PIPE_S *syspipe; if((syspipe = open_system_pipe(NULL, NULL, NULL, PIPE_USER|PIPE_RESET, 0, pipe_callback, pipe_report_error)) != NULL) { suspend_notice("exit"); #ifndef SIGCHLD if(isremote) suspend_warning(); #endif (void) close_system_pipe(&syspipe, NULL, pipe_callback); } } else { suspend_notice("fg"); if(isremote) suspend_warning(); stop_process(); } #endif /* DOS */ now = time((time_t *)0); dprint((1, "\n\n ---- RETURN FROM SUSPEND ---- %s", ctime(&now))); ttyfix(1); #if defined(DOS) || defined(OS2) orig_cols = pine->ttyo->screen_cols; orig_rows = pine->ttyo->screen_rows; #endif fix_windsize(pine); #if defined(DOS) || defined(OS2) if(orig_cols != pine->ttyo->screen_cols || orig_rows != pine->ttyo->screen_rows) retval = KEY_RESIZE; else #endif retval = ctrl('L');; #if defined(DOS) || defined(OS2) if(result == -1) q_status_message1(SM_ORDER | SM_DING, 3, 4, _("Error loading \"%s\""), shell); #endif if(isremote && !pine_mail_ping(ps_global->mail_stream)) q_status_message(SM_ORDER | SM_DING, 4, 9, _("Suspended for too long, IMAP connection broken")); return(retval); #endif /* !_WINDOWS */ }
/* * Turn on a busy cue. * * msg -- the busy message to print in status line * pc_f -- if non-null, call this function to get the percent done, * (an integer between 0 and 100). If null, append dots. * delay -- seconds to delay output of delay notification * * Returns: 0 If busy cue was already set up before we got here * 1 If busy cue was not already set up. * * NOTE: busy_cue and cancel_busy_cue MUST be called symetrically in the * same lexical scope. */ int busy_cue(char *msg, percent_done_t pc_f, int delay) { AFTER_S *a = NULL, **ap; dprint((9, "busy_cue(%s, %p, %d)\n", msg ? msg : "Busy", pc_f, delay)); if(!(ps_global && ps_global->ttyo)){ dprint((9, "busy_cue returns No (ttyo)")); return(0); } /* * If we're already busy'ing, but a cue is invoked that * supplies more useful info, use it... */ if(after_active){ if(msg || pc_f) stop_after(1); /* uninstall old handler */ else return(0); /* nothing to add, return */ } /* get ready to set up list of AFTER_S's */ ap = &a; dotcount = 0; percent_done_ptr = pc_f; if(msg){ strncpy(busy_message, msg, sizeof(busy_message)); final_message = 1; } else{ strncpy(busy_message, "Busy", sizeof(busy_message)); final_message = 0; } busy_message[sizeof(busy_message)-1] = '\0'; busy_width = utf8_width(busy_message); if(!delay){ char progress[MAX_SCREEN_COLS+1]; int space_left, slots_used; final_message = 1; space_left = (ps_global->ttyo ? ps_global->ttyo->screen_cols : 80) - busy_width - 2; /* 2 is for [] */ slots_used = MAX(0, MIN(space_left-3, 10)); if(percent_done_ptr && slots_used >= 4){ snprintf(progress, sizeof(progress), "%s |%*s|", busy_message, slots_used, ""); progress[sizeof(progress)-1] = '\0'; } else{ dotcount++; snprintf(progress, sizeof(progress), "%s%*s", busy_message, spinners[spinner].width + 1, ""); progress[sizeof(progress)-1] = '\0'; } if(status_message_remaining()){ char buf[sizeof(progress) + 30]; char *append = " [not actually shown]"; strncpy(buf, progress, sizeof(buf)-1); buf[sizeof(buf)-1] = '\0'; strncat(buf, append, sizeof(buf) - strlen(buf) - 1); buf[sizeof(buf)-1] = '\0'; add_review_message(buf, -1); } else{ q_status_message(SM_ORDER, 0, 1, progress); /* * We use display_message so that the initial message will * be forced out only if there is not a previous message * currently being displayed that hasn't been displayed for * its min display time yet. In that case, we don't want * to force out the initial message. */ display_message('x'); } fflush(stdout); } /* * Randomly select one of the animations, even taking care * to run through all of them before starting over! * The user won't actually see them all because most of them * will never show up before they are canceled, but it * should still help. */ spinner = -1; if(F_OFF(F_USE_BORING_SPINNER,ps_global) && ps_global->active_status_interval > 0){ int arrsize, eligible, pick_this_one, i, j; arrsize = sizeof(spinners)/sizeof(struct _spinner); /* how many of them are eligible to be used this round? */ for(eligible = i = 0; i < arrsize; i++) if(!spinners[i].used_this_round) eligible++; if(eligible == 0) /* reset */ for(eligible = i = 0; i < arrsize; i++){ spinners[i].used_this_round = 0; eligible++; } if(eligible > 0){ /* it will be */ pick_this_one = random() % eligible; for(j = i = 0; i < arrsize && spinner < 0; i++) if(!spinners[i].used_this_round){ if(j == pick_this_one) spinner = i; else j++; } } } if(spinner < 0 || spinner > sizeof(spinners)/sizeof(struct _spinner) -1) spinner = 0; *ap = new_afterstruct(); (*ap)->delay = (pc_f) ? BUSY_DELAY_PERCENT : BUSY_DELAY_SPINNER; (*ap)->f = do_busy_cue; (*ap)->cf = done_busy_cue; ap = &(*ap)->next; start_after(a); /* launch cue handler */ #ifdef _WINDOWS mswin_setcursor(MSWIN_CURSOR_BUSY); #endif return(1); }