summaryrefslogtreecommitdiff
path: root/alpine/osdep/termin.gen.c
diff options
context:
space:
mode:
Diffstat (limited to 'alpine/osdep/termin.gen.c')
-rw-r--r--alpine/osdep/termin.gen.c1252
1 files changed, 1252 insertions, 0 deletions
diff --git a/alpine/osdep/termin.gen.c b/alpine/osdep/termin.gen.c
new file mode 100644
index 00000000..fb106be1
--- /dev/null
+++ b/alpine/osdep/termin.gen.c
@@ -0,0 +1,1252 @@
+#if !defined(lint) && !defined(DOS)
+static char rcsid[] = "$Id: termin.gen.c 1025 2008-04-08 22:59:38Z 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 <system.h>
+#include <general.h>
+
+#include "../../c-client/mail.h" /* for MAILSTREAM and friends */
+#include "../../c-client/osdep.h"
+#include "../../c-client/rfc822.h" /* for soutr_t and such */
+#include "../../c-client/misc.h" /* for cpystr proto */
+#include "../../c-client/utf8.h" /* for CHARSET and such*/
+#include "../../c-client/imap4r1.h"
+
+#include "../../pith/osdep/color.h"
+
+#include "../../pith/charconv/utf8.h"
+
+#include "../../pith/debug.h"
+#include "../../pith/newmail.h"
+#include "../../pith/conf.h"
+#include "../../pith/busy.h"
+
+#include "../../pico/estruct.h"
+#include "../../pico/pico.h"
+#include "../../pico/keydefs.h"
+
+#include "../../pico/osdep/color.h"
+
+#include "../status.h"
+#include "../folder.h"
+#include "../keymenu.h"
+#include "../send.h"
+#include "../radio.h"
+#include "../busy.h"
+
+#ifdef _WINDOWS
+#include "../../pico/osdep/mswin.h"
+#include "termin.wnt.h"
+#include "termout.wnt.h"
+#else
+#include "termout.unx.h"
+#endif
+
+#include "termin.gen.h"
+#include "termout.gen.h"
+
+#include "../mailcmd.h"
+
+
+#ifdef _WINDOWS
+static int g_mc_row, g_mc_col;
+
+int pcpine_oe_cursor(int, long);
+#endif
+
+
+/*
+ * Generic tty input routines
+ */
+
+
+/*----------------------------------------------------------------------
+ Read a character from keyboard with timeout
+ Input: none
+
+ Result: Returns command read via read_char
+ Times out and returns a null command every so often
+
+ Calculates the timeout for the read, and does a few other house keeping
+things. The duration of the timeout is set in pine.c.
+ ----------------------------------------------------------------------*/
+UCS
+read_command(char **utf8str)
+{
+ int tm = 0, more_freq_timeo;
+ UCS ucs;
+ long dtime;
+ static unsigned char utf8buf[7];
+ unsigned char *newdestp;
+
+ /*
+ * timeo is the mail-check-interval. What we want to do (ignoring the
+ * messages_queued part) is timeout more often than timeo but only
+ * check for new mail every timeo or so seconds. The reason we want to
+ * timeout more often is so that we will have a chance to catch the user
+ * in an idle period where we can do a check_point(). Otherwise, with
+ * a default mail-check-interval, we are almost always calling newmail
+ * right after the user presses a key, making it the worst possible
+ * time to do a checkpoint.
+ */
+
+ more_freq_timeo = MIN(get_input_timeout(), IDLE_TIMEOUT);
+ if(more_freq_timeo == 0)
+ more_freq_timeo = IDLE_TIMEOUT;
+
+ cancel_busy_cue(-1);
+ tm = (messages_queued(&dtime) > 1) ? (int)dtime : more_freq_timeo;
+
+ if(utf8str)
+ *utf8str = NULL;
+
+ ucs = read_char(tm);
+ if(ucs != NO_OP_COMMAND && ucs != NO_OP_IDLE && ucs != KEY_RESIZE)
+ zero_new_mail_count();
+
+#ifdef BACKGROUND_POST
+ /*
+ * Any expired children to report on?
+ */
+ if(ps_global->post && ps_global->post->pid == 0){
+ int winner = 0;
+
+ if(ps_global->post->status < 0){
+ q_status_message(SM_ORDER | SM_DING, 3, 3, "Abysmal failure!");
+ }
+ else{
+ (void) pine_send_status(ps_global->post->status,
+ ps_global->post->fcc, tmp_20k_buf, SIZEOF_20KBUF,
+ &winner);
+ q_status_message(SM_ORDER | (winner ? 0 : SM_DING), 3, 3,
+ tmp_20k_buf);
+
+ }
+
+ if(!winner)
+ q_status_message(SM_ORDER, 0, 3,
+ "Re-send via \"Compose\" then \"Yes\" to \"Continue INTERRUPTED?\"");
+
+ if(ps_global->post->fcc)
+ fs_give((void **) &ps_global->post->fcc);
+
+ fs_give((void **) &ps_global->post);
+ }
+#endif
+
+ /*
+ * The character we get from read_char() is a UCS-4 char. Or it could be a special
+ * value like KEY_UP or NO_OP_IDLE or something similar. From here on out
+ * we're going to operate with UTF-8 internally. This is the point where we
+ * convert the UCS-4 input (actually whatever sort of input the user is typing
+ * was converted to UCS-4 first) to UTF-8. It's easy in this read_command
+ * case because if user types a non-ascii character as a command it's going to be
+ * an error. All commands are ascii. In order to present a reasonable error
+ * message we pass back the UTF-8 string to the caller.
+ */
+ if(ucs >= 0x80 && ucs < KEY_BASE){
+ /*
+ * User typed a character that is non-ascii. Convert it to
+ * UTF-8.
+ */
+ memset(utf8buf, 0, sizeof(utf8buf));
+ newdestp = utf8_put(utf8buf, (unsigned long) ucs);
+ if(newdestp - utf8buf > 1){ /* this should happen */
+ if(utf8str)
+ *utf8str = (char *) utf8buf;
+
+ dprint((9, "Read command: looks like user typed non-ascii command 0x%x %s: returning KEY_UTF8\n", ucs, pretty_command(ucs)));
+ ucs = KEY_UTF8;
+ }
+ else{
+ dprint((9, "Read command: looks like user typed unknown, non-ascii command 0x%x %s: returning KEY_UNKNOWN\n", ucs, pretty_command(ucs)));
+ ucs = KEY_UNKNOWN; /* best we can do, shouldn't happen */
+ }
+ }
+ else{
+ dprint((9, "Read command returning: 0x%x %s\n", ucs, pretty_command(ucs)));
+ }
+
+ return(ucs);
+}
+
+
+int
+read_command_prep()
+{
+ int i;
+ char *fname;
+ MAILSTREAM *m;
+
+ /*
+ * Before we sniff at the input queue, make sure no external event's
+ * changed our picture of the message sequence mapping. If so,
+ * recalculate the dang thing and run thru whatever processing loop
+ * we're in again...
+ */
+ for(i = 0; i < ps_global->s_pool.nstream; i++){
+ m = ps_global->s_pool.streams[i];
+ if(m && sp_flagged(m, SP_LOCKED) && sp_flagged(m, SP_USERFLDR)
+ && sp_expunge_count(m)){
+ fname = STREAMNAME(m);
+ q_status_message3(SM_ORDER, 3, 3,
+ "%s message%s expunged from folder \"%s\"",
+ long2string(sp_expunge_count(m)),
+ plural(sp_expunge_count(m)),
+ pretty_fn(fname));
+ sp_set_expunge_count(m, 0L);
+ display_message('x');
+ }
+ }
+
+ if(sp_mail_box_changed(ps_global->mail_stream)
+ && sp_new_mail_count(ps_global->mail_stream)){
+ dprint((2, "Noticed %ld new msgs! \n",
+ sp_new_mail_count(ps_global->mail_stream)));
+ return(FALSE); /* cycle thru so caller can update */
+ }
+
+ return(TRUE);
+}
+
+
+/*----------------------------------------------------------------------
+ Prompt user for a string in status line with various options
+
+ Args: utf8string -- the buffer result is returned in, and original string (if
+ any) is passed in.
+ y_base -- y position on screen to start on. 0,0 is upper left
+ negative numbers start from bottom
+ x_base -- column position on screen to start on. 0,0 is upper left
+ utf8string_size -- Length of utf8string buffer
+ utf8prompt -- The string to prompt with
+ escape_list -- pointer to array of ESCKEY_S's. input chars matching
+ those in list return value from list.
+ help -- Array of strings for help text in bottom screen lines
+ flags -- pointer (because some are return values) to flags
+ OE_USER_MODIFIED - Set on return if user modified buffer
+ OE_DISALLOW_CANCEL - No cancel in menu.
+ OE_DISALLOW_HELP - No help in menu.
+ OE_KEEP_TRAILING_SPACE - Allow trailing space.
+ OE_SEQ_SENSITIVE - Caller is sensitive to sequence
+ number changes.
+ OE_APPEND_CURRENT - String should not be truncated
+ before accepting user input.
+ OE_PASSWD - Don't echo on screen.
+
+ Result: editing input string
+ returns -1 unexpected errors
+ returns 0 normal entry typed (editing and return or PF2)
+ returns 1 typed ^C or PF2 (cancel)
+ returns 3 typed ^G or PF1 (help)
+ returns 4 typed ^L for a screen redraw
+
+ WARNING: Care is required with regard to the escape_list processing.
+ The passed array is terminated with an entry that has ch = -1.
+ Function key labels and key strokes need to be setup externally!
+ Traditionally, a return value of 2 is used for ^T escapes.
+
+ Unless in escape_list, tabs are trapped by isprint().
+This allows near full weemacs style editing in the line
+ ^A beginning of line
+ ^E End of line
+ ^R Redraw line
+ ^G Help
+ ^F forward
+ ^B backward
+ ^D delete
+----------------------------------------------------------------------*/
+
+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);
+}
+
+
+/*----------------------------------------------------------------------
+ Check to see if the given command is reasonably valid
+
+ Args: ch -- the character to check
+
+ Result: A valid command is returned, or a well know bad command is returned.
+
+ ---*/
+UCS
+validatekeys(UCS ch)
+{
+ if(F_ON(F_USE_FK,ps_global)){
+ if(ch >= 'a' && ch <= 'z')
+ return(KEY_JUNK);
+ }
+ else{
+ if(ch >= PF1 && ch <= PF12)
+ return(KEY_JUNK);
+ }
+
+ return(ch);
+}
+
+
+
+/*----------------------------------------------------------------------
+ Prepend config'd commands to keyboard input
+
+ Args: ch -- pointer to storage for returned command
+
+ Returns: TRUE if we're passing back a useful command, FALSE otherwise
+
+ ---*/
+int
+process_config_input(UCS *ch)
+{
+ static char firsttime = (char) 1;
+ int c;
+ unsigned long octets_so_far, remaining_octets, ret = 0;
+ unsigned char *inputp;
+ UCS ucs;
+ unsigned char inputbuf[20];
+
+ /* commands in config file */
+ if(ps_global->initial_cmds && *ps_global->initial_cmds) {
+ /*
+ * There are a few commands that may require keyboard input before
+ * we enter the main command loop. That input should be interactive,
+ * not from our list of initial keystrokes.
+ */
+ if(ps_global->dont_use_init_cmds)
+ return(ret);
+
+ c = *ps_global->initial_cmds++;
+
+ /*
+ * Use enough bytes to make up a character and convert it to UCS-4.
+ */
+ if(c < 0x80 || c > KEY_BASE){
+ *ch = (UCS) c;
+ ret = 1;
+ }
+ else{
+ memset(inputbuf, 0, sizeof(inputbuf));
+ inputbuf[0] = (0xff & c);
+ octets_so_far = 1;
+
+ while(!ret){
+ remaining_octets = octets_so_far;
+ inputp = inputbuf;
+ ucs = (UCS) utf8_get(&inputp, &remaining_octets);
+ switch(ucs){
+ case U8G_ENDSTRG: /* incomplete character, wait */
+ case U8G_ENDSTRI: /* incomplete character, wait */
+ if(!*ps_global->initial_cmds || octets_so_far >= sizeof(inputbuf)){
+ *ch = BADESC;
+ ret = 1;
+ }
+ else
+ inputbuf[octets_so_far++] = (0xff & *ps_global->initial_cmds++);
+
+ break;
+
+ default:
+ if(ucs & U8G_ERROR || ucs == UBOGON)
+ *ch = BADESC;
+ else
+ *ch = ucs;
+
+ ret = 1;
+ break;
+ }
+ }
+ }
+
+ if(!*ps_global->initial_cmds && ps_global->free_initial_cmds){
+ fs_give((void **) &ps_global->free_initial_cmds);
+ ps_global->initial_cmds = NULL;
+ }
+
+ return(ret);
+ }
+
+ if(firsttime) {
+ firsttime = 0;
+ if(ps_global->in_init_seq) {
+ ps_global->in_init_seq = 0;
+ ps_global->save_in_init_seq = 0;
+ clear_cursor_pos();
+ F_SET(F_USE_FK,ps_global,ps_global->orig_use_fkeys);
+ /* draw screen */
+ *ch = (UCS) ctrl('L');
+ return(1);
+ }
+ }
+
+ return(0);
+}
+
+
+#define TAPELEN 256
+static int tape[TAPELEN];
+static long recorded = 0L;
+static short length = 0;
+
+
+/*
+ * record user keystrokes
+ *
+ * Args: ch -- the character to record
+ *
+ * Returns: character recorded
+ */
+int
+key_recorder(int ch)
+{
+ tape[recorded++ % TAPELEN] = ch;
+ if(length < TAPELEN)
+ length++;
+
+ return(ch);
+}
+
+
+/*
+ * playback user keystrokes
+ *
+ * Args: ch -- ignored
+ *
+ * Returns: character played back or -1 to indicate end of tape
+ */
+int
+key_playback(int ch)
+{
+ ch = length ? tape[(recorded + TAPELEN - length--) % TAPELEN] : -1;
+ return(ch);
+}
+
+
+/*
+ * recent_keystroke - verbose version of key_playback
+ */
+int
+recent_keystroke(int *cv, char *cs, size_t cslen)
+{
+ int c;
+
+ if((c = key_playback(0)) != -1){
+ *cv = c;
+ snprintf(cs, cslen, "%.32s", pretty_command(c));
+ return(0);
+ }
+
+ return(-1);
+}
+
+
+#ifdef _WINDOWS
+int
+pcpine_oe_cursor(col, row)
+ int col;
+ long row;
+{
+ return((row == g_mc_row
+ && col >= g_mc_col
+ && col < ps_global->ttyo->screen_cols)
+ ? MSWIN_CURSOR_IBEAM
+ : MSWIN_CURSOR_ARROW);
+}
+#endif