1 /*
2  * Copyright (c) 1993-2019 Paul Mattes.
3  * Copyright (c) 2004, Don Russell.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above copyright
12  *       notice, this list of conditions and the following disclaimer in the
13  *       documentation and/or other materials provided with the distribution.
14  *     * Neither the names of Paul Mattes, Don Russell nor their
15  *       contributors may be used to endorse or promote products derived
16  *       from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY PAUL MATTES AND DON RUSSELL "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL MATTES OR DON RUSSELL
22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
23  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
24  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 /*
32  *	about.c
33  *		Pop-up window with the current state of x3270.
34  */
35 
36 #include "globals.h"
37 #include "xglobals.h"
38 
39 #include <X11/Shell.h>
40 #include <X11/StringDefs.h>
41 #include <X11/Xaw/Command.h>
42 #include <X11/Xaw/Form.h>
43 #include <X11/Xaw/Label.h>
44 #include "appres.h"
45 #include "objects.h"
46 #include "resources.h"
47 
48 #include "about.h"
49 #include "codepage.h"
50 #include "host.h"
51 #include "keymap.h"
52 #include "lazya.h"
53 #include "linemode.h"
54 #include "popups.h"
55 #include "split_host.h"
56 #include "telnet.h"
57 #include "utf8.h"
58 #include "utils.h"
59 #include "varbuf.h"
60 #include "xappres.h"
61 #include "xscreen.h"
62 #include "xpopups.h"
63 
64 static Widget about_shell = NULL;
65 static Widget about_form;
66 
67 /* Called when OK is pressed on the about popup */
68 static void
saw_about(Widget w _is_unused,XtPointer client_data _is_unused,XtPointer call_data _is_unused)69 saw_about(Widget w _is_unused, XtPointer client_data _is_unused,
70 	XtPointer call_data _is_unused)
71 {
72 	XtPopdown(about_shell);
73 }
74 
75 /* Called when the about popup is popped down */
76 static void
destroy_about(Widget w _is_unused,XtPointer client_data _is_unused,XtPointer call_data _is_unused)77 destroy_about(Widget w _is_unused, XtPointer client_data _is_unused,
78 	XtPointer call_data _is_unused)
79 {
80 	XtDestroyWidget(about_shell);
81 	about_shell = NULL;
82 }
83 
84 /* Return a time difference in English */
85 static char *
hms(time_t ts)86 hms(time_t ts)
87 {
88     time_t t, td;
89     long hr, mn, sc;
90 
91     time(&t);
92 
93     td = t - ts;
94     hr = td / 3600;
95     mn = (td % 3600) / 60;
96     sc = td % 60;
97 
98     if (hr > 0) {
99 	return lazyaf("%ld %s %ld %s %ld %s",
100 		hr, (hr == 1)?
101 		    get_message("hour"): get_message("hours"),
102 		mn, (mn == 1)?
103 		    get_message("minute"): get_message("minutes"),
104 		sc, (sc == 1)?
105 		    get_message("second"): get_message("seconds"));
106     } else if (mn > 0) {
107 	return lazyaf("%ld %s %ld %s",
108 		mn, (mn == 1)?
109 		    get_message("minute"): get_message("minutes"),
110 		sc, (sc == 1)?
111 		    get_message("second"): get_message("seconds"));
112     } else {
113 	    return lazyaf("%ld %s",
114 		sc, (sc == 1)?
115 		    get_message("second"): get_message("seconds"));
116     }
117 }
118 
119 #define MAKE_SMALL(label, n) { \
120 	w_prev = w; \
121 	w = XtVaCreateManagedWidget( \
122 	    ObjSmallLabel, labelWidgetClass, about_form, \
123 	    XtNborderWidth, 0, \
124 	    XtNlabel, label, \
125 	    XtNfromVert, w, \
126 	    XtNleft, XtChainLeft, \
127 	    XtNvertDistance, rescale(n), \
128 	    NULL); \
129 	vd = n; \
130 	}
131 
132 #define MAKE_LABEL(label, n) { \
133 	w_prev = w; \
134 	w = XtVaCreateManagedWidget( \
135 	    ObjNameLabel, labelWidgetClass, about_form, \
136 	    XtNborderWidth, 0, \
137 	    XtNlabel, label, \
138 	    XtNfromVert, w, \
139 	    XtNfromHoriz, left_anchor, \
140 	    XtNleft, XtChainLeft, \
141 	    XtNvertDistance, rescale(n), \
142 	    NULL); \
143 	vd = n; \
144 	}
145 
146 #define MAKE_VALUE(label) { \
147 	v = XtVaCreateManagedWidget( \
148 	    ObjDataLabel, labelWidgetClass, about_form, \
149 	    XtNborderWidth, 0, \
150 	    XtNlabel, label, \
151 	    XtNfromVert, w_prev, \
152 	    XtNfromHoriz, w, \
153 	    XtNhorizDistance, 0, \
154 	    XtNvertDistance, rescale(vd), \
155 	    XtNleft, XtChainLeft, \
156 	    NULL); \
157 	}
158 
159 #define MAKE_LABEL2(label) { \
160 	w = XtVaCreateManagedWidget( \
161 	    ObjNameLabel, labelWidgetClass, about_form, \
162 	    XtNborderWidth, 0, \
163 	    XtNlabel, label, \
164 	    XtNfromVert, w_prev, \
165 	    XtNfromHoriz, v, \
166 	    XtNhorizDistance, 0, \
167 	    XtNvertDistance, rescale(vd), \
168 	    XtNleft, XtChainLeft, \
169 	    NULL); \
170 	}
171 
ignore_vd(int vd _is_unused)172 static void ignore_vd(int vd _is_unused)
173 {
174 }
175 
ignore_w_prev(Widget w_prev _is_unused)176 static void ignore_w_prev(Widget w_prev _is_unused)
177 {
178 }
179 
180 /* Called when the "About x3270->Copyright" button is pressed */
181 void
popup_about_copyright(void)182 popup_about_copyright(void)
183 {
184 	Widget w = NULL, w_prev = NULL;
185 	Widget left_anchor = NULL;
186 	int vd = 4;
187 	static bool catted = false;
188 	static char *s1 = NULL;
189 	static char *s2 = NULL;
190 	static char *s1a =
191 "* Redistributions of source code must retain the above copyright\n\
192 notice, this list of conditions and the following disclaimer.\n\
193 * Redistributions in binary form must reproduce the above copyright\n\
194 notice, this list of conditions and the following disclaimer in the\n";
195 	static char *s1b =
196 "documentation and/or other materials provided with the distribution.\n\
197 * Neither the names of Paul Mattes, Don Russell, Dick Altenbern,\n\
198 Jeff Sparkes, GTRC nor their contributors may be used to endorse or\n\
199 promote products derived from this software without specific prior\n\
200 written permission.";
201 	static char *s2a =
202 "THIS SOFTWARE IS PROVIDED BY PAUL MATTES, DON RUSSELL, DICK ALTENBERN,\n\
203 JEFF SPARKES AND GTRC \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n\
204 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n\
205 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL\n\
206 MATTES, DON RUSSELL, DICK ALTENBERN, JEFF SPARKES OR GTRC BE LIABLE FOR ANY\n\
207 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n";
208 	static char *s2b =
209 "(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n\
210 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n\
211 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n\
212 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n\
213 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n\
214 DAMAGE.";
215 	static char *line1 = NULL;
216 
217 	if (!catted) {
218 	    /* Make up for the ANSI C listerl string length limit. */
219 	    s1 = Malloc(strlen(s1a) + strlen(s1b) + 1);
220 	    strcpy(s1, s1a);
221 	    strcat(s1, s1b);
222 	    s2 = Malloc(strlen(s2a) + strlen(s2b) + 1);
223 	    strcpy(s2, s2a);
224 	    strcat(s2, s2b);
225 	    catted = true;
226 	}
227 
228 	/* Create the popup */
229 
230 	about_shell = XtVaCreatePopupShell(
231 	    "aboutCopyrightPopup", transientShellWidgetClass, toplevel,
232 	    NULL);
233 	XtAddCallback(about_shell, XtNpopupCallback, place_popup,
234 	    (XtPointer) CenterP);
235 	XtAddCallback(about_shell, XtNpopdownCallback, destroy_about,
236 	    NULL);
237 
238 	/* Create a form in the popup */
239 
240 	about_form = XtVaCreateManagedWidget(
241 	    ObjDialog, formWidgetClass, about_shell,
242 	    NULL);
243 
244 	/* Pretty picture */
245 
246 	left_anchor = XtVaCreateManagedWidget(
247 	    "icon", labelWidgetClass, about_form,
248 	    XtNborderWidth, 0,
249 	    XtNbitmap, x3270_icon,
250 	    XtNfromVert, w,
251 	    XtNleft, XtChainLeft,
252 	    NULL);
253 
254 	/* Miscellany */
255 
256 	MAKE_LABEL(build, 4);
257 
258 	/* Everything else at the left margin under the bitmap */
259 	w = left_anchor;
260 	left_anchor = NULL;
261 
262 	if (line1 == NULL) {
263 	    line1 = xs_buffer(
264 "Copyright \251 1993-%s, Paul Mattes.\n\
265 Copyright \251 2004-2005, Don Russell.\n\
266 Copyright \251 1995, Dick Altenbern.\n\
267 Copyright \251 1990, Jeff Sparkes.\n\
268 Copyright \251 1989, Georgia Tech Research Corporation (GTRC), Atlanta, GA 30332.\n\
269 All rights reserved.", cyear);
270 	}
271 	MAKE_SMALL(line1, 4);
272 	MAKE_SMALL(
273 "Redistribution and use in source and binary forms, with or without\n\
274 modification, are permitted provided that the following conditions\n\
275 are met:", 4);
276 	MAKE_SMALL(s1, 4);
277 	MAKE_SMALL(s2, 4);
278 
279 	/* Add "OK" button at the lower left */
280 
281 	w = XtVaCreateManagedWidget(
282 	    ObjConfirmButton, commandWidgetClass, about_form,
283 	    XtNfromVert, w,
284 	    XtNleft, XtChainLeft,
285 	    XtNbottom, XtChainBottom,
286 	    NULL);
287 	XtAddCallback(w, XtNcallback, saw_about, 0);
288 
289 	/* Pop it up */
290 
291 	popup_popup(about_shell, XtGrabExclusive);
292 
293 	/* Make gcc happy. */
294 	ignore_vd(vd);
295 	ignore_w_prev(w_prev);
296 }
297 
298 /* Called when the "About x3270->Configuration" button is pressed */
299 void
popup_about_config(void)300 popup_about_config(void)
301 {
302     Widget w = NULL, w_prev = NULL;
303     Widget v = NULL;
304     Widget left_anchor = NULL;
305     int vd = 4;
306     const char *ftype;
307     char *xbuf;
308 
309     /* Create the popup */
310     about_shell = XtVaCreatePopupShell(
311 	"aboutConfigPopup", transientShellWidgetClass, toplevel,
312 	NULL);
313     XtAddCallback(about_shell, XtNpopupCallback, place_popup,
314 	(XtPointer) CenterP);
315     XtAddCallback(about_shell, XtNpopdownCallback, destroy_about,
316 	NULL);
317 
318     /* Create a form in the popup */
319     about_form = XtVaCreateManagedWidget(
320 	ObjDialog, formWidgetClass, about_shell,
321 	NULL);
322 
323     /* Pretty picture */
324     left_anchor = XtVaCreateManagedWidget(
325 	"icon", labelWidgetClass, about_form,
326 	XtNborderWidth, 0,
327 	XtNbitmap, x3270_icon,
328 	XtNfromVert, w,
329 	XtNleft, XtChainLeft,
330 	NULL);
331 
332     /* Miscellany */
333     MAKE_LABEL(build, 4);
334 
335     /* Everything else at the left margin under the bitmap */
336     w = left_anchor;
337     left_anchor = NULL;
338 
339     MAKE_LABEL(get_message("processId"), 4);
340     MAKE_VALUE(lazyaf("%d", getpid()));
341     MAKE_LABEL2(get_message("windowId"));
342     MAKE_VALUE(lazyaf("0x%lx", XtWindow(toplevel)));
343 
344     MAKE_LABEL(lazyaf("%s %s: %d %s x %d %s, %s, %s",
345 	get_message("model"), model_name,
346 	maxCOLS, get_message("columns"),
347 	maxROWS, get_message("rows"),
348 	appres.interactive.mono? get_message("mono"):
349 	    (mode.m3279? get_message("fullColor"):
350 		get_message("pseudoColor")),
351 	(mode.extended && !HOST_FLAG(STD_DS_HOST))?
352 	    get_message("extendedDs"): get_message("standardDs")), 4);
353 
354     MAKE_LABEL(get_message("terminalName"), 4);
355     MAKE_VALUE(termtype);
356 
357     MAKE_LABEL(get_message("emulatorFont"), 4);
358     MAKE_VALUE(full_efontname);
359     if (*standard_font) {
360 	ftype = get_message("xFont");
361     } else {
362 	ftype = get_message("cgFont");
363     }
364     xbuf = xs_buffer("  %s", ftype);
365     MAKE_LABEL(xbuf, 0);
366     XtFree(xbuf);
367 
368     if (dbcs) {
369 	MAKE_LABEL(get_message("emulatorFontDbcs"), 4);
370 	MAKE_VALUE(full_efontname_dbcs);
371     }
372 
373     MAKE_LABEL(get_message("displayCharacterSet"), 4);
374     if (!efont_matches) {
375 	xbuf = xs_buffer("ascii-7 (%s %s, %s %s)",
376 		get_message("require"), display_charset(),
377 		get_message("have"), efont_charset);
378 	MAKE_VALUE(xbuf);
379 	XtFree(xbuf);
380     } else {
381 	MAKE_VALUE(efont_charset);
382     }
383     if (dbcs) {
384 	MAKE_LABEL(get_message("displayCharacterSetDbcs"), 4);
385 	MAKE_VALUE(efont_charset_dbcs);
386     }
387 
388     MAKE_LABEL(get_message("codepage"), 4);
389     xbuf = xs_buffer("%s (%s)", get_codepage_name(), get_codepage_number());
390     MAKE_VALUE(xbuf);
391     XtFree(xbuf);
392 
393     MAKE_LABEL(get_message("sbcsCgcsgid"), 4);
394     xbuf = xs_buffer("GCSGID %u, CPGID %u",
395 	    (unsigned short)((cgcsgid >> 16) & 0xffff),
396 	    (unsigned short)(cgcsgid & 0xffff));
397     MAKE_VALUE(xbuf);
398     XtFree(xbuf);
399     if (dbcs) {
400 	MAKE_LABEL(get_message("dbcsCgcsgid"), 4);
401 	xbuf = xs_buffer("GCSGID %u, CPGID %u",
402 		(unsigned short)((cgcsgid_dbcs >> 16) & 0xffff),
403 		(unsigned short)(cgcsgid_dbcs & 0xffff));
404 	MAKE_VALUE(xbuf);
405 	XtFree(xbuf);
406 	MAKE_LABEL(get_message("inputMethod"), 4);
407 	if (xappres.input_method) {
408 	    MAKE_VALUE(xappres.input_method);
409 	} else if (getenv("XMODIFIERS") != NULL) {
410 	    MAKE_VALUE("(via environment)");
411 	} else {
412 	    MAKE_VALUE("(unspecified)");
413 	}
414 	MAKE_LABEL2(get_message("ximState"));
415 	if (xim_error) {
416 	    ftype = get_message("ximDisabled");
417 	} else if (im == NULL) {
418 	    ftype = get_message("ximNotFound");
419 	} else {
420 	    ftype = get_message("ximActive");
421 	}
422 	MAKE_VALUE(ftype);
423 	MAKE_LABEL2(get_message("ximLocale"));
424 	if (locale_name != NULL) {
425 	    MAKE_VALUE(locale_name);
426 	} else {
427 	    MAKE_VALUE("(error)");
428 	}
429     }
430     MAKE_LABEL(get_message("localeCodeset"), 4);
431     MAKE_VALUE(locale_codeset);
432 
433     if (trans_list != NULL || temp_keymaps != NULL) {
434 	struct trans_list *t;
435 	varbuf_t r;
436 
437 	vb_init(&r);
438 	for (t = trans_list; t; t = t->next) {
439 	    if (vb_len(&r)) {
440 		vb_appends(&r, ",");
441 	    }
442 	    vb_appends(&r, t->name);
443 	}
444 	for (t = temp_keymaps; t; t = t->next) {
445 	    if (vb_len(&r)) {
446 		vb_appends(&r, " ");
447 	    }
448 	    vb_appends(&r, "+");
449 	    vb_appends(&r, t->name);
450 	}
451 	MAKE_LABEL(get_message("keyboardMap"), 4)
452 	MAKE_VALUE(vb_buf(&r));
453 	vb_free(&r);
454     } else {
455 	MAKE_LABEL(get_message("defaultKeyboardMap"), 4);
456     }
457     if (appres.interactive.compose_map) {
458 	MAKE_LABEL(get_message("composeMap"), 4);
459 	MAKE_VALUE(appres.interactive.compose_map);
460     } else {
461 	MAKE_LABEL(get_message("noComposeMap"), 4);
462     }
463 
464     if (xappres.active_icon) {
465 	MAKE_LABEL(get_message("activeIcon"), 4);
466 	xbuf = xs_buffer("  %s", get_message("iconFont"));
467 	MAKE_LABEL(xbuf, 0);
468 	XtFree(xbuf);
469 	MAKE_VALUE(xappres.icon_font);
470 	if (xappres.label_icon) {
471 	    xbuf = xs_buffer("  %s", get_message("iconLabelFont"));
472 	    MAKE_LABEL(xbuf, 0);
473 	    XtFree(xbuf);
474 	    MAKE_VALUE(xappres.icon_label_font);
475 	}
476     } else {
477 	MAKE_LABEL(get_message("staticIcon"), 4);
478     }
479 
480     /* Add "OK" button at the lower left */
481     w = XtVaCreateManagedWidget(
482 	ObjConfirmButton, commandWidgetClass, about_form,
483 	XtNfromVert, w,
484 	XtNleft, XtChainLeft,
485 	XtNbottom, XtChainBottom,
486 	NULL);
487     XtAddCallback(w, XtNcallback, saw_about, 0);
488 
489     /* Pop it up */
490     popup_popup(about_shell, XtGrabExclusive);
491 }
492 
493 /* Called when the "About x3270->Connection Status" button is pressed */
494 void
popup_about_status(void)495 popup_about_status(void)
496 {
497     Widget w = NULL, w_prev = NULL;
498     Widget v = NULL;
499     Widget left_anchor = NULL;
500     int vd = 4;
501     const char *fbuf;
502     const char *ftype;
503     const char *emode;
504     const char *eopts;
505     const char *ptype;
506     const char *bplu;
507 
508     /* Create the popup */
509     about_shell = XtVaCreatePopupShell(
510 	"aboutStatusPopup", transientShellWidgetClass, toplevel,
511 	NULL);
512     XtAddCallback(about_shell, XtNpopupCallback, place_popup,
513 	(XtPointer) CenterP);
514     XtAddCallback(about_shell, XtNpopdownCallback, destroy_about,
515 	NULL);
516 
517     /* Create a form in the popup */
518     about_form = XtVaCreateManagedWidget(
519 	ObjDialog, formWidgetClass, about_shell,
520 	NULL);
521 
522     /* Pretty picture */
523     left_anchor = XtVaCreateManagedWidget(
524 	"icon", labelWidgetClass, about_form,
525 	XtNborderWidth, 0,
526 	XtNbitmap, x3270_icon,
527 	XtNfromVert, w,
528 	XtNleft, XtChainLeft,
529 	NULL);
530 
531     /* Miscellany */
532     MAKE_LABEL(build, 4);
533 
534     /* Everything else at the left margin under the bitmap */
535     w = left_anchor;
536     left_anchor = NULL;
537 
538     if (CONNECTED) {
539 	MAKE_LABEL(get_message("connectedTo"), 4);
540 #if defined(LOCAL_PROCESS) /*[*/
541 	if (local_process && !strlen(current_host)) {
542 	    MAKE_VALUE("(shell)");
543 	} else
544 #endif /*]*/
545 	{
546 	    if (!xappres.suppress_host) {
547 		MAKE_VALUE(current_host);
548 	    }
549 	}
550 #if defined(LOCAL_PROCESS) /*[*/
551 	if (!local_process) {
552 #endif /*]*/
553 	    MAKE_LABEL2(lazyaf("  %s", get_message("port")));
554 	    MAKE_VALUE(lazyaf("%d", current_port));
555 #if defined(LOCAL_PROCESS) /*[*/
556 	}
557 #endif /*]*/
558 	if (net_secure_connection()) {
559 	    const char *session, *cert;
560 	    const char *newline;
561 
562 	    MAKE_LABEL2(lazyaf("%s%s%s",
563 			get_message("secure"),
564 			net_secure_unverified()? ", ": "",
565 			net_secure_unverified()? get_message("unverified"): ""));
566 	    MAKE_LABEL(lazyaf("%s %s",
567 			get_message("provider"), net_sio_provider()), 2);
568 	    if ((session = net_session_info()) != NULL) {
569 		MAKE_LABEL(get_message("sessionInfo"), 2);
570 		while ((newline = strchr(session, '\n')) != NULL) {
571 		    MAKE_LABEL(lazyaf("   %.*s", (int)(newline - session),
572 				session), 0);
573 		    session = newline + 1;
574 		}
575 		MAKE_LABEL(lazyaf("   %s", session), 0);
576 	    }
577 	    if ((cert = net_server_cert_info()) != NULL) {
578 		int line_len;
579 #		define CERT_WRAP 80
580 		char *break_indent = "";
581 
582 		MAKE_LABEL(get_message("serverCert"), 2);
583 		while ((newline = strchr(cert, '\n')) != NULL) {
584 		    line_len = (int)(newline - cert);
585 		    while (line_len > CERT_WRAP) {
586 			MAKE_LABEL(lazyaf("   %s%.*s", break_indent, CERT_WRAP,
587 				    cert), 0);
588 			cert += CERT_WRAP;
589 			line_len -= CERT_WRAP;
590 			break_indent = "  ";
591 		    }
592 
593 		    MAKE_LABEL(lazyaf("   %s%.*s", break_indent, line_len,
594 				cert), 0);
595 		    cert = newline + 1;
596 		    break_indent = "";
597 		}
598 
599 		line_len = (int)strlen(cert);
600 		while (line_len > CERT_WRAP) {
601 		    MAKE_LABEL(lazyaf("   %s%.*s", break_indent, CERT_WRAP,
602 				cert), 0);
603 		    cert += CERT_WRAP;
604 		    line_len -= CERT_WRAP;
605 		    break_indent = "  ";
606 		}
607 		MAKE_LABEL(lazyaf("   %s%s", break_indent, cert), 0);
608 	    }
609 	}
610 	ptype = net_proxy_type();
611 	if (ptype) {
612 	    MAKE_LABEL(get_message("proxyType"), 4);
613 	    MAKE_VALUE(ptype);
614 	    MAKE_LABEL2(lazyaf("  %s", get_message("server")));
615 	    MAKE_VALUE(net_proxy_host());
616 	    MAKE_LABEL2(lazyaf("  %s", get_message("port")));
617 	    MAKE_VALUE(net_proxy_port());
618 	}
619 
620 	if (IN_E) {
621 	    emode = "TN3270E ";
622 	} else {
623 	    emode = "";
624 	}
625 	if (IN_NVT) {
626 	    if (linemode) {
627 		ftype = get_message("lineMode");
628 	    } else {
629 		ftype = get_message("charMode");
630 	    }
631 	    fbuf = lazyaf("%s%s, ", emode, ftype);
632 	} else if (IN_SSCP) {
633 	    fbuf = lazyaf("%s%s, ", emode, get_message("sscpMode"));
634 	} else if (IN_3270) {
635 	    fbuf = lazyaf("%s%s, ", emode, get_message("dsMode"));
636 	} else if (cstate == CONNECTED_UNBOUND) {
637 	    fbuf = lazyaf("%s%s, ", emode, get_message("unboundMode"));
638 	} else {
639 	    fbuf = "";
640 	}
641 	fbuf = lazyaf("%s%s", fbuf, hms(ns_time));
642 	MAKE_LABEL(fbuf, 0);
643 
644 	if (connected_lu != NULL && connected_lu[0]) {
645 	    MAKE_LABEL(lazyaf("  %s", get_message("luName")), 0);
646 	    MAKE_VALUE(connected_lu);
647 	}
648 	bplu = net_query_bind_plu_name();
649 	if (bplu != NULL && bplu[0]) {
650 	    MAKE_LABEL(lazyaf("  %s", get_message("bindPluName")), 0);
651 	    MAKE_VALUE(bplu);
652 	}
653 
654 	eopts = tn3270e_current_opts();
655 	if (eopts != NULL) {
656 	    MAKE_LABEL(lazyaf("  %s", get_message("tn3270eOpts")), 0);
657 	    MAKE_VALUE(eopts);
658 	} else if (IN_E) {
659 	    MAKE_LABEL(lazyaf("  %s", get_message("tn3270eNoOpts")), 0);
660 	}
661 
662 	if (IN_3270) {
663 	    fbuf = lazyaf("%s %d %s, %d %s\n%s %d %s, %d %s",
664 		    get_message("sent"),
665 		    ns_bsent, (ns_bsent == 1)?
666 			get_message("byte"): get_message("bytes"),
667 			ns_rsent, (ns_rsent == 1)?
668 		    get_message("record"): get_message("records"),
669 		    get_message("Received"),
670 		    ns_brcvd, (ns_brcvd == 1)?
671 			get_message("byte"): get_message("bytes"),
672 		    ns_rrcvd, (ns_rrcvd == 1)?
673 			get_message("record"): get_message("records"));
674 	} else {
675 	    fbuf = lazyaf("%s %d %s, %s %d %s",
676 		    get_message("sent"),
677 		    ns_bsent, (ns_bsent == 1)?
678 			get_message("byte"): get_message("bytes"),
679 		    get_message("received"),
680 		    ns_brcvd, (ns_brcvd == 1)?
681 			get_message("byte"): get_message("bytes"));
682 	}
683 	MAKE_LABEL(fbuf, 4);
684 
685 	if (IN_NVT) {
686 	    struct ctl_char *c = linemode_chars();
687 	    int i;
688 
689 	    MAKE_LABEL(get_message("specialCharacters"), 4);
690 	    for (i = 0; c[i].name; i++) {
691 		if (!i || !(i % 4)) {
692 		    MAKE_LABEL(lazyaf("  %s", c[i].name), 0);
693 		} else {
694 		    MAKE_LABEL2(c[i].name);
695 		}
696 		MAKE_VALUE(c[i].value);
697 	    }
698 	}
699     } else if (HALF_CONNECTED) {
700 	MAKE_LABEL(get_message("connectionPending"), 4);
701 	MAKE_VALUE(current_host);
702     } else if (host_reconnecting()) {
703 	MAKE_LABEL(get_message("reconnecting"), 4);
704     } else {
705 	MAKE_LABEL(get_message("notConnected"), 4);
706     }
707 
708     /* Add "OK" button at the lower left */
709     w = XtVaCreateManagedWidget(
710 	ObjConfirmButton, commandWidgetClass, about_form,
711 	XtNfromVert, w,
712 	XtNleft, XtChainLeft,
713 	XtNbottom, XtChainBottom,
714 	NULL);
715     XtAddCallback(w, XtNcallback, saw_about, 0);
716 
717     /* Pop it up */
718     popup_popup(about_shell, XtGrabExclusive);
719 }
720 
721 #undef MAKE_LABEL
722 #undef MAKE_VALUE
723