/*---------------------------------------------------------------------- Prompt user for a choice among alternatives Args -- utf8prompt: The prompt for the question/selection line: The line to prompt on, if negative then relative to bottom esc_list: ESC_KEY_S list of keys dflt: The selection when the <CR> is pressed (should probably be one of the chars in esc_list) on_ctrl_C: The selection when ^C is pressed help_text: Text to be displayed on bottom two lines flags: Logically OR'd flags modifying our behavior to: RB_FLUSH_IN - Discard any pending input chars. RB_ONE_TRY - Only give one chance to answer. Returns on_ctrl_C value if not answered acceptably on first try. RB_NO_NEWMAIL - Quell the usual newmail check. RB_SEQ_SENSITIVE - The caller is sensitive to sequence number changes so return on_ctrl_C if an unsolicited expunge happens while we're viewing a message. RB_RET_HELP - Instead of the regular internal handling way of handling help_text, this just causes radio_buttons to return 3 when help is asked for, so that the caller handles it instead. Note: If there are enough keys in the esc_list to need a second screen, and there is no help, then the 13th key will be put in the help position. Result -- Returns the letter pressed. Will be one of the characters in the esc_list argument, or dflt, or on_ctrl_C, or SEQ_EXCEPTION. This will pause for any new status message to be seen and then prompt the user. The prompt will be truncated to fit on the screen. Redraw and resize are handled along with ^Z suspension. Typing ^G will toggle the help text on and off. Character types that are not buttons will result in a beep (unless one_try is set). ----*/ int radio_buttons(char *utf8prompt, int line, ESCKEY_S *esc_list, int dflt, int on_ctrl_C, HelpType help_text, int flags) { UCS ucs; register int ch, real_line; char *q, *ds = NULL; unsigned maxcol; int max_label, i, start, fkey_table[12]; int km_popped = 0; struct key rb_keys[12]; struct key_menu rb_keymenu; bitmap_t bitmap; struct variable *vars = ps_global->vars; COLOR_PAIR *lastc = NULL, *promptc = NULL; #ifdef _WINDOWS int cursor_shown; if (mswin_usedialog()){ MDlgButton button_list[25]; LPTSTR free_names[25]; LPTSTR free_labels[25]; int b, i, ret; char **help; memset(&free_names, 0, sizeof(LPTSTR) * 25); memset(&free_labels, 0, sizeof(LPTSTR) * 25); memset(&button_list, 0, sizeof (MDlgButton) * 25); b = 0; if(flags & RB_RET_HELP){ if(help_text != NO_HELP) alpine_panic("RET_HELP and help in radio_buttons!"); button_list[b].ch = '?'; button_list[b].rval = 3; button_list[b].name = TEXT("?"); free_labels[b] = utf8_to_lptstr(N_("Help")); button_list[b].label = free_labels[b]; ++b; } for(i = 0; esc_list && esc_list[i].ch != -1 && i < 23; ++i){ if(esc_list[i].ch != -2){ button_list[b].ch = esc_list[i].ch; button_list[b].rval = esc_list[i].rval; free_names[b] = utf8_to_lptstr(esc_list[i].name); button_list[b].name = free_names[b]; free_labels[b] = utf8_to_lptstr(esc_list[i].label); button_list[b].label = free_labels[b]; ++b; } } button_list[b].ch = -1; /* assumption here is that HelpType is char ** */ help = help_text; ret = mswin_select(utf8prompt, button_list, dflt, on_ctrl_C, help, flags); for(i = 0; i < 25; i++){ if(free_names[i]) fs_give((void **) &free_names[i]); if(free_labels[i]) fs_give((void **) &free_labels[i]); } return (ret); } #endif /* _WINDOWS */ suspend_busy_cue(); flush_ordered_messages(); /* show user previous status msgs */ mark_status_dirty(); /* clear message next display call */ real_line = line > 0 ? line : ps_global->ttyo->screen_rows + line; MoveCursor(real_line, RAD_BUT_COL); CleartoEOLN(); /*---- Find widest label ----*/ max_label = 0; for(i = 0; esc_list && esc_list[i].ch != -1 && i < 11; i++){ if(esc_list[i].ch == -2) /* -2 means to skip this key and leave blank */ continue; if(esc_list[i].name) max_label = MAX(max_label, utf8_width(esc_list[i].name)); } if(ps_global->ttyo->screen_cols - max_label - 1 > 0) maxcol = ps_global->ttyo->screen_cols - max_label - 1; else maxcol = 0; /* * We need to be able to truncate q, so copy it in case it is * a readonly string. */ q = cpystr(utf8prompt); /*---- Init structs for keymenu ----*/ for(i = 0; i < 12; i++) memset((void *)&rb_keys[i], 0, sizeof(struct key)); memset((void *)&rb_keymenu, 0, sizeof(struct key_menu)); rb_keymenu.how_many = 1; rb_keymenu.keys = rb_keys; /*---- Setup key menu ----*/ start = 0; clrbitmap(bitmap); memset(fkey_table, NO_OP_COMMAND, 12 * sizeof(int)); if(flags & RB_RET_HELP && help_text != NO_HELP) alpine_panic("RET_HELP and help in radio_buttons!"); /* if shown, always at position 0 */ if(help_text != NO_HELP || flags & RB_RET_HELP){ rb_keymenu.keys[0].name = "?"; rb_keymenu.keys[0].label = N_("Help"); setbitn(0, bitmap); fkey_table[0] = ctrl('G'); start++; } if(on_ctrl_C){ rb_keymenu.keys[1].name = "^C"; rb_keymenu.keys[1].label = N_("Cancel"); setbitn(1, bitmap); fkey_table[1] = ctrl('C'); start++; } start = start ? 2 : 0; /*---- Show the usual possible keys ----*/ for(i=start; esc_list && esc_list[i-start].ch != -1; i++){ /* * If we have an esc_list item we'd like to put in the non-existent * 13th slot, and there is no help, we put it in the help slot * instead. We're hacking now...! * * We may also have invisible esc_list items that don't show up * on the screen. We use this when we have two different keys * which are synonyms, like ^P and KEY_UP. If all the slots are * already full we can still fit invisible keys off the screen to * the right. A key is invisible if it's label is "". */ if(i >= 12){ if(esc_list[i-start].label && esc_list[i-start].label[0] != '\0'){ /* visible */ if(i == 12){ /* special case where we put it in help slot */ if(help_text != NO_HELP) alpine_panic("Programming botch in radio_buttons(): too many keys"); if(esc_list[i-start].ch != -2) setbitn(0, bitmap); /* the help slot */ fkey_table[0] = esc_list[i-start].ch; rb_keymenu.keys[0].name = esc_list[i-start].name; if(esc_list[i-start].ch != -2 && esc_list[i-start].rval == dflt && esc_list[i-start].label){ size_t l; l = strlen(esc_list[i-start].label) + 2; ds = (char *)fs_get((l+1) * sizeof(char)); snprintf(ds, l+1, "[%s]", esc_list[i-start].label); ds[l] = '\0'; rb_keymenu.keys[0].label = ds; } else rb_keymenu.keys[0].label = esc_list[i-start].label; } else alpine_panic("Botch in radio_buttons(): too many keys"); } } else{ if(esc_list[i-start].ch != -2) setbitn(i, bitmap); fkey_table[i] = esc_list[i-start].ch; rb_keymenu.keys[i].name = esc_list[i-start].name; if(esc_list[i-start].ch != -2 && esc_list[i-start].rval == dflt && esc_list[i-start].label){ size_t l; l = strlen(esc_list[i-start].label) + 2; ds = (char *)fs_get((l+1) * sizeof(char)); snprintf(ds, l+1, "[%s]", esc_list[i-start].label); ds[l] = '\0'; rb_keymenu.keys[i].label = ds; } else rb_keymenu.keys[i].label = esc_list[i-start].label; } } for(; i < 12; i++) rb_keymenu.keys[i].name = NULL; ps_global->mangled_footer = 1; #ifdef _WINDOWS cursor_shown = mswin_showcaret(1); #endif 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(); draw_radio_prompt(real_line, RAD_BUT_COL, maxcol, q); while(1){ fflush(stdout); /*---- Paint the keymenu ----*/ if(lastc) (void)pico_set_colorp(lastc, PSC_NONE); else EndInverse(); draw_keymenu(&rb_keymenu, bitmap, ps_global->ttyo->screen_cols, 1 - FOOTER_ROWS(ps_global), 0, FirstMenu); if(promptc) (void)pico_set_colorp(promptc, PSC_NONE); else StartInverse(); MoveCursor(real_line, MIN(RAD_BUT_COL+utf8_width(q), maxcol+1)); if(flags & RB_FLUSH_IN) flush_input(); newcmd: /* Timeout 5 min to keep imap mail stream alive */ ucs = read_char(600); dprint((2, "Want_to read: %s (0x%x)\n", pretty_command(ucs), ucs)); if((ucs < 0x80) && isupper((unsigned char) ucs)) ucs = tolower((unsigned char) ucs); if(F_ON(F_USE_FK,ps_global) && (((ucs < 0x80) && isalpha((unsigned char) ucs) && !strchr("YyNn",(int) ucs)) || ((ucs >= PF1 && ucs <= PF12) && (ucs = fkey_table[ucs - PF1]) == NO_OP_COMMAND))){ /* * The funky test above does two things. It maps * esc_list character commands to function keys, *and* prevents * character commands from input while in function key mode. * NOTE: this breaks if we ever need more than the first * twelve function keys... */ if(flags & RB_ONE_TRY){ ch = ucs = on_ctrl_C; goto out_of_loop; } Writechar(BELL, 0); continue; } switch(ucs){ default: for(i = 0; esc_list && esc_list[i].ch != -1; i++) if(ucs == esc_list[i].ch){ int len, n; MoveCursor(real_line,len=MIN(RAD_BUT_COL+utf8_width(q),maxcol+1)); for(n = 0, len = ps_global->ttyo->screen_cols - len; esc_list[i].label && esc_list[i].label[n] && len > 0; n++, len--) Writechar(esc_list[i].label[n], 0); ch = esc_list[i].rval; goto out_of_loop; } if(flags & RB_ONE_TRY){ ch = on_ctrl_C; goto out_of_loop; } Writechar(BELL, 0); break; case ctrl('M'): case ctrl('J'): ch = dflt; for(i = 0; esc_list && esc_list[i].ch != -1; i++) if(ch == esc_list[i].rval){ int len, n; MoveCursor(real_line,len=MIN(RAD_BUT_COL+utf8_width(q),maxcol+1)); for(n = 0, len = ps_global->ttyo->screen_cols - len; esc_list[i].label && esc_list[i].label[n] && len > 0; n++, len--) Writechar(esc_list[i].label[n], 0); break; } goto out_of_loop; case ctrl('C'): if(on_ctrl_C || (flags & RB_ONE_TRY)){ ch = on_ctrl_C; goto out_of_loop; } Writechar(BELL, 0); break; case '?': case ctrl('G'): if(FOOTER_ROWS(ps_global) == 1 && km_popped == 0){ km_popped++; FOOTER_ROWS(ps_global) = 3; line = -3; real_line = ps_global->ttyo->screen_rows + line; if(lastc) (void)pico_set_colorp(lastc, PSC_NONE); else EndInverse(); clearfooter(ps_global); if(promptc) (void)pico_set_colorp(promptc, PSC_NONE); else StartInverse(); draw_radio_prompt(real_line, RAD_BUT_COL, maxcol, q); break; } if(flags & RB_RET_HELP){ ch = 3; goto out_of_loop; } else if(help_text != NO_HELP && FOOTER_ROWS(ps_global) > 1){ mark_keymenu_dirty(); if(lastc) (void)pico_set_colorp(lastc, PSC_NONE); else EndInverse(); MoveCursor(real_line + 1, RAD_BUT_COL); CleartoEOLN(); MoveCursor(real_line + 2, RAD_BUT_COL); CleartoEOLN(); radio_help(real_line, RAD_BUT_COL, help_text); sleep(5); MoveCursor(real_line, MIN(RAD_BUT_COL+utf8_width(q), maxcol+1)); if(promptc) (void)pico_set_colorp(promptc, PSC_NONE); else StartInverse(); } else Writechar(BELL, 0); break; case NO_OP_COMMAND: goto newcmd; /* misunderstood escape? */ case NO_OP_IDLE: /* UNODIR, keep the stream alive */ if(flags & RB_NO_NEWMAIL) goto newcmd; i = new_mail(0, VeryBadTime, NM_DEFER_SORT); if(sp_expunge_count(ps_global->mail_stream) && flags & RB_SEQ_SENSITIVE){ if(on_ctrl_C) ch = on_ctrl_C; else ch = SEQ_EXCEPTION; goto out_of_loop; } if(i < 0) break; /* no changes, get on with life */ /* Else fall into redraw to adjust displayed numbers and such */ case KEY_RESIZE: case ctrl('L'): real_line = line > 0 ? line : ps_global->ttyo->screen_rows + line; if(lastc) (void)pico_set_colorp(lastc, PSC_NONE); else EndInverse(); ClearScreen(); redraw_titlebar(); if(ps_global->redrawer != NULL) (*ps_global->redrawer)(); if(FOOTER_ROWS(ps_global) == 3 || km_popped) redraw_keymenu(); if(ps_global->ttyo->screen_cols - max_label - 1 > 0) maxcol = ps_global->ttyo->screen_cols - max_label - 1; else maxcol = 0; if(promptc) (void)pico_set_colorp(promptc, PSC_NONE); else StartInverse(); draw_radio_prompt(real_line, RAD_BUT_COL, maxcol, q); break; } /* switch */ } out_of_loop: #ifdef _WINDOWS if(!cursor_shown) mswin_showcaret(0); #endif fs_give((void **) &q); if(ds) fs_give((void **) &ds); if(lastc){ (void) pico_set_colorp(lastc, PSC_NONE); free_color_pair(&lastc); if(promptc) free_color_pair(&promptc); } else EndInverse(); fflush(stdout); resume_busy_cue(0); if(km_popped){ FOOTER_ROWS(ps_global) = 1; clearfooter(ps_global); ps_global->mangled_body = 1; } return(ch); }
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); }
/* * pipe_callback - handle pine-specific pipe setup like child * signal handler and possibly any display stuff * BUG: this function should probably be in a "alpine/pipe.c" */ void pipe_callback(PIPE_S *syspipe, int flags, void *data) { #ifdef _WINDOWS bitmap_t bitmap; #endif if(flags & OSB_PRE_OPEN) { dprint((5, "Opening pipe: (%s%s%s%s%s%s)\n", (syspipe->mode & PIPE_WRITE) ? "W":"", (syspipe->mode & PIPE_READ) ? "R":"", (syspipe->mode & PIPE_NOSHELL) ? "N":"", (syspipe->mode & PIPE_PROT) ? "P":"", (syspipe->mode & PIPE_USER) ? "U":"", (syspipe->mode & PIPE_RESET) ? "T":"")); #ifdef _WINDOWS q_status_message(SM_ORDER, 0, 0, "Waiting for called program to finish..."); flush_status_messages(1); setbitmap(bitmap); draw_keymenu(&pipe_cancel_keymenu, bitmap, ps_global->ttyo->screen_cols, 1-FOOTER_ROWS(ps_global), 0, FirstMenu); #else /* UNIX */ if(!(syspipe->mode & (PIPE_WRITE | PIPE_READ)) && !(syspipe->mode & PIPE_SILENT)) { flush_status_messages(0); /* just clean up display */ ClearScreen(); fflush(stdout); } if(syspipe->mode & PIPE_RESET) ttyfix(0); #ifdef SIGCHLD /* * Prepare for demise of child. Use SIGCHLD if it's available so * we can do useful things, like keep the IMAP stream alive, while * we're waiting on the child. The handler may have been changed by * something in the composer, in particular, by an alt_editor call. * So we need to re-set it to child_signal and then set it back * when we're done. */ child_signalled = child_jump = 0; syspipe->chld = signal(SIGCHLD, child_signal); #endif #endif /* UNIX */ } else if(flags & OSB_POST_OPEN) { #ifdef _WINDOWS clearfooter(ps_global); ps_global->mangled_footer = 1; if((int) data == -2) q_status_message1(SM_ORDER, 2, 3, "Ignoring completion of %s", syspipe->command); #else /* UNIX */ if(!(syspipe->mode & (PIPE_WRITE | PIPE_READ)) && !(syspipe->mode & PIPE_SILENT)) { ClearScreen(); ps_global->mangled_screen = 1; } if(syspipe->mode & PIPE_RESET) ttyfix(1); #ifdef SIGCHLD (void) signal(SIGCHLD, SIG_DFL); #endif #endif /* UNIX */ } else if(flags & OSB_PRE_CLOSE) { #ifdef SIGCHLD /* * this is here so close_system_pipe so it has something * to do while we're waiting on the other end of the * pipe to complete. When we're in the background for * a shell, the the side effect is pinging */ RETSIGTYPE (*alarm_sig)(); int old_cue = F_ON(F_SHOW_DELAY_CUE, ps_global); /* * remember the current SIGALRM handler, and make sure it's * installed when we're finished just in case the longjmp * out of the SIGCHLD handler caused sleep() to lose it. * Don't pay any attention to that man behind the curtain. */ alarm_sig = signal(SIGALRM, SIG_IGN); (void) F_SET(F_SHOW_DELAY_CUE, ps_global, 0); ps_global->noshow_timeout = 1; while(!child_signalled) { /* wake up and prod server */ if(!(syspipe->mode & PIPE_NONEWMAIL)) new_mail(0, 2, (syspipe->mode & PIPE_RESET) ? NM_NONE : NM_DEFER_SORT); if(!child_signalled) { if(setjmp(child_state) == 0) { child_jump = 1; /* prepare to wake up */ sleep(600); /* give it 5mins to happend */ } else our_sigunblock(SIGCHLD); } child_jump = 0; } ps_global->noshow_timeout = 0; F_SET(F_SHOW_DELAY_CUE, ps_global, old_cue); (void) signal(SIGALRM, alarm_sig); (void) signal(SIGCHLD, syspipe->chld); #endif } else if(flags & OSB_POST_CLOSE) { if(syspipe->mode & PIPE_RESET) /* restore our tty modes */ ttyfix(1); if(!(syspipe->mode & (PIPE_WRITE | PIPE_READ | PIPE_SILENT))) { ClearScreen(); /* No I/O to forked child */ ps_global->mangled_screen = 1; } } }