1 /*
2  * Copyright (c) 1993-2009, 2013-2015, 2018-2020 Paul Mattes.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *     * Redistributions of source code must retain the above copyright
9  *       notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above copyright
11  *       notice, this list of conditions and the following disclaimer in the
12  *       documentation and/or other materials provided with the distribution.
13  *     * Neither the name of Paul Mattes nor his contributors may be used
14  *       to endorse or promote products derived from this software without
15  *       specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY PAUL MATTES "AS IS" AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL PAUL MATTES BE LIABLE FOR ANY DIRECT,
21  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  *	status.c
32  *		This module handles the 3270 status line.
33  */
34 
35 #include "globals.h"
36 #include "xglobals.h"
37 
38 #include <assert.h>
39 #include <X11/StringDefs.h>
40 #include <X11/Shell.h>
41 #include "3270ds.h"
42 #include "appres.h"
43 #include "cg.h"
44 
45 #include "actions.h"
46 #include "kybd.h"
47 #include "host.h"
48 #include "screen.h"
49 #include "status.h"
50 #include "tables.h"
51 #include "trace.h" /* temp */
52 #include "unicodec.h"
53 #include "utils.h"
54 #include "xappres.h"
55 #include "xscreen.h"
56 #include "xtables.h"
57 
58 static XChar2b *status_2b;
59 static unsigned char *status_1b;
60 static XChar2b *display_2b;
61 static bool *sxcursor_want;
62 static bool *sxcursor_have;
63 static bool  status_changed = false;
64 
65 static struct status_line {
66     bool         changed;
67     int             start, len, color;
68     XChar2b        *s2b;
69     unsigned char  *s1b;
70     XChar2b        *d2b;
71 } *status_line;
72 
73 static int offsets[] = {
74     0,	/* connection status */
75     8,	/* wait, locked */
76     39,	/* shift, insert, timing, cursor position */
77     -1
78 };
79 #define SSZ ((sizeof(offsets)/sizeof(offsets[0])) - 1)
80 
81 #define CTLR_REGION	0
82 #define WAIT_REGION	1
83 #define MISC_REGION	2
84 
85 static int colors[SSZ] =  {
86     FA_INT_NORM_NSEL,
87     FA_INT_HIGH_SEL,
88     FA_INT_NORM_NSEL
89 };
90 
91 static int colors3279[SSZ] =  {
92     HOST_COLOR_BLUE,
93     HOST_COLOR_WHITE,
94     HOST_COLOR_BLUE
95 };
96 
97 #define CM	(60 * 10)	/* csec per minute */
98 
99 /*
100  * The status line is laid out thusly (M is maxCOLS):
101  *
102  *   0		"4" in a square
103  *   1		"A" underlined
104  *   2		solid box if connected, "?" in a box if not
105  *   3..7	empty
106  *   8...	message area
107  *   M-41	Meta indication ("M" or blank)
108  *   M-40	Alt indication ("A" or blank)
109  *   M-39	Shift indication (Special symbol/"^" or blank)
110  *   M-38	APL indication (Special symbol/"a" or blank)
111  *   M-37	empty
112  *   M-36	Compose indication ("C" or blank)
113  *   M-35	Compose first character
114  *   M-34	empty
115  *   M-33	Typeahead indication ("T" or blank)
116  *   M-32	Screentrace count
117  *   M-31	Alternate keymap indication ("K" or blank)
118  *   M-30	Reverse input mode indication ("R" or blank)
119  *   M-29	Insert mode indication (Special symbol/"I" or blank)
120  *   M-28	Printer indication ("P" or blank)
121  *   M-27	Script indication ("s" or blank)
122  *   M-26..M-16	empty
123  *   M-15..M-9	command timing (Clock symbol and m:ss, or blank)
124  *   M-7..M	cursor position (rrr/ccc or blank)
125  */
126 
127 /* Positions */
128 
129 #define LBOX	0		/* left-hand box */
130 #define CNCT	1		/* connection between */
131 #define RBOX	2		/* right-hand box */
132 
133 #define M0	8		/* message area */
134 
135 #define SHIFT	(maxCOLS-39)	/* shift indication */
136 
137 #define COMPOSE	(maxCOLS-36)	/* compose characters */
138 
139 #define TYPEAHD	(maxCOLS-33)	/* typeahead */
140 
141 #define SCRNTRC	(maxCOLS-32)	/* screentrace */
142 
143 #define KMAP	(maxCOLS-31)	/* alt keymap in effect */
144 
145 #define REVERSE (maxCOLS-30)	/* reverse input mode in effect */
146 
147 #define INSERT	(maxCOLS-29)	/* insert mode */
148 
149 #define PSESS	(maxCOLS-28)	/* printer session */
150 
151 #define SCRIPT	(maxCOLS-27)	/* script in progress */
152 
153 #define LU	(maxCOLS-25)	/* LU name */
154 #define LUCNT	8
155 
156 #define T0	(maxCOLS-15)	/* timings */
157 #define	TCNT	7
158 
159 #define C0	(maxCOLS-7)	/* cursor position */
160 #define CCNT	7
161 
162 #define STATUS_Y	(*screen_height - *descent)
163 
164 static unsigned char	nullblank;
165 static Position		status_y;
166 
167 /* Status line contents (high-level) */
168 
169 static void do_disconnected(void);
170 static void do_reconnecting(void);
171 static void do_resolving(void);
172 static void do_connecting(void);
173 static void do_tls(void);
174 static void do_proxy(void);
175 static void do_telnet(void);
176 static void do_tn3270e(void);
177 static void do_awaiting_first(void);
178 static void do_unlock_delay(void);
179 static void do_inhibit(void);
180 static void do_blank(void);
181 static void do_twait(void);
182 static void do_syswait(void);
183 static void do_protected(void);
184 static void do_numeric(void);
185 static void do_overflow(void);
186 static void do_dbcs(void);
187 static void do_scrolled(void);
188 static void do_minus(void);
189 static void do_disabled(void);
190 
191 static bool oia_undera = true;
192 static bool oia_boxsolid = false;
193 static int oia_shift = 0;
194 static bool oia_typeahead = false;
195 static int oia_screentrace = -1;
196 static bool oia_compose = false;
197 static ucs4_t oia_compose_char = 0;
198 static enum keytype oia_compose_keytype = KT_STD;
199 static enum msg {
200     DISCONNECTED,	/* X Not Connected */
201     XRECONNECTING,	/* X Reconnecting */
202     XRESOLVING,		/* X [DNS] */
203     CONNECTING,		/* X [TCP] */
204     TLS,		/* X [TLS] */
205     PROXY,		/* X [PROXY] */
206     TELNET,		/* X [TELNET] */
207     TN3270E,		/* X [TN3270E] */
208     AWAITING_FIRST,	/* X [Field] */
209     UNLOCK_DELAY,	/* X */
210     INHIBIT,		/* X Inhibit */
211     BLANK,		/* (blank) */
212     TWAIT,		/* X Wait */
213     SYSWAIT,		/* X SYSTEM */
214     PROTECTED,		/* X Protected */
215     NUMERIC,		/* X Numeric */
216     OVERFLOW,		/* X Overflow */
217     DBCS,		/* X DBCS */
218     SCROLLED,		/* X Scrolled */
219     MINUS,		/* X -f */
220     KBD_DISABLED,	/* X Disabled */
221     N_MSGS
222 } oia_msg = DISCONNECTED, scroll_saved_msg, disabled_saved_msg = BLANK;
223 static char oia_lu[LUCNT+1];
224 static bool msg_is_saved = false;
225 static int n_scrolled = 0;
226 static void (*msg_proc[N_MSGS])(void) = {
227     do_disconnected,
228     do_reconnecting,
229     do_resolving,
230     do_connecting,
231     do_tls,
232     do_proxy,
233     do_telnet,
234     do_tn3270e,
235     do_awaiting_first,
236     do_unlock_delay,
237     do_inhibit,
238     do_blank,
239     do_twait,
240     do_syswait,
241     do_protected,
242     do_numeric,
243     do_overflow,
244     do_dbcs,
245     do_scrolled,
246     do_minus,
247     do_disabled
248 };
249 static int msg_color[N_MSGS] = {
250     FA_INT_NORM_NSEL,	/* disconnected */
251     FA_INT_NORM_NSEL,	/* reconnecting */
252     FA_INT_NORM_NSEL,	/* resolving */
253     FA_INT_NORM_NSEL,	/* connecting */
254     FA_INT_NORM_NSEL,	/* tls */
255     FA_INT_NORM_NSEL,	/* proxy */
256     FA_INT_NORM_NSEL,	/* telnet */
257     FA_INT_NORM_NSEL,	/* tn3270e */
258     FA_INT_NORM_NSEL,	/* awaiting_first */
259     FA_INT_NORM_NSEL,	/* unlock_delay */
260     FA_INT_NORM_NSEL,	/* inhibit */
261     FA_INT_NORM_NSEL,	/* blank */
262     FA_INT_NORM_NSEL,	/* twait */
263     FA_INT_NORM_NSEL,	/* syswait */
264     FA_INT_HIGH_SEL,	/* protected */
265     FA_INT_HIGH_SEL,	/* numeric */
266     FA_INT_HIGH_SEL,	/* overflow */
267     FA_INT_HIGH_SEL,	/* dbcs */
268     FA_INT_NORM_NSEL,	/* scrolled */
269     FA_INT_HIGH_SEL,	/* minus */
270     FA_INT_HIGH_SEL,	/* disabled */
271 };
272 static int msg_color3279[N_MSGS] = {
273     HOST_COLOR_WHITE,	/* disconnected */
274     HOST_COLOR_WHITE,	/* reconnecting */
275     HOST_COLOR_WHITE,	/* resolving */
276     HOST_COLOR_WHITE,	/* connecting */
277     HOST_COLOR_WHITE,	/* tls */
278     HOST_COLOR_WHITE,	/* proxy */
279     HOST_COLOR_WHITE,	/* telnet */
280     HOST_COLOR_WHITE,	/* tn3270e */
281     HOST_COLOR_WHITE,	/* awaiting_first */
282     HOST_COLOR_WHITE,	/* unlock_delay */
283     HOST_COLOR_WHITE,	/* inhibit */
284     HOST_COLOR_BLUE,	/* blank */
285     HOST_COLOR_WHITE,	/* twait */
286     HOST_COLOR_WHITE,	/* syswait */
287     HOST_COLOR_RED,	/* protected */
288     HOST_COLOR_RED,	/* numeric */
289     HOST_COLOR_RED,	/* overflow */
290     HOST_COLOR_RED,	/* dbcs */
291     HOST_COLOR_WHITE,	/* scrolled */
292     HOST_COLOR_RED,	/* minus */
293     HOST_COLOR_RED,	/* disabled */
294 };
295 static bool oia_insert = false;
296 static bool oia_reverse = false;
297 static bool oia_kmap = false;
298 static bool oia_script = false;
299 static bool oia_printer = false;
300 static char *oia_cursor = (char *) 0;
301 static char *oia_timing = (char *) 0;
302 
303 static unsigned char disc_msg[] = {
304     CG_lock, CG_space, CG_commhi, CG_badcommhi, CG_commhi, CG_commjag,
305     CG_commlo, CG_space
306 };
307 static int disc_len = sizeof(disc_msg);
308 
309 static unsigned char recon_msg[] = {
310     CG_lock, CG_space, CG_commhi, CG_badcommhi, CG_commhi, CG_commjag,
311     CG_commlo, CG_space, CG_clockleft, CG_clockright
312 };
313 static int recon_len = sizeof(recon_msg);
314 
315 static unsigned char rslv_msg[] = {
316     CG_lock, CG_space, CG_commhi, CG_badcommhi, CG_commhi, CG_commjag,
317     CG_commlo, CG_space, CG_bracketleft, CG_D, CG_N, CG_S, CG_bracketright
318 };
319 static int rslv_len = sizeof(rslv_msg);
320 
321 static unsigned char cnct_msg[] = {
322     CG_lock, CG_space, CG_commhi, CG_badcommhi, CG_commhi, CG_commjag,
323     CG_commlo, CG_space, CG_bracketleft, CG_T, CG_C, CG_P, CG_bracketright
324 };
325 static int cnct_len = sizeof(cnct_msg);
326 
327 static unsigned char tls_msg[] = {
328     CG_lock, CG_space, CG_commhi, CG_badcommhi, CG_commhi, CG_commjag,
329     CG_commlo, CG_space, CG_bracketleft, CG_T, CG_L, CG_S, CG_bracketright
330 };
331 static int tls_len = sizeof(tls_msg);
332 
333 static unsigned char proxy_msg[] = {
334     CG_lock, CG_space, CG_commhi, CG_badcommhi, CG_commhi, CG_commjag,
335     CG_commlo, CG_space, CG_bracketleft, CG_P, CG_r, CG_o, CG_x, CG_y,
336     CG_bracketright
337 };
338 static int proxy_len = sizeof(proxy_msg);
339 
340 static unsigned char telnet_msg[] = {
341     CG_lock, CG_space, CG_commhi, CG_badcommhi, CG_commhi, CG_commjag,
342     CG_commlo, CG_space, CG_bracketleft, CG_T, CG_E, CG_L, CG_N, CG_E, CG_T,
343     CG_bracketright
344 };
345 static int telnet_len = sizeof(telnet_msg);
346 
347 static unsigned char tn3270e_msg[] = {
348     CG_lock, CG_space, CG_commhi, CG_badcommhi, CG_commhi, CG_commjag,
349     CG_commlo, CG_space, CG_bracketleft, CG_T, CG_N, CG_3, CG_2, CG_7, CG_0,
350     CG_E, CG_bracketright
351 };
352 static int tn3270e_len = sizeof(tn3270e_msg);
353 
354 static unsigned char awaiting_first_msg[] = {
355     CG_lock, CG_space, CG_bracketleft, CG_F, CG_i, CG_e, CG_l, CG_d,
356     CG_bracketright
357 };
358 static int awaiting_first_len = sizeof(awaiting_first_msg);
359 
360 static unsigned char *a_not_connected;
361 static unsigned char *a_reconnecting;
362 static unsigned char *a_resolving;
363 static unsigned char *a_connecting;
364 static unsigned char *a_tls;
365 static unsigned char *a_proxy;
366 static unsigned char *a_telnet;
367 static unsigned char *a_tn3270e;
368 static unsigned char *a_awaiting_first;
369 static unsigned char *a_inhibit;
370 static unsigned char *a_twait;
371 static unsigned char *a_syswait;
372 static unsigned char *a_protected;
373 static unsigned char *a_numeric;
374 static unsigned char *a_overflow;
375 static unsigned char *a_dbcs;
376 static unsigned char *a_scrolled;
377 static unsigned char *a_minus;
378 static unsigned char *a_disabled;
379 
380 static ioid_t revert_timer_id = NULL_IOID;
381 
382 static unsigned char *make_amsg(const char *key);
383 
384 static void cancel_disabled_revert(void);
385 static void status_render(int region);
386 static void do_ctlr(void);
387 static void do_msg(enum msg t);
388 static void paint_msg(enum msg t);
389 static void do_insert(bool on);
390 static void do_reverse(bool on);
391 static void do_kmap(bool on);
392 static void do_script(bool on);
393 static void do_printer(bool on);
394 static void do_shift(int state);
395 static void do_typeahead(int state);
396 static void do_screentrace(int state);
397 static void do_compose(bool on, ucs4_t ucs4, enum keytype keytype);
398 static void do_lu(const char *lu);
399 static void do_timing(char *buf);
400 static void do_cursor(char *buf);
401 
402 static void status_connect(bool connected);
403 static void status_3270_mode(bool connected);
404 static void status_printer(bool on);
405 
406 /**
407  * Status line module registration.
408  */
409 void
status_register(void)410 status_register(void)
411 {
412     register_schange(ST_NEGOTIATING, status_connect);
413     register_schange(ST_CONNECT, status_connect);
414     register_schange(ST_3270_MODE, status_3270_mode);
415     register_schange(ST_PRINTER, status_printer);
416 }
417 
418 /* Initialize the status line */
419 void
status_init(void)420 status_init(void)
421 {
422     a_not_connected = make_amsg("statusNotConnected");
423     a_reconnecting = make_amsg("statusReconnecting");
424     a_resolving = make_amsg("statusResolving");
425     a_connecting = make_amsg("statusConnecting");
426     a_tls = make_amsg("statusTlsPending");
427     a_proxy = make_amsg("statusProxyPending");
428     a_telnet = make_amsg("statusTelnetPending");
429     a_tn3270e = make_amsg("statusTn3270ePending");
430     a_awaiting_first = make_amsg("statusAwaitingFirst");
431     a_inhibit = make_amsg("statusInhibit");
432     a_twait = make_amsg("statusTwait");
433     a_syswait = make_amsg("statusSyswait");
434     a_protected = make_amsg("statusProtected");
435     a_numeric = make_amsg("statusNumeric");
436     a_overflow = make_amsg("statusOverflow");
437     a_dbcs = make_amsg("statusDbcs");
438     a_scrolled = make_amsg("statusScrolled");
439     a_minus = make_amsg("statusMinus");
440     a_disabled = make_amsg("statusDisabled");
441 
442     oia_shift = toggled(APL_MODE)? AplMode: 0;
443 }
444 
445 /* Reinitialize the status line */
446 void
status_reinit(unsigned cmask)447 status_reinit(unsigned cmask)
448 {
449     unsigned i;
450 
451     if (cmask & FONT_CHANGE) {
452 	nullblank = *standard_font ? ' ' : CG_space;
453     }
454     if (cmask & (FONT_CHANGE | MODEL_CHANGE | SCROLL_CHANGE)) {
455 	status_y = STATUS_Y;
456 	if (!*descent) {
457 	    ++status_y;
458 	}
459     }
460     if (cmask & MODEL_CHANGE) {
461 	Replace(status_line,
462 		(struct status_line *)XtCalloc(sizeof(struct status_line),
463 		    SSZ));
464 	Replace(status_2b,
465 		(XChar2b *)XtCalloc(sizeof(XChar2b), maxCOLS));
466 	Replace(status_1b,
467 		(unsigned char *)XtCalloc(sizeof(unsigned char), maxCOLS));
468 	Replace(display_2b,
469 		(XChar2b *)XtCalloc(sizeof(XChar2b), maxCOLS));
470 	Replace(sxcursor_want,
471 		(bool *)XtCalloc(sizeof(bool), maxCOLS));
472 	Replace(sxcursor_have,
473 		(bool *)XtCalloc(sizeof(bool), maxCOLS));
474 	offsets[SSZ] = maxCOLS;
475 	if (appres.interactive.mono) {
476 	    colors[1] = FA_INT_NORM_NSEL;
477 	}
478 	for (i = 0; i < SSZ; i++) {
479 	    status_line[i].start = offsets[i];
480 	    status_line[i].len = offsets[i+1] - offsets[i];
481 	    status_line[i].s2b = status_2b + offsets[i];
482 	    status_line[i].s1b = status_1b + offsets[i];
483 	    status_line[i].d2b = display_2b + offsets[i];
484 	}
485     } else {
486 	memset(display_2b, 0, maxCOLS * sizeof(XChar2b));
487     }
488     if (cmask & (COLOR_CHANGE | MODEL_CHANGE)) {
489 	for (i = 0; i < SSZ; i++) {
490 	    status_line[i].color = mode.m3279 ? colors3279[i] : colors[i];
491 	}
492     }
493 
494     for (i = 0; i < SSZ; i++) {
495 	status_line[i].changed = true;
496     }
497     status_changed = true;
498 
499     /*
500      * Always redraw all the fields; it's easier than keeping track of
501      * what may have changed and why.
502      */
503     do_ctlr();
504     paint_msg(oia_msg);
505     do_insert(oia_insert);
506     do_reverse(oia_reverse);
507     do_kmap(oia_kmap);
508     do_script(oia_script);
509     do_printer(oia_printer);
510     do_shift(oia_shift);
511     do_typeahead(oia_typeahead);
512     do_screentrace(oia_screentrace);
513     do_compose(oia_compose, oia_compose_char, oia_compose_keytype);
514     do_lu(oia_lu);
515     do_cursor(oia_cursor);
516     do_timing(oia_timing);
517 }
518 
519 /* Check for a space. */
520 static bool
status_space(int col)521 status_space(int col)
522 {
523     return (*standard_font &&
524 	    (status_1b[col] == ' ' || status_1b[col] == 0)) ||
525 	   (!*standard_font &&
526 	    (status_1b[col] == CG_space || status_1b[col] == CG_null));
527 }
528 
529 /* Render the status line onto the screen */
530 void
status_disp(void)531 status_disp(void)
532 {
533     unsigned i;
534     int col;
535 
536     if (!status_changed) {
537 	return;
538     }
539     for (i = 0; i < SSZ; i++) {
540 	if (status_line[i].changed) {
541 	    status_render(i);
542 	    memmove(status_line[i].d2b, status_line[i].s2b,
543 		    status_line[i].len * sizeof(XChar2b));
544 	    status_line[i].changed = false;
545 	}
546     }
547 
548     /* Draw or undraw the crosshair. */
549     for (col = 0; col < maxCOLS; col++) {
550 	if (sxcursor_want[col]) {
551 	    if (status_space(col)) {
552 		XTextItem16 text1;
553 		XChar2b text = screen_vcrosshair();
554 
555 		text1.chars = &text;
556 		text1.nchars = 1;
557 		text1.delta = 0;
558 		text1.font = *fid;
559 		XDrawText16(display, *screen_window,
560 			screen_crosshair_gc(),
561 			COL_TO_X(col), status_y, &text1, 1);
562 		sxcursor_have[col] = true;
563 	    }
564 	} else if (sxcursor_have[col]) {
565 	    XFillRectangle(display, *screen_window, screen_invgc(0),
566 		    COL_TO_X(col),
567 		    status_y - *ascent,
568 		    *char_width, *char_height);
569 	    sxcursor_have[col] = false;
570 	}
571     }
572 
573     status_changed = false;
574 }
575 
576 /* Mark the entire status line as changed */
577 void
status_touch(void)578 status_touch(void)
579 {
580     unsigned i;
581 
582     for (i = 0; i < SSZ; i++) {
583 	status_line[i].changed = true;
584 	memset(status_line[i].d2b, 0, status_line[i].len * sizeof(XChar2b));
585     }
586     status_changed = true;
587 }
588 
589 /* Connected or disconnected */
590 static void
status_connect(bool connected)591 status_connect(bool connected)
592 {
593     if (connected) {
594 	oia_boxsolid = IN_3270 && !IN_SSCP;
595 	do_ctlr();
596 	if (cstate == RECONNECTING) {
597 	    cancel_disabled_revert();
598 	    do_msg(XRECONNECTING);
599 	} else if (cstate == RESOLVING) {
600 	    oia_boxsolid = false;
601 	    do_ctlr();
602 	    cancel_disabled_revert();
603 	    do_msg(XRESOLVING);
604 	    status_untiming();
605 	    status_uncursor_pos();
606 	} else if (cstate == TCP_PENDING) {
607 	    oia_boxsolid = false;
608 	    do_ctlr();
609 	    cancel_disabled_revert();
610 	    do_msg(CONNECTING);
611 	    status_untiming();
612 	    status_uncursor_pos();
613 	} else if (cstate == TLS_PENDING) {
614 	    oia_boxsolid = false;
615 	    do_ctlr();
616 	    cancel_disabled_revert();
617 	    do_msg(TLS);
618 	    status_untiming();
619 	    status_uncursor_pos();
620 	} else if (cstate == PROXY_PENDING) {
621 	    oia_boxsolid = false;
622 	    do_ctlr();
623 	    cancel_disabled_revert();
624 	    do_msg(PROXY);
625 	    status_untiming();
626 	    status_uncursor_pos();
627 	} else if (cstate == TELNET_PENDING) {
628 	    oia_boxsolid = false;
629 	    do_ctlr();
630 	    cancel_disabled_revert();
631 	    do_msg(TELNET);
632 	    status_untiming();
633 	    status_uncursor_pos();
634 	} else if (cstate == CONNECTED_UNBOUND) {
635 	    oia_boxsolid = false;
636 	    do_ctlr();
637 	    cancel_disabled_revert();
638 	    do_msg(TN3270E);
639 	    status_untiming();
640 	    status_uncursor_pos();
641 	} else if (kybdlock & KL_AWAITING_FIRST) {
642 	    cancel_disabled_revert();
643 	    do_msg(AWAITING_FIRST);
644 	} else {
645 	    cancel_disabled_revert();
646 	    do_msg(BLANK);
647 	}
648     } else {
649 	oia_boxsolid = false;
650 	do_ctlr();
651 	cancel_disabled_revert();
652 	do_msg(DISCONNECTED);
653 	status_uncursor_pos();
654     }
655     status_untiming();
656 }
657 
658 /* Changed 3270 mode */
659 static void
status_3270_mode(bool connected)660 status_3270_mode(bool connected)
661 {
662     oia_boxsolid = IN_3270 && !IN_SSCP;
663     do_ctlr();
664     status_untiming();
665     status_connect(CONNECTED);
666 }
667 
668 /* Toggle printer session mode */
669 static void
status_printer(bool on)670 status_printer(bool on)
671 {
672     do_printer(oia_printer = on);
673 }
674 
675 /* Revert the disabled message. */
676 static void
revert_disabled(ioid_t id _is_unused)677 revert_disabled(ioid_t id _is_unused)
678 {
679     assert(disabled_saved_msg != KBD_DISABLED);
680     paint_msg(disabled_saved_msg);
681     revert_timer_id = NULL_IOID;
682 }
683 
684 /* Cancel the revert timer. */
685 static void
cancel_disabled_revert(void)686 cancel_disabled_revert(void)
687 {
688     if (revert_timer_id != NULL_IOID) {
689 	RemoveTimeOut(revert_timer_id);
690 	revert_timer_id = NULL_IOID;
691     }
692 }
693 
694 /* Revert early. */
695 static void
revert_early(void)696 revert_early(void)
697 {
698     if (revert_timer_id != NULL_IOID) {
699 	RemoveTimeOut(revert_timer_id);
700 	revert_disabled(NULL_IOID);
701     }
702 }
703 
704 /* Keyboard disable flash. */
705 void
status_keyboard_disable_flash()706 status_keyboard_disable_flash()
707 {
708     if (keyboard_disabled()) {
709 	if (oia_msg == KBD_DISABLED) {
710 	    /* Push out the revert timer. */
711 	    if (revert_timer_id != NULL_IOID) {
712 		RemoveTimeOut(revert_timer_id);
713 		revert_timer_id = AddTimeOut(1000, revert_disabled);
714 	    }
715 	} else {
716 	    disabled_saved_msg = oia_msg;
717 	    paint_msg(KBD_DISABLED);
718 
719 	    /* Revert the message in 1s. */
720 	    assert(revert_timer_id == NULL_IOID);
721 	    revert_timer_id = AddTimeOut(1000, revert_disabled);
722 	}
723     } else {
724 	if (oia_msg == KBD_DISABLED) {
725 	    cancel_disabled_revert();
726 	    paint_msg(disabled_saved_msg);
727 	}
728     }
729 }
730 
731 /* Lock the keyboard (twait) */
732 void
status_twait(void)733 status_twait(void)
734 {
735     oia_undera = false;
736     do_ctlr();
737     cancel_disabled_revert();
738     do_msg(TWAIT);
739 }
740 
741 /* Done with controller confirmation */
742 void
status_ctlr_done(void)743 status_ctlr_done(void)
744 {
745     oia_undera = true;
746     do_ctlr();
747 }
748 
749 /* Lock the keyboard (X SYSTEM) */
750 void
status_syswait(void)751 status_syswait(void)
752 {
753     cancel_disabled_revert();
754     do_msg(SYSWAIT);
755 }
756 
757 /* Lock the keyboard (operator error) */
758 void
status_oerr(int error_type)759 status_oerr(int error_type)
760 {
761     switch (error_type) {
762     case KL_OERR_PROTECTED:
763 	cancel_disabled_revert();
764 	do_msg(PROTECTED);
765 	break;
766     case KL_OERR_NUMERIC:
767 	cancel_disabled_revert();
768 	do_msg(NUMERIC);
769 	break;
770     case KL_OERR_OVERFLOW:
771 	cancel_disabled_revert();
772 	do_msg(OVERFLOW);
773 	break;
774     case KL_OERR_DBCS:
775 	cancel_disabled_revert();
776 	do_msg(DBCS);
777 	break;
778     }
779 }
780 
781 /*
782  * The interaction of SCROLLED and KBD_DISABLED is somewhat complex.
783  *
784  * KBD_DISABLED overlays SCROLLED, and KBD_DISABLED overlays SCROLLED.  When
785  * the disable revert timer expires, SCROLLED will be restored (if we are still
786  * scrolled). But when SCROLLED reverts, KBD_DISABLED will *not* be restored.
787  *
788  * Meanwhile, any other OIA state that is set while showing SCROLLED (or
789  * showing KBD_DISABLED which is overlaying SCROLLED) will be saved, to be
790  * restored when scrolling reverts.
791  */
792 
793 /* Lock the keyboard (X Scrolled) */
794 void
status_scrolled(int n)795 status_scrolled(int n)
796 {
797     /* Fire the 'X Disabled' revert timer early. */
798     revert_early();
799 
800     n_scrolled = n;
801     if (n != 0) {
802 	if (!msg_is_saved) {
803 	    scroll_saved_msg = oia_msg;
804 	    assert(scroll_saved_msg != SCROLLED);
805 	    assert(scroll_saved_msg != KBD_DISABLED);
806 	    msg_is_saved = true;
807 	}
808 	paint_msg(SCROLLED);
809     } else {
810 	if (msg_is_saved) {
811 	    msg_is_saved = false;
812 	    paint_msg(scroll_saved_msg);
813 	}
814     }
815 }
816 
817 /* Lock the keyboard (X -f) */
818 void
status_minus(void)819 status_minus(void)
820 {
821     cancel_disabled_revert();
822     do_msg(MINUS);
823 }
824 
825 /* Unlock the keyboard */
826 void
status_reset(void)827 status_reset(void)
828 {
829     cancel_disabled_revert();
830     if (kybdlock & KL_ENTER_INHIBIT) {
831 	do_msg(INHIBIT);
832     } else if (kybdlock & KL_DEFERRED_UNLOCK) {
833 	do_msg(UNLOCK_DELAY);
834     } else {
835 	status_connect(PCONNECTED);
836     }
837 }
838 
839 /* Toggle insert mode */
840 void
status_insert_mode(bool on)841 status_insert_mode(bool on)
842 {
843     do_insert(oia_insert = on);
844 }
845 
846 /* Toggle reverse mode */
847 void
status_reverse_mode(bool on)848 status_reverse_mode(bool on)
849 {
850     do_reverse(oia_reverse = on);
851 }
852 
853 /* Toggle kmap mode */
854 void
status_kmap(bool on)855 status_kmap(bool on)
856 {
857     do_kmap(oia_kmap = on);
858 }
859 
860 /* Toggle script mode */
861 void
status_script(bool on)862 status_script(bool on)
863 {
864     do_script(oia_script = on);
865 }
866 
867 /* Toggle shift mode */
868 void
status_shift_mode(int state)869 status_shift_mode(int state)
870 {
871     do_shift(oia_shift = (oia_shift & AplMode) | state);
872 }
873 
874 /* Toggle APL mode. */
875 void
status_apl_mode(bool on)876 status_apl_mode(bool on)
877 {
878     do_shift(oia_shift = (oia_shift & ~AplMode) | (on? AplMode: 0));
879 }
880 
881 /* Toggle typeahead */
882 void
status_typeahead(bool on)883 status_typeahead(bool on)
884 {
885     do_typeahead(oia_typeahead = on);
886 }
887 
888 /* Change screentrace */
889 void
status_screentrace(int n)890 status_screentrace(int n)
891 {
892     do_screentrace(oia_screentrace = n);
893 }
894 
895 /* Set compose character */
896 void
status_compose(bool on,ucs4_t ucs4,enum keytype keytype)897 status_compose(bool on, ucs4_t ucs4, enum keytype keytype)
898 {
899     oia_compose = on;
900     oia_compose_char = ucs4;
901     oia_compose_keytype = keytype;
902     do_compose(on, ucs4, keytype);
903 }
904 
905 /* Set LU name */
906 void
status_lu(const char * lu)907 status_lu(const char *lu)
908 {
909     if (lu != NULL) {
910 	strncpy(oia_lu, lu, LUCNT);
911 	oia_lu[LUCNT] = '\0';
912     } else {
913 	memset(oia_lu, '\0', sizeof(oia_lu));
914     }
915     do_lu(oia_lu);
916 }
917 
918 /* Display timing */
919 void
status_timing(struct timeval * t0,struct timeval * t1)920 status_timing(struct timeval *t0, struct timeval *t1)
921 {
922     static char no_time[] = ":??.?";
923     static char buf[32];
924 
925     if (t1->tv_sec - t0->tv_sec > (99*60)) {
926 	do_timing(oia_timing = no_time);
927     } else {
928 	unsigned long cs;	/* centiseconds */
929 
930 	cs = (t1->tv_sec - t0->tv_sec) * 10 +
931 	     (t1->tv_usec - t0->tv_usec + 50000) / 100000;
932 	if (cs < CM) {
933 	    snprintf(buf, sizeof(buf), ":%02ld.%ld", cs / 10, cs % 10);
934 	} else {
935 	    snprintf(buf, sizeof(buf), "%02ld:%02ld", cs / CM, (cs % CM) / 10);
936 	}
937 	do_timing(oia_timing = buf);
938     }
939 }
940 
941 /* Erase timing indication */
942 void
status_untiming(void)943 status_untiming(void)
944 {
945     do_timing(oia_timing = (char *) 0);
946 }
947 
948 /* Update cursor position */
949 void
status_cursor_pos(int ca)950 status_cursor_pos(int ca)
951 {
952     static char buf[CCNT+1];
953 
954     if (xappres.xquartz_hack) {
955 	snprintf(buf, sizeof(buf), "%02d/%02d", (ca/COLS + 1) % 100,
956 		(ca%COLS + 1) % 100);
957     } else {
958 	snprintf(buf, sizeof(buf), "%03d/%03d", ca/COLS + 1, ca%COLS + 1);
959     }
960     do_cursor(oia_cursor = buf);
961 }
962 
963 /* Erase cursor position */
964 void
status_uncursor_pos(void)965 status_uncursor_pos(void)
966 {
967     do_cursor(oia_cursor = (char *) 0);
968 }
969 
970 /* Internal routines */
971 
972 /* Set the changed status for a particular status-line column. */
973 static void
set_status_changed(int col)974 set_status_changed(int col)
975 {
976     unsigned i;
977 
978     status_changed = true;
979     for (i = 0; i < SSZ; i++) {
980 	if (col >= status_line[i].start &&
981 	    col <  status_line[i].start + status_line[i].len) {
982 	    status_line[i].changed = true;
983 	    break;
984 	}
985     }
986 }
987 
988 /* Update the status line by displaying "symbol" at column "col".  */
989 static void
status_add(int col,unsigned char symbol,enum keytype keytype)990 status_add(int col, unsigned char symbol, enum keytype keytype)
991 {
992     XChar2b n2b;
993 
994     /* Store the text. */
995     n2b.byte1 = (keytype == KT_STD) ? 0 : 1;
996     n2b.byte2 = symbol;
997     if (status_2b[col].byte1 == n2b.byte1 &&
998 	    status_2b[col].byte2 == n2b.byte2) {
999 	return;
1000     }
1001     status_2b[col] = n2b;
1002     status_1b[col] = symbol;
1003 
1004     /* Update change status. */
1005     set_status_changed(col);
1006 }
1007 
1008 /**
1009  * Draw the crosshair cursor.
1010  *
1011  * @param[in] column	Column where the cursor should be
1012  */
1013 void
status_crosshair(int column)1014 status_crosshair(int column)
1015 {
1016     sxcursor_want[column] = true;
1017     set_status_changed(column);
1018 }
1019 
1020 /**
1021  * Turn off the crosshair cursor, wherever it is.
1022  */
1023 void
status_crosshair_off(void)1024 status_crosshair_off(void)
1025 {
1026     int i;
1027 
1028     for (i = 0; i < maxCOLS; i++) {
1029 	if (sxcursor_want[i]) {
1030 	    sxcursor_want[i] = false;
1031 	    set_status_changed(i);
1032 	}
1033     }
1034 }
1035 
1036 /*
1037  * Render a region of the status line onto the display, the idea being to
1038  * minimize the number of redundant X drawing operations performed.
1039  *
1040  * What isn't optimized is what happens when "ABC" becomes "XBZ" -- should we
1041  * redundantly draw over B or not?  Right now we don't.
1042  */
1043 static void
status_render(int region)1044 status_render(int region)
1045 {
1046     int i;
1047     struct status_line *sl = &status_line[region];
1048     int nd = 0;
1049     int i0 = -1;
1050     XTextItem16 text1;
1051 
1052     /* The status region may change colors; don't be so clever */
1053     if (region == WAIT_REGION) {
1054 	XFillRectangle(display, *screen_window,
1055 		screen_invgc(sl->color),
1056 		COL_TO_X(sl->start), status_y - *ascent,
1057 		*char_width * sl->len, *char_height);
1058 	text1.chars = sl->s2b;
1059 	text1.nchars = sl->len;
1060 	text1.delta = 0;
1061 	text1.font = *fid;
1062 	XDrawText16(display, *screen_window, screen_gc(sl->color),
1063 		COL_TO_X(sl->start), status_y, &text1, 1);
1064     } else {
1065 	for (i = 0; i < sl->len; i++) {
1066 	    if (*funky_font || *xtra_width) {
1067 		if (!sl->s1b[i]) {
1068 		    continue;
1069 		}
1070 		XFillRectangle(display, *screen_window,
1071 			screen_invgc(sl->color),
1072 			COL_TO_X(sl->start + i), status_y - *ascent,
1073 			*char_width, *char_height);
1074 		text1.chars = sl->s2b + i;
1075 		text1.nchars = 1;
1076 		text1.delta = 0;
1077 		text1.font = *fid;
1078 		XDrawText16(display,
1079 			*screen_window,
1080 			screen_gc(sl->color),
1081 			COL_TO_X(sl->start + i),
1082 			status_y,
1083 			&text1, 1);
1084 		continue;
1085 	    }
1086 	    if (sl->s2b[i].byte1 == sl->d2b[i].byte1 &&
1087 		sl->s2b[i].byte2 == sl->d2b[i].byte2) {
1088 		if (nd) {
1089 		    XFillRectangle(display, *screen_window,
1090 			    screen_invgc(sl->color), COL_TO_X(sl->start + i0),
1091 			    status_y - *ascent, *char_width * nd,
1092 			    *char_height);
1093 		    text1.chars = sl->s2b + i0;
1094 		    text1.nchars = nd;
1095 		    text1.delta = 0;
1096 		    text1.font = *fid;
1097 		    XDrawText16(display, *screen_window, screen_gc(sl->color),
1098 			    COL_TO_X(sl->start + i0), status_y, &text1, 1);
1099 		    nd = 0;
1100 		    i0 = -1;
1101 		}
1102 	    } else {
1103 		if (!nd++) {
1104 		    i0 = i;
1105 		}
1106 	    }
1107 	}
1108 	if (nd) {
1109 	    XFillRectangle(display, *screen_window, screen_invgc(sl->color),
1110 		    COL_TO_X(sl->start + i0), status_y - *ascent,
1111 		    *char_width * nd, *char_height);
1112 	    text1.chars = sl->s2b + i0;
1113 	    text1.nchars = nd;
1114 	    text1.delta = 0;
1115 	    text1.font = *fid;
1116 	    XDrawText16(display, *screen_window,
1117 		screen_gc(sl->color),
1118 		COL_TO_X(sl->start + i0), status_y,
1119 		&text1, 1);
1120 	}
1121     }
1122 
1123     /* Leftmost region has unusual attributes */
1124     if (*standard_font && region == CTLR_REGION) {
1125 	XFillRectangle(display, *screen_window,
1126 		screen_invgc(sl->color),
1127 		COL_TO_X(sl->start), status_y - *ascent,
1128 		*char_width * 3, *char_height);
1129 	XFillRectangle(display, *screen_window,
1130 		screen_gc(sl->color),
1131 		COL_TO_X(sl->start + LBOX), status_y - *ascent,
1132 		*char_width, *char_height);
1133 	XFillRectangle(display, *screen_window,
1134 		screen_gc(sl->color),
1135 		COL_TO_X(sl->start + RBOX), status_y - *ascent,
1136 		*char_width, *char_height);
1137 	text1.chars = sl->s2b + LBOX;
1138 	text1.nchars = 1;
1139 	text1.delta = 0;
1140 	text1.font = *fid;
1141 	XDrawText16(display, *screen_window,
1142 		screen_invgc(sl->color),
1143 		COL_TO_X(sl->start + LBOX), status_y,
1144 		&text1, 1);
1145 	XDrawRectangle(display, *screen_window, screen_gc(sl->color),
1146 		COL_TO_X(sl->start + CNCT),
1147 		status_y - *ascent + *char_height - 1,
1148 		*char_width - 1, 0);
1149 	text1.chars = sl->s2b + CNCT;
1150 	XDrawText16(display, *screen_window,
1151 		screen_gc(sl->color),
1152 		COL_TO_X(sl->start + CNCT), status_y,
1153 		&text1, 1);
1154 	text1.chars = sl->s2b + RBOX;
1155 	XDrawText16(display, *screen_window,
1156 		screen_invgc(sl->color),
1157 		COL_TO_X(sl->start + RBOX), status_y,
1158 		&text1, 1);
1159     }
1160 }
1161 
1162 /* Write into the message area of the status line */
1163 static void
status_msg_set(unsigned const char * msg,int len)1164 status_msg_set(unsigned const char *msg, int len)
1165 {
1166     int i;
1167 
1168     for (i = 0; i < status_line[WAIT_REGION].len; i++) {
1169 	status_add(M0 + i, len ? msg[i] : nullblank, KT_STD);
1170 	if (len) {
1171 	    len--;
1172 	}
1173     }
1174 }
1175 
1176 /* Controller status */
1177 static void
do_ctlr(void)1178 do_ctlr(void)
1179 {
1180     if (*standard_font) {
1181 	status_add(LBOX, '4', KT_STD);
1182 	if (oia_undera) {
1183 	    status_add(CNCT, (IN_E ? 'B' : 'A'), KT_STD);
1184 	} else {
1185 	    status_add(CNCT, ' ', KT_STD);
1186 	}
1187 	if (IN_NVT) {
1188 	    status_add(RBOX, 'N', KT_STD);
1189 	} else if (oia_boxsolid) {
1190 	    status_add(RBOX, ' ', KT_STD);
1191 	} else if (IN_SSCP) {
1192 	    status_add(RBOX, 'S', KT_STD);
1193 	} else {
1194 	    status_add(RBOX, '?', KT_STD);
1195 	}
1196     } else {
1197 	status_add(LBOX, CG_box4, KT_STD);
1198 	if (oia_undera) {
1199 	    status_add(CNCT, (IN_E ? CG_underB : CG_underA), KT_STD);
1200 	} else {
1201 	    status_add(CNCT, CG_space, KT_STD);
1202 	}
1203 	if (IN_NVT) {
1204 	    status_add(RBOX, CG_N, KT_STD);
1205 	} else if (oia_boxsolid) {
1206 	    status_add(RBOX, CG_boxsolid, KT_STD);
1207 	} else if (IN_SSCP) {
1208 	    status_add(RBOX, CG_boxhuman, KT_STD);
1209 	} else {
1210 	    status_add(RBOX, CG_boxquestion, KT_STD);
1211 	}
1212     }
1213 }
1214 
1215 /* Message area */
1216 
1217 /* Change the state of the message area, or if scrolled, the saved message */
1218 static void
do_msg(enum msg t)1219 do_msg(enum msg t)
1220 {
1221     if (msg_is_saved) {
1222 	scroll_saved_msg = t;
1223 	return;
1224     }
1225     paint_msg(t);
1226 }
1227 
1228 /* Paint the message area. */
1229 static void
paint_msg(enum msg t)1230 paint_msg(enum msg t)
1231 {
1232     oia_msg = t;
1233     (*msg_proc[(int)t])();
1234     if (!appres.interactive.mono) {
1235 	status_line[WAIT_REGION].color = mode.m3279 ?
1236 	    msg_color3279[(int)t] : msg_color[(int)t];
1237     }
1238 }
1239 
1240 static void
do_blank(void)1241 do_blank(void)
1242 {
1243     status_msg_set((unsigned char *) 0, 0);
1244 }
1245 
1246 static void
do_disconnected(void)1247 do_disconnected(void)
1248 {
1249     if (*standard_font) {
1250 	status_msg_set(a_not_connected, strlen((char *)a_not_connected));
1251     } else {
1252 	status_msg_set(disc_msg, disc_len);
1253     }
1254 }
1255 
1256 static void
do_reconnecting(void)1257 do_reconnecting(void)
1258 {
1259     if (*standard_font) {
1260 	status_msg_set(a_reconnecting, strlen((char *)a_reconnecting));
1261     } else {
1262 	status_msg_set(recon_msg, recon_len);
1263     }
1264 }
1265 
1266 static void
do_resolving(void)1267 do_resolving(void)
1268 {
1269     if (*standard_font) {
1270 	status_msg_set(a_resolving, strlen((char *)a_resolving));
1271     } else {
1272 	status_msg_set(rslv_msg, rslv_len);
1273     }
1274 }
1275 
1276 static void
do_connecting(void)1277 do_connecting(void)
1278 {
1279     if (*standard_font) {
1280 	status_msg_set(a_connecting, strlen((char *)a_connecting));
1281     } else {
1282 	status_msg_set(cnct_msg, cnct_len);
1283     }
1284 }
1285 
1286 static void
do_tls(void)1287 do_tls(void)
1288 {
1289     if (*standard_font) {
1290 	status_msg_set(a_tls, strlen((char *)a_tls));
1291     } else {
1292 	status_msg_set(tls_msg, tls_len);
1293     }
1294 }
1295 
1296 static void
do_proxy(void)1297 do_proxy(void)
1298 {
1299     if (*standard_font) {
1300 	status_msg_set(a_proxy, strlen((char *)a_proxy));
1301     } else {
1302 	status_msg_set(proxy_msg, proxy_len);
1303     }
1304 }
1305 
1306 static void
do_telnet(void)1307 do_telnet(void)
1308 {
1309     if (*standard_font) {
1310 	status_msg_set(a_telnet, strlen((char *)a_telnet));
1311     } else {
1312 	status_msg_set(telnet_msg, telnet_len);
1313     }
1314 }
1315 
1316 static void
do_tn3270e(void)1317 do_tn3270e(void)
1318 {
1319     if (*standard_font) {
1320 	status_msg_set(a_tn3270e, strlen((char *)a_tn3270e));
1321     } else {
1322 	status_msg_set(tn3270e_msg, tn3270e_len);
1323     }
1324 }
1325 
1326 static void
do_awaiting_first(void)1327 do_awaiting_first(void)
1328 {
1329     if (*standard_font) {
1330 	status_msg_set(a_awaiting_first, strlen((char *)a_awaiting_first));
1331     } else {
1332 	status_msg_set(awaiting_first_msg, awaiting_first_len);
1333     }
1334 }
1335 
1336 static void
do_unlock_delay(void)1337 do_unlock_delay(void)
1338 {
1339     static unsigned char unlock_delay[] = {
1340 	CG_lock
1341     };
1342 
1343     if (*standard_font) {
1344 	status_msg_set((unsigned const char *)"X", 1);
1345     } else {
1346 	status_msg_set(unlock_delay, sizeof(unlock_delay));
1347     }
1348 }
1349 
1350 static void
do_inhibit(void)1351 do_inhibit(void)
1352 {
1353     static unsigned char inhibit[] = {
1354 	CG_lock, CG_space, CG_I, CG_n, CG_h, CG_i, CG_b, CG_i, CG_t
1355     };
1356 
1357     if (*standard_font) {
1358 	status_msg_set(a_inhibit, strlen((char *)a_inhibit));
1359     } else {
1360 	status_msg_set(inhibit, sizeof(inhibit));
1361     }
1362 }
1363 
1364 static void
do_twait(void)1365 do_twait(void)
1366 {
1367     static unsigned char twait[] = {
1368 	CG_lock, CG_space, CG_clockleft, CG_clockright
1369     };
1370 
1371     if (*standard_font) {
1372 	status_msg_set(a_twait, strlen((char *)a_twait));
1373     } else {
1374 	status_msg_set(twait, sizeof(twait));
1375     }
1376 }
1377 
1378 static void
do_syswait(void)1379 do_syswait(void)
1380 {
1381     static unsigned char syswait[] = {
1382 	CG_lock, CG_space, CG_S, CG_Y, CG_S, CG_T, CG_E, CG_M
1383     };
1384 
1385     if (*standard_font) {
1386 	status_msg_set(a_syswait, strlen((char *)a_syswait));
1387     } else {
1388 	status_msg_set(syswait, sizeof(syswait));
1389     }
1390 }
1391 
1392 static void
do_protected(void)1393 do_protected(void)
1394 {
1395     static unsigned char protected[] = {
1396 	CG_lock, CG_space, CG_leftarrow, CG_human, CG_rightarrow
1397     };
1398 
1399     if (*standard_font) {
1400 	status_msg_set(a_protected, strlen((char *)a_protected));
1401     } else {
1402 	status_msg_set(protected, sizeof(protected));
1403     }
1404 }
1405 
1406 static void
do_numeric(void)1407 do_numeric(void)
1408 {
1409     static unsigned char numeric[] = {
1410 	CG_lock, CG_space, CG_human, CG_N, CG_U, CG_M
1411     };
1412 
1413     if (*standard_font) {
1414 	status_msg_set(a_numeric, strlen((char *)a_numeric));
1415     } else {
1416 	status_msg_set(numeric, sizeof(numeric));
1417     }
1418 }
1419 
1420 static void
do_overflow(void)1421 do_overflow(void)
1422 {
1423     static unsigned char overflow[] = {
1424 	CG_lock, CG_space, CG_human, CG_greater
1425     };
1426 
1427     if (*standard_font) {
1428 	status_msg_set(a_overflow, strlen((char *)a_overflow));
1429     } else {
1430 	status_msg_set(overflow, sizeof(overflow));
1431     }
1432 }
1433 
1434 static void
do_dbcs(void)1435 do_dbcs(void)
1436 {
1437     static unsigned char dbcs[] = {
1438 	CG_lock, CG_space, CG_less, CG_S, CG_greater
1439     };
1440 
1441     if (*standard_font) {
1442 	status_msg_set(a_dbcs, strlen((char *)a_dbcs));
1443     } else {
1444 	status_msg_set(dbcs, sizeof(dbcs));
1445     }
1446 }
1447 
1448 static void
do_scrolled(void)1449 do_scrolled(void)
1450 {
1451     static unsigned char scrolled[] = {
1452 	CG_lock, CG_space, CG_S, CG_c, CG_r, CG_o, CG_l, CG_l, CG_e,
1453 	CG_d, CG_space, CG_space, CG_space, CG_space, CG_space
1454     };
1455     static unsigned char spaces[] = {
1456 	CG_space, CG_space, CG_space, CG_space
1457     };
1458 
1459     if (*standard_font) {
1460 	char *t;
1461 
1462 	t = XtMalloc(strlen((char *)a_scrolled) + 4);
1463 	sprintf(t, "%s %d", (char *)a_scrolled, n_scrolled);
1464 	status_msg_set((unsigned char *)t, strlen(t));
1465 	XtFree(t);
1466     } else {
1467 	char nnn[5];
1468 	int i;
1469 
1470 	sprintf(nnn, "%d", n_scrolled);
1471 	memcpy((char *)&scrolled[11], (char *)spaces, sizeof(spaces));
1472 	for (i = 0; nnn[i]; i++) {
1473 	    scrolled[11 + i] = asc2cg0[(int)nnn[i]];
1474 	}
1475 	status_msg_set(scrolled, sizeof(scrolled));
1476     }
1477 }
1478 
1479 static void
do_minus(void)1480 do_minus(void)
1481 {
1482     static unsigned char minus[] = {
1483 	CG_lock, CG_space, CG_minus, CG_f
1484     };
1485 
1486     if (*standard_font) {
1487 	status_msg_set(a_minus, strlen((char *)a_minus));
1488     } else {
1489 	status_msg_set(minus, sizeof(minus));
1490     }
1491 }
1492 
1493 static void
do_disabled(void)1494 do_disabled(void)
1495 {
1496     static unsigned char disabled[] = {
1497 	CG_lock, CG_space, CG_keyleft, CG_keyright
1498     };
1499 
1500     if (*standard_font) {
1501 	status_msg_set(a_minus, strlen((char *)a_minus));
1502     } else {
1503 	status_msg_set(disabled, sizeof(disabled));
1504     }
1505 }
1506 
1507 /* Insert, reverse, kmap, script, shift, compose */
1508 
1509 static void
do_insert(bool on)1510 do_insert(bool on)
1511 {
1512     status_add(INSERT,
1513 	    on ? (*standard_font ? 'I' : CG_insert) : nullblank, KT_STD);
1514 }
1515 
1516 static void
do_reverse(bool on)1517 do_reverse(bool on)
1518 {
1519     status_add(REVERSE,
1520 	    on ? (*standard_font ? 'R' : CG_R) : nullblank, KT_STD);
1521 }
1522 
1523 static void
do_kmap(bool on)1524 do_kmap(bool on)
1525 {
1526     status_add(KMAP,
1527 	    on ? (*standard_font ? 'K' : CG_K) : nullblank, KT_STD);
1528 }
1529 
1530 static void
do_script(bool on)1531 do_script(bool on)
1532 {
1533     status_add(SCRIPT,
1534 	    on ? (*standard_font ? 's' : CG_s) : nullblank, KT_STD);
1535 }
1536 
1537 static void
do_printer(bool on)1538 do_printer(bool on)
1539 {
1540     status_add(PSESS,
1541 	    on ? (*standard_font ? 'P' : CG_P) : nullblank, KT_STD);
1542 }
1543 
1544 static void
do_shift(int state)1545 do_shift(int state)
1546 {
1547     status_add(SHIFT-2, (state & MetaKeyDown) ?
1548 	    (*standard_font ? 'M' : CG_M) : nullblank, KT_STD);
1549     status_add(SHIFT-1, (state & AltKeyDown) ?
1550 	    (*standard_font ? 'A' : CG_A) : nullblank, KT_STD);
1551     status_add(SHIFT, (state & ShiftKeyDown) ?
1552 	    (*standard_font ? '^' : CG_upshift) : nullblank, KT_STD);
1553 
1554     /* APL requires some somersaults. */
1555     if (state & AplMode) {
1556 	status_add(SHIFT + 1,
1557 		*full_apl_font? (CG_alpha & 0xff) :
1558 		    (*standard_font? 'a': CG_a),
1559 		*full_apl_font? KT_GE: KT_STD);
1560     } else {
1561 	status_add(SHIFT + 1, nullblank, KT_STD);
1562     }
1563 }
1564 
1565 static void
do_typeahead(int state)1566 do_typeahead(int state)
1567 {
1568     status_add(TYPEAHD,
1569 	    state ? (*standard_font ? 'T' : CG_T) : nullblank, KT_STD);
1570 }
1571 
1572 static void
do_screentrace(int n)1573 do_screentrace(int n)
1574 {
1575     unsigned char c;
1576 
1577     if (n < 0) {
1578 	c = *standard_font? ' ': CG_space;
1579     } else if (n < 9) {
1580 	c = *standard_font? ('1' + n): (CG_1 + n);
1581     } else {
1582 	c = *standard_font? '+': CG_plus;
1583     }
1584 
1585     status_add(SCRNTRC, c, KT_STD);
1586 }
1587 
1588 static void
do_compose(bool on,ucs4_t ucs4,enum keytype keytype)1589 do_compose(bool on, ucs4_t ucs4, enum keytype keytype)
1590 {
1591     if (on) {
1592 	status_add(COMPOSE,
1593 		(unsigned char)(*standard_font ? 'C' : CG_C), KT_STD);
1594 	if (!ucs4) {
1595 	    status_add(COMPOSE + 1, nullblank, KT_STD);
1596 	} else {
1597 	    if (*standard_font) {
1598 		status_add(COMPOSE + 1, ucs4, KT_STD);
1599 	    } else {
1600 		ebc_t ebc;
1601 		bool ge;
1602 
1603 		ebc = unicode_to_ebcdic_ge(ucs4, &ge, false);
1604 		status_add(COMPOSE + 1, ebc2cg0[ebc], ge? KT_GE: KT_STD);
1605 	    }
1606 	}
1607     } else {
1608 	status_add(COMPOSE, nullblank, KT_STD);
1609 	status_add(COMPOSE + 1, nullblank, KT_STD);
1610     }
1611 }
1612 
1613 static void
do_lu(const char * lu)1614 do_lu(const char *lu)
1615 {
1616     int i;
1617 
1618     for (i = 0; i < LUCNT; i++) {
1619 	status_add(LU + i,
1620 	    lu[i]? (*standard_font? lu[i]: asc2cg0[(int)lu[i]]):
1621 		nullblank,
1622 	    KT_STD);
1623     }
1624 }
1625 
1626 /* Timing */
1627 static void
do_timing(char * buf)1628 do_timing(char *buf)
1629 {
1630     int i;
1631 
1632     if (buf) {
1633 	if (*standard_font) {
1634 	    status_add(T0, nullblank, KT_STD);
1635 	    status_add(T0 + 1, nullblank, KT_STD);
1636 	} else {
1637 	    status_add(T0, CG_clockleft, KT_STD);
1638 	    status_add(T0 + 1, CG_clockright, KT_STD);
1639 	}
1640 	for (i = 0; i < (int) strlen(buf); i++) {
1641 	    status_add(T0 + 2 + i,
1642 		    *standard_font?
1643 			buf[i]:
1644 			asc2cg0[(unsigned char) buf[i]], KT_STD);
1645 	}
1646     } else {
1647 	for (i = 0; i < TCNT; i++) {
1648 	    status_add(T0 + i, nullblank, KT_STD);
1649 	}
1650     }
1651 }
1652 
1653 /* Cursor position */
1654 static void
do_cursor(char * buf)1655 do_cursor(char *buf)
1656 {
1657     int i;
1658 
1659     if (buf) {
1660 	for (i = 0; i < (int) strlen(buf); i++) {
1661 	    status_add(C0 + i,
1662 		    *standard_font?
1663 		    buf[i]: asc2cg0[(unsigned char) buf[i]], KT_STD);
1664 	}
1665     } else {
1666 	for (i = 0; i < CCNT; i++) {
1667 	    status_add(C0 + i, nullblank, KT_STD);
1668 	}
1669     }
1670 }
1671 
1672 /* Prepare status messages */
1673 
1674 static unsigned char *
make_amsg(const char * key)1675 make_amsg(const char *key)
1676 {
1677     return (unsigned char *)xs_buffer("X %s", get_message(key));
1678 }
1679