1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: termin.gen.c 1025 2008-04-08 22:59:38Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2006-2008 University of Washington
8 * Copyright 2013-2017 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
21 #include "../../c-client/mail.h" /* for MAILSTREAM and friends */
22 #include "../../c-client/osdep.h"
23 #include "../../c-client/rfc822.h" /* for soutr_t and such */
24 #include "../../c-client/misc.h" /* for cpystr proto */
25 #include "../../c-client/utf8.h" /* for CHARSET and such*/
26 #include "../../c-client/imap4r1.h"
28 #include "../../pith/osdep/color.h"
30 #include "../../pith/charconv/utf8.h"
32 #include "../../pith/debug.h"
33 #include "../../pith/newmail.h"
34 #include "../../pith/conf.h"
35 #include "../../pith/busy.h"
37 #include "../../pico/estruct.h"
38 #include "../../pico/pico.h"
39 #include "../../pico/keydefs.h"
41 #include "../../pico/osdep/color.h"
43 #include "../status.h"
44 #include "../folder.h"
45 #include "../keymenu.h"
51 #include "../../pico/osdep/mswin.h"
52 #include "termin.wnt.h"
53 #include "termout.wnt.h"
55 #include "termout.unx.h"
58 #include "termin.gen.h"
59 #include "termout.gen.h"
61 #include "../mailcmd.h"
65 static int g_mc_row
, g_mc_col
;
67 int pcpine_oe_cursor(int, long);
72 * Generic tty input routines
76 /*----------------------------------------------------------------------
77 Read a character from keyboard with timeout
80 Result: Returns command read via read_char
81 Times out and returns a null command every so often
83 Calculates the timeout for the read, and does a few other house keeping
84 things. The duration of the timeout is set in pine.c.
85 ----------------------------------------------------------------------*/
87 read_command(char **utf8str
)
89 int tm
= 0, more_freq_timeo
;
92 static unsigned char utf8buf
[7];
93 unsigned char *newdestp
;
96 * timeo is the mail-check-interval. What we want to do (ignoring the
97 * messages_queued part) is timeout more often than timeo but only
98 * check for new mail every timeo or so seconds. The reason we want to
99 * timeout more often is so that we will have a chance to catch the user
100 * in an idle period where we can do a check_point(). Otherwise, with
101 * a default mail-check-interval, we are almost always calling newmail
102 * right after the user presses a key, making it the worst possible
103 * time to do a checkpoint.
106 more_freq_timeo
= MIN(get_input_timeout(), IDLE_TIMEOUT
);
107 if(more_freq_timeo
== 0)
108 more_freq_timeo
= IDLE_TIMEOUT
;
111 tm
= (messages_queued(&dtime
) > 1) ? (int)dtime
: more_freq_timeo
;
117 if(ucs
!= NO_OP_COMMAND
&& ucs
!= NO_OP_IDLE
&& ucs
!= KEY_RESIZE
)
118 zero_new_mail_count();
120 #ifdef BACKGROUND_POST
122 * Any expired children to report on?
124 if(ps_global
->post
&& ps_global
->post
->pid
== 0){
127 if(ps_global
->post
->status
< 0){
128 q_status_message(SM_ORDER
| SM_DING
, 3, 3, "Abysmal failure!");
131 (void) pine_send_status(ps_global
->post
->status
,
132 ps_global
->post
->fcc
, tmp_20k_buf
, SIZEOF_20KBUF
,
134 q_status_message(SM_ORDER
| (winner
? 0 : SM_DING
), 3, 3,
140 q_status_message(SM_ORDER
, 0, 3,
141 "Re-send via \"Compose\" then \"Yes\" to \"Continue INTERRUPTED?\"");
143 if(ps_global
->post
->fcc
)
144 fs_give((void **) &ps_global
->post
->fcc
);
146 fs_give((void **) &ps_global
->post
);
151 * The character we get from read_char() is a UCS-4 char. Or it could be a special
152 * value like KEY_UP or NO_OP_IDLE or something similar. From here on out
153 * we're going to operate with UTF-8 internally. This is the point where we
154 * convert the UCS-4 input (actually whatever sort of input the user is typing
155 * was converted to UCS-4 first) to UTF-8. It's easy in this read_command
156 * case because if user types a non-ascii character as a command it's going to be
157 * an error. All commands are ascii. In order to present a reasonable error
158 * message we pass back the UTF-8 string to the caller.
160 if(ucs
>= 0x80 && ucs
< KEY_BASE
){
162 * User typed a character that is non-ascii. Convert it to
165 memset(utf8buf
, 0, sizeof(utf8buf
));
166 newdestp
= utf8_put(utf8buf
, (unsigned long) ucs
);
167 if(newdestp
- utf8buf
> 1){ /* this should happen */
169 *utf8str
= (char *) utf8buf
;
171 dprint((9, "Read command: looks like user typed non-ascii command 0x%x %s: returning KEY_UTF8\n", ucs
, pretty_command(ucs
)));
175 dprint((9, "Read command: looks like user typed unknown, non-ascii command 0x%x %s: returning KEY_UNKNOWN\n", ucs
, pretty_command(ucs
)));
176 ucs
= KEY_UNKNOWN
; /* best we can do, shouldn't happen */
180 dprint((9, "Read command returning: 0x%x %s\n", ucs
, pretty_command(ucs
)));
195 * Before we sniff at the input queue, make sure no external event's
196 * changed our picture of the message sequence mapping. If so,
197 * recalculate the dang thing and run thru whatever processing loop
200 for(i
= 0; i
< ps_global
->s_pool
.nstream
; i
++){
201 m
= ps_global
->s_pool
.streams
[i
];
202 if(m
&& sp_flagged(m
, SP_LOCKED
) && sp_flagged(m
, SP_USERFLDR
)
203 && sp_expunge_count(m
)){
204 fname
= STREAMNAME(m
);
205 q_status_message3(SM_ORDER
, 3, 3,
206 "%s message%s expunged from folder \"%s\"",
207 long2string(sp_expunge_count(m
)),
208 plural(sp_expunge_count(m
)),
210 sp_set_expunge_count(m
, 0L);
211 display_message('x');
215 if(sp_mail_box_changed(ps_global
->mail_stream
)
216 && sp_new_mail_count(ps_global
->mail_stream
)){
217 dprint((2, "Noticed %ld new msgs! \n",
218 sp_new_mail_count(ps_global
->mail_stream
)));
219 return(FALSE
); /* cycle thru so caller can update */
226 /*----------------------------------------------------------------------
227 Prompt user for a string in status line with various options
229 Args: utf8string -- the buffer result is returned in, and original string (if
231 y_base -- y position on screen to start on. 0,0 is upper left
232 negative numbers start from bottom
233 x_base -- column position on screen to start on. 0,0 is upper left
234 utf8string_size -- Length of utf8string buffer
235 utf8prompt -- The string to prompt with
236 escape_list -- pointer to array of ESCKEY_S's. input chars matching
237 those in list return value from list.
238 help -- Array of strings for help text in bottom screen lines
239 flags -- pointer (because some are return values) to flags
240 OE_USER_MODIFIED - Set on return if user modified buffer
241 OE_DISALLOW_CANCEL - No cancel in menu.
242 OE_DISALLOW_HELP - No help in menu.
243 OE_KEEP_TRAILING_SPACE - Allow trailing space.
244 OE_SEQ_SENSITIVE - Caller is sensitive to sequence
246 OE_APPEND_CURRENT - String should not be truncated
247 before accepting user input.
248 OE_PASSWD - Don't echo on screen.
250 Result: editing input string
251 returns -1 unexpected errors
252 returns 0 normal entry typed (editing and return or PF2)
253 returns 1 typed ^C or PF2 (cancel)
254 returns 3 typed ^G or PF1 (help)
255 returns 4 typed ^L for a screen redraw
257 WARNING: Care is required with regard to the escape_list processing.
258 The passed array is terminated with an entry that has ch = -1.
259 Function key labels and key strokes need to be setup externally!
260 Traditionally, a return value of 2 is used for ^T escapes.
262 Unless in escape_list, tabs are trapped by isprint().
263 This allows near full weemacs style editing in the line
271 ----------------------------------------------------------------------*/
274 optionally_enter(char *utf8string
, int y_base
, int x_base
, int utf8string_size
,
275 char *utf8prompt
, ESCKEY_S
*escape_list
, HelpType help
, int *flags
)
277 UCS
*string
= NULL
, ucs
;
280 UCS
*saved_original
= NULL
;
282 UCS
*kill_buffer
= NULL
;
284 int field_pos
; /* offset into array dline.vl */
285 int i
, j
, return_v
, cols
, prompt_width
, too_thin
,
286 real_y_base
, km_popped
, passwd
;
291 COLOR_PAIR
*lastc
= NULL
, *promptc
= NULL
;
292 struct variable
*vars
= ps_global
->vars
;
293 struct display_line dline
;
298 dprint((5, "=== optionally_enter called ===\n"));
299 dprint((9, "utf8string:\"%s\" y:%d x:%d length: %d append: %d\n",
300 utf8string
? utf8string
: "",
301 x_base
, y_base
, utf8string_size
,
302 (flags
&& *flags
& OE_APPEND_CURRENT
)));
303 dprint((9, "passwd:%d utf8prompt:\"%s\" label:\"%s\"\n",
304 (flags
&& *flags
& OE_PASSWD_NOAST
) ? 10 :
305 (flags
&& *flags
& OE_PASSWD
) ? 1 : 0,
306 utf8prompt
? utf8prompt
: "",
307 (escape_list
&& escape_list
[0].ch
!= -1 && escape_list
[0].label
)
308 ? escape_list
[0].label
: ""));
311 return(pre_screen_config_opt_enter(utf8string
, utf8string_size
, utf8prompt
,
312 escape_list
, help
, flags
));
315 if (mswin_usedialog ())
316 return(win_dialog_opt_enter(utf8string
, utf8string_size
, utf8prompt
,
317 escape_list
, help
, flags
));
322 * Utf8string comes in as UTF-8. We'll convert it to a UCS-4 array and operate on
323 * that array, then convert it back before returning. Utf8string_size is the size
324 * of the utf8string array but that doesn't help us much for the array we need to
325 * operate on here. We'll just allocate a big array and then cut it off when
328 * This should come before the specialized calls above but those aren't
329 * converted to use UCS-4 yet.
331 string
= utf8_to_ucs4_cpystr(utf8string
);
332 dline
.vused
= ucs4_strlen(string
);
334 string_size
= (2 * MAX(utf8string_size
,dline
.vused
) + 100);
335 fs_resize((void **) &string
, string_size
* sizeof(UCS
));
338 cols
= ps_global
->ttyo
->screen_cols
;
339 prompt_width
= utf8_width(utf8prompt
);
343 real_y_base
= y_base
;
345 real_y_base
= y_base
+ ps_global
->ttyo
->screen_rows
;
346 real_y_base
= MAX(real_y_base
, 0);
349 flush_ordered_messages();
352 if(flags
&& *flags
& OE_APPEND_CURRENT
) /* save a copy in case of cancel */
353 saved_original
= ucs4_cpystr(string
);
356 * build the function key mapping table, skipping predefined keys...
358 memset(fkey_table
, NO_OP_COMMAND
, 12 * sizeof(long));
359 for(i
= 0, j
= 0; escape_list
&& escape_list
[i
].ch
!= -1 && i
+j
< 12; i
++){
360 if(i
+j
== OE_HELP_KEY
)
363 if(i
+j
== OE_CANCEL_KEY
)
366 if(i
+j
== OE_ENTER_KEY
)
369 fkey_table
[i
+j
] = escape_list
[i
].ch
;
372 /* assumption that HelpType is char ** */
374 if(help_text
){ /*---- Show help text -----*/
375 int width
= ps_global
->ttyo
->screen_cols
- x_base
;
377 if(FOOTER_ROWS(ps_global
) == 1){
379 FOOTER_ROWS(ps_global
) = 3;
380 clearfooter(ps_global
);
383 real_y_base
= y_base
+ ps_global
->ttyo
->screen_rows
;
386 for(j
= 0; j
< 2 && help_text
[j
]; j
++){
387 MoveCursor(real_y_base
+ 1 + j
, x_base
);
390 if(width
< utf8_width(help_text
[j
])){
391 char *tmp
= cpystr(help_text
[j
]);
392 (void) utf8_truncate(tmp
, width
);
393 PutLine0(real_y_base
+ 1 + j
, x_base
, tmp
);
394 fs_give((void **) &tmp
);
397 PutLine0(real_y_base
+ 1 + j
, x_base
, help_text
[j
]);
402 clrbitmap((km
= &oe_keymenu
)->bitmap
); /* force formatting */
403 if(!(flags
&& (*flags
) & OE_DISALLOW_HELP
))
404 setbitn(OE_HELP_KEY
, bitmap
);
406 setbitn(OE_ENTER_KEY
, bitmap
);
407 if(!(flags
&& (*flags
) & OE_DISALLOW_CANCEL
))
408 setbitn(OE_CANCEL_KEY
, bitmap
);
410 setbitn(OE_CTRL_T_KEY
, bitmap
);
412 /*---- Show the usual possible keys ----*/
413 for(i
=0,j
=0; escape_list
&& escape_list
[i
].ch
!= -1 && i
+j
< 12; i
++){
414 if(i
+j
== OE_HELP_KEY
)
417 if(i
+j
== OE_CANCEL_KEY
)
420 if(i
+j
== OE_ENTER_KEY
)
423 oe_keymenu
.keys
[i
+j
].label
= escape_list
[i
].label
;
424 oe_keymenu
.keys
[i
+j
].name
= escape_list
[i
].name
;
425 setbitn(i
+j
, bitmap
);
428 for(i
= i
+j
; i
< 12; i
++)
429 if(!(i
== OE_HELP_KEY
|| i
== OE_ENTER_KEY
|| i
== OE_CANCEL_KEY
))
430 oe_keymenu
.keys
[i
].name
= NULL
;
432 draw_keymenu(km
, bitmap
, cols
, 1-FOOTER_ROWS(ps_global
), 0, FirstMenu
);
435 if(pico_usingcolor() && VAR_PROMPT_FORE_COLOR
&&
436 VAR_PROMPT_BACK_COLOR
&&
437 pico_is_good_color(VAR_PROMPT_FORE_COLOR
) &&
438 pico_is_good_color(VAR_PROMPT_BACK_COLOR
)){
439 lastc
= pico_get_cur_color();
441 promptc
= new_color_pair(VAR_PROMPT_FORE_COLOR
,
442 VAR_PROMPT_BACK_COLOR
);
443 (void)pico_set_colorp(promptc
, PSC_NONE
);
450 * if display length isn't wide enough to support input,
451 * shorten up the prompt...
453 if((dline
.dwid
= cols
- (x_base
+ prompt_width
)) < MIN_OPT_ENT_WIDTH
){
458 * Scoot prompt pointer forward at least (MIN_OPT_ENT_WIDTH - dline.dwid) screencells.
460 p
= utf8_count_forw_width(utf8prompt
, MIN_OPT_ENT_WIDTH
-dline
.dwid
, &got_width
);
461 if(got_width
< MIN_OPT_ENT_WIDTH
-dline
.dwid
)
462 p
= utf8_count_forw_width(utf8prompt
, MIN_OPT_ENT_WIDTH
+1-dline
.dwid
, &got_width
);
465 prompt_width
= utf8_width(p
);
466 dline
.dwid
= cols
- (x_base
+ prompt_width
);
472 * How many UCS-4 characters will we need to make up the width dwid? It could be
473 * unlimited because of zero-width characters, I suppose, but realistically it
474 * isn't going to be much more than dwid.
476 dline
.dlen
= 2 * dline
.dwid
+ 100;
478 dline
.dl
= (UCS
*) fs_get(dline
.dlen
* sizeof(UCS
));
479 dline
.olddl
= (UCS
*) fs_get(dline
.dlen
* sizeof(UCS
));
480 memset(dline
.dl
, 0, dline
.dlen
* sizeof(UCS
));
481 memset(dline
.olddl
, 0, dline
.dlen
* sizeof(UCS
));
483 dline
.movecursor
= MoveCursor
;
484 dline
.writechar
= Writewchar
;
486 dline
.row
= real_y_base
;
487 dline
.col
= x_base
+ prompt_width
;
490 dline
.vlen
= --string_size
; /* -1 for terminating zero */
491 dline
.vbase
= field_pos
= 0;
494 cursor_shown
= mswin_showcaret(1);
497 PutLine0(real_y_base
, x_base
, utf8prompt
);
500 * If appending, position field_pos at end of input.
502 if(flags
&& *flags
& OE_APPEND_CURRENT
)
503 while(string
[field_pos
])
506 passwd
= (flags
&& *flags
& OE_PASSWD_NOAST
) ? 10 :
507 (flags
&& *flags
& OE_PASSWD
) ? 1 : 0;
508 line_paint(field_pos
, &dline
, &passwd
);
510 /*----------------------------------------------------------------------
512 loops until someone sets the return_v.
513 ----------------------------------------------------------------------*/
516 while(return_v
== -10) {
519 mouse_in_content(KEY_MOUSE
, -1, -1, 0x5, 0);
520 register_mfunc(mouse_in_content
,
521 real_y_base
, x_base
+ prompt_width
,
522 real_y_base
, ps_global
->ttyo
->screen_cols
);
525 mswin_allowpaste(MSWIN_PASTE_LINE
);
526 g_mc_row
= real_y_base
;
527 g_mc_col
= x_base
+ prompt_width
;
528 mswin_mousetrackcallback(pcpine_oe_cursor
);
531 /* Timeout 10 min to keep imap mail stream alive */
532 ps_global
->conceal_sensitive_debugging
= passwd
? 1 : 0;
533 ucs
= read_char(600);
534 ps_global
->conceal_sensitive_debugging
= 0;
537 clear_mfunc(mouse_in_content
);
540 mswin_allowpaste(MSWIN_PASTE_DISABLE
);
541 mswin_mousetrackcallback(NULL
);
545 * Don't want to intercept all characters if typing in passwd.
546 * We select an ad hoc set that we will catch and let the rest
547 * through. We would have caught the set below in the big switch
548 * but we skip the switch instead. Still catch things like ^K,
549 * DELETE, ^C, RETURN.
566 if(too_thin
&& ucs
!= KEY_RESIZE
&& ucs
!= ctrl('Z') && ucs
!= ctrl('C'))
571 /*--------------- KEY RIGHT ---------------*/
574 if(field_pos
>= string_size
|| string
[field_pos
] == '\0')
577 line_paint(++field_pos
, &dline
, &passwd
);
580 /*--------------- KEY LEFT ---------------*/
586 line_paint(--field_pos
, &dline
, &passwd
);
589 /*-------------------- WORD SKIP --------------------*/
592 * Note: read_char *can* return NO_OP_COMMAND which is
593 * the def'd with the same value as ^@ (NULL), BUT since
594 * read_char has a big timeout (>25 secs) it won't.
597 /* skip thru current word */
598 while(string
[field_pos
]
599 && isalnum((unsigned char) string
[field_pos
]))
602 /* skip thru current white space to next word */
603 while(string
[field_pos
]
604 && !isalnum((unsigned char) string
[field_pos
]))
607 line_paint(field_pos
, &dline
, &passwd
);
610 /*-------------------- RETURN --------------------*/
612 if(F_OFF(F_USE_FK
,ps_global
)) goto bleep
;
618 /*-------------------- Destructive backspace --------------------*/
619 case '\177': /* DEL */
621 /* Try and do this with by telling the terminal to delete a
622 a character. If that fails, then repaint the rest of the
623 line, acheiving the same much less efficiently
629 /* drop thru to pull line back ... */
631 /*-------------------- Delete char --------------------*/
634 if(field_pos
>= string_size
|| !string
[field_pos
])
638 for(s2
= &string
[field_pos
]; *s2
!= 0; s2
++)
641 *s2
= 0; /* Copy last NULL */
642 line_paint(field_pos
, &dline
, &passwd
);
643 if(flags
) /* record change if requested */
644 *flags
|= OE_USER_MODIFIED
;
648 /*--------------- Kill line -----------------*/
650 if(kill_buffer
!= NULL
)
651 fs_give((void **) &kill_buffer
);
653 if(field_pos
!= 0 || string
[0]){
654 if(!passwd
&& F_ON(F_DEL_FROM_DOT
, ps_global
))
655 dline
.vused
-= ucs4_strlen(&string
[i
= field_pos
]);
659 kill_buffer
= ucs4_cpystr(&string
[field_pos
= i
]);
660 string
[field_pos
] = '\0';
661 line_paint(field_pos
, &dline
, &passwd
);
662 if(flags
) /* record change if requested */
663 *flags
|= OE_USER_MODIFIED
;
668 /*------------------- Undelete line --------------------*/
670 if(kill_buffer
== NULL
)
673 /* Make string so it will fit */
674 kb
= ucs4_cpystr(kill_buffer
);
675 if(ucs4_strlen(kb
) + ucs4_strlen(string
) > string_size
)
676 kb
[string_size
- ucs4_strlen(string
)] = '\0';
678 if(string
[field_pos
] == '\0') {
679 /*--- adding to the end of the string ----*/
681 string
[field_pos
++] = *k
;
683 string
[field_pos
] = '\0';
688 shift
= ucs4_strlen(kb
);
690 /* shift field_pos ... end to right */
691 for(k
= &string
[field_pos
] + ucs4_strlen(&string
[field_pos
]);
692 k
>= &string
[field_pos
]; k
--)
696 string
[field_pos
++] = *k
;
699 if(*kb
&& flags
) /* record change if requested */
700 *flags
|= OE_USER_MODIFIED
;
702 dline
.vused
= ucs4_strlen(string
);
703 fs_give((void **) &kb
);
704 line_paint(field_pos
, &dline
, &passwd
);
707 /*-------------------- Interrupt --------------------*/
708 case ctrl('C'): /* ^C */
709 if(F_ON(F_USE_FK
,ps_global
) || (flags
&& ((*flags
) & OE_DISALLOW_CANCEL
)))
715 if(F_OFF(F_USE_FK
,ps_global
) || (flags
&& ((*flags
) & OE_DISALLOW_CANCEL
)))
721 for(i
= 0; saved_original
[i
]; i
++)
722 string
[i
] = saved_original
[i
];
731 /*-------------------- Start of line -------------*/
732 line_paint(field_pos
= 0, &dline
, &passwd
);
737 /*-------------------- End of line ---------------*/
738 line_paint(field_pos
= dline
.vused
, &dline
, &passwd
);
741 /*-------------------- Help --------------------*/
744 if(flags
&& ((*flags
) & OE_DISALLOW_HELP
))
746 else if(FOOTER_ROWS(ps_global
) == 1 && km_popped
== 0){
748 FOOTER_ROWS(ps_global
) = 3;
749 clearfooter(ps_global
);
751 (void)pico_set_colorp(lastc
, PSC_NONE
);
755 draw_keymenu(km
, bitmap
, cols
, 1-FOOTER_ROWS(ps_global
),
759 (void)pico_set_colorp(promptc
, PSC_NONE
);
763 mark_keymenu_dirty();
765 dline
.row
= real_y_base
= y_base
+ ps_global
->ttyo
->screen_rows
;
766 PutLine0(real_y_base
, x_base
, utf8prompt
);
767 memset(dline
.dl
, 0, dline
.dlen
* sizeof(UCS
));
768 memset(dline
.olddl
, 0, dline
.dlen
* sizeof(UCS
));
769 line_paint(field_pos
, &dline
, &passwd
);
773 if(FOOTER_ROWS(ps_global
) > 1){
774 mark_keymenu_dirty();
784 /* Mouse support untested in pine 5.00 */
790 mouse_get_last (NULL
, &mp
);
793 case M_BUTTON_LEFT
: /* position cursor */
797 * We have to figure out which character is under the cursor.
798 * This is complicated by the fact that characters may
799 * be other than one cell wide.
802 /* the -1 is for the '<' when text is offscreen left */
803 w
= (dline
.vbase
> 0) ? mp
.col
-1 : mp
.col
;
806 field_pos
= dline
.vbase
- 1;
808 if(dline
.vused
<= dline
.vbase
809 || ucs4_str_width_a_to_b(dline
.vl
,dline
.vbase
,dline
.vused
-1) <= w
)
810 field_pos
= dline
.vused
;
813 * Find index of 1st character that causes the
817 ucs4_str_width_a_to_b(dline
.vl
,dline
.vbase
,dline
.vbase
+i
) <= w
;
821 field_pos
= dline
.vbase
+ i
;
825 field_pos
= MIN(MAX(field_pos
, 0), dline
.vused
);
827 /* just allow line_paint to choose vbase */
828 line_paint(field_pos
, &dline
, &passwd
);
831 case M_BUTTON_RIGHT
:
835 * Same as M_BUTTON_LEFT except we paste in text after
841 /* the -1 is for the '<' when text is offscreen left */
842 w
= (dline
.vbase
> 0) ? mp
.col
-1 : mp
.col
;
845 field_pos
= dline
.vbase
- 1;
847 if(dline
.vused
<= dline
.vbase
848 || ucs4_str_width_a_to_b(dline
.vl
,dline
.vbase
,dline
.vused
-1) <= w
)
849 field_pos
= dline
.vused
;
852 * Find index of 1st character that causes the
856 ucs4_str_width_a_to_b(dline
.vl
,dline
.vbase
,dline
.vbase
+i
) <= w
;
860 field_pos
= dline
.vbase
+ i
;
864 field_pos
= MIN(MAX(field_pos
, 0), dline
.vused
);
866 line_paint(field_pos
, &dline
, &passwd
);
868 mswin_allowpaste(MSWIN_PASTE_LINE
);
870 mswin_allowpaste(MSWIN_PASTE_DISABLE
);
874 case M_BUTTON_MIDDLE
: /* NO-OP for now */
875 default: /* just ignore */
886 * Keep mail stream alive by checking for new mail.
887 * If we're asking for a password in a login prompt
888 * we don't want to check for new_mail because the
889 * new mail check might be what got us here in the first
890 * place (because of a filter trying to save a message).
891 * If we need to wait for the user to come back then
892 * the caller will just have to deal with the failure
896 if(!ps_global
->no_newmail_check_from_optionally_enter
)
897 i
= new_mail(0, 2, NM_DEFER_SORT
);
899 if(sp_expunge_count(ps_global
->mail_stream
) &&
900 flags
&& ((*flags
) & OE_SEQ_SENSITIVE
))
904 line_paint(field_pos
, &dline
, &passwd
);
905 break; /* no changes, get on with life */
907 /* Else fall into redraw */
909 /*-------------------- Redraw --------------------*/
911 /*---------------- re size ----------------*/
914 dline
.row
= real_y_base
= y_base
> 0 ? y_base
:
915 y_base
+ ps_global
->ttyo
->screen_rows
;
917 (void)pico_set_colorp(lastc
, PSC_NONE
);
923 if(ps_global
->redrawer
!= (void (*)(void))NULL
)
924 (*ps_global
->redrawer
)();
928 (void)pico_set_colorp(promptc
, PSC_NONE
);
932 PutLine0(real_y_base
, x_base
, utf8prompt
);
933 cols
= ps_global
->ttyo
->screen_cols
;
935 if(cols
< x_base
+ prompt_width
+ 4){
937 PutLine0(real_y_base
, 0, "Screen's too thin. Ouch!");
941 dline
.col
= x_base
+ prompt_width
;
942 dline
.dwid
= cols
- (x_base
+ prompt_width
);
943 dline
.dlen
= 2 * dline
.dwid
+ 100;
944 fs_resize((void **) &dline
.dl
, (size_t) dline
.dlen
* sizeof(UCS
));
945 fs_resize((void **) &dline
.olddl
, (size_t) dline
.dlen
* sizeof(UCS
));
946 memset(dline
.dl
, 0, dline
.dlen
* sizeof(UCS
));
947 memset(dline
.olddl
, 0, dline
.dlen
* sizeof(UCS
));
948 line_paint(field_pos
, &dline
, &passwd
);
954 "optionally_enter RESIZE new_cols:%d too_thin: %d\n",
958 case PF3
: /* input to potentially remap */
967 if(F_ON(F_USE_FK
,ps_global
)
968 && fkey_table
[ucs
- PF1
] != NO_OP_COMMAND
)
969 ucs
= fkey_table
[ucs
- PF1
]; /* remap function key input */
972 if(escape_list
){ /* in the escape key list? */
973 for(j
=0; escape_list
[j
].ch
!= -1; j
++){
974 if(escape_list
[j
].ch
== ucs
){
975 return_v
= escape_list
[j
].rval
;
984 if(ucs
< 0x80 && FILTER_THIS((unsigned char) ucs
)){
991 /*--- Insert a character -----*/
992 if(dline
.vused
>= string_size
)
995 /*---- extending the length of the string ---*/
996 for(s2
= &string
[++dline
.vused
]; s2
- string
> field_pos
; s2
--)
999 string
[field_pos
++] = ucs
;
1000 line_paint(field_pos
, &dline
, &passwd
);
1001 if(flags
) /* record change if requested */
1002 *flags
|= OE_USER_MODIFIED
;
1004 } /*---- End of switch on char ----*/
1013 fs_give((void **) &dline
.dl
);
1016 fs_give((void **) &dline
.olddl
);
1019 fs_give((void **) &saved_original
);
1022 fs_give((void **) &kill_buffer
);
1025 * Change string back into UTF-8.
1027 candidate
= ucs4_to_utf8_cpystr(string
);
1030 fs_give((void **) &string
);
1033 strncpy(utf8string
, candidate
, utf8string_size
);
1034 utf8string
[utf8string_size
-1] = '\0';
1035 fs_give((void **) &candidate
);
1038 if (!(flags
&& (*flags
) & OE_KEEP_TRAILING_SPACE
))
1039 removing_trailing_white_space(utf8string
);
1042 (void)pico_set_colorp(lastc
, PSC_NONE
);
1043 free_color_pair(&lastc
);
1045 free_color_pair(&promptc
);
1050 MoveCursor(real_y_base
, x_base
); /* Move the cursor to show we're done */
1054 FOOTER_ROWS(ps_global
) = 1;
1055 clearfooter(ps_global
);
1056 ps_global
->mangled_body
= 1;
1063 /*----------------------------------------------------------------------
1064 Check to see if the given command is reasonably valid
1066 Args: ch -- the character to check
1068 Result: A valid command is returned, or a well know bad command is returned.
1072 validatekeys(UCS ch
)
1074 if(F_ON(F_USE_FK
,ps_global
)){
1075 if(ch
>= 'a' && ch
<= 'z')
1079 if(ch
>= PF1
&& ch
<= PF12
)
1088 /*----------------------------------------------------------------------
1089 Prepend config'd commands to keyboard input
1091 Args: ch -- pointer to storage for returned command
1093 Returns: TRUE if we're passing back a useful command, FALSE otherwise
1097 process_config_input(UCS
*ch
)
1099 static char firsttime
= (char) 1;
1101 unsigned long octets_so_far
, remaining_octets
, ret
= 0;
1102 unsigned char *inputp
;
1104 unsigned char inputbuf
[20];
1106 /* commands in config file */
1107 if(ps_global
->initial_cmds
&& *ps_global
->initial_cmds
) {
1109 * There are a few commands that may require keyboard input before
1110 * we enter the main command loop. That input should be interactive,
1111 * not from our list of initial keystrokes.
1113 if(ps_global
->dont_use_init_cmds
)
1116 c
= *ps_global
->initial_cmds
++;
1119 * Use enough bytes to make up a character and convert it to UCS-4.
1121 if(c
< 0x80 || c
> KEY_BASE
){
1126 memset(inputbuf
, 0, sizeof(inputbuf
));
1127 inputbuf
[0] = (0xff & c
);
1131 remaining_octets
= octets_so_far
;
1133 ucs
= (UCS
) utf8_get(&inputp
, &remaining_octets
);
1135 case U8G_ENDSTRG
: /* incomplete character, wait */
1136 case U8G_ENDSTRI
: /* incomplete character, wait */
1137 if(!*ps_global
->initial_cmds
|| octets_so_far
>= sizeof(inputbuf
)){
1142 inputbuf
[octets_so_far
++] = (0xff & *ps_global
->initial_cmds
++);
1147 if(ucs
& U8G_ERROR
|| ucs
== UBOGON
)
1158 if(!*ps_global
->initial_cmds
&& ps_global
->free_initial_cmds
){
1159 fs_give((void **) &ps_global
->free_initial_cmds
);
1160 ps_global
->initial_cmds
= NULL
;
1168 if(ps_global
->in_init_seq
) {
1169 ps_global
->in_init_seq
= 0;
1170 ps_global
->save_in_init_seq
= 0;
1172 F_SET(F_USE_FK
,ps_global
,ps_global
->orig_use_fkeys
);
1174 *ch
= (UCS
) ctrl('L');
1184 static int tape
[TAPELEN
];
1185 static long recorded
= 0L;
1186 static short length
= 0;
1190 * record user keystrokes
1192 * Args: ch -- the character to record
1194 * Returns: character recorded
1197 key_recorder(int ch
)
1199 tape
[recorded
++ % TAPELEN
] = ch
;
1200 if(length
< TAPELEN
)
1208 * playback user keystrokes
1210 * Args: ch -- ignored
1212 * Returns: character played back or -1 to indicate end of tape
1215 key_playback(int ch
)
1217 ch
= length
? tape
[(recorded
+ TAPELEN
- length
--) % TAPELEN
] : -1;
1223 * recent_keystroke - verbose version of key_playback
1226 recent_keystroke(int *cv
, char *cs
, size_t cslen
)
1230 if((c
= key_playback(0)) != -1){
1232 snprintf(cs
, cslen
, "%.32s", pretty_command(c
));
1242 pcpine_oe_cursor(col
, row
)
1246 return((row
== g_mc_row
1248 && col
< ps_global
->ttyo
->screen_cols
)
1249 ? MSWIN_CURSOR_IBEAM
1250 : MSWIN_CURSOR_ARROW
);