2 * ========================================================================
3 * Copyright 2006-2008 University of Washington
4 * Copyright 2013-2022 Eduardo Chappa
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
17 #include "../../c-client/mail.h" /* for MAILSTREAM and friends */
18 #include "../../c-client/osdep.h"
19 #include "../../c-client/rfc822.h" /* for soutr_t and such */
20 #include "../../c-client/misc.h" /* for cpystr proto */
21 #include "../../c-client/utf8.h" /* for CHARSET and such*/
22 #include "../../c-client/imap4r1.h"
24 #include "../../pith/osdep/color.h"
26 #include "../../pith/charconv/utf8.h"
28 #include "../../pith/debug.h"
29 #include "../../pith/newmail.h"
30 #include "../../pith/conf.h"
31 #include "../../pith/busy.h"
33 #include "../../pico/estruct.h"
34 #include "../../pico/pico.h"
35 #include "../../pico/keydefs.h"
37 #include "../../pico/osdep/color.h"
39 #include "../status.h"
40 #include "../folder.h"
41 #include "../keymenu.h"
47 #include "../../pico/osdep/mswin.h"
48 #include "termin.wnt.h"
49 #include "termout.wnt.h"
51 #include "termout.unx.h"
54 #include "termin.gen.h"
55 #include "termout.gen.h"
57 #include "../mailcmd.h"
61 static int g_mc_row
, g_mc_col
;
63 int pcpine_oe_cursor(int, long);
68 * Generic tty input routines
72 /*----------------------------------------------------------------------
73 Read a character from keyboard with timeout
76 Result: Returns command read via read_char
77 Times out and returns a null command every so often
79 Calculates the timeout for the read, and does a few other house keeping
80 things. The duration of the timeout is set in pine.c.
81 ----------------------------------------------------------------------*/
83 read_command(char **utf8str
)
85 int tm
= 0, more_freq_timeo
;
88 static unsigned char utf8buf
[7];
89 unsigned char *newdestp
;
92 * timeo is the mail-check-interval. What we want to do (ignoring the
93 * messages_queued part) is timeout more often than timeo but only
94 * check for new mail every timeo or so seconds. The reason we want to
95 * timeout more often is so that we will have a chance to catch the user
96 * in an idle period where we can do a check_point(). Otherwise, with
97 * a default mail-check-interval, we are almost always calling newmail
98 * right after the user presses a key, making it the worst possible
99 * time to do a checkpoint.
102 more_freq_timeo
= MIN(get_input_timeout(), IDLE_TIMEOUT
);
103 if(more_freq_timeo
== 0)
104 more_freq_timeo
= IDLE_TIMEOUT
;
107 tm
= (messages_queued(&dtime
) > 1) ? (int)dtime
: more_freq_timeo
;
113 if(ucs
!= NO_OP_COMMAND
&& ucs
!= NO_OP_IDLE
&& ucs
!= KEY_RESIZE
)
114 zero_new_mail_count();
116 #ifdef BACKGROUND_POST
118 * Any expired children to report on?
120 if(ps_global
->post
&& ps_global
->post
->pid
== 0){
123 if(ps_global
->post
->status
< 0){
124 q_status_message(SM_ORDER
| SM_DING
, 3, 3, "Abysmal failure!");
127 (void) pine_send_status(ps_global
->post
->status
,
128 ps_global
->post
->fcc
, tmp_20k_buf
, SIZEOF_20KBUF
,
130 q_status_message(SM_ORDER
| (winner
? 0 : SM_DING
), 3, 3,
136 q_status_message(SM_ORDER
, 0, 3,
137 "Re-send via \"Compose\" then \"Yes\" to \"Continue INTERRUPTED?\"");
139 if(ps_global
->post
->fcc
)
140 fs_give((void **) &ps_global
->post
->fcc
);
142 fs_give((void **) &ps_global
->post
);
147 * The character we get from read_char() is a UCS-4 char. Or it could be a special
148 * value like KEY_UP or NO_OP_IDLE or something similar. From here on out
149 * we're going to operate with UTF-8 internally. This is the point where we
150 * convert the UCS-4 input (actually whatever sort of input the user is typing
151 * was converted to UCS-4 first) to UTF-8. It's easy in this read_command
152 * case because if user types a non-ascii character as a command it's going to be
153 * an error. All commands are ascii. In order to present a reasonable error
154 * message we pass back the UTF-8 string to the caller.
156 if(ucs
>= 0x80 && ucs
< KEY_BASE
){
158 * User typed a character that is non-ascii. Convert it to
161 memset(utf8buf
, 0, sizeof(utf8buf
));
162 newdestp
= utf8_put(utf8buf
, (unsigned long) ucs
);
163 if(newdestp
- utf8buf
> 1){ /* this should happen */
165 *utf8str
= (char *) utf8buf
;
167 dprint((9, "Read command: looks like user typed non-ascii command 0x%x %s: returning KEY_UTF8\n", ucs
, pretty_command(ucs
)));
171 dprint((9, "Read command: looks like user typed unknown, non-ascii command 0x%x %s: returning KEY_UNKNOWN\n", ucs
, pretty_command(ucs
)));
172 ucs
= KEY_UNKNOWN
; /* best we can do, shouldn't happen */
176 dprint((9, "Read command returning: 0x%x %s\n", ucs
, pretty_command(ucs
)));
191 * Before we sniff at the input queue, make sure no external event's
192 * changed our picture of the message sequence mapping. If so,
193 * recalculate the dang thing and run thru whatever processing loop
196 for(i
= 0; i
< ps_global
->s_pool
.nstream
; i
++){
197 m
= ps_global
->s_pool
.streams
[i
];
198 if(m
&& sp_flagged(m
, SP_LOCKED
) && sp_flagged(m
, SP_USERFLDR
)
199 && sp_expunge_count(m
)){
200 fname
= STREAMNAME(m
);
201 q_status_message3(SM_ORDER
, 3, 3,
202 "%s message%s expunged from folder \"%s\"",
203 long2string(sp_expunge_count(m
)),
204 plural(sp_expunge_count(m
)),
206 sp_set_expunge_count(m
, 0L);
207 display_message('x');
211 if(sp_mail_box_changed(ps_global
->mail_stream
)
212 && sp_new_mail_count(ps_global
->mail_stream
)){
213 dprint((2, "Noticed %ld new msgs! \n",
214 sp_new_mail_count(ps_global
->mail_stream
)));
215 return(FALSE
); /* cycle thru so caller can update */
222 /*----------------------------------------------------------------------
223 Prompt user for a string in status line with various options
225 Args: utf8string -- the buffer result is returned in, and original string (if
227 y_base -- y position on screen to start on. 0,0 is upper left
228 negative numbers start from bottom
229 x_base -- column position on screen to start on. 0,0 is upper left
230 utf8string_size -- Length of utf8string buffer
231 utf8prompt -- The string to prompt with
232 escape_list -- pointer to array of ESCKEY_S's. input chars matching
233 those in list return value from list.
234 help -- Array of strings for help text in bottom screen lines
235 flags -- pointer (because some are return values) to flags
236 OE_USER_MODIFIED - Set on return if user modified buffer
237 OE_DISALLOW_CANCEL - No cancel in menu.
238 OE_DISALLOW_HELP - No help in menu.
239 OE_KEEP_TRAILING_SPACE - Allow trailing space.
240 OE_SEQ_SENSITIVE - Caller is sensitive to sequence
242 OE_APPEND_CURRENT - String should not be truncated
243 before accepting user input.
244 OE_PASSWD - Don't echo on screen.
246 Result: editing input string
247 returns -1 unexpected errors
248 returns 0 normal entry typed (editing and return or PF2)
249 returns 1 typed ^C or PF2 (cancel)
250 returns 3 typed ^G or PF1 (help)
251 returns 4 typed ^L for a screen redraw
253 WARNING: Care is required with regard to the escape_list processing.
254 The passed array is terminated with an entry that has ch = -1.
255 Function key labels and key strokes need to be setup externally!
256 Traditionally, a return value of 2 is used for ^T escapes.
258 Unless in escape_list, tabs are trapped by isprint().
259 This allows near full weemacs style editing in the line
267 ----------------------------------------------------------------------*/
270 optionally_enter(char *utf8string
, int y_base
, int x_base
, int utf8string_size
,
271 char *utf8prompt
, ESCKEY_S
*escape_list
, HelpType help
, int *flags
)
273 UCS
*string
= NULL
, ucs
;
276 UCS
*saved_original
= NULL
;
278 UCS
*kill_buffer
= NULL
;
280 int field_pos
; /* offset into array dline.vl */
281 int i
, j
, return_v
, cols
, prompt_width
, too_thin
,
282 real_y_base
, km_popped
, passwd
;
287 COLOR_PAIR
*lastc
= NULL
, *promptc
= NULL
;
288 struct variable
*vars
= ps_global
->vars
;
289 struct display_line dline
;
294 dprint((5, "=== optionally_enter called ===\n"));
295 dprint((9, "utf8string:\"%s\" y:%d x:%d length: %d append: %d\n",
296 utf8string
? utf8string
: "",
297 x_base
, y_base
, utf8string_size
,
298 (flags
&& *flags
& OE_APPEND_CURRENT
)));
299 dprint((9, "passwd:%d utf8prompt:\"%s\" label:\"%s\"\n",
300 (flags
&& *flags
& OE_PASSWD_NOAST
) ? 10 :
301 (flags
&& *flags
& OE_PASSWD
) ? 1 : 0,
302 utf8prompt
? utf8prompt
: "",
303 (escape_list
&& escape_list
[0].ch
!= -1 && escape_list
[0].label
)
304 ? escape_list
[0].label
: ""));
307 return(pre_screen_config_opt_enter(utf8string
, utf8string_size
, utf8prompt
,
308 escape_list
, help
, flags
));
311 if (mswin_usedialog ())
312 return(win_dialog_opt_enter(utf8string
, utf8string_size
, utf8prompt
,
313 escape_list
, help
, flags
));
318 * Utf8string comes in as UTF-8. We'll convert it to a UCS-4 array and operate on
319 * that array, then convert it back before returning. Utf8string_size is the size
320 * of the utf8string array but that doesn't help us much for the array we need to
321 * operate on here. We'll just allocate a big array and then cut it off when
324 * This should come before the specialized calls above but those aren't
325 * converted to use UCS-4 yet.
327 string
= utf8_to_ucs4_cpystr(utf8string
);
328 dline
.vused
= ucs4_strlen(string
);
330 string_size
= (2 * MAX(utf8string_size
,dline
.vused
) + 100);
331 fs_resize((void **) &string
, string_size
* sizeof(UCS
));
334 cols
= ps_global
->ttyo
->screen_cols
;
335 prompt_width
= utf8_width(utf8prompt
);
339 real_y_base
= y_base
;
341 real_y_base
= y_base
+ ps_global
->ttyo
->screen_rows
;
342 real_y_base
= MAX(real_y_base
, 0);
345 flush_ordered_messages();
348 if(flags
&& *flags
& OE_APPEND_CURRENT
) /* save a copy in case of cancel */
349 saved_original
= ucs4_cpystr(string
);
352 * build the function key mapping table, skipping predefined keys...
354 memset(fkey_table
, NO_OP_COMMAND
, 12 * sizeof(long));
355 for(i
= 0, j
= 0; escape_list
&& escape_list
[i
].ch
!= -1 && i
+j
< 12; i
++){
356 if(i
+j
== OE_HELP_KEY
)
359 if(i
+j
== OE_CANCEL_KEY
)
362 if(i
+j
== OE_ENTER_KEY
)
365 fkey_table
[i
+j
] = escape_list
[i
].ch
;
368 /* assumption that HelpType is char ** */
370 if(help_text
){ /*---- Show help text -----*/
371 int width
= ps_global
->ttyo
->screen_cols
- x_base
;
373 if(FOOTER_ROWS(ps_global
) == 1){
375 FOOTER_ROWS(ps_global
) = 3;
376 clearfooter(ps_global
);
379 real_y_base
= y_base
+ ps_global
->ttyo
->screen_rows
;
382 for(j
= 0; j
< 2 && help_text
[j
]; j
++){
383 MoveCursor(real_y_base
+ 1 + j
, x_base
);
386 if(width
< utf8_width(help_text
[j
])){
387 char *tmp
= cpystr(help_text
[j
]);
388 (void) utf8_truncate(tmp
, width
);
389 PutLine0(real_y_base
+ 1 + j
, x_base
, tmp
);
390 fs_give((void **) &tmp
);
393 PutLine0(real_y_base
+ 1 + j
, x_base
, help_text
[j
]);
398 clrbitmap((km
= &oe_keymenu
)->bitmap
); /* force formatting */
399 if(!(flags
&& (*flags
) & OE_DISALLOW_HELP
))
400 setbitn(OE_HELP_KEY
, bitmap
);
402 setbitn(OE_ENTER_KEY
, bitmap
);
403 if(!(flags
&& (*flags
) & OE_DISALLOW_CANCEL
))
404 setbitn(OE_CANCEL_KEY
, bitmap
);
406 setbitn(OE_CTRL_T_KEY
, bitmap
);
408 /*---- Show the usual possible keys ----*/
409 for(i
=0,j
=0; escape_list
&& escape_list
[i
].ch
!= -1 && i
+j
< 12; i
++){
410 if(i
+j
== OE_HELP_KEY
)
413 if(i
+j
== OE_CANCEL_KEY
)
416 if(i
+j
== OE_ENTER_KEY
)
419 oe_keymenu
.keys
[i
+j
].label
= escape_list
[i
].label
;
420 oe_keymenu
.keys
[i
+j
].name
= escape_list
[i
].name
;
421 setbitn(i
+j
, bitmap
);
424 for(i
= i
+j
; i
< 12; i
++)
425 if(!(i
== OE_HELP_KEY
|| i
== OE_ENTER_KEY
|| i
== OE_CANCEL_KEY
))
426 oe_keymenu
.keys
[i
].name
= NULL
;
428 draw_keymenu(km
, bitmap
, cols
, 1-FOOTER_ROWS(ps_global
), 0, FirstMenu
);
431 if(F_ON(F_ENABLE_DEL_WHEN_WRITING
, ps_global
))
432 ClearLine(real_y_base
);
433 if(pico_usingcolor() && VAR_PROMPT_FORE_COLOR
&&
434 VAR_PROMPT_BACK_COLOR
&&
435 pico_is_good_color(VAR_PROMPT_FORE_COLOR
) &&
436 pico_is_good_color(VAR_PROMPT_BACK_COLOR
)){
437 lastc
= pico_get_cur_color();
439 promptc
= new_color_pair(VAR_PROMPT_FORE_COLOR
,
440 VAR_PROMPT_BACK_COLOR
);
441 (void)pico_set_colorp(promptc
, PSC_NONE
);
448 * if display length isn't wide enough to support input,
449 * shorten up the prompt...
451 if((dline
.dwid
= cols
- (x_base
+ prompt_width
)) < MIN_OPT_ENT_WIDTH
){
456 * Scoot prompt pointer forward at least (MIN_OPT_ENT_WIDTH - dline.dwid) screencells.
458 p
= utf8_count_forw_width(utf8prompt
, MIN_OPT_ENT_WIDTH
-dline
.dwid
, &got_width
);
459 if(got_width
< MIN_OPT_ENT_WIDTH
-dline
.dwid
)
460 p
= utf8_count_forw_width(utf8prompt
, MIN_OPT_ENT_WIDTH
+1-dline
.dwid
, &got_width
);
463 prompt_width
= utf8_width(p
);
464 dline
.dwid
= cols
- (x_base
+ prompt_width
);
470 * How many UCS-4 characters will we need to make up the width dwid? It could be
471 * unlimited because of zero-width characters, I suppose, but realistically it
472 * isn't going to be much more than dwid.
474 dline
.dlen
= 2 * dline
.dwid
+ 100;
476 dline
.dl
= (UCS
*) fs_get(dline
.dlen
* sizeof(UCS
));
477 dline
.olddl
= (UCS
*) fs_get(dline
.dlen
* sizeof(UCS
));
478 memset(dline
.dl
, 0, dline
.dlen
* sizeof(UCS
));
479 memset(dline
.olddl
, 0, dline
.dlen
* sizeof(UCS
));
481 dline
.movecursor
= MoveCursor
;
482 dline
.writechar
= Writewchar
;
484 dline
.row
= real_y_base
;
485 dline
.col
= x_base
+ prompt_width
;
488 dline
.vlen
= --string_size
; /* -1 for terminating zero */
489 dline
.vbase
= field_pos
= 0;
492 cursor_shown
= mswin_showcaret(1);
495 PutLine0(real_y_base
, x_base
, utf8prompt
);
498 * If appending, position field_pos at end of input.
500 if(flags
&& *flags
& OE_APPEND_CURRENT
)
501 while(string
[field_pos
])
504 passwd
= (flags
&& *flags
& OE_PASSWD_NOAST
) ? 10 :
505 (flags
&& *flags
& OE_PASSWD
) ? 1 : 0;
506 line_paint(field_pos
, &dline
, &passwd
);
508 /*----------------------------------------------------------------------
510 loops until someone sets the return_v.
511 ----------------------------------------------------------------------*/
514 while(return_v
== -10) {
517 mouse_in_content(KEY_MOUSE
, -1, -1, 0x5, 0);
518 register_mfunc(mouse_in_content
,
519 real_y_base
, x_base
+ prompt_width
,
520 real_y_base
, ps_global
->ttyo
->screen_cols
);
523 mswin_allowpaste(MSWIN_PASTE_LINE
);
524 g_mc_row
= real_y_base
;
525 g_mc_col
= x_base
+ prompt_width
;
526 mswin_mousetrackcallback(pcpine_oe_cursor
);
529 /* Timeout 10 min to keep imap mail stream alive */
530 ps_global
->conceal_sensitive_debugging
= passwd
? 1 : 0;
531 ucs
= read_char(600);
532 ps_global
->conceal_sensitive_debugging
= 0;
535 clear_mfunc(mouse_in_content
);
538 mswin_allowpaste(MSWIN_PASTE_DISABLE
);
539 mswin_mousetrackcallback(NULL
);
543 * Don't want to intercept all characters if typing in passwd.
544 * We select an ad hoc set that we will catch and let the rest
545 * through. We would have caught the set below in the big switch
546 * but we skip the switch instead. Still catch things like ^K,
547 * DELETE, ^C, RETURN.
564 if(too_thin
&& ucs
!= KEY_RESIZE
&& ucs
!= ctrl('Z') && ucs
!= ctrl('C'))
569 /*--------------- KEY RIGHT ---------------*/
572 if(field_pos
>= string_size
|| string
[field_pos
] == '\0')
575 line_paint(++field_pos
, &dline
, &passwd
);
578 /*--------------- KEY LEFT ---------------*/
584 line_paint(--field_pos
, &dline
, &passwd
);
587 /*-------------------- WORD SKIP --------------------*/
590 * Note: read_char *can* return NO_OP_COMMAND which is
591 * the def'd with the same value as ^@ (NULL), BUT since
592 * read_char has a big timeout (>25 secs) it won't.
595 /* skip thru current word */
596 while(string
[field_pos
]
597 && isalnum((unsigned char) string
[field_pos
]))
600 /* skip thru current white space to next word */
601 while(string
[field_pos
]
602 && !isalnum((unsigned char) string
[field_pos
]))
605 line_paint(field_pos
, &dline
, &passwd
);
608 /*-------------------- RETURN --------------------*/
610 if(F_OFF(F_USE_FK
,ps_global
)) goto bleep
;
616 /*-------------------- Destructive backspace --------------------*/
617 case '\177': /* DEL */
619 /* Try and do this with by telling the terminal to delete a
620 a character. If that fails, then repaint the rest of the
621 line, achieving the same much less efficiently
627 /* drop thru to pull line back ... */
629 /*-------------------- Delete char --------------------*/
632 if(field_pos
>= string_size
|| !string
[field_pos
])
636 for(s2
= &string
[field_pos
]; *s2
!= 0; s2
++)
639 *s2
= 0; /* Copy last NULL */
640 line_paint(field_pos
, &dline
, &passwd
);
641 if(flags
) /* record change if requested */
642 *flags
|= OE_USER_MODIFIED
;
646 /*--------------- Kill line -----------------*/
648 if(kill_buffer
!= NULL
)
649 fs_give((void **) &kill_buffer
);
651 if(field_pos
!= 0 || string
[0]){
652 if(!passwd
&& F_ON(F_DEL_FROM_DOT
, ps_global
))
653 dline
.vused
-= ucs4_strlen(&string
[i
= field_pos
]);
657 kill_buffer
= ucs4_cpystr(&string
[field_pos
= i
]);
658 string
[field_pos
] = '\0';
659 line_paint(field_pos
, &dline
, &passwd
);
660 if(flags
) /* record change if requested */
661 *flags
|= OE_USER_MODIFIED
;
666 /*------------------- Undelete line --------------------*/
668 if(kill_buffer
== NULL
)
671 /* Make string so it will fit */
672 kb
= ucs4_cpystr(kill_buffer
);
673 if(ucs4_strlen(kb
) + ucs4_strlen(string
) > string_size
)
674 kb
[string_size
- ucs4_strlen(string
)] = '\0';
676 if(string
[field_pos
] == '\0') {
677 /*--- adding to the end of the string ----*/
679 string
[field_pos
++] = *k
;
681 string
[field_pos
] = '\0';
686 shift
= ucs4_strlen(kb
);
688 /* shift field_pos ... end to right */
689 for(k
= &string
[field_pos
] + ucs4_strlen(&string
[field_pos
]);
690 k
>= &string
[field_pos
]; k
--)
694 string
[field_pos
++] = *k
;
697 if(*kb
&& flags
) /* record change if requested */
698 *flags
|= OE_USER_MODIFIED
;
700 dline
.vused
= ucs4_strlen(string
);
701 fs_give((void **) &kb
);
702 line_paint(field_pos
, &dline
, &passwd
);
705 /*-------------------- Interrupt --------------------*/
706 case ctrl('C'): /* ^C */
707 if(F_ON(F_USE_FK
,ps_global
) || (flags
&& ((*flags
) & OE_DISALLOW_CANCEL
)))
713 if(F_OFF(F_USE_FK
,ps_global
) || (flags
&& ((*flags
) & OE_DISALLOW_CANCEL
)))
719 for(i
= 0; saved_original
[i
]; i
++)
720 string
[i
] = saved_original
[i
];
729 /*-------------------- Start of line -------------*/
730 line_paint(field_pos
= 0, &dline
, &passwd
);
735 /*-------------------- End of line ---------------*/
736 line_paint(field_pos
= dline
.vused
, &dline
, &passwd
);
739 /*-------------------- Help --------------------*/
742 if(flags
&& ((*flags
) & OE_DISALLOW_HELP
))
744 else if(FOOTER_ROWS(ps_global
) == 1 && km_popped
== 0){
746 FOOTER_ROWS(ps_global
) = 3;
747 clearfooter(ps_global
);
749 (void)pico_set_colorp(lastc
, PSC_NONE
);
753 draw_keymenu(km
, bitmap
, cols
, 1-FOOTER_ROWS(ps_global
),
757 (void)pico_set_colorp(promptc
, PSC_NONE
);
761 mark_keymenu_dirty();
763 dline
.row
= real_y_base
= y_base
+ ps_global
->ttyo
->screen_rows
;
764 PutLine0(real_y_base
, x_base
, utf8prompt
);
765 memset(dline
.dl
, 0, dline
.dlen
* sizeof(UCS
));
766 memset(dline
.olddl
, 0, dline
.dlen
* sizeof(UCS
));
767 line_paint(field_pos
, &dline
, &passwd
);
771 if(FOOTER_ROWS(ps_global
) > 1){
772 mark_keymenu_dirty();
782 /* Mouse support untested in pine 5.00 */
788 mouse_get_last (NULL
, &mp
);
791 case M_BUTTON_LEFT
: /* position cursor */
795 * We have to figure out which character is under the cursor.
796 * This is complicated by the fact that characters may
797 * be other than one cell wide.
800 /* the -1 is for the '<' when text is offscreen left */
801 w
= (dline
.vbase
> 0) ? mp
.col
-1 : mp
.col
;
804 field_pos
= dline
.vbase
- 1;
806 if(dline
.vused
<= dline
.vbase
807 || ucs4_str_width_a_to_b(dline
.vl
,dline
.vbase
,dline
.vused
-1) <= w
)
808 field_pos
= dline
.vused
;
811 * Find index of 1st character that causes the
815 ucs4_str_width_a_to_b(dline
.vl
,dline
.vbase
,dline
.vbase
+i
) <= w
;
819 field_pos
= dline
.vbase
+ i
;
823 field_pos
= MIN(MAX(field_pos
, 0), dline
.vused
);
825 /* just allow line_paint to choose vbase */
826 line_paint(field_pos
, &dline
, &passwd
);
829 case M_BUTTON_RIGHT
:
833 * Same as M_BUTTON_LEFT except we paste in text after
839 /* the -1 is for the '<' when text is offscreen left */
840 w
= (dline
.vbase
> 0) ? mp
.col
-1 : mp
.col
;
843 field_pos
= dline
.vbase
- 1;
845 if(dline
.vused
<= dline
.vbase
846 || ucs4_str_width_a_to_b(dline
.vl
,dline
.vbase
,dline
.vused
-1) <= w
)
847 field_pos
= dline
.vused
;
850 * Find index of 1st character that causes the
854 ucs4_str_width_a_to_b(dline
.vl
,dline
.vbase
,dline
.vbase
+i
) <= w
;
858 field_pos
= dline
.vbase
+ i
;
862 field_pos
= MIN(MAX(field_pos
, 0), dline
.vused
);
864 line_paint(field_pos
, &dline
, &passwd
);
866 mswin_allowpaste(MSWIN_PASTE_LINE
);
868 mswin_allowpaste(MSWIN_PASTE_DISABLE
);
872 case M_BUTTON_MIDDLE
: /* NO-OP for now */
873 default: /* just ignore */
884 * Keep mail stream alive by checking for new mail.
885 * If we're asking for a password in a login prompt
886 * we don't want to check for new_mail because the
887 * new mail check might be what got us here in the first
888 * place (because of a filter trying to save a message).
889 * If we need to wait for the user to come back then
890 * the caller will just have to deal with the failure
894 if(!ps_global
->no_newmail_check_from_optionally_enter
)
895 i
= new_mail(0, 2, NM_DEFER_SORT
);
897 if(sp_expunge_count(ps_global
->mail_stream
) &&
898 flags
&& ((*flags
) & OE_SEQ_SENSITIVE
))
902 line_paint(field_pos
, &dline
, &passwd
);
903 break; /* no changes, get on with life */
905 /* Else fall into redraw */
907 /*-------------------- Redraw --------------------*/
909 /*---------------- re size ----------------*/
912 dline
.row
= real_y_base
= y_base
> 0 ? y_base
:
913 y_base
+ ps_global
->ttyo
->screen_rows
;
915 (void)pico_set_colorp(lastc
, PSC_NONE
);
921 if(ps_global
->redrawer
!= (void (*)(void))NULL
)
922 (*ps_global
->redrawer
)();
926 (void)pico_set_colorp(promptc
, PSC_NONE
);
930 PutLine0(real_y_base
, x_base
, utf8prompt
);
931 cols
= ps_global
->ttyo
->screen_cols
;
933 if(cols
< x_base
+ prompt_width
+ 4){
935 PutLine0(real_y_base
, 0, "Screen's too thin. Ouch!");
939 dline
.col
= x_base
+ prompt_width
;
940 dline
.dwid
= cols
- (x_base
+ prompt_width
);
941 dline
.dlen
= 2 * dline
.dwid
+ 100;
942 fs_resize((void **) &dline
.dl
, (size_t) dline
.dlen
* sizeof(UCS
));
943 fs_resize((void **) &dline
.olddl
, (size_t) dline
.dlen
* sizeof(UCS
));
944 memset(dline
.dl
, 0, dline
.dlen
* sizeof(UCS
));
945 memset(dline
.olddl
, 0, dline
.dlen
* sizeof(UCS
));
946 line_paint(field_pos
, &dline
, &passwd
);
952 "optionally_enter RESIZE new_cols:%d too_thin: %d\n",
956 case PF3
: /* input to potentially remap */
965 if(F_ON(F_USE_FK
,ps_global
)
966 && fkey_table
[ucs
- PF1
] != NO_OP_COMMAND
)
967 ucs
= fkey_table
[ucs
- PF1
]; /* remap function key input */
970 if(escape_list
){ /* in the escape key list? */
971 for(j
=0; escape_list
[j
].ch
!= -1; j
++){
972 if(escape_list
[j
].ch
== ucs
){
973 return_v
= escape_list
[j
].rval
;
982 if(ucs
< 0x80 && FILTER_THIS((unsigned char) ucs
)){
989 /*--- Insert a character -----*/
990 if(dline
.vused
>= string_size
)
993 /*---- extending the length of the string ---*/
994 for(s2
= &string
[++dline
.vused
]; s2
- string
> field_pos
; s2
--)
997 string
[field_pos
++] = ucs
;
998 line_paint(field_pos
, &dline
, &passwd
);
999 if(flags
) /* record change if requested */
1000 *flags
|= OE_USER_MODIFIED
;
1002 } /*---- End of switch on char ----*/
1011 fs_give((void **) &dline
.dl
);
1014 fs_give((void **) &dline
.olddl
);
1017 fs_give((void **) &saved_original
);
1020 fs_give((void **) &kill_buffer
);
1023 * Change string back into UTF-8.
1025 candidate
= ucs4_to_utf8_n_cpystr(string
, utf8string_size
);
1028 fs_give((void **) &string
);
1031 strcpy(utf8string
, candidate
);
1032 fs_give((void **) &candidate
);
1035 if (!(flags
&& (*flags
) & OE_KEEP_TRAILING_SPACE
))
1036 removing_trailing_white_space(utf8string
);
1039 (void)pico_set_colorp(lastc
, PSC_NONE
);
1040 free_color_pair(&lastc
);
1042 free_color_pair(&promptc
);
1047 MoveCursor(real_y_base
, x_base
); /* Move the cursor to show we're done */
1051 FOOTER_ROWS(ps_global
) = 1;
1052 clearfooter(ps_global
);
1053 ps_global
->mangled_body
= 1;
1060 /*----------------------------------------------------------------------
1061 Check to see if the given command is reasonably valid
1063 Args: ch -- the character to check
1065 Result: A valid command is returned, or a well know bad command is returned.
1069 validatekeys(UCS ch
)
1071 if(F_ON(F_USE_FK
,ps_global
)){
1072 if(ch
>= 'a' && ch
<= 'z')
1076 if(ch
>= PF1
&& ch
<= PF12
)
1085 /*----------------------------------------------------------------------
1086 Prepend config'd commands to keyboard input
1088 Args: ch -- pointer to storage for returned command
1090 Returns: TRUE if we're passing back a useful command, FALSE otherwise
1094 process_config_input(UCS
*ch
)
1096 static char firsttime
= (char) 1;
1098 unsigned long octets_so_far
, remaining_octets
, ret
= 0;
1099 unsigned char *inputp
;
1101 unsigned char inputbuf
[20];
1103 /* commands in config file */
1104 if(ps_global
->initial_cmds
&& *ps_global
->initial_cmds
) {
1106 * There are a few commands that may require keyboard input before
1107 * we enter the main command loop. That input should be interactive,
1108 * not from our list of initial keystrokes.
1110 if(ps_global
->dont_use_init_cmds
)
1113 c
= *ps_global
->initial_cmds
++;
1116 * Use enough bytes to make up a character and convert it to UCS-4.
1118 if(c
< 0x80 || c
> KEY_BASE
){
1123 memset(inputbuf
, 0, sizeof(inputbuf
));
1124 inputbuf
[0] = (0xff & c
);
1128 remaining_octets
= octets_so_far
;
1130 ucs
= (UCS
) utf8_get(&inputp
, &remaining_octets
);
1132 case U8G_ENDSTRG
: /* incomplete character, wait */
1133 case U8G_ENDSTRI
: /* incomplete character, wait */
1134 if(!*ps_global
->initial_cmds
|| octets_so_far
>= sizeof(inputbuf
)){
1139 inputbuf
[octets_so_far
++] = (0xff & *ps_global
->initial_cmds
++);
1144 if(ucs
& U8G_ERROR
|| ucs
== UBOGON
)
1155 if(ps_global
->initial_cmds
&& !*ps_global
->initial_cmds
&& ps_global
->free_initial_cmds
){
1156 fs_give((void **) &ps_global
->free_initial_cmds
);
1157 ps_global
->initial_cmds
= NULL
;
1165 if(ps_global
->in_init_seq
) {
1166 ps_global
->in_init_seq
= 0;
1167 ps_global
->save_in_init_seq
= 0;
1169 F_SET(F_USE_FK
,ps_global
,ps_global
->orig_use_fkeys
);
1171 *ch
= (UCS
) ctrl('L');
1181 static int tape
[TAPELEN
];
1182 static long recorded
= 0L;
1183 static short length
= 0;
1187 * record user keystrokes
1189 * Args: ch -- the character to record
1191 * Returns: character recorded
1194 key_recorder(int ch
)
1196 tape
[recorded
++ % TAPELEN
] = ch
;
1197 if(length
< TAPELEN
)
1205 * playback user keystrokes
1207 * Args: ch -- ignored
1209 * Returns: character played back or -1 to indicate end of tape
1212 key_playback(int ch
)
1214 ch
= length
? tape
[(recorded
+ TAPELEN
- length
--) % TAPELEN
] : -1;
1220 * recent_keystroke - verbose version of key_playback
1223 recent_keystroke(int *cv
, char *cs
, size_t cslen
)
1227 if((c
= key_playback(0)) != -1){
1229 snprintf(cs
, cslen
, "%.32s", pretty_command(c
));
1239 pcpine_oe_cursor(col
, row
)
1243 return((row
== g_mc_row
1245 && col
< ps_global
->ttyo
->screen_cols
)
1246 ? MSWIN_CURSOR_IBEAM
1247 : MSWIN_CURSOR_ARROW
);