applied 050_ck_patch.patch
[ckermit.git] / ckuus7.c
1 #include "ckcsym.h"
2
3 /*  C K U U S 7 --  "User Interface" for C-Kermit, part 7  */
4
5 /*
6   Authors:
7     Frank da Cruz <fdc@columbia.edu>,
8       The Kermit Project, Columbia University, New York City
9     Jeffrey E Altman <jaltman@secure-endpoints.com>
10       Secure Endpoints Inc., New York City
11
12   Copyright (C) 1985, 2004,
13     Trustees of Columbia University in the City of New York.
14     All rights reserved.  See the C-Kermit COPYING.TXT file or the
15     copyright text in the ckcmai.c module for disclaimer and permissions.
16 */
17
18 /*
19   This file created from parts of ckuus3.c, which became too big for
20   Mark Williams Coherent compiler to handle.
21 */
22
23 /*
24   Definitions here supersede those from system include files.
25 */
26 #include "ckcdeb.h"                     /* Debugging & compiler things */
27 #include "ckcasc.h"                     /* ASCII character symbols */
28 #include "ckcker.h"                     /* Kermit application definitions */
29 #include "ckcxla.h"                     /* Character set translation */
30 #include "ckcnet.h"                     /* Network symbols */
31 #include "ckuusr.h"                     /* User interface symbols */
32 #include "ckucmd.h"
33 #include "ckclib.h"
34
35 #ifdef VMS
36 #ifndef TCPSOCKET
37 #include <errno.h>
38 #endif /* TCPSOCKET */
39 #endif /* VMS */
40
41 #ifdef OS2
42 #ifndef NT
43 #define INCL_NOPM
44 #define INCL_VIO                        /* Needed for ckocon.h */
45 #define INCL_DOSMODULEMGR
46 #include <os2.h>
47 #undef COMMENT
48 #else /* NT */
49 #define APIRET ULONG
50 #include <windows.h>
51 #include <tapi.h>
52 #include "cknwin.h"
53 #include "ckntap.h"
54 #endif /* NT */
55 #include "ckowin.h"
56 #include "ckocon.h"
57 #include "ckodir.h"
58 #ifdef OS2MOUSE
59 #include "ckokey.h"
60 #endif /* OS2MOUSE */
61 #ifdef KUI
62 #include "ikui.h"
63 #endif /* KUI */
64 #ifdef putchar
65 #undef putchar
66 #endif /* putchar */
67 #define putchar(x) conoc(x)
68 extern int mskkeys;
69 #endif /* OS2 */
70
71 #ifdef CK_AUTHENTICATION
72 #include "ckuath.h"
73 #endif /* CK_AUTHENTICATION */
74 #ifdef CK_SSL
75 #include "ck_ssl.h"
76 #endif /* CK_SSL */
77 #ifdef SSHBUILTIN
78 #include "ckossh.h"
79 #endif /* SSHBUILTIN */
80 #ifdef STRATUS                          /* Stratus Computer, Inc.  VOS */
81 #ifdef putchar
82 #undef putchar
83 #endif /* putchar */
84 #define putchar(x) conoc(x)
85 #ifdef getchar
86 #undef getchar
87 #endif /* getchar */
88 #define getchar(x) coninc(0)
89 #endif /* STRATUS */
90
91 char * slmsg = NULL;
92
93 static int x, y = 0, z;
94 static char *s;
95
96 extern CHAR feol;
97 extern int g_matchdot, hints, xcmdsrc, rcdactive;
98
99 extern char * k_info_dir;
100
101 #ifdef CK_LOGIN
102 #ifdef CK_PAM
103 int gotemptypasswd = 0;   /* distinguish empty passwd from none given */
104 #endif /* CK_PAM */
105 #endif /* CK_LOGIN */
106
107 #ifndef NOSPL
108 extern int nmac;
109 extern struct mtab *mactab;
110 #endif /* NOSPL */
111
112 #ifndef NOXFER
113 #ifdef CK_SPEED
114 extern short ctlp[];                    /* Control-char prefixing table */
115 #endif /* CK_SPEED */
116
117 #ifdef PIPESEND
118 extern char * sndfilter, * g_sfilter;
119 extern char * rcvfilter, * g_rfilter;
120 #endif /* PIPESEND */
121
122 extern char * snd_move;
123 extern char * snd_rename;
124 extern char * g_snd_move;
125 extern char * g_snd_rename;
126 extern char * rcv_move;
127 extern char * rcv_rename;
128 extern char * g_rcv_move;
129 extern char * g_rcv_rename;
130
131 #ifdef PATTERNS
132 extern char *binpatterns[], *txtpatterns[];
133 extern int patterns;
134 #endif /* PATTERNS */
135
136 extern char * remdest;
137 #ifdef CK_TMPDIR
138 char * dldir = NULL;
139 #endif /* CK_TMPDIR */
140
141 extern struct ck_p ptab[];
142
143 extern int protocol, remfile, rempipe, remappd, reliable, xreliable, fmask,
144   fncnv, frecl, maxrps, wslotr, bigsbsiz, bigrbsiz, urpsiz, rpsiz, spsiz,
145   bctr, npad, timef, timint, spsizr, spsizf, maxsps, spmax, nfils, displa,
146   atcapr, pkttim, rtimo, fncact, mypadn, fdispla, f_save, pktpaus, setreliable,
147   fnrpath, fnspath, atenci, atenco, atdati, atdato, atleni, atleno, atblki,
148   atblko, attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
149
150 extern int stathack;
151
152 extern int atfrmi, atfrmo;
153 #ifdef STRATUS
154 extern int atcrei, atcreo, atacti, atacto;
155 #endif /* STRATUS */
156 #ifdef CK_PERMS
157 extern int atlpri, atlpro, atgpri, atgpro;
158 #endif /* CK_PERMS */
159
160 extern CHAR
161   sstate, eol, seol, stchr, mystch, mypadc, padch, ctlq, myctlq;
162
163 #ifdef IKSD
164 extern int inserver;
165 #ifdef IKSDCONF
166 extern int iksdcf;
167 #endif /* IKSDCONF */
168 #endif /* IKSD */
169
170 extern char *cmarg, *cmarg2;
171
172 #ifndef NOFRILLS
173 extern char optbuf[];                   /* Buffer for MAIL or PRINT options */
174 extern int rprintf;                     /* REMOTE PRINT flag */
175 #endif /* NOFRILLS */
176 #endif /* NOXFER */
177
178 #ifdef CK_TRIGGER
179 extern char * tt_trigger[];
180 #endif /* CK_TRIGGER */
181
182 extern int tcs_transp;
183 #ifdef PCTERM
184 extern int tt_pcterm;
185 #endif /* PCTERM */
186 #ifdef NT
187 extern int tt_vtnt;
188 #endif /* NT */
189
190 #ifdef SSHBUILTIN
191 int sl_ssh_xfw = 0;
192 int sl_ssh_xfw_saved = 0;
193 int sl_ssh_ver = 0;
194 int sl_ssh_ver_saved = 0;
195 #endif /* SSHBUILTIN */
196
197 #ifdef CK_AUTHENTICATION
198 extern int auth_type_user[];
199 int sl_auth_type_user[AUTHTYPLSTSZ] = {AUTHTYPE_NULL, AUTHTYPE_NULL};
200 int sl_auth_saved = 0;
201 int sl_topt_a_su = 0;
202 int sl_topt_a_s_saved = 0;
203 int sl_topt_a_cm = 0;
204 int sl_topt_a_c_saved = 0;
205 #endif /* CK_AUTHENTICATION */
206 #ifdef CK_ENCRYPTION
207 extern int cx_type;
208 int sl_cx_type = 0;
209 int sl_cx_saved = 0;
210 int sl_topt_e_su = 0;
211 int sl_topt_e_sm = 0;
212 int sl_topt_e_s_saved = 0;
213 int sl_topt_e_cu = 0;
214 int sl_topt_e_cm = 0;
215 int sl_topt_e_c_saved = 0;
216 #endif /* CK_ENCRYPTION */
217 extern char uidbuf[];
218 static int uidflag = 0;
219 char sl_uidbuf[UIDBUFLEN] = { NUL, NUL };
220 int  sl_uid_saved = 0;
221 #ifdef TNCODE
222 int  sl_tn_wait = 0;
223 int  sl_tn_saved = 0;
224 #endif /* TNCODE */
225
226 #ifdef TNCODE
227 extern int tn_wait_flg;
228 #endif /* TNCODE */
229
230 VOID
231 slrestor() {
232 #ifdef CK_AUTHENTICATION
233     int x;
234     if (sl_auth_saved) {
235         for (x = 0; x < AUTHTYPLSTSZ; x++)
236           auth_type_user[x] = sl_auth_type_user[x];
237         sl_auth_saved = 0;
238     }
239     if (sl_topt_a_s_saved) {
240         TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = sl_topt_a_su;
241         sl_topt_a_s_saved = 0;
242     }
243     if (sl_topt_a_c_saved) {
244         TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = sl_topt_a_cm;
245         sl_topt_a_c_saved = 0;
246     }
247 #endif /* CK_AUTHENTICATION */
248 #ifdef CK_ENCRYPTION
249     if (sl_cx_saved) {
250         cx_type = sl_cx_type;
251         sl_cx_saved = 0;
252     }
253     if (sl_topt_e_s_saved) {
254         TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION)  = sl_topt_e_su;
255         TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = sl_topt_e_sm;
256         sl_topt_e_s_saved = 0;
257     }
258     if (sl_topt_e_c_saved) {
259         TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION)  = sl_topt_e_cu;
260         TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = sl_topt_e_cm;
261         sl_topt_e_c_saved = 0;
262     }
263 #endif /* CK_ENCRYPTION */
264     if (sl_uid_saved) {
265         ckstrncpy(uidbuf,sl_uidbuf,UIDBUFLEN);
266         sl_uid_saved = 0;
267     }
268 #ifdef TNCODE
269     if (sl_tn_saved) {
270         tn_wait_flg = sl_tn_wait;
271         sl_tn_saved = 0;
272     }
273 #endif /* TNCODE */
274 #ifdef SSHBUILTIN
275     if (sl_ssh_xfw_saved) {
276         ssh_xfw = sl_ssh_xfw;
277         sl_ssh_xfw_saved = 0;
278     }
279     if (sl_ssh_ver_saved) {
280         ssh_ver = sl_ssh_ver;
281         sl_ssh_ver_saved = 0;
282     }
283 #endif /* SSHBUILTIN */
284 }
285
286 int oldplex = -1;                       /* Duplex holder around network */
287
288 #ifndef NOICP
289 #ifdef LOCUS
290 extern int locus, autolocus;
291 #endif /* LOCUS */
292 #ifndef NODIAL
293 extern int dialsta;
294 #endif /* NODIAL */
295
296 /* Note: gcc -Wall wants braces around each keyword table entry. */
297
298 static struct keytab psltab[] = {       /* SET LINE/PORT command options */
299     { "/connect", SL_CNX, 0 },
300 #ifdef OS2ORVMS
301     { "/noshare", SL_NSH, 0 },
302 #endif /* OS2ORVMS */
303     { "/server",  SL_SRV, 0 },
304 #ifdef OS2ORVMS
305     { "/share",   SL_SHR, 0 },
306 #endif /* OS2ORVMS */
307     { "", 0, 0 }
308 };
309 static int npsltab = sizeof(psltab)/sizeof(struct keytab) - 1;
310
311 #ifdef NETCONN
312 static struct keytab shtab[] = {        /* SET HOST command options */
313 #ifdef NETCMD
314     /* (COMMAND is also a network type) */
315     { "/command",      SL_CMD,    CM_INV },
316 #endif /* NETCMD */
317     { "/connect",      SL_CNX,    0 },
318     { "/network-type", SL_NET,    CM_ARG },
319     { "/nowait",       SL_NOWAIT, 0 },
320 #ifndef NOSPL
321 #ifdef CK_AUTHENTICATION
322     { "/password",     SL_PSW,    CM_ARG },
323 #endif /* CK_AUTHENTICATION */
324 #endif /* NOSPL */
325 #ifdef NETCMD
326     { "/pipe",         SL_CMD,    0 },
327 #endif /* NETCMD */
328 #ifdef NETPTY
329     { "/pty",          SL_PTY,    0 },
330 #endif /* NETPTY */
331     { "/server",       SL_SRV,    0 },
332     { "/timeout",      SL_TMO,    CM_ARG },
333     { "/userid",       SL_UID,    CM_ARG },
334     { "/wait",         SL_WAIT,   0 },
335     { "", 0, 0 }
336 };
337 static int nshtab = sizeof(shtab)/sizeof(struct keytab) - 1;
338
339 static struct keytab shteltab[] = {     /* TELNET command options */
340 #ifdef CK_AUTHENTICATION
341     { "/auth",         SL_AUTH,   CM_ARG },
342 #endif /* CK_AUTHENTICATION */
343 #ifdef CK_ENCRYPTION
344     { "/encrypt",      SL_ENC,    CM_ARG },
345 #endif /* CK_ENCRYPTION */
346     { "/nowait",       SL_NOWAIT, 0 },
347 #ifndef NOSPL
348 #ifdef CK_AUTHENTICATION
349     { "/password",     SL_PSW,    CM_ARG },
350 #endif /* CK_AUTHENTICATION */
351 #endif /* NOSPL */
352     { "/timeout",      SL_TMO,    CM_ARG },
353     { "/userid",       SL_UID,    CM_ARG },
354     { "/wait",         SL_WAIT,   0 },
355     { "", 0 ,0 }
356 };
357 static int nshteltab = sizeof(shteltab)/sizeof(struct keytab) - 1;
358
359 #ifdef RLOGCODE
360 static struct keytab shrlgtab[] = {     /* SET HOST RLOGIN command options */
361 #ifdef CK_KERBEROS
362 #ifdef CK_ENCRYPTION
363     { "/encrypt",      SL_ENC, 0 },
364 #endif /* CK_ENCRYPTION */
365     { "/k4",           SL_KRB4, CM_INV },
366     { "/k5",           SL_KRB5, CM_INV },
367     { "/kerberos4",    SL_KRB4, 0 },
368     { "/kerberos5",    SL_KRB5, 0 },
369     { "/kerberos_iv",  SL_KRB4, CM_INV },
370     { "/kerberos_v",   SL_KRB5, CM_INV },
371     { "/krb4",         SL_KRB4, CM_INV },
372     { "/krb5",         SL_KRB5, CM_INV },
373 #endif /* CK_KERBEROS */
374     { "", 0 ,0 }
375 };
376 static int nshrlgtab = sizeof(shrlgtab)/sizeof(struct keytab)-1;
377 #endif /* RLOGCODE */
378
379 extern struct keytab netcmd[];
380 extern int nnets;
381 #ifndef NODIAL
382 extern int dirline;
383 extern int nnetdir;                     /* Network services directory */
384 extern char *netdir[];
385 _PROTOTYP( VOID ndreset, (void) );
386 char *nh_p[MAXDNUMS + 1];               /* Network directory entry pointers */
387 char *nh_p2[MAXDNUMS + 1];              /* Network directory entry nettype */
388 char *nh_px[4][MAXDNUMS + 1];           /* Network-specific stuff... */
389 #endif /* NODIAL */
390 int nhcount = 0;
391 int ndinited = 0;
392 char * n_name = NULL;                   /* Network name pointer */
393 #endif /* NETCONN */
394
395 _PROTOTYP(int remtxt, (char **) );
396 _PROTOTYP(VOID rmsg, (void) );
397 _PROTOTYP(static int remcfm, (void) );
398
399 extern int nopush;
400
401 int mdmsav = -1;                        /* Save modem type around network */
402 extern int isguest;                     /* Global flag for anonymous login */
403
404 extern xx_strp xxstring;
405
406 extern int success, binary, b_save, ckwarn, msgflg, quiet, cmask, pflag, local,
407   nettype, escape, mdmtyp, duplex, dfloc, network, cdtimo, autoflow, tnlm,
408   sosi, tlevel, lf_opts, backgrd, flow, debses, parity, ttnproto, ckxech,
409   x_ifnum, cmflgs, haveline, cxtype, cxflow[], maclvl;
410
411 #ifdef DCMDBUF
412 extern struct cmdptr *cmdstk;           /* The command stack itself */
413 #else
414 extern struct cmdptr cmdstk[];          /* The command stack itself */
415 #endif /* DCMDBUF */
416 extern FILE * tfile[];
417 extern char * macp[];
418
419 extern char psave[];                    /* For saving & restoring prompt */
420 extern int sprmlen, rprmlen;
421
422 #ifdef OS2
423 static struct keytab strmkeytab[] = {
424     { "clear",   0, 0 },
425     { "default", 1, 0 }
426 };
427 static int nstrmkeytab = sizeof(strmkeytab)/sizeof(struct keytab);
428
429 static struct keytab strmswitab[] = {
430     { "/literal", 0, 0 }
431 };
432 static int nstrmswitab = sizeof(strmswitab)/sizeof(struct keytab);
433
434 static struct keytab normrev[] = {
435     { "dark-display", 0, 0 },
436     { "light-display", 1, 0 },
437     { "normal",   0, 0 },
438     { "reverse",  1, 0 }
439 };
440
441 static struct keytab prnmtab[] = {
442     { "auto", 1, 0 },
443     { "copy", 2, 0 },
444     { "off",  0, 0 },
445     { "on",   1, CM_INV },              /* Compatibility with XPRINT version */
446     { "user", 3, 0 },
447     { "transparent", 3, CM_INV }        /* not really transparent */
448 };
449 static int nprnmtab = sizeof(prnmtab)/sizeof(struct keytab);
450
451 extern int tt_diff_upd;
452
453 #ifdef NT
454 #define stricmp _stricmp
455 extern int tt_attr_bug;
456 #endif /* NT */
457 extern int tt_rows[], tt_cols[];
458 extern int tt_cols_usr;
459 extern int tt_szchng[VNUM];
460 int tt_modechg = TVC_ENA;
461 extern int tt_url_hilite, tt_url_hilite_attr;
462 extern struct _vtG G[4];
463 extern int priority;
464 extern bool send_c1;
465 int send_c1_usr = FALSE;
466 extern int sgrcolors;
467 extern int marginbell, marginbellcol;
468 extern int autoscroll, wy_autopage;
469 extern int tt_sac;
470 extern int dec_nrc, dec_lang, dec_kbd;
471 #else /* OS2 */
472 extern int tt_rows, tt_cols;
473 #endif /*  OS2 */
474
475 extern int tt_escape;
476 extern long speed;
477
478 extern char *dftty;
479
480 extern char *tp, *lp;                   /* Temporary buffer & pointers */
481 extern char ttname[];
482
483 #ifdef CK_TAPI
484 int tttapi = 0;                         /* is Line TAPI? */
485 struct keytab * tapilinetab = NULL;
486 struct keytab * _tapilinetab = NULL;
487 int ntapiline = 0;
488 #endif /* CK_TAPI */
489
490 #ifdef NETCONN                          /* Network items */
491
492 #ifdef ANYX25
493 extern int revcall, closgr, cudata, nx25;
494 extern char udata[];
495 extern struct keytab x25tab[];
496 #ifndef IBMX25
497 extern int npadx3;
498 extern CHAR padparms[];
499 extern struct keytab padx3tab[];
500 #endif /* IBMX25 */
501 #endif /* ANYX25 */
502
503 #ifdef OS2
504 extern bool ttshare;
505 #ifndef NT
506 extern bool ttslip,ttppp;
507 #endif /* NT */
508 #endif /* OS2 */
509 #ifdef NPIPE
510 extern char pipename[];
511 #endif /* NPIPE */
512
513 #ifdef TCPSOCKET
514 static struct keytab tcprawtab[] = {    /* SET HOST options */
515     { "/default",    NP_DEFAULT,    CM_INV },
516 #ifdef CK_AUTHENTICATION
517 #ifdef CK_KERBEROS
518 #ifdef RLOGCODE
519     { "/ek4login",    NP_EK4LOGIN,    0 },
520     { "/ek5login",    NP_EK5LOGIN,    0 },
521     { "/k4login",     NP_K4LOGIN,     0 },
522     { "/k5login",     NP_K5LOGIN,     0 },
523 #endif /* RLOGCODE */
524 #ifdef KRB5_U2U
525     { "/k5user2user", NP_K5U2U,       0 },
526 #endif /* KRB5_U2U */
527 #endif /* CK_KERBEROS */
528 #endif /* CK_AUTHENTICATION */
529     { "/no-telnet-init", NP_NONE,   0 },
530     { "/none",       NP_NONE,   CM_INV },
531     { "/raw-socket", NP_TCPRAW, 0 },
532 #ifdef RLOGCODE
533     { "/rlogin",     NP_RLOGIN, 0 },
534 #endif /* RLOGCODE */
535 #ifdef CK_SSL
536     { "/ssl",        NP_SSL,    0 },
537     { "/ssl-telnet", NP_SSL_TELNET, 0 },
538 #endif /* CK_SSL */
539     { "/telnet",     NP_TELNET, 0 },
540 #ifdef CK_SSL
541     { "/tls",        NP_TLS,    0 },
542     { "/tls-telnet", NP_TLS_TELNET, 0 },
543 #endif /* CK_SSL */
544     { "", 0, 0 }
545 };
546 static int ntcpraw = (sizeof(tcprawtab) / sizeof(struct keytab)) - 1;
547
548 #ifdef RLOGCODE
549 _PROTOTYP( int rlog_naws, (void) );
550 #endif /* RLOGCODE */
551 #endif /* TCPSOCKET */
552
553 #ifdef SUPERLAT
554 extern char slat_pwd[18];
555 #endif /* SUPERLAT */
556 #endif /* NETCONN */
557
558 #ifdef COMMENT
559 #ifndef NOSETKEY
560 extern KEY *keymap;
561 #ifndef OS2
562 #define mapkey(x) keymap[x]
563 #endif /* OS2 */
564 extern MACRO *macrotab;
565 #ifndef NOKVERBS
566 extern struct keytab kverbs[];
567 extern int nkverbs;
568 #endif /* NOKVERBS */
569 #endif /* NOSETKEY */
570 #else
571 #ifndef NOSETKEY
572 extern KEY *keymap;
573 extern MACRO *macrotab;
574 #ifndef NOKVERBS
575 extern struct keytab kverbs[];
576 extern int nkverbs;
577 #endif /* NOKVERBS */
578 #endif /* NOSETKEY */
579 #endif /* COMMENT */
580
581 #ifdef OS2                              /* AUTODOWNLOAD parameters */
582 extern int    adl_kmode, adl_zmode;     /* Match Packet to signal download */
583 extern char * adl_kstr;                 /* KERMIT Download String */
584 extern char * adl_zstr;                 /* ZMODEM Download String */
585 extern int adl_kc0, adl_zc0;            /* Process ADL C0s in emulation */
586 #endif /* OS2 */
587
588 /* Keyword tables ... */
589
590 extern struct keytab onoff[], rltab[];
591 extern int nrlt;
592
593 #ifndef NOCSETS
594 static struct keytab fdfltab[] = {
595     { "7bit-character-set", 7, 0 },
596     { "8bit-character-set", 8, 0 }
597 };
598 static int nfdflt = (sizeof(fdfltab) / sizeof(struct keytab));
599 #endif /* NOCSETS */
600
601 /* SET FILE parameters */
602
603 static struct keytab filtab[] = {
604 #ifndef NOXFER
605 #ifdef PATTERNS
606     { "binary-patterns",   XYFIBP,  0 },
607 #endif /* PATTERNS */
608     { "bytesize",         XYFILS,   0 },
609 #ifndef NOCSETS
610     { "character-set",    XYFILC,   0 },
611 #endif /* NOCSETS */
612     { "collision",        XYFILX,   0 },
613     { "default",          XYF_DFLT, 0 },
614     { "destination",      XYFILY,   0 },
615     { "display",          XYFILD,   CM_INV },
616 #ifdef CK_TMPDIR
617     { "download-directory", XYFILG, 0 },
618 #endif /* CK_TMPDIR */
619 #endif /* NOXFER */
620     { "end-of-line",      XYFILA,   0 },
621     { "eol",              XYFILA,   CM_INV },
622 #ifdef CK_CTRLZ
623     { "eof",              XYFILV,   0 },
624 #endif /* CK_CTRLZ */
625 #ifndef NOXFER
626     { "fastlookups",      9997,     CM_INV },
627     { "incomplete",       XYFILI,   0 },
628 #ifndef datageneral
629     { "inspection",       XYF_INSP, CM_INV },
630 #endif /* datageneral */
631 #ifdef CK_LABELED
632     { "label",            XYFILL, 0 },
633 #endif /* CK_LABELED */
634
635 #ifdef UNIX
636 #ifdef DYNAMIC
637     { "listsize",         XYF_LSIZ, 0 },
638 #endif /* DYNAMIC */
639 #endif /* UNIX */
640
641     { "names",            XYFILN, 0 },
642 #ifdef UNIX
643     { "output",           XYFILH, 0 },
644 #endif /* UNIX */
645 #ifdef PATTERNS
646     { "patterns",         XYFIPA, 0 },
647 #endif /* PATTERNS */
648 #ifdef COMMENT /* Not implemented (but see CHMOD) */
649     { "permissions",      XYF_PRM, CM_INV },
650     { "protection",       XYF_PRM, 0 },
651 #endif /* COMMENt */
652 #ifdef VMS
653     { "record-length",    XYFILR, 0 },
654 #endif /* VMS */
655 #ifndef datageneral
656     { "scan",             XYF_INSP, 0 },
657 #endif /* datageneral */
658
659 #ifdef UNIX
660 #ifdef DYNAMIC
661     { "stringspace",      XYF_SSPA, 0 },
662 #endif /* DYNAMIC */
663 #endif /* UNIX */
664
665 #ifdef PATTERNS
666     { "t",                XYFILT, CM_INV|CM_ABR },
667     { "text-patterns",    XYFITP, 0 },
668 #endif /* PATTERNS */
669 #endif /* NOXFER */
670     { "type",             XYFILT, 0 },
671 #ifdef UNICODE
672     { "ucs",              XYFILU, 0 },
673 #endif /* UNICODE */
674 #ifndef NOXFER
675     { "warning",          XYFILW, CM_INV }
676 #endif /* NOXFER */
677 };
678 static int nfilp = (sizeof(filtab) / sizeof(struct keytab));
679
680 struct keytab pathtab[] = {
681     { "absolute",  PATH_ABS,  0      },
682     { "none",      PATH_OFF,  CM_INV },
683     { "off",       PATH_OFF,  0      },
684     { "on",        PATH_ABS,  CM_INV },
685     { "relative",  PATH_REL,  0      }
686 };
687 int npathtab = (sizeof(pathtab) / sizeof(struct keytab));
688
689 struct keytab rpathtab[] = {
690     { "absolute",  PATH_ABS,  0      },
691     { "auto",      PATH_AUTO, 0      },
692     { "none",      PATH_OFF,  CM_INV },
693     { "off",       PATH_OFF,  0      },
694     { "on",        PATH_ABS,  CM_INV },
695     { "relative",  PATH_REL,  0      }
696 };
697 int nrpathtab = (sizeof(rpathtab) / sizeof(struct keytab));
698
699 #ifdef CK_CTRLZ
700 struct keytab eoftab[] = {              /* EOF detection method */
701     { "ctrl-z",          1, 0      },
702     { "length",          0, 0      },
703     { "noctrl-z",        0, CM_INV }
704 };
705 #endif /* CK_CTRLZ */
706
707 struct keytab fttab[] = {               /* File types for SET FILE TYPE */
708     { "ascii",     XYFT_T, CM_INV },
709 #ifdef VMS
710     { "b",         XYFT_B, CM_INV|CM_ABR },
711 #endif /* VMS */
712     { "binary",    XYFT_B, 0 },
713 #ifdef VMS
714     { "block",     XYFT_I, CM_INV },
715     { "image",     XYFT_I, 0 },
716 #endif /* VMS */
717 #ifdef CK_LABELED
718     { "labeled",   XYFT_L, 0 },
719 #endif /* CK_LABELED */
720 #ifdef MAC
721     { "macbinary", XYFT_M, 0 },
722 #endif /* MAC */
723     { "text",      XYFT_T, 0 }
724 };
725 int nfttyp = (sizeof(fttab) / sizeof(struct keytab));
726
727 static struct keytab rfttab[] = {       /* File types for REMOTE SET FILE */
728     { "ascii",     XYFT_T, CM_INV },
729     { "binary",    XYFT_B, 0 },
730 #ifdef VMS
731     { "labeled",   XYFT_L, 0 },
732 #else
733 #ifdef OS2
734     { "labeled",   XYFT_L, 0 },
735 #endif /* OS2 */
736 #endif /* VMS */
737     { "text",      XYFT_T, 0 }
738 };
739 static int nrfttyp = (sizeof(rfttab) / sizeof(struct keytab));
740
741 #ifdef OS2ORUNIX
742 #define ZOF_BLK  0
743 #define ZOF_NBLK 1
744 #define ZOF_BUF  2
745 #define ZOF_NBUF 3
746 static struct keytab zoftab[] = {
747     { "blocking",    ZOF_BLK,  0 },
748     { "buffered",    ZOF_BUF,  0 },
749     { "nonblocking", ZOF_NBLK, 0 },
750     { "unbuffered",  ZOF_NBUF, 0 }
751 };
752 static int nzoftab = (sizeof(zoftab) / sizeof(struct keytab));
753 #endif /* OS2ORUNIX */
754
755 extern int query;                       /* Global flag for QUERY active */
756
757 #ifndef NOSPL
758 #ifndef NOXFER
759 static struct keytab vartyp[] = {       /* Variable types for REMOTE QUERY */
760     { "global",   (int) 'G', CM_INV },
761     { "kermit",   (int) 'K', 0 },
762     { "system",   (int) 'S', 0 },
763     { "user",     (int) 'G', 0 }
764 };
765 static int nvartyp = (sizeof(vartyp) / sizeof(struct keytab));
766 #endif /* NOXFER */
767 #endif /* NOSPL */
768
769 #ifdef CK_TIMERS
770 static struct keytab timotab[] = {      /* Timer types */
771     { "dynamic", 1, 0 },
772     { "fixed",   0, 0 }
773 };
774 #endif /* CK_TIMERS */
775
776 #ifdef DCMDBUF
777 extern char *atxbuf, *atmbuf;           /* Atom buffer */
778 extern char *cmdbuf;                    /* Command buffer */
779 extern char *line, *tmpbuf;             /* Character buffers for anything */
780 extern int *intime;                     /* INPUT TIMEOUT */
781
782 #else  /* Not DCMDBUF ... */
783
784 extern char atxbuf[], atmbuf[];         /* Atom buffer */
785 extern char cmdbuf[];                   /* Command buffer */
786 extern char line[], tmpbuf[];           /* Character buffer for anything */
787 extern int intime[];
788
789 #endif /* DCMDBUF */
790
791 #ifndef NOCSETS
792 extern struct keytab fcstab[];          /* For SET FILE CHARACTER-SET */
793 extern struct csinfo fcsinfo[];         /* File character set info. */
794 extern struct keytab ttcstab[];
795 extern int nfilc, fcharset, tcharset, ntermc, tcsr, tcsl, dcset7, dcset8;
796 #ifdef CKOUNI
797 extern int tt_utf8;
798 #endif /* CKOUNI */
799 #ifdef OS2
800 _PROTOTYP( int os2setcp, (int) );
801 _PROTOTYP( int os2getcp, (void) );
802 _PROTOTYP( void os2debugoff, (void) );
803 #endif /* OS2 */
804 #endif /* NOCSETS */
805
806 extern int cmdlvl;                      /* Overall command level */
807
808 #ifndef NOSPL
809 #ifdef DCMDBUF
810 extern int *inpcas;                     /* INPUT CASE setting on cmd stack */
811 #else
812 extern int inpcas[];
813 #endif /* DCMDBUF */
814 #endif /* NOSPL */
815
816 #ifdef CK_CURSES
817 #ifndef VMS
818 _PROTOTYP(int tgetent,(char *, char *));
819 #else
820 #ifdef __DECC
821 _PROTOTYP(int tgetent,(char *, char *));
822 #endif /* __DECC */
823 #endif /* VMS */
824 #endif /* CK_CURSES */
825
826 #ifndef NOXMIT
827 #define XMITF 0                         /* SET TRANSMIT values */
828 #define XMITL 1                         /* (Local to this module) */
829 #define XMITP 2
830 #define XMITE 3
831 #define XMITX 4
832 #define XMITS 5
833 #define XMITW 6
834 #define XMITT 7
835
836 #define XMBUFL 50
837 extern int xmitf, xmitl, xmitp, xmitx, xmits, xmitw, xmitt;
838 char xmitbuf[XMBUFL+1] = { NUL };       /* TRANSMIT eof string */
839
840 struct keytab xmitab[] = {              /* SET TRANSMIT */
841     { "echo",          XMITX, 0 },
842     { "eof",           XMITE, 0 },
843     { "fill",          XMITF, 0 },
844     { "linefeed",      XMITL, 0 },
845     { "locking-shift", XMITS, 0 },
846     { "pause",         XMITW, 0 },
847     { "prompt",        XMITP, 0 },
848     { "timeout",       XMITT, 0 }
849 };
850 int nxmit = (sizeof(xmitab) / sizeof(struct keytab));
851 #endif /* NOXMIT */
852
853 /* For SET FILE COLLISION */
854 /* Some of the following may be possible for some C-Kermit implementations */
855 /* but not others.  Those that are not possible for your implementation */
856 /* should be ifdef'd out. */
857
858 struct keytab colxtab[] = { /* SET FILE COLLISION options */
859 #ifndef MAC
860     { "append",    XYFX_A, 0 },         /* append to old file */
861 #endif /* MAC */
862 #ifdef COMMENT
863     { "ask",       XYFX_Q, 0 },         /* ask what to do (not implemented) */
864 #endif
865     { "backup",    XYFX_B, 0 },         /* rename old file */
866 #ifndef MAC
867     /* This crashes Mac Kermit. */
868     { "discard",   XYFX_D, 0 },         /* don't accept new file */
869     { "no-supersede", XYFX_D, CM_INV }, /* ditto (MSK compatibility) */
870 #endif /* MAC */
871     { "overwrite", XYFX_X, 0 },         /* overwrite the old file */
872     { "rename",    XYFX_R, 0 },         /* rename the incoming file */
873 #ifndef MAC                             /* This crashes Mac Kermit. */
874     { "update",    XYFX_U, 0 },         /* replace if newer */
875 #endif /* MAC */
876     { "", 0, 0 }
877 };
878 int ncolx = (sizeof(colxtab) / sizeof(struct keytab)) - 1;
879
880 static struct keytab rfiltab[] = {      /* for REMOTE SET FILE */
881 #ifndef NOCSETS
882     { "character-set", XYFILC, 0 },
883 #endif /* NOCSETS */
884     { "collision",     XYFILX, 0 },
885     { "incomplete",    XYFILI, 0 },
886     { "names",         XYFILN, 0 },
887     { "record-length", XYFILR, 0 },
888     { "type",          XYFILT, 0 }
889 };
890 int nrfilp = (sizeof(rfiltab) / sizeof(struct keytab));
891
892 struct keytab eoltab[] = {              /* File eof delimiters */
893     { "cr",        XYFA_C, 0 },
894     { "crlf",      XYFA_2, 0 },
895     { "lf",        XYFA_L, 0 }
896 };
897 static int neoltab = (sizeof(eoltab) / sizeof(struct keytab));
898
899 struct keytab fntab[] = {               /* File naming */
900     { "converted", XYFN_C, 0      },
901     { "literal",   XYFN_L, 0      },
902     { "standard",  XYFN_C, CM_INV }
903 };
904 int nfntab = (sizeof(fntab) / sizeof(struct keytab));
905
906 #ifndef NOLOCAL
907 /* Terminal parameters table */
908 static struct keytab trmtab[] = {
909 #ifdef OS2
910     { "answerback",    XYTANS,    0 },
911 #endif /* OS2 */
912 #ifdef CK_APC
913     { "apc",           XYTAPC,    0 },
914 #endif /* CK_APC */
915 #ifdef OS2
916     { "arrow-keys",    XYTARR,    0 },
917 #endif /* OS2 */
918 #ifdef NT
919     { "at",            XYTATTR,   CM_INV|CM_ABR },
920     { "att",           XYTATTR,   CM_INV|CM_ABR },
921     { "attr",          XYTATTR,   CM_INV|CM_ABR },
922     { "attr-bug",      XYTATTBUG, CM_INV },
923 #endif /* NT */
924 #ifdef OS2
925     { "attribute",     XYTATTR,   0 },
926 #endif /* OS2 */
927 #ifdef CK_APC
928 #ifdef CK_AUTODL
929    { "autodownload",   XYTAUTODL, 0, },
930 #endif /* CK_AUTODL */
931 #endif /* CK_APC */
932 #ifdef OS2
933     { "autopage",      XYTAPAGE,  0 },
934     { "autoscroll",    XYTASCRL,  0 },
935     { "bell",          XYTBEL,    CM_INV },
936 #endif /* OS2 */
937     { "bytesize",      XYTBYT,    0 },
938 #ifndef NOCSETS
939     { "character-set", XYTCS,     0 },
940 #endif /* NOCSETS */
941 #ifdef OS2
942     { "code-page",     XYTCPG,    0 },
943     { "color",         XYTCOL,    0 },
944     { "controls",      XYTCTRL,   0 },
945 #endif /* OS2 */
946     { "cr-display",    XYTCRD,    0 },
947 #ifdef OS2
948     { "cursor",        XYTCUR,    0 },
949 #endif /* OS2 */
950     { "debug",         XYTDEB,    0 },
951 #ifdef OS2
952     { "dg-unix-mode",  XYTUNX,    0 },
953 #endif /* OS2 */
954     { "echo",          XYTEC,     0 },
955     { "escape-character", XYTESC, 0 },
956 #ifdef OS2
957 #ifdef PCFONTS
958     { "font",          XYTFON,    0 },
959 #else
960 #ifdef KUI
961     { "font",          XYTFON,    0 },
962 #endif /* KUI */
963 #endif /* PCFONTS */
964 #endif /* OS2 */
965     { "height",        XYTHIG,    0 },
966 #ifdef CKTIDLE
967     { "idle-action",   XYTIACT,   0 },
968     { "idle-limit",    XYTITMO,   CM_INV },
969     { "idle-send",     XYTIDLE,   CM_INV },
970     { "idle-timeout",  XYTITMO,   0 },
971 #endif /* CKTIDLE */
972 #ifdef OS2
973 #ifndef NOCSETS
974     { "kbd-follows-gl/gr", XYTKBDGL, 0 },
975 #endif /* NOCSETS */
976     { "key",           XYTKEY,    0 },
977     { "keyboard-mode", XYTKBMOD,  0 },
978     { "keypad-mode",   XYTKPD,    0 },
979 #endif /* OS2 */
980 #ifndef NOCSETS
981 #ifdef OS2
982 #ifndef KUI
983     { "line-spacing",  XYTLSP,    CM_INV },
984     { "local-character-set", XYTLCS,  0 },
985 #else
986     { "line-spacing",  XYTLSP,    0 },
987     { "local-character-set", XYTLCS,  CM_INV },
988 #endif /* KUI */
989 #else
990     { "local-character-set", XYTLCS,  CM_INV },
991 #endif /* OS2 */
992 #endif /* NOCSETS */
993     { "locking-shift", XYTSO,     0 },
994 #ifdef OS2
995     { "margin-bell",   XYTMBEL,   0 },
996 #endif /* OS2 */
997 #ifdef OS2MOUSE
998     { "mouse",         XYTMOU,    CM_INV },
999 #endif /* OS2MOUSE */
1000     { "newline-mode",  XYTNL,     0 },
1001 #ifdef OS2
1002     { "output-pacing", XYTPAC,    0 },
1003 #ifdef PCTERM
1004     { "pcterm",        XYTPCTERM, 0 },
1005 #endif /* PCTERM */
1006 #endif /* OS2 */
1007 #ifdef OS2ORUNIX
1008     { "print",         XYTPRN,    0 },
1009 #endif /* OS2ORUNIX */
1010 #ifndef NOCSETS
1011 #ifdef OS2
1012     { "remote-character-set", XYTRCS,  0 },
1013 #else
1014     { "remote-character-set", XYTRCS,  CM_INV },
1015 #endif /* OS2 */
1016 #endif /* NOCSETS */
1017 #ifdef OS2
1018     { "roll-mode",       XYTROL, 0 },
1019     { "s",               XYTUPD, CM_ABR|CM_INV },
1020     { "sc",              XYTUPD, CM_ABR|CM_INV },
1021     { "scr",             XYTUPD, CM_ABR|CM_INV },
1022     { "scree",           XYTUPD, CM_ABR|CM_INV },
1023     { "screen",          XYTUPD, CM_ABR|CM_INV },
1024     { "screen-",         XYTUPD, CM_ABR|CM_INV },
1025     { "screen-mode",     XYTSCNM,   0 },
1026     { "screen-optimize", XYTOPTI,   0 },
1027     { "screen-update",   XYTUPD,    0 },
1028     { "scrollback",      XYSCRS,    0 },
1029     { "send-data",         XYTSEND, 0 },
1030     { "send-end-of-block", XYTSEOB, 0 },
1031     { "sgr-colors",            XYTSGRC,  0 },
1032     { "sni-ch.code",           XYTSNICC, 0 },
1033     { "sni-firmware-versions", XYTSNIFV, 0 },
1034     { "sni-language",          XYTVTLNG, 0 },
1035     { "sni-pagemode",          XYTSNIPM, CM_INV },
1036     { "sni-scrollmode",              XYTSNISM, CM_INV },
1037     { "spacing-attribute-character", XYTSAC,   CM_INV },
1038     { "statusline",                  XYTSTAT,  0 },
1039     { "tra",                         XYTCTS,   CM_INV|CM_ABR },
1040     { "transmit-timeout",            XYTCTS,   0 },
1041 #endif /* OS2 */
1042
1043 #ifdef OS2ORUNIX
1044     { "transparent-print", XYTPRN,   CM_INV },
1045 #endif /* OS2ORUNIX */
1046
1047 #ifdef CK_TRIGGER
1048     { "trigger",           XYTRIGGER,0 },
1049 #endif /* CK_TRIGGER */
1050 #ifdef OS2
1051     { "type",              XYTTYP,   0 },
1052 #else
1053     { "type",              XYTTYP,   CM_INV },
1054 #endif /* OS2 */
1055
1056 #ifndef NOCSETS
1057 #ifdef UNICODE
1058 #ifdef CKOUNI
1059     { "unicode",           XYTUNI,   CM_INV },
1060 #endif /* CKOUNI */
1061 #endif /* UNICODE */
1062 #endif /* NOCSETS */
1063 #ifdef OS2
1064     { "unix-mode",         XYTUNX,   CM_INV },
1065     { "url-highlight",     XYTURLHI, 0 },
1066 #ifdef NT
1067     { "video-change",      XYTVCH,   0 },
1068 #endif /* NT */
1069     { "vt-language",       XYTVTLNG, 0 },
1070     { "vt-nrc-mode",       XYTVTNRC, 0 },
1071 #endif /* OS2 */
1072     { "width",             XYTWID,   0 },
1073 #ifdef OS2
1074     { "wrap",              XYTWRP,   0 },
1075 #endif /* OS2 */
1076     { "", 0, 0 }
1077 };
1078 int ntrm = (sizeof(trmtab) / sizeof(struct keytab)) - 1;
1079
1080 #ifdef OS2
1081 struct keytab termctrl[] = {    /* SET TERM CONTROLS */
1082     { "7",      7, 0 },
1083     { "8",      8, 0 }
1084 };
1085 int ntermctrl = (sizeof(termctrl) / sizeof(struct keytab));
1086
1087 struct keytab curontab[] = {    /* SET TERM CURSOR */
1088 #ifdef KUI
1089     { "noblink", 2, 0 },
1090 #else
1091     { "noblink", 2, CM_INV },
1092 #endif /* KUI */
1093     { "off",     0, 0 },
1094     { "on",      1, 0 }
1095 };
1096 int ncuron = (sizeof(curontab) / sizeof(struct keytab));
1097
1098 struct keytab rolltab[] = {   /* Set TERM Roll Options */
1099     { "insert",    TTR_INSERT, 0      },
1100     { "keystrokes",TTR_KEYS,   0      },
1101     { "off",       TTR_OVER,   CM_INV },
1102     { "on",        TTR_INSERT, CM_INV },
1103     { "overwrite", TTR_OVER,   0      }
1104 };
1105 int nroll = (sizeof(rolltab) / sizeof(struct keytab));
1106
1107 struct keytab rollkeytab[] = {          /* Set TERM ROLL KEYSTROKES */
1108     { "ignore",            TTRK_IGN, 0 },
1109     { "restore-and-send",  TTRK_RST, 0 },
1110     { "send",              TTRK_SND, 0 }
1111 };
1112 int nrollkey = (sizeof(rollkeytab) / sizeof(struct keytab));
1113
1114 #define TT_GR_ALL 4
1115 #define TT_GR_G0  0
1116 #define TT_GR_G1  1
1117 #define TT_GR_G2  2
1118 #define TT_GR_G3  3
1119 #define TT_GR_KBD 4
1120 struct keytab graphsettab[] = {  /* DEC VT Graphic Sets */
1121     { "all",      TT_GR_ALL, 0 },
1122     { "g0",       TT_GR_G0,  0 },
1123     { "g1",       TT_GR_G1,  0 },
1124     { "g2",       TT_GR_G2,  0 },
1125     { "g3",       TT_GR_G3,  0 },
1126     { "keyboard", TT_GR_KBD, 0 }
1127 };
1128 int ngraphset = (sizeof(graphsettab) / sizeof(struct keytab));
1129 #endif /* OS2 */
1130
1131 struct keytab adltab[] = {              /* Autodownload Options */
1132     { "ask",     TAD_ASK, 0 },
1133     { "error",   TAD_ERR, 0 },
1134 #ifdef OS2
1135     { "kermit",  TAD_K,   0 },
1136 #endif /* OS2 */
1137     { "off",     TAD_OFF, 0 },
1138     { "on",      TAD_ON,  0 },
1139 #ifdef OS2
1140     { "zmodem",  TAD_Z,   0 },
1141 #endif /* OS2 */
1142     { "", 0, 0 }
1143 };
1144 int nadltab = (sizeof(adltab) / sizeof(struct keytab)) - 1;
1145
1146 struct keytab adlerrtab[] = {           /* Autodownload Error Options */
1147     { "continue", 0, 0 },
1148     { "go",       0, CM_INV },
1149     { "stop",     1, 0 }
1150 };
1151 int nadlerrtab = (sizeof(adlerrtab) / sizeof(struct keytab));
1152
1153 #ifdef OS2
1154 struct keytab adlxtab[] = {             /* Autodownload Options */
1155     { "c0-conflicts",     TAD_X_C0,     0 },
1156     { "detection-method", TAD_X_DETECT, 0 },
1157     { "string",           TAD_X_STR,    0 }
1158 };
1159 int nadlxtab = (sizeof(adlxtab) / sizeof(struct keytab));
1160
1161 struct keytab adldtab[] = {             /* Auto-dl Detection Methods */
1162     { "packet",           ADL_PACK,     0 },
1163     { "string",           ADL_STR,      0 }
1164 };
1165 int nadldtab = (sizeof(adldtab) / sizeof(struct keytab));
1166
1167 struct keytab adlc0tab[] = {            /* Auto-dl Detection Methods */
1168     { "ignored-by-emulator",    0,      0 },
1169     { "processed-by-emulator",  1,      0 }
1170 };
1171 int nadlc0tab = (sizeof(adlc0tab) / sizeof(struct keytab));
1172
1173 #ifndef NOCSETS
1174 struct keytab vtlangtab[] = {
1175     { "belgian",        VTL_BELGIAN , 0 },
1176     { "british",        VTL_BRITISH , 0 },
1177     { "canadian",       VTL_CANADIAN, 0 },
1178     { "czech",          VTL_CZECH   , 0 },
1179     { "danish",         VTL_DANISH  , 0 },
1180     { "dutch",          VTL_DUTCH   , 0 },
1181     { "finnish",        VTL_FINNISH , 0 },
1182     { "french",         VTL_FRENCH  , 0 },
1183     { "french-canadian",VTL_FR_CAN  , 0 },
1184     { "german",         VTL_GERMAN  , 0 },
1185     { "greek",          VTL_GREEK   , 0 },
1186     { "hebrew",         VTL_HEBREW  , 0 },
1187     { "hungarian",      VTL_HUNGARIA, 0 },
1188     { "italian",        VTL_ITALIAN , 0 },
1189     { "latin-american", VTL_LATIN_AM, 0 },
1190     { "north-american", VTL_NORTH_AM, 0 },
1191     { "norwegian",      VTL_NORWEGIA, 0 },
1192     { "polish",         VTL_POLISH  , 0 },
1193     { "portugese",      VTL_PORTUGES, 0 },
1194     { "romanian",       VTL_ROMANIAN, 0 },
1195     { "russian",        VTL_RUSSIAN , 0 },
1196     { "scs",            VTL_SCS     , CM_INV },
1197     { "slovak",         VTL_SLOVAK  , 0 },
1198     { "spanish",        VTL_SPANISH , 0 },
1199     { "swedish",        VTL_SWEDISH , 0 },
1200     { "swiss-french",   VTL_SW_FR   , 0 },
1201     { "swiss-german",   VTL_SW_GR   , 0 },
1202     { "turkish-f",      VTL_TURK_F  , CM_INV },
1203     { "turkish-q",      VTL_TURK_Q  , CM_INV }
1204 };
1205 int nvtlangtab = (sizeof(vtlangtab) / sizeof(struct keytab));
1206 #endif /* NOCSETS */
1207 #endif /* OS2 */
1208
1209 struct keytab crdtab[] = {              /* Carriage-return display */
1210     { "crlf",        1, 0 },
1211     { "normal",      0, 0 }
1212 };
1213 extern int tt_crd;                      /* Carriage-return display variable */
1214
1215 #ifdef CK_APC
1216 extern int apcstatus, apcactive;
1217 static struct keytab apctab[] = {       /* Terminal APC parameters */
1218     {  "no-input", APC_ON|APC_NOINP,0 },
1219     { "off",       APC_OFF,  0 },
1220     { "on",        APC_ON,   0 },
1221     { "unchecked", APC_ON|APC_UNCH, 0 },
1222     { "unchecked-no-input", APC_ON|APC_NOINP|APC_UNCH, 0 }
1223 };
1224 int napctab = (sizeof(apctab) / sizeof(struct keytab));
1225 #endif /* CK_APC */
1226 #endif /* NOLOCAL */
1227
1228 extern int autodl, adl_err, adl_ask;
1229
1230 struct keytab beltab[] = {              /* Terminal bell mode */
1231 #ifdef OS2
1232     { "audible", XYB_AUD,  0 },
1233     { "none",    XYB_NONE, 0 },
1234 #else
1235     { "audible", XYB_AUD,  CM_INV },
1236     { "none",    XYB_NONE, CM_INV },
1237 #endif /* OS2 */
1238 #ifdef OS2
1239     { "off",     XYB_NONE, CM_INV },
1240     { "on",      XYB_AUD,  CM_INV },
1241 #else
1242     { "off",     XYB_NONE, 0 },
1243     { "on",      XYB_AUD,  0 },
1244 #endif /* OS2 */
1245 #ifdef OS2
1246     { "visible", XYB_VIS,  0 },
1247 #endif /* OS2 */
1248     { "", 0, 0 }
1249 };
1250 int nbeltab = sizeof(beltab)/sizeof(struct keytab) - 1;
1251
1252 int tt_unicode = 1;                     /* Use Unicode if possible */
1253 #ifdef CKTIDLE
1254 int tt_idlesnd_tmo = 0;                 /* Idle Send Timeout, disabled */
1255 char * tt_idlesnd_str = NULL;           /* Idle Send String, none */
1256 char * tt_idlestr = NULL;
1257 extern int tt_idleact, tt_idlelimit;
1258 #endif /* CKTIDLE */
1259
1260 #ifdef OS2
1261 #ifndef NOLOCAL
1262 /*
1263   OS/2 serial communication devices.
1264 */
1265 struct keytab os2devtab[] = {
1266     { "1",    1, CM_INV },                      /* Invisible synonyms, like */
1267     { "2",    2, CM_INV },                      /* "set port 1" */
1268     { "3",    3, CM_INV },
1269     { "4",    4, CM_INV },
1270     { "5",    5, CM_INV },
1271     { "6",    6, CM_INV },
1272     { "7",    7, CM_INV },
1273     { "8",    8, CM_INV },
1274     { "com1", 1, 0 },                   /* Real device names */
1275     { "com2", 2, 0 },
1276     { "com3", 3, 0 },
1277     { "com4", 4, 0 },
1278     { "com5", 5, 0 },
1279     { "com6", 6, 0 },
1280     { "com7", 7, 0 },
1281     { "com8", 8, 0 },
1282 #ifdef OS2ONLY
1283     { "slipcom1", 1, 0 },                       /* For use with SLIP driver */
1284     { "slipcom2", 2, 0 },                       /* shared access */
1285     { "slipcom3", 3, 0 },
1286     { "slipcom4", 4, 0 },
1287     { "slipcom5", 5, 0 },
1288     { "slipcom6", 6, 0 },
1289     { "slipcom7", 7, 0 },
1290     { "slipcom8", 8, 0 },
1291     { "pppcom1", 1, 0 },                        /* For use with PPP driver */
1292     { "pppcom2", 2, 0 },                        /* shared access */
1293     { "pppcom3", 3, 0 },
1294     { "pppcom4", 4, 0 },
1295     { "pppcom5", 5, 0 },
1296     { "pppcom6", 6, 0 },
1297     { "pppcom7", 7, 0 },
1298     { "pppcom8", 8, 0 }
1299 #endif /* OS2ONLY */
1300 };
1301 int nos2dev = (sizeof(os2devtab) / sizeof(struct keytab)) - 1;
1302
1303 #ifdef OS2ONLY
1304 struct keytab os2ppptab[] = {
1305     { "0",    0, CM_INV },
1306     { "1",    1, CM_INV },                      /* Invisible synonyms, like */
1307     { "2",    2, CM_INV },                      /* "set port 1" */
1308     { "3",    3, CM_INV },
1309     { "4",    4, CM_INV },
1310     { "5",    5, CM_INV },
1311     { "6",    6, CM_INV },
1312     { "7",    7, CM_INV },
1313     { "8",    8, CM_INV },
1314     { "9",    9, CM_INV },
1315     { "ppp0", 0, 0 },
1316     { "ppp1", 1, 0 },                   /* For use with PPP driver */
1317     { "ppp2", 2, 0 },                   /* shared access */
1318     { "ppp3", 3, 0 },
1319     { "ppp4", 4, 0 },
1320     { "ppp5", 5, 0 },
1321     { "ppp6", 6, 0 },
1322     { "ppp7", 7, 0 },
1323     { "ppp8", 8, 0 },
1324     { "ppp9", 9, 0 }
1325 };
1326 int nos2ppp = (sizeof(os2ppptab) / sizeof(struct keytab));
1327 #endif /* OS2ONLY */
1328
1329 /*
1330   Terminal parameters that can be set by SET commands.
1331   Used by the ck?con.c terminal emulator code.
1332   For now, only used for #ifdef OS2.  Should add these for Macintosh.
1333 */
1334 int tt_arrow = TTK_NORM;                /* Arrow key mode: normal (cursor) */
1335 int tt_keypad = TTK_NORM;               /* Keypad mode: normal (numeric) */
1336 int tt_shift_keypad = 0;                /* Keypad Shift mode: Off */
1337 int tt_wrap = 1;                        /* Terminal wrap, 1 = On */
1338 int tt_type = TT_VT320;                 /* Terminal type, initially VT320 */
1339 int tt_type_mode = TT_VT320;            /* Terminal type set by host command */
1340 int tt_cursor = 0;                      /* Terminal cursor, 0 = Underline */
1341 int tt_cursor_usr = 0;                  /* Users Terminal cursor type */
1342 int tt_cursorena_usr = 1;               /* Users Terminal cursor enabled */
1343 int tt_cursor_blink = 1;                /* Terminal Cursor Blink */
1344 int tt_answer = 0;                      /* Terminal answerback (disabled) */
1345 int tt_scrsize[VNUM] = {512,512,512,1}; /* Terminal scrollback buffer size */
1346 int tt_roll[VNUM] = {1,1,1,1};          /* Terminal roll (on) */
1347 int tt_rkeys[VNUM] = {1,1,1,1};         /* Terminal roll keys (send) */
1348 int tt_pacing = 0;                      /* Terminal output-pacing (none) */
1349 int tt_ctstmo = 15;                     /* Terminal transmit-timeout */
1350 int tt_codepage = -1;                   /* Terminal code-page */
1351 int tt_update = 100;                    /* Terminal screen-update interval */
1352 int tt_updmode = TTU_FAST;              /* Terminal screen-update mode FAST */
1353 extern int updmode;
1354 #ifndef KUI
1355 int tt_status[VNUM] = {1,1,0,0};        /* Terminal status line displayed */
1356 int tt_status_usr[VNUM] = {1,1,0,0};
1357 #else  /* KUI */
1358 extern CKFLOAT floatval;
1359 CKFLOAT tt_linespacing[VNUM] = {1.0,1.0,1.0,1.0};
1360 #ifdef K95G
1361 int tt_status[VNUM] = {1,1,0,0};        /* Terminal status line displayed */
1362 int tt_status_usr[VNUM] = {1,1,0,0};
1363 #else /* K95G */
1364 int tt_status[VNUM] = {0,0,0,0};        /* Terminal status line displayed */
1365 int tt_status_usr[VNUM] = {0,0,0,0};
1366 #endif /* K95G */
1367 #endif /* KUI */
1368 int tt_senddata = 0;                    /* Let host read terminal data */
1369 extern int wy_blockend;                 /* Terminal Send Data EOB type */
1370 int tt_hidattr = 1;                     /* Attributes are hidden */
1371
1372 extern unsigned char colornormal, colorselect,
1373 colorunderline, colorstatus, colorhelp, colorborder,
1374 colorgraphic, colordebug, colorreverse, coloritalic;
1375
1376 extern int trueblink, trueunderline, truereverse, trueitalic, truedim;
1377
1378 extern int bgi, fgi;
1379 extern int scrninitialized[];
1380
1381 struct keytab audibletab[] = {          /* Terminal Bell Audible mode */
1382     { "beep",          XYB_BEEP, 0 },   /* Values ORd with bell mode */
1383     { "system-sounds", XYB_SYS,  0 }
1384 };
1385 int naudibletab = sizeof(audibletab)/sizeof(struct keytab);
1386
1387 struct keytab akmtab[] = {              /* Arrow key mode */
1388     { "application", TTK_APPL, 0 },
1389     { "cursor",      TTK_NORM, 0 }
1390 };
1391 struct keytab kpmtab[] = {              /* Keypad mode */
1392     { "application", TTK_APPL, 0 },
1393     { "numeric",     TTK_NORM, 0 }
1394 };
1395
1396 struct keytab ttcolmodetab[] = {
1397     { "current-color", 0, 0 },
1398     { "default-color", 1, 0 }
1399 };
1400 int ncolmode = sizeof(ttcolmodetab)/sizeof(struct keytab);
1401
1402 #define TTCOLNOR  0
1403 #define TTCOLREV  1
1404 #define TTCOLUND  2
1405 #define TTCOLSTA  3
1406 #define TTCOLHLP  4
1407 #define TTCOLBOR  5
1408 #define TTCOLSEL  6
1409 #define TTCOLDEB  7
1410 #define TTCOLGRP  8
1411 #define TTCOLITA  9
1412 #define TTCOLRES  10
1413 #define TTCOLERA  11
1414
1415 struct keytab ttycoltab[] = {                   /* Terminal Screen coloring */
1416     { "border",             TTCOLBOR, 0 },      /* Screen border color */
1417     { "debug-terminal",     TTCOLDEB, 0 },      /* Debug color */
1418     { "erase",              TTCOLERA, 0 },      /* Erase mode */
1419     { "graphic",            TTCOLGRP, 0 },      /* Graphic Color */
1420     { "help-text",          TTCOLHLP, 0 },      /* Help screens */
1421     { "italic",             TTCOLITA, 0 },      /* Italic Color */
1422     { "normal",             TTCOLNOR, CM_INV }, /* Normal screen text */
1423     { "reset-on-esc[0m",    TTCOLRES, 0 },      /* Reset on ESC [ 0 m */
1424     { "reverse-video",      TTCOLREV, 0 },      /* Reverse video */
1425     { "status-line",        TTCOLSTA, 0 },      /* Status line */
1426     { "selection",          TTCOLSEL, 0 },      /* Selection color */
1427     { "terminal-screen",    TTCOLNOR, 0 },      /* Better name than "normal" */
1428     { "underlined-text",    TTCOLUND, 0 }       /* Underlined text */
1429 };
1430 int ncolors = (sizeof(ttycoltab) / sizeof(struct keytab));
1431
1432 #define TTATTNOR  0
1433 #define TTATTBLI  1
1434 #define TTATTREV  2
1435 #define TTATTUND  3
1436 #define TTATTPRO  4
1437 #define TTATTBLD  5
1438 #define TTATTDIM  6
1439 #define TTATTINV  7
1440 #define TTATTITA  8
1441 #define TTATTDONE 9
1442
1443 struct keytab ttyattrtab[] = {
1444     { "blink",     TTATTBLI, 0 },
1445     { "dim",       TTATTDIM, 0 },
1446     { "italic",    TTATTITA, 0 },
1447     { "protected", TTATTPRO, 0 },
1448     { "reverse",   TTATTREV, 0 },
1449     { "underline", TTATTUND, 0 }
1450 };
1451 int nattrib = (sizeof(ttyattrtab) / sizeof(struct keytab));
1452
1453 struct keytab ttyprotab[] = {
1454     { "blink",       TTATTBLI,  0 },
1455     { "bold",        TTATTBLD,  0 },
1456     { "dim",         TTATTDIM,  0 },
1457     { "done",        TTATTDONE, CM_INV },
1458     { "invisible",   TTATTINV,  0 },
1459     { "italic",      TTATTITA,  0 },
1460     { "normal",      TTATTNOR,  0 },
1461     { "reverse",     TTATTREV,  0 },
1462     { "underlined",  TTATTUND,  0 }
1463
1464 };
1465 int nprotect = (sizeof(ttyprotab) / sizeof(struct keytab));
1466
1467 struct keytab ttyseobtab[] = {
1468     { "crlf_etx",  1, 0 },
1469     { "us_cr",     0, 0 }
1470 };
1471
1472 struct keytab ttyclrtab[] = {           /* Colors */
1473     { "black",         0, 0      },
1474     { "blue",          1, 0      },
1475     { "brown",         6, 0      },
1476     { "cyan",          3, 0      },
1477     { "darkgray",      8, CM_INV },
1478     { "dgray",         8, 0      },
1479     { "green",         2, 0      },
1480     { "lblue",         9, CM_INV },
1481     { "lcyan",        11, CM_INV },
1482     { "lgray",         7, CM_INV },
1483     { "lgreen",       10, CM_INV },
1484     { "lightblue",     9, 0      },
1485     { "lightcyan",    11, 0      },
1486     { "lightgray",     7, 0      },
1487     { "lightgreen",   10, 0      },
1488     { "lightmagenta", 13, 0      },
1489     { "lightred",     12, 0      },
1490     { "lmagenta",     13, CM_INV },
1491     { "lred",         12, CM_INV },
1492     { "magenta",       5, 0      },
1493     { "red",           4, 0      },
1494     { "white",        15, 0      },
1495     { "yellow",       14, 0      }
1496 };
1497 int nclrs = (sizeof (ttyclrtab) / sizeof (struct keytab));
1498
1499 struct keytab ttycurtab[] = {
1500     { "full",        TTC_BLOCK, 0 },
1501     { "half",        TTC_HALF,  0 },
1502     { "underline",   TTC_ULINE, 0 }
1503 };
1504 int ncursors = 3;
1505
1506 struct keytab ttyptab[] = {
1507     { "aaa",      TT_AAA,     CM_INV },     /* AnnArbor */
1508     { "adm3a",    TT_ADM3A,   0 },          /* LSI ADM-3A */
1509     { "adm5",     TT_ADM5,    0 },          /* LSI ADM-5 */
1510     { "aixterm",  TT_AIXTERM, 0 },          /* IBM AIXterm */
1511     { "annarbor", TT_AAA,     0 },          /* AnnArbor */
1512     { "ansi-bbs", TT_ANSI,    0 },          /* ANSI.SYS (BBS) */
1513     { "at386",    TT_AT386,   0 },          /* Unixware ANSI */
1514     { "avatar/0+",TT_ANSI,    0 },          /* AVATAR/0+ */
1515     { "ba80",     TT_BA80,    0 },          /* Nixdorf BA80 */
1516     { "be",       TT_BEOS,    CM_INV|CM_ABR },
1517     { "beos-ansi",TT_BEOS,    CM_INV },     /* BeOS ANSI */
1518     { "beterm",   TT_BEOS,    0 },          /* BeOS Terminal (as of PR2 ) */
1519     { "d200",     TT_DG200,   CM_INV|CM_ABR }, /* Data General DASHER 200 */
1520     { "d210",     TT_DG210,   CM_INV|CM_ABR }, /* Data General DASHER 210 */
1521     { "d217",     TT_DG217,   CM_INV|CM_ABR }, /* Data General DASHER 217 */
1522     { "dg200",    TT_DG200,   0 },          /* Data General DASHER 200 */
1523     { "dg210",    TT_DG210,   0 },          /* Data General DASHER 210 */
1524     { "dg217",    TT_DG217,   0 },          /* Data General DASHER 217 */
1525     { "h1500",    TT_HZL1500, CM_INV },     /* Hazeltine 1500 */
1526     { "h19",      TT_H19,     CM_INV },     /* Heath-19 */
1527     { "heath19",  TT_H19,     0 },          /* Heath-19 */
1528     { "hft",      TT_HFT,     0 },          /* IBM High Function Terminal */
1529     { "hp2621a",  TT_HP2621,  0 },          /* HP 2621A */
1530     { "hpterm",   TT_HPTERM,  0 },          /* HP TERM */
1531     { "hz1500",   TT_HZL1500, 0 },          /* Hazeltine 1500 */
1532     { "ibm3151",  TT_IBM31,   0 },          /* IBM 3101-xx,3161 */
1533     { "linux",    TT_LINUX,   0 },          /* Linux */
1534     { "qansi",    TT_QANSI,   0 },          /* QNX ANSI */
1535     { "qnx",      TT_QNX,     0 },          /* QNX Console */
1536     { "scoansi",  TT_SCOANSI, 0 },          /* SCO ANSI */
1537     { "sni-97801",TT_97801,   0 },          /* SNI 97801 */
1538     { "sun",      TT_SUN,     0 },          /* SUN Console */
1539 /*
1540   The idea of NONE is to let the console driver handle the escape sequences,
1541   which, in theory at least, would give not only ANSI emulation, but also any
1542   other kind of emulation that might be provided by alternative console
1543   drivers, if any existed.
1544
1545   For this to work, ckocon.c would need to be modified to make higher-level
1546   calls, like VioWrtTTY(), DosWrite(), or (simply) write(), rather than
1547   VioWrt*Cell() and similar, and it would also have to give up its rollback
1548   feature, and its status line and help screens would also have to be
1549   forgotten or else done in an ANSI way.
1550
1551   As matters stand, we already have perfectly good ANSI emulation built in,
1552   and there are no alternative console drivers available, so there is no point
1553   in having a terminal type of NONE, so it is commented out.  However, should
1554   you uncomment it, it will work like a "glass tty" -- no escape sequence
1555   interpretation at all; somewhat similar to debug mode, except without the
1556   debugging (no highlighting of control chars or escape sequences); help
1557   screens, status line, and rollback will still work.
1558 */
1559 #ifdef OS2PM
1560 #ifdef COMMENT
1561     { "tek4014", TT_TEK40,  0 },
1562 #endif /* COMMENT */
1563 #endif /* OS2PM */
1564     { "tty",     TT_NONE,   0 },
1565     { "tvi910+", TT_TVI910, 0 },
1566     { "tvi925",  TT_TVI925, 0 },
1567     { "tvi950",  TT_TVI950, 0 },
1568     { "vc404",   TT_VC4404, 0 },
1569     { "vc4404",  TT_VC4404, CM_INV },
1570     { "vip7809", TT_VIP7809,0 },
1571     { "vt100",   TT_VT100,  0 },
1572     { "vt102",   TT_VT102,  0 },
1573     { "vt220",   TT_VT220,  0 },
1574     { "vt220pc", TT_VT220PC,0 },
1575     { "vt320",   TT_VT320,  0 },
1576     { "vt320pc", TT_VT320PC,0 },
1577     { "vt52",    TT_VT52,   0 },
1578 #ifdef NT
1579     { "vtnt",    TT_VTNT,   0 },
1580 #else /* NT */
1581     { "vtnt",    TT_VTNT,  CM_INV },
1582 #endif /* NT */
1583     { "wy160",   TT_WY160,  0 },
1584     { "wy30",    TT_WY30,   0 },
1585     { "wy370",   TT_WY370,  0 },
1586     { "wy50",    TT_WY50,   0 },
1587     { "wy60",    TT_WY60,   0 },
1588     { "wyse30",  TT_WY30,   CM_INV },
1589     { "wyse370", TT_WY370,  CM_INV },
1590     { "wyse50",  TT_WY50,   CM_INV },
1591     { "wyse60",  TT_WY60,   CM_INV }
1592 };
1593 int nttyp = (sizeof(ttyptab) / sizeof(struct keytab));
1594
1595 struct keytab ttkeytab[] = {
1596     { "aaa",       TT_AAA,        CM_INV },        /* AnnArbor */
1597     { "adm3a",     TT_ADM3A,      0 },             /* LSI ADM-3A */
1598     { "adm5",      TT_ADM5,       0 },             /* LSI ADM-5 */
1599     { "aixterm",   TT_AIXTERM,    0 },             /* IBM AIXterm */
1600     { "annarbor",  TT_AAA,        0 },             /* AnnArbor */
1601     { "ansi-bbs",  TT_ANSI,       0 },             /* ANSI.SYS (BBS) */
1602     { "at386",     TT_AT386,      0 },             /* Unixware ANSI */
1603     { "avatar/0+", TT_ANSI,       0 },             /* AVATAR/0+ */
1604     { "ba80",      TT_BA80,       0 },             /* Nixdorf BA80 */
1605     { "be",        TT_BEOS,       CM_INV|CM_ABR },
1606     { "beos-ansi", TT_BEOS,       CM_INV },        /* BeOS ANSI */
1607     { "beterm",    TT_BEOS,       0 },             /* BeOS Terminal (DR2) */
1608     { "d200",      TT_DG200,      CM_INV|CM_ABR }, /* DG DASHER 200 */
1609     { "d210",      TT_DG210,      CM_INV|CM_ABR }, /* DG DASHER 210 */
1610     { "d217",      TT_DG217,      CM_INV|CM_ABR }, /* DG DASHER 217 */
1611     { "dg200",     TT_DG200,      0 },             /* DG DASHER 200 */
1612     { "dg210",     TT_DG210,      0 },             /* DG DASHER 210 */
1613     { "dg217",     TT_DG217,      0 },             /* DG DASHER 217 */
1614     { "emacs",     TT_KBM_EMACS,  0 },             /* Emacs mode */
1615     { "h19",       TT_H19,        CM_INV },        /* Heath-19 */
1616     { "heath19",   TT_H19,        0 },             /* Heath-19 */
1617     { "hebrew",    TT_KBM_HEBREW, 0 },             /* Hebrew mode */
1618     { "hft",       TT_HFT,        0 },             /* IBM High Function Term */
1619     { "hp2621a",   TT_HP2621,     0 },             /* HP 2621A */
1620     { "hpterm",    TT_HPTERM,     0 },             /* HP TERM */
1621     { "hz1500",    TT_HZL1500,    0 },             /* Hazeltine 1500 */
1622     { "ibm3151",   TT_IBM31,      0 },             /* IBM 3101-xx,3161 */
1623     { "linux",     TT_LINUX,      0 },             /* Linux */
1624     { "qansi",     TT_QANSI,      0 },             /* QNX ANSI */
1625     { "qnx",       TT_QNX,        0 },             /* QNX */
1626     { "russian",   TT_KBM_RUSSIAN,0 },             /* Russian mode */
1627     { "scoansi",   TT_SCOANSI,    0 },             /* SCO ANSI */
1628     { "sni-97801", TT_97801,      0 },             /* SNI 97801 */
1629     { "sun",       TT_SUN,        0 },             /* SUN Console */
1630 #ifdef OS2PM
1631 #ifdef COMMENT
1632     { "tek4014",   TT_TEK40,      0 },
1633 #endif /* COMMENT */
1634 #endif /* OS2PM */
1635     { "tty",       TT_NONE,       0 },
1636     { "tvi910+",   TT_TVI910,     0 },
1637     { "tvi925",    TT_TVI925,     0 },
1638     { "tvi950",    TT_TVI950,     0 },
1639     { "vc404",     TT_VC4404,     0 },
1640     { "vc4404",    TT_VC4404,     CM_INV },
1641     { "vip7809",   TT_VIP7809,    0 },
1642     { "vt100",     TT_VT100,      0 },
1643     { "vt102",     TT_VT102,      0 },
1644     { "vt220",     TT_VT220,      0 },
1645     { "vt220pc",   TT_VT220PC,    0 },
1646     { "vt320",     TT_VT320,      0 },
1647     { "vt320pc",   TT_VT320PC,    0 },
1648     { "vt52",      TT_VT52,       0 },
1649     { "vtnt",      TT_VTNT,       CM_INV },
1650     { "wp",        TT_KBM_WP,     0 },             /* Word Perfect mode */
1651     { "wy160",     TT_WY160,      0 },
1652     { "wy30",      TT_WY30,       0 },
1653     { "wy370",     TT_WY370,      0 },
1654     { "wy50",      TT_WY50,       0 },
1655     { "wy60",      TT_WY60,       0 },
1656     { "wyse30",    TT_WY30,       CM_INV },
1657     { "wyse370",   TT_WY370,      CM_INV },
1658     { "wyse50",    TT_WY50,       CM_INV },
1659     { "wyse60",    TT_WY60,       CM_INV }
1660 };
1661 int nttkey = (sizeof(ttkeytab) / sizeof(struct keytab));
1662
1663 #ifndef NOSETKEY
1664 struct keytab kbmodtab[] = {
1665     { "emacs",   KBM_EM, 0      },
1666     { "english", KBM_EN, CM_INV },
1667     { "hebrew",  KBM_HE, 0      },
1668     { "normal",  KBM_EN, 0      },
1669     { "none",    KBM_EN, CM_INV },
1670     { "russian", KBM_RU, 0      },
1671     { "wp",      KBM_WP, 0      }
1672 };
1673 int nkbmodtab = (sizeof(kbmodtab) / sizeof(struct keytab));
1674 #endif /* NOSETKEY */
1675 #endif /* NOLOCAL */
1676
1677 int tt_inpacing = 0;                    /* input-pacing (none) */
1678
1679 struct keytab prtytab[] = { /* OS/2 Priority Levels */
1680     { "foreground-server", XYP_SRV, 0       },
1681     { "idle",              XYP_IDLE, CM_INV },
1682     { "regular",           XYP_REG, 0       },
1683     { "time-critical",     XYP_RTP, 0       }
1684 };
1685 int nprty = (sizeof(prtytab) / sizeof(struct keytab));
1686 #endif /* OS2 */
1687
1688 #ifdef NT
1689 struct keytab win95tab[] = { /* Win95 work-arounds */
1690     { "8.3-filenames",         XYW8_3,    0 },
1691     { "alt-gr",                XYWAGR,    0 },
1692     { "horizontal-scan-line-substitutions", XYWHSL, 0 },
1693     { "keyboard-translation",  XYWKEY,    0 },
1694     { "lucida-substitutions",  XYWLUC,    0 },
1695     { "overlapped-io",         XYWOIO,    0 },
1696     { "popups",                XYWPOPUP,  0 },
1697     { "select-bug",            XYWSELECT, 0 }
1698 };
1699 int nwin95 = (sizeof(win95tab) / sizeof(struct keytab));
1700 #endif /* NT */
1701
1702 #ifdef OS2MOUSE
1703 extern int wideresult;
1704 int tt_mouse = 1;                       /* Terminal mouse on/off */
1705
1706 struct keytab mousetab[] = {            /* Mouse items */
1707     { "activate", XYM_ON,     0 },
1708     { "button",   XYM_BUTTON, 0 },
1709     { "clear",    XYM_CLEAR,  0 },
1710     { "debug",    XYM_DEBUG,  0 }
1711 };
1712 int nmtab = (sizeof(mousetab)/sizeof(struct keytab));
1713
1714 struct keytab mousebuttontab[] = {      /* event button */
1715     { "1",             XYM_B1, 0 },
1716     { "2",             XYM_B2, 0 },
1717     { "3",             XYM_B3, 0 },
1718     { "one",           XYM_B1, CM_INV },
1719     { "three",         XYM_B3, CM_INV },
1720     { "two",           XYM_B2, CM_INV }
1721 };
1722 int nmbtab = (sizeof(mousebuttontab) / sizeof(struct keytab));
1723
1724 struct keytab mousemodtab[] = {         /* event button key modifier */
1725     { "alt",              XYM_ALT,   0 },
1726     { "alt-shift",        XYM_SHIFT|XYM_ALT, 0 },
1727     { "ctrl",             XYM_CTRL,  0 },
1728     { "ctrl-alt",         XYM_CTRL|XYM_ALT, 0 },
1729     { "ctrl-alt-shift",   XYM_CTRL|XYM_SHIFT|XYM_ALT, 0 },
1730     { "ctrl-shift",       XYM_CTRL|XYM_SHIFT, 0 },
1731     { "none",             0, 0 },
1732     { "shift",            XYM_SHIFT, 0 }
1733 };
1734 int nmmtab = (sizeof(mousemodtab) / sizeof(struct keytab));
1735
1736 struct keytab mclicktab[] = {           /* event button click modifier */
1737     { "click",        XYM_C1,   0 },
1738     { "drag",         XYM_DRAG, 0 },
1739     { "double-click", XYM_C2,   0 }
1740 };
1741 int nmctab = (sizeof(mclicktab) / sizeof(struct keytab));
1742
1743 #ifndef NOKVERBS
1744 extern int nkverbs;
1745 extern struct keytab kverbs[];
1746 #endif /* NOKVERBS */
1747 #endif /* OS2MOUSE */
1748
1749 /* #ifdef VMS */
1750 struct keytab fbtab[] = {               /* Binary record types for VMS */
1751     { "fixed",     XYFT_B, 0 },         /* Fixed is normal for binary */
1752     { "undefined", XYFT_U, 0 }          /* Undefined if they ask for it */
1753 };
1754 int nfbtyp = (sizeof(fbtab) / sizeof(struct keytab));
1755 /* #endif */
1756
1757 #ifdef VMS
1758 struct keytab lbltab[] = {              /* Labeled File info */
1759     { "acl",         LBL_ACL, 0 },
1760     { "backup-date", LBL_BCK, 0 },
1761     { "name",        LBL_NAM, 0 },
1762     { "owner",       LBL_OWN, 0 },
1763     { "path",        LBL_PTH, 0 }
1764 };
1765 int nlblp = (sizeof(lbltab) / sizeof(struct keytab));
1766 #else
1767 #ifdef OS2
1768 struct keytab lbltab[] = {              /* Labeled File info */
1769     { "archive",   LBL_ARC, 0 },
1770     { "extended",  LBL_EXT, 0 },
1771     { "hidden",    LBL_HID, 0 },
1772     { "read-only", LBL_RO,  0 },
1773     { "system",    LBL_SYS, 0 }
1774 };
1775 int nlblp = (sizeof(lbltab) / sizeof(struct keytab));
1776 #endif /* OS2 */
1777 #endif /* VMS */
1778
1779 #ifdef CK_CURSES
1780 #ifdef CK_PCT_BAR
1781 static struct keytab fdftab[] = {       /* SET FILE DISPLAY FULL options */
1782     { "thermometer",    1, 0, },
1783     { "no-thermometer", 0, 0  }
1784 };
1785 extern int thermometer;
1786 #endif /* CK_PCT_BAR */
1787 #endif /* CK_CURSES */
1788
1789 static struct keytab fdtab[] = {        /* SET FILE DISPLAY options */
1790 #ifdef MAC                              /* Macintosh */
1791     { "fullscreen", XYFD_R,      0 },   /* Full-screen but not curses */
1792     { "none",       XYFD_N,      0 },
1793     { "off",        XYFD_N, CM_INV },
1794     { "on",         XYFD_R, CM_INV },
1795     { "quiet",      XYFD_N, CM_INV },
1796 #else                                   /* Not Mac */
1797     { "brief", XYFD_B, 0 },             /* Brief */
1798     { "crt", XYFD_S, 0 },               /* CRT display */
1799 #ifdef CK_CURSES
1800 #ifdef COMMENT
1801     { "curses",     XYFD_C,  CM_INV },  /* Full-screen, curses */
1802 #endif /* COMMENT */
1803     { "fullscreen", XYFD_C,  0 },       /* Full-screen, whatever the method */
1804 #endif /* CK_CURSES */
1805 #ifdef KUI
1806     { "gui",    XYFD_G, 0 },            /* GUI */
1807 #endif /* KUI */        
1808     { "none",   XYFD_N, 0      },       /* No display */
1809     { "off",    XYFD_N, CM_INV },       /* Ditto */
1810     { "on",     XYFD_R, CM_INV },       /* On = Serial */
1811     { "quiet",  XYFD_N, CM_INV },       /* No display */
1812     { "serial", XYFD_R, 0      },       /* Serial */
1813 #endif /* MAC */
1814     { "", 0, 0 }
1815 };
1816 int nfdtab = (sizeof(fdtab) / sizeof(struct keytab)) - 1;
1817
1818 struct keytab rsrtab[] = {              /* For REMOTE SET RECEIVE */
1819     { "packet-length", XYLEN,  0 },
1820     { "timeout",       XYTIMO, 0 }
1821 };
1822 int nrsrtab = (sizeof(rsrtab) / sizeof(struct keytab));
1823
1824 /* Send/Receive Parameters */
1825
1826 struct keytab srtab[] = {
1827     { "backup", XYBUP, 0 },
1828 #ifndef NOCSETS
1829     { "character-set-selection", XYCSET, 0 },
1830 #endif /* NOCSETS */
1831     { "control-prefix", XYQCTL, 0 },
1832 #ifdef CKXXCHAR
1833     { "double-character", XYDBL, 0 },
1834 #endif /* CKXXCHAR */
1835     { "end-of-packet", XYEOL, 0 },
1836 #ifdef PIPESEND
1837     { "filter", XYFLTR, 0 },
1838 #endif /* PIPESEND */
1839 #ifdef CKXXCHAR
1840     { "ignore-character", XYIGN, 0 },
1841 #endif /* CKXXCHAR */
1842     { "i-packets", 993, 0 },
1843     { "move-to", XYMOVE, 0 },
1844     { "negotiation-string-max-length", XYINIL, CM_INV },
1845     { "packet-length", XYLEN, 0 },
1846     { "pad-character", XYPADC, 0 },
1847     { "padding", XYNPAD, 0 },
1848     { "pathnames", XYFPATH, 0 },
1849     { "pause", XYPAUS, 0 },
1850 #ifdef CK_PERMS
1851     { "permissions", 994, 0},           /* 206 */
1852 #endif /* CK_PERMS */
1853     { "quote", XYQCTL, CM_INV },        /* = CONTROL-PREFIX */
1854     { "rename-to", XYRENAME, 0 },
1855     { "start-of-packet", XYMARK, 0 },
1856     { "timeout", XYTIMO, 0 },
1857 #ifdef VMS
1858     { "version-numbers", 887, 0 },      /* VMS version numbers */
1859 #endif /* VMS */
1860     { "", 0, 0 }
1861 };
1862 int nsrtab = (sizeof(srtab) / sizeof(struct keytab)) - 1;
1863
1864 #ifdef UNICODE
1865 #define UCS_BOM 1
1866 #define UCS_BYT 2
1867 static struct keytab ucstab[] = {
1868     { "bom",        UCS_BOM, 0 },
1869     { "byte-order", UCS_BYT, 0 },
1870     { "", 0, 0 }
1871 };
1872 int nucstab = (sizeof(ucstab) / sizeof(struct keytab)) - 1;
1873
1874 static struct keytab botab[] = {
1875     { "big-endian",    0, 0 },
1876     { "little-endian", 1, 0 }
1877 };
1878 static int nbotab = 2;
1879 #endif /* UNICODE */
1880
1881 /* REMOTE SET */
1882
1883 struct keytab rmstab[] = {
1884     { "attributes",  XYATTR, 0      },
1885     { "block-check", XYCHKT, 0      },
1886     { "file",        XYFILE, 0      },
1887     { "incomplete",  XYIFD,  CM_INV },  /* = REMOTE SET FILE INCOMPLETE */
1888     { "match",       XYMATCH,0      },
1889     { "receive",     XYRECV, 0      },
1890     { "retry",       XYRETR, 0      },
1891     { "server",      XYSERV, 0      },
1892     { "transfer",    XYXFER, 0      },
1893     { "window",      XYWIND, 0      },
1894     { "xfer",        XYXFER, CM_INV }
1895 };
1896 int nrms = (sizeof(rmstab) / sizeof(struct keytab));
1897
1898 struct keytab attrtab[] = {
1899 #ifdef STRATUS
1900     { "account",       AT_ACCT, 0 },
1901 #endif /* STRATUS */
1902     { "all",           AT_XALL, 0 },
1903 #ifdef COMMENT
1904     { "blocksize",     AT_BLKS, 0 },    /* (not used) */
1905 #endif /* COMMENT */
1906 #ifndef NOCSETS
1907     { "character-set", AT_ENCO, 0 },
1908 #endif /* NOCSETS */
1909 #ifdef STRATUS
1910     { "creator",       AT_CREA, 0 },
1911 #endif /* STRATUS */
1912     { "date",          AT_DATE, 0 },
1913     { "disposition",   AT_DISP, 0 },
1914     { "encoding",      AT_ENCO, CM_INV },
1915     { "format",        AT_RECF, CM_INV },
1916     { "length",        AT_LENK, 0 },
1917     { "off",           AT_ALLN, 0 },
1918     { "on",            AT_ALLY, 0 },
1919 #ifdef COMMENT
1920     { "os-specific",   AT_SYSP, 0 },    /* (not used by UNIX or VMS) */
1921 #endif /* COMMENT */
1922 #ifdef CK_PERMS
1923     { "protection",    AT_LPRO, 0 },
1924     { "permissions",   AT_LPRO, CM_INV },
1925 #endif /* CK_PERMS */
1926     { "record-format", AT_RECF, 0 },
1927     { "system-id",     AT_SYSI, 0 },
1928     { "type",          AT_FTYP, 0 }
1929 };
1930 int natr = (sizeof(attrtab) / sizeof(struct keytab)); /* how many attributes */
1931
1932 #ifdef CKTIDLE
1933 struct keytab idlacts[] = {
1934     { "exit",       IDLE_EXIT, 0 },
1935     { "hangup",     IDLE_HANG, 0 },
1936     { "output",     IDLE_OUT,  0 },
1937     { "return",     IDLE_RET,  0 },
1938 #ifdef TNCODE
1939     { "telnet-nop", IDLE_TNOP, 0 },
1940     { "telnet-ayt", IDLE_TAYT, 0 },
1941 #endif /* TNCODE */
1942     { "", 0, 0 }
1943 };
1944 int nidlacts = (sizeof(idlacts) / sizeof(struct keytab)) - 1;
1945 #endif /* CKTIDLE */
1946
1947 #ifndef NOSPL
1948 extern int indef, inecho, insilence, inbufsize, inautodl, inintr;
1949 #ifdef CKFLOAT
1950 extern CKFLOAT inscale;
1951 #endif  /* CKFLOAT */
1952 extern char * inpbuf, * inpbp;
1953 #ifdef OS2
1954 extern int interm;
1955 #endif /* OS2 */
1956 struct keytab inptab[] = {              /* SET INPUT parameters */
1957 #ifdef CK_AUTODL
1958     { "autodownload",    IN_ADL, 0 },
1959 #endif /* CK_AUTODL */
1960     { "buffer-length",   IN_BUF, 0 },
1961     { "cancellation",    IN_CAN, 0 },
1962     { "case",            IN_CAS, 0 },
1963     { "default-timeout", IN_DEF, CM_INV }, /* There is no default timeout */
1964     { "echo",            IN_ECH, 0 },
1965 #ifdef OS2
1966     { "pacing",          IN_PAC, CM_INV },
1967 #endif /* OS2 */
1968     { "scale-factor",    IN_SCA, 0 },
1969     { "silence",         IN_SIL, 0 },
1970 #ifdef OS2
1971     { "terminal",        IN_TRM, 0 },
1972 #endif /* OS2 */
1973     { "timeout-action",  IN_TIM, 0 }
1974 };
1975 int ninp = (sizeof(inptab) / sizeof(struct keytab));
1976
1977 struct keytab intimt[] = {              /* SET INPUT TIMEOUT parameters */
1978     { "proceed", 0, 0 },                /* 0 = proceed */
1979     { "quit",    1, 0 }                 /* 1 = quit */
1980 };
1981
1982 struct keytab incast[] = {              /* SET INPUT CASE parameters */
1983     { "ignore",  0, 0 },                /* 0 = ignore */
1984     { "observe", 1, 0 }                 /* 1 = observe */
1985 };
1986 #endif /* NOSPL */
1987
1988 struct keytab nabltab[] = {             /* For any command that needs */
1989     { "disabled", 0, 0 },
1990     { "enabled",  1, 0 },
1991     { "off",      0, CM_INV },          /* these keywords... */
1992     { "on",       1, CM_INV }
1993 };
1994 int nnabltab = sizeof(nabltab) / sizeof(struct keytab);
1995
1996 #ifdef OS2
1997 struct keytab tvctab[] = {              /* SET TERM VIDEO-CHANGE */
1998     { "disabled",     TVC_DIS, 0 },
1999     { "enabled",      TVC_ENA, 0 },
2000 #ifdef NT
2001     { "win95-safe",   TVC_W95, 0 },
2002 #endif /* NT */
2003     { "", 0, 0 }
2004 };
2005 int ntvctab = (sizeof(tvctab) / sizeof(struct keytab)) - 1;
2006
2007 struct keytab msktab[] = { /* SET MS-DOS KERMIT compatibilities */
2008 #ifdef COMMENT
2009     { "color",    MSK_COLOR,  0 },
2010 #endif /* COMMENT */
2011     { "keycodes", MSK_KEYS,   0 }
2012 };
2013 int nmsk = (sizeof(msktab) / sizeof(struct keytab));
2014
2015 struct keytab scrnupd[] = {             /* SET TERMINAL SCREEN-UPDATE */
2016     { "fast",   TTU_FAST,   0 },
2017     { "smooth", TTU_SMOOTH, 0 }
2018 };
2019 int nscrnupd = (sizeof(scrnupd) / sizeof(struct keytab));
2020
2021 #ifdef PCFONTS
2022 /* This definition of the term_font[] table is only for     */
2023 /* the OS/2 Full Screen Session and is not used on Windows */
2024 struct keytab term_font[] = {           /* SET TERMINAL FONT */
2025 #ifdef COMMENT
2026     { "cp111", TTF_111, 0 },
2027     { "cp112", TTF_112, 0 },
2028     { "cp113", TTF_113, 0 },
2029 #endif /* COMMENT */
2030     { "cp437", TTF_437, 0 },
2031     { "cp850", TTF_850, 0 },
2032 #ifdef COMMENT
2033     { "cp851", TTF_851, 0 },
2034 #endif /* COMMENT */
2035     { "cp852", TTF_852, 0 },
2036 #ifdef COMMENT
2037     { "cp853", TTF_853, 0 },
2038     { "cp860", TTF_860, 0 },
2039     { "cp861", TTF_861, 0 },
2040 #endif /* COMMENT */
2041     { "cp862", TTF_862, 0 },
2042 #ifdef COMMENT
2043     { "cp863", TTF_863, 0 },
2044     { "cp864", TTF_864, 0 },
2045     { "cp865", TTF_865, 0 },
2046 #endif /* COMMENT */
2047     { "cp866", TTF_866, 0 },
2048 #ifdef COMMENT
2049     { "cp880", TTF_880, 0 },
2050     { "cp881", TTF_881, 0 },
2051     { "cp882", TTF_882, 0 },
2052     { "cp883", TTF_883, 0 },
2053     { "cp884", TTF_884, 0 },
2054     { "cp885", TTF_885, 0 },
2055 #endif /* COMMENT */
2056     { "default",TTF_ROM,0 }
2057 };
2058 int ntermfont = (sizeof(term_font) / sizeof(struct keytab));
2059 int tt_font = TTF_ROM;                  /* Terminal screen font */
2060 #else /* PCFONTS */
2061 #ifdef NT
2062 #ifdef KUI
2063 struct keytab * term_font = NULL;
2064 struct keytab * _term_font = NULL;
2065 char * tt_facename = NULL;
2066 int ntermfont = 0;
2067 int tt_font = 0;
2068 int tt_font_size = 0;
2069 #endif /* KUI */
2070 #endif /* NT */
2071 #endif /* PCFONTS */
2072
2073 struct keytab anbktab[] = {             /* For any command that needs */
2074     { "message", 2, 0 },                /* these keywords... */
2075     { "off",     0, 0 },
2076     { "on",      1, 0 },
2077     { "unsafe-messag0", 99, CM_INV },
2078     { "unsafe-message", 3,  CM_INV }
2079 };
2080 int nansbk = (sizeof(anbktab) / sizeof(struct keytab));
2081
2082 int win95_popup = 1;
2083 #ifdef NT
2084 #ifdef KUI
2085 int win95lucida = 0;
2086 int win95hsl = 1;
2087 #else /* KUI */
2088 int win95lucida = 1;
2089 int win95hsl = 1;
2090 #endif /* KUI */
2091 #else /* NT */
2092 int win95lucida = 0;
2093 int win95hsl = 1;
2094 #endif /* NT */
2095 #ifdef NT
2096 int win95altgr  = 0;
2097 extern int win95selectbug;
2098 extern int win95_8_3;
2099
2100 #ifdef COMMENT
2101 extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR);
2102 extern struct keytab tcstab[];
2103 extern int ntcs;
2104 #endif /* COMMENT */
2105 extern int maxow, maxow_usr; owwait;    /* Overlapped I/O variables */
2106 #endif /* NT */
2107 #endif /* OS2 */
2108
2109
2110 /* The following routines broken out of doprm() to give compilers a break. */
2111
2112 /*  S E T O N  --  Parse on/off (default on), set parameter to result  */
2113
2114 int
2115 seton(prm) int *prm; {
2116     int x, y;
2117     if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
2118     if ((x = cmcfm()) < 0) return(x);
2119     *prm = y;
2120     return(1);
2121 }
2122
2123 /*  S E T O N A U T O --  Parse on/off/auto (default auto) & set result */
2124
2125 struct keytab onoffaut[] = {
2126     { "auto", SET_AUTO, 0 },            /* 2 */
2127     { "off",  SET_OFF,  0 },            /* 0 */
2128     { "on",   SET_ON,   0 }             /* 1 */
2129 };
2130
2131 int
2132 setonaut(prm) int *prm; {
2133     int x, y;
2134     if ((y = cmkey(onoffaut,3,"","auto",xxstring)) < 0) return(y);
2135     if ((x = cmcfm()) < 0) return(x);
2136     *prm = y;
2137     return(1);
2138 }
2139
2140 /*  S E T N U M  --  Set parameter to result of cmnum() parse.  */
2141 /*
2142  Call with pointer to integer variable to be set,
2143    x = number from cnum parse, y = return code from cmnum,
2144    max = maximum value to accept, -1 if no maximum.
2145  Returns -9 on failure, after printing a message, or 1 on success.
2146 */
2147 int
2148 setnum(prm,x,y,max) int x, y, *prm, max; {
2149     debug(F101,"setnum","",y);
2150     if (y == -3) {
2151         printf("\n?Value required\n");
2152         return(-9);
2153     }
2154     if (y == -2) {
2155         printf("%s?Not a number: %s\n",cmflgs == 1 ? "" : "\n", atxbuf);
2156         return(-9);
2157     }
2158     if (y < 0) return(y);
2159     if (max > -1 && x > max) {
2160         printf("?Sorry, %d is the maximum\n",max);
2161         return(-9);
2162     }
2163     if ((y = cmcfm()) < 0) return(y);
2164     *prm = x;
2165     return(1);
2166 }
2167
2168 /*  S E T C C  --  Set parameter var to an ASCII control character value.  */
2169 /*
2170   Parses a number, or a literal control character, or a caret (^) followed
2171   by an ASCII character whose value is 63-95 or 97-122, then gets confirmation,
2172   then sets the parameter to the code value of the character given.  If there
2173   are any parse errors, they are returned, otherwise on success 1 is returned.
2174 */
2175 int
2176 setcc(dflt,var) char *dflt; int *var; {
2177     int x, y;
2178     unsigned int c;
2179     char *hlpmsg = "Control character,\n\
2180  numeric ASCII value,\n\
2181  or in ^X notation,\n\
2182  or preceded by a backslash and entered literally";
2183
2184     /* This is a hack to turn off complaints from expression evaluator. */
2185     x_ifnum = 1;
2186     y = cmnum(hlpmsg, dflt, 10, &x, xxstring); /* Parse a number */
2187     x_ifnum = 0;                               /* Allow complaints again */
2188     if (y < 0) {                        /* Parse failed */
2189         if (y != -2)                    /* Reparse needed or somesuch */
2190           return(y);                    /* Pass failure back up the chain */
2191     }
2192     /* Real control character or literal 8-bit character... */
2193
2194     for (c = strlen(atmbuf) - 1; c > 0; c--) /* Trim */
2195       if (atmbuf[c] == SP) atmbuf[c] = NUL;
2196
2197     if (y < 0) {                        /* It was not a number */
2198         if (((c = atmbuf[0])) && !atmbuf[1]) { /* Literal character? */
2199             c &= 0xff;
2200             if (((c > 31) && (c < 127)) || (c > 255)) {
2201                 printf("\n?%d: Out of range - must be 0-31 or 127-255\n",c);
2202                 return(-9);
2203             } else {
2204                 if ((y = cmcfm()) < 0)  /* Confirm */
2205                   return(y);
2206                 *var = c;               /* Set the variable */
2207                 return(1);
2208             }
2209         } else if (atmbuf[0] == '^' && !atmbuf[2]) { /* Or ^X notation? */
2210             c = atmbuf[1];
2211             if (islower((char) c))      /* Uppercase lowercase letters */
2212               c = toupper(c);
2213             if (c > 62 && c < 96) {     /* Check range */
2214                 if ((y = cmcfm()) < 0)
2215                   return(y);
2216                 *var = ctl(c);          /* OK */
2217                 return(1);
2218             } else {
2219                 printf("?Not a control character - %s\n", atmbuf);
2220                 return(-9);
2221             }
2222         } else {                        /* Something illegal was typed */
2223             printf("?Invalid - %s\n", atmbuf);
2224             return(-9);
2225         }
2226     }
2227     if (((x > 31) && (x < 127)) || (x > 255)) { /* They typed a number */
2228         printf("\n?%d: Out of range - must be 0-31 or 127-255\n",x);
2229         return(-9);
2230     }
2231     if ((y = cmcfm()) < 0)              /* In range, confirm */
2232       return(y);
2233     *var = x;                           /* Set variable */
2234     return(1);
2235 }
2236
2237 #ifndef NOSPL                           /* The SORT command... */
2238
2239 static struct keytab srtswtab[] = {     /* SORT command switches */
2240     { "/case",    SRT_CAS, CM_ARG },
2241     { "/key",     SRT_KEY, CM_ARG },
2242     { "/numeric", SRT_NUM, 0 },
2243     { "/range",   SRT_RNG, CM_ARG },
2244     { "/reverse", SRT_REV, 0 }
2245 };
2246 static int nsrtswtab = sizeof(srtswtab)/sizeof(struct keytab);
2247
2248 extern char **a_ptr[];                  /* Array pointers */
2249 extern int a_dim[];                     /* Array dimensions */
2250
2251 int
2252 dosort() {                              /* Do the SORT command */
2253     char c, *p = NULL, ** ap, ** xp = NULL;
2254     struct FDB sw, fl, cm;
2255     int hi, lo;
2256     int xn = 0, xr = -1, xk = -1, xc = -1, xs = 0;
2257     int getval = 0, range[2], confirmed = 0;
2258
2259     cmfdbi(&sw,                         /* First FDB - command switches */
2260            _CMKEY,                      /* fcode */
2261            "Array name or switch",
2262            "",                          /* default */
2263            "",                          /* addtl string data */
2264            nsrtswtab,                   /* addtl numeric data 1: tbl size */
2265            4,                           /* addtl numeric data 2: 4 = cmswi */
2266            NULL,                        /* Processing function */
2267            srtswtab,                    /* Keyword table */
2268            &fl                          /* Pointer to next FDB */
2269            );
2270     cmfdbi(&fl,                         /* Anything that doesn't match */
2271            _CMFLD,                      /* fcode */
2272            "Array name",                /* hlpmsg */
2273            "",                          /* default */
2274            "",                          /* addtl string data */
2275            0,                           /* addtl numeric data 1 */
2276            0,                           /* addtl numeric data 2 */
2277            NULL,
2278            NULL,
2279            &cm
2280            );
2281     cmfdbi(&cm,                         /* Or premature confirmation */
2282            _CMCFM,                      /* fcode */
2283            "",                          /* hlpmsg */
2284            "",                          /* default */
2285            "",                          /* addtl string data */
2286            0,                           /* addtl numeric data 1 */
2287            0,                           /* addtl numeric data 2 */
2288            NULL,
2289            NULL,
2290            NULL
2291            );
2292
2293     range[0] = -1;
2294     range[1] = -1;
2295
2296     while (1) {                         /* Parse 0 or more switches */
2297         x = cmfdb(&sw);
2298         if (x < 0)
2299           return(x);
2300         if (cmresult.fcode != _CMKEY)   /* Break out if not a switch */
2301           break;
2302         c = cmgbrk();
2303         getval = (c == ':' || c == '=');
2304         if (getval && !(cmresult.kflags & CM_ARG)) {
2305             printf("?This switch does not take arguments\n");
2306             return(-9);
2307         }
2308         switch (cmresult.nresult) {
2309           case SRT_REV:
2310             xr = 1;
2311             break;
2312           case SRT_KEY:
2313             if (getval) {
2314                 if ((y = cmnum("Column for comparison (1-based)",
2315                                "1",10,&x,xxstring)) < 0)
2316                   return(y);
2317                 xk = x - 1;
2318             } else
2319               xk = 0;
2320             break;
2321           case SRT_CAS:
2322             if (getval) {
2323                 if ((y = cmkey(onoff,2,"","on",xxstring)) < 0)
2324                   return(y);
2325                 xc = y;
2326             } else
2327               xc = 1;
2328             break;
2329           case SRT_RNG:                 /* /RANGE */
2330             if (getval) {
2331                 char buf[32];
2332                 char buf2[16];
2333                 int i;
2334                 char * p, * q;
2335                 if ((y = cmfld("low:high element","1",&s,NULL)) < 0)
2336                   return(y);
2337                 s = brstrip(s);
2338                 ckstrncpy(buf,s,32);
2339                 p = buf;
2340                 for (i = 0; *p && i < 2; i++) { /* Get low and high */
2341                     q = p;              /* Start of this piece */
2342                     while (*p) {        /* Find end of this piece */
2343                         if (*p == ':') {
2344                             *p = NUL;
2345                             p++;
2346                             break;
2347                         }
2348                         p++;
2349                     }
2350                     y = 15;             /* Evaluate this piece */
2351                     s = buf2;
2352                     zzstring(q,&s,&y);
2353                     s = evalx(buf2);
2354                     if (s) if (*s) ckstrncpy(buf2,s,16);
2355                     if (!rdigits(buf2)) {
2356                         printf("?Not numeric: %s\n",buf2);
2357                         return(-9);
2358                     }
2359                     range[i] = atoi(buf2);
2360                 }
2361             }
2362             break;
2363           case SRT_NUM:                 /* /NUMERIC */
2364             xn = 1;
2365             break;
2366           default:
2367             return(-2);
2368         }
2369     }
2370     switch (cmresult.fcode) {
2371       case _CMCFM:
2372         confirmed = 1;
2373         break;
2374       case _CMFLD:
2375         ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Safe copy of name */
2376         s = line;
2377         break;
2378       default:
2379         printf("?Unexpected function code: %d\n",cmresult.fcode);
2380         return(-9);
2381     }
2382     if (confirmed) {
2383         printf("?Array name required\n");
2384         return(-9);
2385     }
2386     ckmakmsg(tmpbuf,TMPBUFSIZ,
2387              "Second array to sort according to ",s,NULL,NULL);
2388     if ((x = cmfld(tmpbuf,"",&p,NULL)) < 0)
2389       if (x != -3)
2390         return(x);
2391     tmpbuf[0] = NUL;
2392     ckstrncpy(tmpbuf,p,TMPBUFSIZ);
2393     p = tmpbuf;
2394     if ((x = cmcfm()) < 0)              /* Get confirmation */
2395       return(x);
2396
2397     x = arraybounds(s,&lo,&hi);         /* Get array index & bounds */
2398     if (x < 0) {                        /* Check */
2399         printf("?Bad array name: %s\n",s);
2400         return(-9);
2401     }
2402     if (lo > -1) range[0] = lo;         /* Set range */
2403     if (hi > -1) range[1] = hi;
2404     ap = a_ptr[x];                      /* Get pointer to array element list */
2405     if (!ap) {                          /* Check */
2406         printf("?Array not declared: %s\n", s);
2407         return(-9);
2408     }
2409     if (range[0] < 0)                   /* Starting element */
2410       range[0] = 1;
2411     if (range[1] < 0)                   /* Final element */
2412       range[1] = a_dim[x];
2413     if (range[1] > a_dim[x]) {
2414         printf("?range %d:%d exceeds array dimension %d\n",
2415                range[0],range[1],a_dim[x]
2416                );
2417         return(-9);
2418     }
2419     ap += range[0];
2420     xs = range[1] - range[0] + 1;       /* Number of elements to sort */
2421     if (xs < 1) {                       /* Check */
2422         printf("?Bad range: %d:%d\n",range[0],range[1]);
2423         return(-9);
2424     }
2425     if (xk < 0) xk = 0;                 /* Key position */
2426     if (xr < 0) xr = 0;                 /* Reverse flag */
2427     if (xn)                             /* Numeric flag */
2428       xc = 2;
2429     else if (xc < 0)                    /* Not numeric */
2430       xc = inpcas[cmdlvl];              /* so alpha case option */
2431
2432     if (*p) {                           /* Parallel array given? */
2433         y = xarray(p);                  /* Yes, get its index. */
2434         if (y < 0) {
2435             printf("?Bad array name: %s\n", p);
2436             return(-9);
2437         }
2438         if (y != x) {                   /* If the 2 arrays are different  */
2439             xp = a_ptr[y];              /* Pointer to 2nd array element list */
2440             if (!xp) {
2441                 printf("?Array not declared: %s\n", p);
2442                 return(-9);
2443             }
2444             if (a_dim[y] < range[1]) {
2445                 printf("?Array %s smaller than %s\n", p, s);
2446                 return(-9);
2447             }
2448             xp += range[0];             /* Set base to same as 1st array */
2449         }
2450     }
2451     sh_sort(ap,xp,xs,xk,xr,xc);         /* Sort the array(s) */
2452     return(success = 1);                /* Always succeeds */
2453 }
2454 #endif /* NOSPL */
2455
2456 static struct keytab purgtab[] = {      /* PURGE command switches */
2457     { "/after",        PU_AFT,  CM_ARG },
2458     { "/ask",          PU_ASK,  0 },
2459     { "/before",       PU_BEF,  CM_ARG },
2460     { "/delete",       PU_DELE, CM_INV },
2461 #ifdef UNIXOROSK
2462     { "/dotfiles",     PU_DOT,  0 },
2463 #endif /* UNIXOROSK */
2464     { "/except",       PU_EXC,  CM_ARG },
2465     { "/heading",      PU_HDG,  0 },
2466     { "/keep",         PU_KEEP, CM_ARG },
2467     { "/larger-than",  PU_LAR,  CM_ARG },
2468     { "/list",         PU_LIST, 0 },
2469     { "/log",          PU_LIST, CM_INV },
2470     { "/noask",        PU_NASK, 0 },
2471     { "/nodelete",     PU_NODE, CM_INV },
2472 #ifdef UNIXOROSK
2473     { "/nodotfiles",   PU_NODOT,0 },
2474 #endif /* UNIXOROSK */
2475     { "/noheading",    PU_NOH,  0 },
2476     { "/nol",          PU_NOLI, CM_INV|CM_ABR },
2477     { "/nolist",       PU_NOLI, 0 },
2478     { "/nolog",        PU_NOLI, CM_INV },
2479 #ifdef CK_TTGWSIZ
2480     { "/nopage",       PU_NOPA, 0 },
2481 #endif /* CK_TTGWSIZ */
2482     { "/not-after",    PU_NAF,  CM_ARG },
2483     { "/not-before",   PU_NBF,  CM_ARG },
2484     { "/not-since",    PU_NAF,  CM_INV|CM_ARG },
2485 #ifdef CK_TTGWSIZ
2486     { "/page",         PU_PAGE, 0 },
2487 #endif /* CK_TTGWSIZ */
2488     { "/quiet",        PU_QUIE, CM_INV },
2489 #ifdef RECURSIVE
2490     { "/recursive",    PU_RECU, 0 },
2491 #endif /* RECURSIVE */
2492     { "/since",        PU_AFT,  CM_ARG|CM_INV },
2493     { "/simulate",     PU_NODE, 0 },
2494     { "/smaller-than", PU_SMA,  CM_ARG },
2495     { "/verbose",      PU_VERB, CM_INV }
2496 };
2497 static int npurgtab = sizeof(purgtab)/sizeof(struct keytab);
2498
2499
2500
2501
2502
2503 int
2504 bkupnum(s,i) char * s; int *i; {
2505     int k = 0, pos = 0;
2506     char * p = NULL, *q;
2507     *i = pos;
2508     if (!s) s = "";
2509     if (!*s)
2510       return(-1);
2511     if ((k = strlen(s)) < 5)
2512       return(-1);
2513
2514     if (s[k-1] != '~')
2515       return(-1);
2516     pos = k - 2;
2517     q = s + pos;
2518     while (q >= s && isdigit(*q)) {
2519         p = q--;
2520         pos--;
2521     }
2522     if (!p)
2523       return(-1);
2524     if (q < s+2)
2525       return(-1);
2526     if (*q != '~' || *(q-1) != '.')
2527       return(-1);
2528     pos--;
2529     *i = pos;
2530     debug(F111,"bkupnum",s+pos,pos);
2531     return(atoi(p));
2532 }
2533
2534 #ifdef CKPURGE
2535 /* Presently only for UNIX because we need direct access to the file array. */
2536 /* Not needed for VMS anyway, because we don't make backup files there. */
2537
2538 #define MAXKEEP 32                      /* Biggest /KEEP: value */
2539
2540 static int
2541   pu_keep = 0, pu_list = 0, pu_dot = 0, pu_ask = 0, pu_hdg = 0;
2542
2543 #ifdef CK_TTGWSIZ
2544 static int pu_page = -1;
2545 #else
2546 static int pu_page = 0;
2547 #endif /* CK_TTGWSIZ */
2548
2549 #ifndef NOSHOW
2550 VOID
2551 showpurgopts() {                        /* SHOW PURGE command options */
2552     int x = 0;
2553     extern int optlines;
2554     prtopt(&optlines,"PURGE");
2555     if (pu_ask > -1) {
2556         x++;
2557         prtopt(&optlines, pu_ask ? "/ASK" : "/NOASK");
2558     }
2559 #ifdef UNIXOROSK
2560     if (pu_dot > -1) {
2561         x++;
2562         prtopt(&optlines, pu_dot ? "/DOTFILES" : "/NODOTFILES");
2563     }
2564 #endif /* UNIXOROSK */
2565     if (pu_keep > -1) {
2566         x++;
2567         ckmakmsg(tmpbuf,TMPBUFSIZ,"/KEEP:",ckitoa(pu_keep),NULL,NULL);
2568         prtopt(&optlines,tmpbuf);
2569     }
2570     if (pu_list > -1) {
2571         x++;
2572         prtopt(&optlines, pu_list ? "/LIST" : "/NOLIST");
2573     }
2574     if (pu_hdg > -1) {
2575         x++;
2576         prtopt(&optlines, pu_hdg ? "/HEADING" : "/NOHEADING");
2577     }
2578 #ifdef CK_TTGWSIZ
2579     if (pu_page > -1) {
2580         x++;
2581         prtopt(&optlines, pu_page ? "/PAGE" : "/NOPAGE");
2582     }
2583 #endif /* CK_TTGWSIZ */
2584     if (!x) prtopt(&optlines,"(no options set)");
2585     prtopt(&optlines,"");
2586 }
2587 #endif /* NOSHOW */
2588
2589 int
2590 setpurgopts() {                         /* Set PURGE command options */
2591     int c, z, getval = 0;
2592     int
2593       x_keep  = -1, x_list = -1, x_page = -1,
2594       x_hdg   = -1, x_ask  = -1, x_dot  = -1;
2595
2596     while (1) {
2597         if ((y = cmswi(purgtab,npurgtab,"Switch","",xxstring)) < 0) {
2598             if (y == -3)
2599               break;
2600             else
2601               return(y);
2602         }
2603         c = cmgbrk();
2604         if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
2605             printf("?This switch does not take an argument\n");
2606             return(-9);
2607         }
2608         if (!getval && (cmgkwflgs() & CM_ARG)) {
2609             printf("?This switch requires an argument\n");
2610             return(-9);
2611         }
2612         switch (y) {
2613           case PU_KEEP:
2614             z = 1;
2615             if (c == ':' || c == '=')
2616               if ((y = cmnum("How many backup files to keep",
2617                              "1",10,&z,xxstring)) < 0)
2618                 return(y);
2619             if (z < 0 || z > MAXKEEP) {
2620                 printf("?Please specify a number between 0 and %d\n",
2621                        MAXKEEP
2622                        );
2623                 return(-9);
2624             }
2625             x_keep = z;
2626             break;
2627           case PU_LIST:
2628           case PU_VERB:
2629             x_list = 1;
2630             break;
2631           case PU_QUIE:
2632           case PU_NOLI:
2633             x_list = 0;
2634             break;
2635 #ifdef CK_TTGWSIZ
2636           case PU_PAGE:
2637             x_page = 1;
2638             break;
2639           case PU_NOPA:
2640             x_page = 0;
2641             break;
2642 #endif /* CK_TTGWSIZ */
2643           case PU_HDG:
2644             x_hdg = 1;
2645             break;
2646           case PU_NOH:
2647             x_hdg = 0;
2648             break;
2649           case PU_ASK:
2650             x_ask = 1;
2651             break;
2652           case PU_NASK:
2653             x_ask = 0;
2654             break;
2655 #ifdef UNIXOROSK
2656           case PU_DOT:
2657             x_dot = 1;
2658             break;
2659           case PU_NODOT:
2660             x_dot = 0;
2661             break;
2662 #endif /* UNIXOROSK */
2663           default:
2664             printf("?This option can not be set\n");
2665             return(-9);
2666         }
2667     }
2668     if ((x = cmcfm()) < 0)              /* Get confirmation */
2669       return(x);
2670     if (x_keep > -1)                    /* Set PURGE defaults. */
2671       pu_keep = x_keep;
2672     if (x_list > -1)
2673       pu_list = x_list;
2674 #ifdef CK_TTGWSIZ
2675     if (x_page > -1)
2676       pu_page = x_page;
2677 #endif /* CK_TTGWSIZ */
2678     if (x_hdg > -1)
2679       pu_hdg = x_hdg;
2680     if (x_ask > -1)
2681       pu_ask = x_ask;
2682     if (x_dot > -1)
2683       pu_dot = x_dot;
2684     return(success = 1);
2685 }
2686
2687 int
2688 dopurge() {                             /* Do the PURGE command */
2689     extern char ** mtchs;
2690     extern int xaskmore, cmd_rows, recursive;
2691     int simulate = 0, asking = 0;
2692     int listing = 0, paging = -1, lines = 0, deleting = 1, errors = 0;
2693     struct FDB sw, sf, cm;
2694     int g, i, j, k, m = 0, n, x, y, z, done = 0, count = 0, flags = 0;
2695     int tokeep = 0, getval = 0, havename = 0, confirmed = 0;
2696     int xx[MAXKEEP+1];                  /* Array of numbers to keep */
2697     int min = -1;
2698     int x_hdg = 0, fs = 0, rc = 0;
2699     long minsize = -1L, maxsize = -1L;
2700     char namebuf[CKMAXPATH+4];
2701     char basebuf[CKMAXPATH+4];
2702     char
2703       * pu_aft = NULL,
2704       * pu_bef = NULL,
2705       * pu_naf = NULL,
2706       * pu_nbf = NULL,
2707       * pu_exc = NULL;
2708     char * pxlist[8];                   /* Exception list */
2709
2710     if (pu_keep > -1)                   /* Set PURGE defaults. */
2711       tokeep = pu_keep;
2712     if (pu_list > -1)
2713       listing = pu_list;
2714 #ifdef CK_TTGWSIZ
2715     if (pu_page > -1)
2716       paging = pu_page;
2717 #endif /* CK_TTGWSIZ */
2718
2719     for (i = 0; i <= MAXKEEP; i++)      /* Clear this number buffer */
2720       xx[i] = 0;
2721     for (i = 0; i < 8; i++)             /* Initialize these... */
2722       pxlist[i] = NULL;
2723
2724     g_matchdot = matchdot;              /* Save these... */
2725
2726     cmfdbi(&sw,                         /* 1st FDB - PURGE switches */
2727            _CMKEY,                      /* fcode */
2728            "Filename or switch",        /* hlpmsg */
2729            "",                          /* default */
2730            "",                          /* addtl string data */
2731            npurgtab,                    /* addtl numeric data 1: tbl size */
2732            4,                           /* addtl numeric data 2: 4 = cmswi */
2733            xxstring,                    /* Processing function */
2734            purgtab,                     /* Keyword table */
2735            &sf                          /* Pointer to next FDB */
2736            );
2737     cmfdbi(&sf,                         /* 2nd FDB - filespec to purge */
2738            _CMIFI,                      /* fcode */
2739            "",
2740            "",                          /* default */
2741            "",                          /* addtl string data */
2742            0,                           /* addtl numeric data 1 */
2743            0,                           /* addtl numeric data 2 */
2744            xxstring,
2745            NULL,
2746            &cm
2747            );
2748     cmfdbi(&cm,                         /* Or premature confirmation */
2749            _CMCFM,                      /* fcode */
2750            "",                          /* hlpmsg */
2751            "",                          /* default */
2752            "",                          /* addtl string data */
2753            0,                           /* addtl numeric data 1 */
2754            0,                           /* addtl numeric data 2 */
2755            NULL,
2756            NULL,
2757            NULL
2758            );
2759
2760     while (!havename && !confirmed) {
2761         x = cmfdb(&sw);                 /* Parse something */
2762         if (x < 0) {                    /* Error */
2763             rc = x;
2764             goto xpurge;
2765         } else if (cmresult.fcode == _CMKEY) {
2766             char c;
2767             c = cmgbrk();
2768             if ((getval = (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
2769                 printf("?This switch does not take an argument\n");
2770                 rc = -9;
2771                 goto xpurge;
2772             }
2773             if (!getval && (cmgkwflgs() & CM_ARG)) {
2774                 printf("?This switch requires an argument\n");
2775                 rc = -9;
2776                 goto xpurge;
2777             }
2778             switch (k = cmresult.nresult) {
2779               case PU_KEEP:
2780                 z = 1;
2781                 if (c == ':' || c == '=') {
2782                     if ((y = cmnum("How many backup files to keep",
2783                                    "1",10,&z,xxstring)) < 0) {
2784                         rc = y;
2785                         goto xpurge;
2786                     }
2787                 }
2788                 if (z < 0 || z > MAXKEEP) {
2789                     printf("?Please specify a number between 0 and %d\n",
2790                            MAXKEEP
2791                            );
2792                     rc = -9;
2793                     goto xpurge;
2794                 }
2795                 tokeep = z;
2796                 break;
2797               case PU_LIST:
2798                 listing = 1;
2799                 break;
2800               case PU_NOLI:
2801                 listing = 0;
2802                 break;
2803 #ifdef CK_TTGWSIZ
2804               case PU_PAGE:
2805                 paging = 1;
2806                 break;
2807               case PU_NOPA:
2808                 paging = 0;
2809                 break;
2810 #endif /* CK_TTGWSIZ */
2811               case PU_DELE:
2812                 deleting = 1;
2813                 break;
2814               case PU_NODE:
2815                 deleting = 0;
2816                 simulate = 1;
2817                 listing = 1;
2818                 break;
2819               case PU_ASK:
2820                 asking = 1;
2821                 break;
2822               case PU_NASK:
2823                 asking = 0;
2824                 break;
2825               case PU_AFT:
2826               case PU_BEF:
2827               case PU_NAF:
2828               case PU_NBF:
2829                 if ((x = cmdate("File-time","",&s,0,xxstring)) < 0) {
2830                     if (x == -3) {
2831                         printf("?Date-time required\n");
2832                         rc = -9;
2833                     } else
2834                       rc = x;
2835                     goto xpurge;
2836                 }
2837                 fs++;
2838                 switch (k) {
2839                   case PU_AFT: makestr(&pu_aft,s); break;
2840                   case PU_BEF: makestr(&pu_bef,s); break;
2841                   case PU_NAF: makestr(&pu_naf,s); break;
2842                   case PU_NBF: makestr(&pu_nbf,s); break;
2843                 }
2844                 break;
2845               case PU_SMA:
2846               case PU_LAR:
2847                 if ((x = cmnum("File size in bytes","0",10,&y,xxstring)) < 0) {
2848                     rc = x;
2849                     goto xpurge;
2850                 }
2851                 fs++;
2852                 switch (cmresult.nresult) {
2853                   case PU_SMA: minsize = y; break;
2854                   case PU_LAR: maxsize = y; break;
2855                 }
2856                 break;
2857               case PU_DOT:
2858                 matchdot = 1;
2859                 break;
2860               case PU_NODOT:
2861                 matchdot = 0;
2862                 break;
2863               case PU_EXC:
2864                 if ((x = cmfld("Pattern","",&s,xxstring)) < 0) {
2865                     if (x == -3) {
2866                         printf("?Pattern required\n");
2867                         rc = -9;
2868                     } else
2869                       rc = x;
2870                     goto xpurge;
2871                 }
2872                 fs++;
2873                 makestr(&pu_exc,s);
2874                 break;
2875               case PU_HDG:
2876                 x_hdg = 1;
2877                 break;
2878 #ifdef RECURSIVE
2879               case PU_RECU:             /* /RECURSIVE */
2880                 recursive = 2;
2881                 break;
2882 #endif /* RECURSIVE */
2883               default:
2884                 printf("?Not implemented yet - \"%s\"\n",atmbuf);
2885                 rc = -9;
2886                 goto xpurge;
2887             }
2888         } else if (cmresult.fcode == _CMIFI) {
2889             havename = 1;
2890         } else if (cmresult.fcode == _CMCFM) {
2891             confirmed = 1;
2892         } else {
2893             rc = -2;
2894             goto xpurge;
2895         }
2896     }
2897     if (havename) {
2898 #ifdef CKREGEX
2899         ckmakmsg(line,LINBUFSIZ,cmresult.sresult,".~[1-9]*~",NULL,NULL);
2900 #else
2901         ckmakmsg(line,LINBUFSIZ,cmresult.sresult,".~*~",NULL,NULL);
2902 #endif /* CKREGEX */
2903     } else {
2904 #ifdef CKREGEX
2905         ckstrncpy(line,"*.~[1-9]*~",LINBUFSIZ);
2906 #else
2907         ckstrncpy(line,"*.~*~",LINBUFSIZ);
2908 #endif /* CKREGEX */
2909     }
2910     if (!confirmed) {
2911         if ((x = cmcfm()) < 0) {
2912             rc = x;
2913             goto xpurge;
2914         }
2915     }
2916     /* Parse finished - now action */
2917
2918 #ifdef CK_LOGIN
2919     if (isguest) {
2920         printf("?File deletion by guests not permitted.\n");
2921         rc = -9;
2922         goto xpurge;
2923     }
2924 #endif /* CK_LOGIN */
2925
2926 #ifdef CK_TTGWSIZ
2927     if (paging < 0)                     /* /[NO]PAGE not given */
2928       paging = xaskmore;                /* so use prevailing */
2929 #endif /* CK_TTGWSIZ */
2930
2931     lines = 0;
2932     if (x_hdg > 0) {
2933         printf("Purging %s, keeping %d...%s\n",
2934                s,
2935                tokeep,
2936                simulate ? " (SIMULATION)" : "");
2937         lines += 2;
2938     }
2939     flags = ZX_FILONLY;
2940     if (recursive) flags |= ZX_RECURSE;
2941     n = nzxpand(line,flags);            /* Get list of backup files */
2942     if (tokeep < 1) {                   /* Deleting all of them... */
2943         for (i = 0; i < n; i++) {
2944             if (fs) if (fileselect(mtchs[i],
2945                                    pu_aft,pu_bef,pu_naf,pu_nbf,
2946                                    minsize,maxsize,0,8,pxlist) < 1) {
2947                 if (listing > 0) {
2948                     printf(" %s (SKIPPED)\n",mtchs[i]);
2949 #ifdef CK_TTGWSIZ
2950                     if (paging)
2951                       if (++lines > cmd_rows - 3) {
2952                           if (!askmore()) goto xpurge; else lines = 0;
2953                       }
2954 #endif /* CK_TTGWSIZ */
2955                 }
2956                 continue;
2957             }
2958             if (asking) {
2959                 int x;
2960                 ckmakmsg(tmpbuf,TMPBUFSIZ," Delete ",mtchs[i],"?",NULL);
2961                 x = getyesno(tmpbuf,1);
2962                 switch (x) {
2963                   case 0: continue;
2964                   case 1: break;
2965                   case 2: goto xpurge;
2966                 }
2967             }
2968             x = deleting ? zdelet(mtchs[i]) : 0;
2969             if (x > -1) {
2970                 if (listing)
2971                   printf(" %s (%s)\n", mtchs[i],deleting ? "OK" : "SELECTED");
2972                 count++;
2973             } else {
2974                 errors++;
2975                 if (listing)
2976                   printf(" %s (FAILED)\n", mtchs[i]);
2977             }
2978 #ifdef CK_TTGWSIZ
2979             if (listing && paging)
2980               if (++lines > cmd_rows - 3) {
2981                   if (!askmore()) goto xpurge; else lines = 0;
2982               }
2983 #endif /* CK_TTGWSIZ */
2984         }
2985         goto xpurge;
2986     }
2987     if (n < tokeep) {                   /* Not deleting any */
2988         count = 0;
2989         if (listing)
2990           printf(" Matches = %d: Not enough to purge.\n");
2991         goto xpurge;
2992     }
2993
2994     /* General case - delete some but not others */
2995
2996     sh_sort(mtchs,NULL,n,0,0,filecase); /* Alphabetize the list (ESSENTIAL) */
2997
2998     g = 0;                              /* Start of current group */
2999     for (i = 0; i < n; i++) {           /* Go thru sorted file list */
3000         x = znext(namebuf);             /* Get next file */
3001         if (x < 1 || !namebuf[0] || i == n - 1) /* No more? */
3002           done = 1;                     /* NOTE: 'done' must be 0 or 1 only */
3003         if (fs) if (fileselect(namebuf,
3004                                pu_aft,pu_bef,pu_naf,pu_nbf,
3005                                minsize,maxsize,0,8,pxlist) < 1) {
3006             if (listing > 0) {
3007                 printf(" %s (SKIPPED)\n",namebuf);
3008                 if (++lines > cmd_rows - 3)
3009                   if (!askmore()) goto xpurge; else lines = 0;
3010             }
3011             continue;
3012         }
3013         if (x > 0)
3014           if ((m = bkupnum(namebuf,&z)) < 0) /* This file's backup number. */
3015             continue;
3016         for (j = 0; j < tokeep; j++) {  /* Insert in list. */
3017             if (m > xx[j]) {
3018                 for (k = tokeep - 1; k > j; k--)
3019                   xx[k] = xx[k-1];
3020                 xx[j] = m;
3021                 break;
3022             }
3023         }
3024         /* New group? */
3025         if (done || (i > 0 && ckstrcmp(namebuf,basebuf,z,1))) {
3026             if (i + done - g > tokeep) { /* Do we have enough to purge? */
3027                 min = xx[tokeep-1];     /* Yes, lowest backup number to keep */
3028                 debug(F111,"dopurge group",basebuf,min);
3029                 for (j = g; j < i + done; j++) { /* Go through this group */
3030                     x = bkupnum(mtchs[j],&z);    /* Get file backup number */
3031                     if (x > 0 && x < min) {      /* Below minimum? */
3032                         x = deleting ? zdelet(mtchs[j]) : 0;
3033                         if (x < 0) errors++;
3034                         if (listing)
3035                           printf(" %s (%s)\n",
3036                                  mtchs[j],
3037                                  ((x < 0) ? "ERROR" :
3038                                   (deleting ? "DELETED" : "SELECTED"))
3039                                  );
3040                         count++;
3041                     } else if (listing) /* Not below minimum - keep this one */
3042                       printf(" %s (KEPT)\n",mtchs[j]);
3043 #ifdef CK_TTGWSIZ
3044                     if (listing && paging)
3045                       if (++lines > cmd_rows - 3) {
3046                           if (!askmore()) goto xpurge; else lines = 0;
3047                       }
3048 #endif /* CK_TTGWSIZ */
3049                 }
3050             } else if (listing && paging) { /* Not enough to purge */
3051                 printf(" %s.~*~ (KEPT)\n",basebuf);
3052 #ifdef CK_TTGWSIZ
3053                 if (++lines > cmd_rows - 3) {
3054                     if (!askmore()) goto xpurge; else lines = 0;
3055                 }
3056 #endif /* CK_TTGWSIZ */
3057             }
3058             for (j = 0; j < tokeep; j++) /* Clear the backup number list */
3059               xx[j] = 0;
3060             g = i;                      /* Reset the group pointer */
3061         }
3062         if (done)                       /* No more files, done. */
3063           break;
3064         strncpy(basebuf,namebuf,z);     /* Set basename of this file */
3065         basebuf[z] = NUL;
3066     }
3067   xpurge:                               /* Common exit point */
3068     if (g_matchdot > -1) {
3069         matchdot = g_matchdot;          /* Restore these... */
3070         g_matchdot = -1;
3071     }
3072     if (rc < 0) return(rc);             /* Parse error */
3073     if (x_hdg)
3074       printf("Files purged: %d%s\n",
3075              count,
3076              deleting ? "" : " (not really)"
3077              );
3078     return(success = count > 0 ? 1 : (errors > 0) ? 0 : 1);
3079 }
3080 #endif /* CKPURGE */
3081
3082 #ifndef NOXFER
3083 #ifndef NOLOCAL
3084 int
3085 doxdis(which) int which; {              /* 1 = Kermit, 2 = FTP */
3086     extern int nolocal;
3087     int x, y = 0, z;
3088 #ifdef NEWFTP
3089     extern int ftp_dis;
3090 #endif /* NEWFTP */
3091
3092 #ifdef COMMENT
3093     char *s;
3094 #endif /* COMMENT */
3095
3096     if ((x = cmkey(fdtab,nfdtab,"file transfer display style","",
3097                    xxstring)) < 0)
3098       return(x);
3099 #ifdef CK_PCT_BAR
3100     if ((y = cmkey(fdftab,2,"","thermometer",xxstring)) < 0)
3101       return(y);
3102 #endif /* CK_PCT_BAR */
3103     if ((z = cmcfm()) < 0) return(z);
3104 #ifdef CK_CURSES
3105     if (x == XYFD_C) {                  /* FULLSCREEN */
3106 #ifdef COMMENT
3107 #ifndef MYCURSES
3108         extern char * trmbuf;           /* Real curses */
3109         int z;
3110 #endif /* MYCURSES */
3111 #endif /* COMMENT */
3112
3113         if (nolocal)                    /* Nothing to do in this case */
3114           return(success = 1);
3115
3116 #ifdef COMMENT
3117 #ifndef MYCURSES
3118 #ifndef VMS
3119         s = getenv("TERM");
3120         debug(F110,"doxdis TERM",s,0);
3121         if (!s) s = "";
3122         fxdinit(x);
3123         if (*s && trmbuf) {             /* Don't call tgetent */
3124             z = tgetent(trmbuf,s);      /* if trmbuf not allocated */
3125             debug(F111,"doxdis tgetent",s,z);
3126         } else {
3127             z = 0;
3128             debug(F110,"doxdis tgetent skipped",s,0);
3129         }
3130         if (z < 1) {
3131             printf("Sorry, terminal type unknown: \"%s\"\n",s);
3132             return(success = 0);
3133         }
3134 #endif /* VMS */
3135 #endif /* MYCURSES */
3136 #else
3137         fxdinit(x);
3138 #endif /* COMMENT */
3139
3140 #ifdef CK_PCT_BAR
3141         thermometer = y;
3142 #endif /* CK_PCT_BAR */
3143
3144         line[0] = '\0';                 /* (What's this for?) */
3145     }
3146 #endif /* CK_CURSES */
3147     if (which == 1)                     /* It's OK. */
3148       fdispla = x;
3149 #ifdef NEWFTP
3150     else
3151       ftp_dis = x;
3152 #endif /* NEWFTP */
3153     return(success = 1);
3154 }
3155 #endif /* NOLOCAL */
3156 #endif /* NOXFER */
3157
3158 int
3159 setfil(rmsflg) int rmsflg; {
3160 #ifdef COMMENT
3161     extern int en_del;
3162 #endif /* COMMENT */
3163 #ifndef NOXFER
3164     if (rmsflg) {
3165         if ((y = cmkey(rfiltab,nrfilp,"Remote file parameter","",
3166                        xxstring)) < 0) {
3167             if (y == -3) {
3168                 printf("?Remote file parameter required\n");
3169                 return(-9);
3170             } else return(y);
3171         }
3172     } else {
3173 #endif /* NOXFER */
3174         if ((y = cmkey(filtab,nfilp,"File parameter","",xxstring)) < 0)
3175           return(y);
3176 #ifndef NOXFER
3177     }
3178 #endif /* NOXFER */
3179     switch (y) {
3180 #ifdef COMMENT                          /* Not needed */
3181       case XYFILB:                      /* Blocksize */
3182         if ((y = cmnum("file block size",ckitoa(DBLKSIZ),10,&z,xxstring)) < 0)
3183           return(y);
3184         if ((x = cmcfm()) < 0) return(x);
3185         if (rmsflg) {
3186             sstate = setgen('S', "311", ckitoa(z), "");
3187             return((int) sstate);
3188         } else {
3189             fblksiz = z;
3190             return(success = 1);
3191         }
3192 #endif /* COMMENT */
3193
3194 #ifndef NOXFER
3195       case XYFILS:                      /* Byte size */
3196         if ((y = cmnum("file byte size (7 or 8)","8",10,&z,xxstring)) < 0)
3197           return(y);
3198         if (z != 7 && z != 8) {
3199             printf("\n?The choices are 7 and 8\n");
3200             return(0);
3201         }
3202         if ((y = cmcfm()) < 0) return(y);
3203         if (z == 7) fmask = 0177;
3204         else if (z == 8) fmask = 0377;
3205         return(success = 1);
3206
3207 #ifndef NOCSETS
3208       case XYFILC: {                    /* Character set */
3209           char * csetname = NULL;
3210           extern int
3211             r_cset, s_cset, afcset[];   /* SEND CHARACTER-SET AUTO or MANUAL */
3212
3213           struct FDB kw, fl;
3214           cmfdbi(&kw,                   /* First FDB - command switches */
3215                  _CMKEY,                /* fcode */
3216                  rmsflg ? "server character-set name" : "",  /* help */
3217                  "",                    /* default */
3218                  "",                    /* addtl string data */
3219                  nfilc,                 /* addtl numeric data 1: tbl size */
3220                  0,                     /* addtl numeric data 2: 0 = keyword */
3221                  xxstring,              /* Processing function */
3222                  fcstab,                /* Keyword table */
3223                  rmsflg ? &fl : NULL    /* Pointer to next FDB */
3224            );
3225           cmfdbi(&fl,                   /* Anything that doesn't match */
3226                  _CMFLD,                /* fcode */
3227                  "",                    /* hlpmsg */
3228                  "",                    /* default */
3229                  "",                    /* addtl string data */
3230                  0,                     /* addtl numeric data 1 */
3231                  0,                     /* addtl numeric data 2 */
3232                  xxstring,
3233                  NULL,
3234                  NULL
3235                  );
3236           if ((x = cmfdb(&kw)) < 0)
3237             return(x);
3238           if (cmresult.fcode == _CMKEY) {
3239               x = cmresult.nresult;
3240               csetname = fcsinfo[x].keyword;
3241           } else {
3242               ckstrncpy(line,cmresult.sresult,LINBUFSIZ);
3243               csetname = line;
3244           }
3245           if ((z = cmcfm()) < 0) return(z);
3246           if (rmsflg) {
3247               sstate = setgen('S', "320", csetname, "");
3248               return((int) sstate);
3249           }
3250           fcharset = x;
3251           if (s_cset == XMODE_A)        /* If SEND CHARACTER-SET is AUTO */
3252             if (x > -1 && x <= MAXFCSETS)
3253               if (afcset[x] > -1 && afcset[x] <= MAXTCSETS)
3254                 tcharset = afcset[x]; /* Pick corresponding xfer charset */
3255           setxlatype(tcharset,fcharset); /* Translation type */
3256           /* If I say SET FILE CHARACTER-SET blah, I want to be blah! */
3257           r_cset = XMODE_M;             /* Don't switch incoming set! */
3258           x = fcsinfo[fcharset].size;   /* Also set default x-bit charset */
3259           if (x == 128)                 /* 7-bit... */
3260             dcset7 = fcharset;
3261           else if (x == 256)            /* 8-bit... */
3262             dcset8 = fcharset;
3263           return(success = 1);
3264       }
3265 #endif /* NOCSETS */
3266
3267 #ifndef NOLOCAL
3268       case XYFILD:                      /* Display */
3269         return(doxdis(1));              /* 1 == kermit */
3270 #endif /* NOLOCAL */
3271 #endif /* NOXFER */
3272
3273       case XYFILA:                      /* End-of-line */
3274 #ifdef NLCHAR
3275         s = "";
3276         if (NLCHAR == 015)
3277           s = "cr";
3278         else if (NLCHAR == 012)
3279           s = "lf";
3280         if ((x = cmkey(eoltab, neoltab,
3281                        "local text-file line terminator",s,xxstring)) < 0)
3282           return(x);
3283 #else
3284         if ((x = cmkey(eoltab, neoltab,
3285                        "local text-file line terminator","crlf",xxstring)) < 0)
3286           return(x);
3287 #endif /* NLCHAR */
3288         if ((z = cmcfm()) < 0) return(z);
3289         feol = (CHAR) x;
3290         return(success = 1);
3291
3292 #ifndef NOXFER
3293       case XYFILN:                      /* Names */
3294         if ((x = cmkey(fntab,nfntab,"how to handle filenames","converted",
3295                        xxstring)) < 0)
3296           return(x);
3297         if ((z = cmcfm()) < 0) return(z);
3298         if (rmsflg) {
3299             sstate = setgen('S', "301", ckitoa(1 - x), "");
3300             return((int) sstate);
3301         } else {
3302             ptab[protocol].fncn = x;    /* Set structure */
3303             fncnv = x;                  /* Set variable */
3304             f_save = x;                 /* And set "permanent" variable */
3305             return(success = 1);
3306         }
3307
3308       case XYFILR:                      /* Record length */
3309         if ((y = cmnum("file record length",
3310                        ckitoa(DLRECL),10,&z,xxstring)) < 0)
3311           return(y);
3312         if ((x = cmcfm()) < 0) return(x);
3313         if (rmsflg) {
3314             sstate = setgen('S', "312", ckitoa(z), "");
3315             return((int) sstate);
3316         } else {
3317             frecl = z;
3318             return(success = 1);
3319         }
3320
3321 #ifdef COMMENT
3322       case XYFILO:                      /* Organization */
3323         if ((x = cmkey(forgtab,nforg,"file organization","sequential",
3324                        xxstring)) < 0)
3325           return(x);
3326         if ((y = cmcfm()) < 0) return(y);
3327         if (rmsflg) {
3328             sstate = setgen('S', "314", ckitoa(x), "");
3329             return((int) sstate);
3330         } else {
3331             forg = x;
3332             return(success = 1);
3333         }
3334 #endif /* COMMENT */
3335
3336 #ifdef COMMENT                          /* Not needed */
3337       case XYFILF:                      /* Format */
3338         if ((x = cmkey(frectab,nfrec,"file record format","stream",
3339                        xxstring)) < 0)
3340           return(x);
3341         if ((y = cmcfm()) < 0) return(y);
3342         if (rmsflg) {
3343             sstate = setgen('S', "313", ckitoa(x), "");
3344             return((int) sstate);
3345         } else {
3346             frecfm = x;
3347             return(success = 1);
3348         }
3349 #endif /* COMMENT */
3350
3351 #ifdef COMMENT
3352       case XYFILP:                      /* Printer carriage control */
3353         if ((x = cmkey(fcctab,nfcc,"file carriage control","newline",
3354                        xxstring)) < 0)
3355           return(x);
3356         if ((y = cmcfm()) < 0) return(y);
3357         if (rmsflg) {
3358             sstate = setgen('S', "315", ckitoa(x), "");
3359             return((int) sstate);
3360         } else {
3361             fcctrl = x;
3362             return(success = 1);
3363         }
3364 #endif /* COMMENT */
3365 #endif /* NOXFER */
3366
3367       case XYFILT:                      /* Type */
3368         if ((x = cmkey(rmsflg ? rfttab  : fttab,
3369                        rmsflg ? nrfttyp : nfttyp,
3370                        "type of file transfer","text",xxstring)) < 0)
3371           return(x);
3372
3373 #ifdef VMS
3374         /* Allow VMS users to choose record format for binary files */
3375         if ((x == XYFT_B) && (rmsflg == 0)) {
3376             if ((x = cmkey(fbtab,nfbtyp,"VMS record format","fixed",
3377                            xxstring)) < 0)
3378               return(x);
3379         }
3380 #endif /* VMS */
3381         if ((y = cmcfm()) < 0) return(y);
3382         binary = x;
3383         b_save = x;
3384 #ifdef MAC
3385         (void) mac_setfildflg(binary);
3386 #endif /* MAC */
3387 #ifndef NOXFER
3388         if (rmsflg) {
3389             /* Allow for LABELED in VMS & OS/2 */
3390             sstate = setgen('S', "300", ckitoa(x), "");
3391             return((int) sstate);
3392         } else {
3393 #endif /* NOXFER */
3394             return(success = 1);
3395 #ifndef NOXFER
3396         }
3397 #endif /* NOXFER */
3398
3399 #ifndef NOXFER
3400       case XYFILX:                      /* Collision Action */
3401         if ((x = cmkey(colxtab,ncolx,"Filename collision action","backup",
3402                        xxstring)) < 0)
3403           return(x);
3404         if ((y = cmcfm()) < 0) return(y);
3405 #ifdef CK_LOGIN
3406         if (isguest) {
3407             /* Don't let guests change existing files */
3408             printf("?This command not valid for guests\n");
3409             return(-9);
3410         }
3411 #endif /* CK_LOGIN */
3412 #ifdef COMMENT
3413         /* Not appropriate - DISABLE DELETE only refers to server */
3414         if ((x == XYFX_X || x == XYFX_B || x == XYFX_U || x == XYFX_A) &&
3415             (!ENABLED(en_del))) {
3416             printf("?Sorry, file deletion is disabled.\n");
3417             return(-9);
3418         }
3419 #endif /* COMMENT */
3420         fncact = x;
3421         ptab[protocol].fnca = x;
3422         if (rmsflg) {
3423             sstate = setgen('S', "302", ckitoa(fncact), "");
3424             return((int) sstate);
3425         } else {
3426             if (fncact == XYFX_R) ckwarn = 1; /* FILE WARNING implications */
3427             if (fncact == XYFX_X) ckwarn = 0; /* ... */
3428             return(success = 1);
3429         }
3430
3431       case XYFILW:                      /* Warning/Write-Protect */
3432         if ((x = seton(&ckwarn)) < 0) return(x);
3433         if (ckwarn)
3434           fncact = XYFX_R;
3435         else
3436           fncact = XYFX_X;
3437         return(success = 1);
3438
3439 #ifdef CK_LABELED
3440       case XYFILL:                      /* LABELED FILE parameters */
3441         if ((x = cmkey(lbltab,nlblp,"Labeled file feature","",
3442                        xxstring)) < 0)
3443           return(x);
3444         if ((success = seton(&y)) < 0)
3445           return(success);
3446         if (y)                          /* Set or reset the selected bit */
3447           lf_opts |= x;                 /* in the options bitmask. */
3448         else
3449           lf_opts &= ~x;
3450         return(success);
3451 #endif /* CK_LABELED */
3452
3453       case XYFILI: {                    /* INCOMPLETE */
3454           extern struct keytab ifdatab[];
3455           extern int keep;
3456           if ((y = cmkey(ifdatab,3,"","auto",xxstring)) < 0) return(y);
3457           if ((x = cmcfm()) < 0) return(x);
3458           if (rmsflg) {
3459               sstate = setgen('S',
3460                               "310",
3461                               y == 0 ? "0" : (y == 1 ? "1" : "2"),
3462                               ""
3463                               );
3464               return((int) sstate);
3465           } else {
3466               keep = y;
3467               return(success = 1);
3468           }
3469       }
3470
3471 #ifdef CK_TMPDIR
3472       case XYFILG: {                    /* Download directory */
3473           int x;
3474           char *s;
3475 #ifdef ZFNQFP
3476           struct zfnfp * fnp;
3477 #endif /* ZFNQFP */
3478 #ifdef MAC
3479           char temp[34];
3480 #endif /* MAC */
3481
3482 #ifdef GEMDOS
3483           if ((x = cmdir("Name of local directory, or carriage return",
3484                          "",&s,
3485                          NULL)) < 0 ) {
3486               if (x != -3)
3487                 return(x);
3488           }
3489 #else
3490 #ifdef OS2
3491           if ((x = cmdir("Name of PC disk and/or directory,\n\
3492        or press the Enter key to use current directory",
3493                          "",&s,xxstring)) < 0 ) {
3494               if (x != -3)
3495                 return(x);
3496           }
3497 #else
3498 #ifdef MAC
3499           x = ckstrncpy(temp,zhome(),32);
3500           if (x > 0) if (temp[x-1] != ':') { temp[x] = ':'; temp[x+1] = NUL; }
3501           if ((x = cmtxt("Name of Macintosh volume and/or folder,\n\
3502  or press the Return key for the desktop on the boot disk",
3503                          temp,&s, xxstring)) < 0 )
3504             return(x);
3505 #else
3506           if ((x = cmdir("Name of local directory, or carriage return",
3507                          "", &s, xxstring)) < 0 ) {
3508               if (x != -3)
3509                 return(x);
3510           }
3511 #endif /* MAC */
3512 #endif /* OS2 */
3513 #endif /* GEMDOS */
3514           debug(F110,"download dir",s,0);
3515
3516 #ifndef MAC
3517           if (x == 2) {
3518               printf("?Wildcards not allowed in directory name\n");
3519               return(-9);
3520           }
3521 #endif /* MAC */
3522
3523 #ifdef ZFNQFP
3524           if ((fnp = zfnqfp(s,TMPBUFSIZ - 1,tmpbuf))) {
3525               if (fnp->fpath)
3526                 if ((int) strlen(fnp->fpath) > 0)
3527                   s = fnp->fpath;
3528           }
3529           debug(F110,"download zfnqfp",s,0);
3530 #endif /* ZFNQFP */
3531
3532           ckstrncpy(line,s,LINBUFSIZ);  /* Make a safe copy */
3533 #ifndef MAC
3534           if ((x = cmcfm()) < 0)        /* Get confirmation */
3535             return(x);
3536 #endif /* MAC */
3537
3538 #ifdef CK_LOGIN
3539         if (isguest) {
3540             /* Don't let guests change existing files */
3541             printf("?This command not valid for guests\n");
3542             return(-9);
3543         }
3544 #endif /* CK_LOGIN */
3545           x = strlen(s);
3546
3547           if (x) {
3548 #ifdef datageneral                      /* AOS/VS */
3549               if (s[x-1] == ':')        /* homdir ends in colon, */
3550                 s[x-1] = NUL;           /* and "dir" doesn't like that... */
3551 #else
3552 #ifdef OS2ORUNIX                        /* Unix or K-95... */
3553               if ((x < (LINBUFSIZ - 2)) && /* Add trailing dirsep */
3554                   (s[x-1] != '/')) {    /* if none present.  */
3555                   s[x] = '/';           /* Note that Windows path has */
3556                   s[x+1] = NUL;         /* been canonicalized to forward */
3557               }                         /* slashes at this point. */
3558 #endif /* OS2ORUNIX */
3559 #endif /* datageneral */
3560               makestr(&dldir,s);
3561           } else
3562             makestr(&dldir,NULL);       /* dldir is NULL when not assigned */
3563
3564           return(success = 1);
3565       }
3566 #endif /* CK_TMPDIR */
3567       case XYFILY:
3568         return(setdest());
3569 #endif /* NOXFER */
3570
3571 #ifdef CK_CTRLZ
3572       case XYFILV: {                    /* EOF */
3573           extern int eofmethod;
3574           if ((x = cmkey(eoftab,3,"end-of-file detection method","",
3575                          xxstring)) < 0)
3576             return(x);
3577           if ((y = cmcfm()) < 0)
3578             return(y);
3579           eofmethod = x;
3580           return(success = 1);
3581       }
3582 #endif /* CK_CTRLZ */
3583
3584 #ifndef NOXFER
3585 #ifdef UNIX
3586       case XYFILH: {                    /* OUTPUT */
3587           extern int zofbuffer, zobufsize, zofblock;
3588 #ifdef DYNAMIC
3589           extern char * zoutbuffer;
3590 #endif /* DYNAMIC */
3591
3592           if ((x = cmkey(zoftab,nzoftab,"output file writing method","",
3593                          xxstring)) < 0)
3594             return(x);
3595           if (x == ZOF_BUF || x == ZOF_NBUF) {
3596               if ((y = cmnum("output buffer size","32768",10,&z,xxstring)) < 0)
3597                 return(y);
3598               if (z < 1) {
3599                   printf("?Bad size - %d\n", z);
3600                   return(-9);
3601               }
3602           }
3603           if ((y = cmcfm()) < 0) return(y);
3604           switch (x) {
3605             case ZOF_BUF:
3606             case ZOF_NBUF:
3607               zofbuffer = (x == ZOF_BUF);
3608               zobufsize = z;
3609               break;
3610             case ZOF_BLK:
3611             case ZOF_NBLK:
3612               zofblock = (x == ZOF_BLK);
3613               break;
3614           }
3615 #ifdef DYNAMIC
3616           if (zoutbuffer) free(zoutbuffer);
3617           if (!(zoutbuffer = (char *)malloc(z))) {
3618               printf("MEMORY ALLOCATION ERROR - FATAL\n");
3619               doexit(BAD_EXIT,-1);
3620           } else
3621             zobufsize = z;
3622 #else
3623           if (z <= OBUFSIZE) {
3624               zobufsize = z;
3625           } else {
3626               printf("?Sorry, %d is too big - %d is the maximum\n",z,OBUFSIZE);
3627               return(-9);
3628           }
3629 #endif /* DYNAMIC */
3630           return(success = 1);
3631       }
3632 #endif /* UNIX */
3633
3634 #ifdef PATTERNS
3635       case XYFIBP:                      /* BINARY-PATTERN */
3636       case XYFITP: {                    /* TEXT-PATTERN */
3637           char * tmp[FTPATTERNS];
3638           int i, n = 0;
3639           while (n < FTPATTERNS) {
3640               tmp[n] = NULL;
3641               if ((x = cmfld("Pattern","",&s,xxstring)) < 0)
3642                 break;
3643               ckstrncpy(line,s,LINBUFSIZ);
3644               s = brstrip(line);
3645               makestr(&(tmp[n++]),s);
3646           }
3647           if (x == -3) x = cmcfm();
3648           for (i = 0; i <= n; i++) {
3649               if (x > -1) {
3650                   if (y == XYFIBP)
3651                     makestr(&(binpatterns[i]),tmp[i]);
3652                   else
3653                     makestr(&(txtpatterns[i]),tmp[i]);
3654               }
3655               free(tmp[i]);
3656           }
3657           if (y == XYFIBP)              /* Null-terminate the list */
3658             makestr(&(binpatterns[i]),NULL);
3659           else
3660             makestr(&(txtpatterns[i]),NULL);
3661           return(x);
3662       }
3663
3664       case XYFIPA:                      /* PATTERNS */
3665         if ((x = setonaut(&patterns)) < 0)
3666           return(x);
3667         return(success = 1);
3668 #endif /* PATTERNS */
3669 #endif /* NOXFER */
3670
3671 #ifdef UNICODE
3672       case XYFILU: {                    /* UCS */
3673           extern int ucsorder, ucsbom, byteorder;
3674           if ((x = cmkey(ucstab,nucstab,"","",xxstring)) < 0)
3675             return(x);
3676           switch (x) {
3677             case UCS_BYT:
3678               if ((y = cmkey(botab,nbotab,
3679                              "Byte order",
3680                              byteorder ? "little-endian" : "big-endian",
3681                              xxstring
3682                              )
3683                    ) < 0)
3684                 return(y);
3685               if ((x = cmcfm()) < 0)
3686                 return(x);
3687               ucsorder = y;
3688               return(success = 1);
3689             case UCS_BOM:
3690               if ((y = cmkey(onoff,2,"","on",xxstring)) < 0)
3691                 return(y);
3692               if ((x = cmcfm()) < 0)
3693                 return(x);
3694               ucsbom = y;
3695               return(success = 1);
3696             default:
3697               return(-2);
3698           }
3699       }
3700 #endif /* UNICODE */
3701
3702 #ifndef datageneral
3703       case XYF_INSP: {                  /* SCAN (INSPECTION) */
3704           extern int filepeek, nscanfile;
3705           if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
3706             return(x);
3707           if (y) {
3708               if ((y = cmnum("How much to scan",ckitoa(SCANFILEBUF),
3709                              10,&z,xxstring)) < 0)
3710                 return(y);
3711           }
3712           if ((y = cmcfm()) < 0)
3713             return(y);
3714 #ifdef VMS
3715           filepeek = 0;
3716           nscanfile = 0;
3717           return(success = 0);
3718 #else
3719           filepeek = x;
3720           nscanfile = z;
3721           return(success = 1);
3722 #endif /* VMS */
3723       }
3724 #endif /* datageneral */
3725
3726       case XYF_DFLT:
3727         y = 0;
3728 #ifndef NOCSETS
3729         if ((y = cmkey(fdfltab,nfdflt,"","",xxstring)) < 0)
3730           return(y);
3731         if (y == 7 || y == 8) {
3732             if (y == 7)
3733               s = fcsinfo[dcset7].keyword;
3734             else
3735               s = fcsinfo[dcset8].keyword;
3736             if ((x = cmkey(fcstab,nfilc,"character-set",s,xxstring)) < 0)
3737               return(x);
3738         }
3739         ckstrncpy(line,fcsinfo[x].keyword,LINBUFSIZ);
3740         s = line;
3741 #endif /* NOCSETS */
3742         if ((z = cmcfm()) < 0)
3743           return(z);
3744         switch (y) {
3745 #ifndef NOCSETS
3746           case 7:
3747             if (fcsinfo[x].size != 128) {
3748                 printf("%s - Not a 7-bit set\n",s);
3749                 return(-9);
3750             }
3751             dcset7 = x;
3752             break;
3753           case 8:
3754             if (fcsinfo[x].size != 256) {
3755                 printf("%s - Not an 8-bit set\n",s);
3756                 return(-9);
3757             }
3758             dcset8 = x;
3759             break;
3760 #endif /* NOCSETS */
3761           default:
3762             return(-2);
3763         }
3764         return(success = 1);
3765
3766 #ifndef NOXFER
3767       case 9997:                        /* FASTLOOKUPS */
3768         return(success = seton(&stathack));
3769 #endif /* NOXFER */
3770
3771 #ifdef UNIX
3772 #ifdef DYNAMIC
3773       case XYF_LSIZ: {                  /* LISTSIZE */
3774           int zz;
3775           y = cmnum("Maximum number of filenames","",10,&x,xxstring);
3776           if ((x = setnum(&zz,x,y,-1)) < 0)
3777             return(x);
3778           if (zsetfil(zz,3) < 0) {
3779               printf("?Memory allocation failure\n");
3780               return(-9);
3781           }
3782           return(success = 1);
3783       }
3784       case XYF_SSPA: {                  /* STRINGSPACE */
3785           int zz;
3786           y = cmnum("Number of characters for filename list",
3787                     "",10,&x,xxstring);
3788           if ((x = setnum(&zz,x,y,-1)) < 0)
3789             return(x);
3790           if (zsetfil(zz,1) < 0) {
3791               printf("?Memory allocation failure\n");
3792               return(-9);
3793           }
3794           return(success = 1);
3795       }
3796
3797 #endif /* DYNAMIC */
3798 #endif /* UNIX */
3799
3800       default:
3801         printf("?unexpected file parameter\n");
3802         return(-2);
3803     }
3804 }
3805
3806 #ifndef NOLOCAL
3807 #ifdef OS2
3808 /* MS-DOS KERMIT compatibility modes */
3809 int
3810 setmsk() {
3811     if ((y = cmkey(msktab,nmsk,"MS-DOS Kermit compatibility mode",
3812                     "keycodes",xxstring)) < 0) return(y);
3813
3814     switch ( y ) {
3815 #ifdef COMMENT
3816       case MSK_COLOR:
3817         return(seton(&mskcolors));
3818 #endif /* COMMENT */
3819       case MSK_KEYS:
3820         return(seton(&mskkeys));
3821       default:                          /* Shouldn't get here. */
3822         return(-2);
3823     }
3824 }
3825 #endif /* OS2 */
3826
3827 int
3828 settrmtyp() {
3829 #ifdef OS2
3830 #ifdef TNCODE
3831     extern int ttnum;                    /* Last Telnet Terminal Type sent */
3832     extern int ttnumend;                 /* Has end of list been found */
3833 #endif /* TNCODE */
3834     if ((x = cmkey(ttyptab,nttyp,"","vt320",xxstring)) < 0)
3835       return(x);
3836     if ((y = cmcfm()) < 0)
3837       return(y);
3838     settermtype(x,1);
3839 #ifdef TNCODE
3840     /* So we send the correct terminal name to the host if it asks for it */
3841     ttnum = -1;                         /* Last Telnet Terminal Type sent */
3842     ttnumend = 0;                       /* end of list not found */
3843 #endif /* TNCODE */
3844     return(success = 1);
3845 #else  /* Not OS2 */
3846     printf(
3847 "\n Sorry, this version of C-Kermit does not support the SET TERMINAL TYPE\n");
3848     printf(
3849 " command.  Type \"help set terminal\" for further information.\n");
3850 #endif /* OS2 */
3851     return(success = 0);
3852 }
3853
3854 #ifdef CKTIDLE
3855 static char iactbuf[132];
3856
3857 char *
3858 getiact() {
3859     switch (tt_idleact) {
3860       case IDLE_RET:  return("return");
3861       case IDLE_EXIT: return("exit");
3862       case IDLE_HANG: return("hangup");
3863 #ifdef TNCODE
3864       case IDLE_TNOP: return("Telnet NOP");
3865       case IDLE_TAYT: return("Telnet AYT");
3866 #endif /* TNCODE */
3867
3868       case IDLE_OUT: {
3869           int c, k, n;
3870           char * p, * q, * t;
3871           k = ckstrncpy(iactbuf,"output ",132);
3872           n = k;
3873           q = &iactbuf[k];
3874           p = tt_idlestr;
3875           if (!p) p = "";
3876           if (!*p) return("output (nothing)");
3877           while ((c = *p++) && n < 131) {
3878               c &= 0xff;
3879               if (c == '\\') {
3880                   if (n > 130) break;
3881                   *q++ = '\\';
3882                   *q++ = '\\';
3883                   *q = NUL;
3884                   n += 2;
3885               } else if ((c > 31 && c < 127) || c > 159) {
3886                   *q++ = c;
3887                   *q = NUL;
3888                   n++;
3889               } else {
3890                   if (n > (131 - 6))
3891                     break;
3892                   sprintf(q,"\\{%d}",c);
3893                   k = strlen(q);
3894                   q += k;
3895                   n += k;
3896                   *q = NUL;
3897               }
3898           }
3899           *q = NUL;
3900 #ifdef OS2
3901           k = tt_cols[VTERM];
3902 #else
3903           k = tt_cols;
3904 #endif /* OS2 */
3905           if (n > k - 52) {
3906               n = k - 52;
3907               iactbuf[n-2] = '.';
3908               iactbuf[n-1] = '.';
3909               iactbuf[n] = NUL;
3910           }
3911           return(iactbuf);
3912       }
3913       default: return("unknown");
3914     }
3915 }
3916 #endif /* CKTIDLE */
3917
3918 #ifndef NOCSETS
3919 VOID
3920 setlclcharset(x) int x; {
3921     int i;
3922     tcsl = y;                   /* Local character set */
3923 #ifdef OS2
3924     for (i = 0; i < 4; i++) {
3925         G[i].init = TRUE;
3926         x = G[i].designation;
3927         G[i].c1 = (x != tcsl) && cs_is_std(x);
3928         x = G[i].def_designation;
3929         G[i].def_c1 = (x != tcsl) && cs_is_std(x);
3930     }
3931 #endif /* OS2 */
3932 }
3933
3934 VOID
3935 setremcharset(x, z) int x, z; {
3936     int i;
3937
3938 #ifdef KUI
3939     KuiSetProperty( KUI_TERM_REMCHARSET, (long) x, (long) z ) ;
3940 #endif /* KUI */
3941 #ifdef UNICODE
3942     if (x == TX_TRANSP)
3943 #else /* UNICODE */
3944     if (x == FC_TRANSP)
3945 #endif /* UNICODE */
3946     {                           /* TRANSPARENT? */
3947 #ifndef OS2
3948         tcsr = tcsl;            /* Make both sets the same */
3949 #else /* OS2 */
3950 #ifdef CKOUNI
3951         tt_utf8 = 0;            /* Turn off UTF8 flag */
3952         tcsr = tcsl = dec_kbd = TX_TRANSP; /* No translation */
3953         tcs_transp = 1;
3954
3955         if (!cs_is_nrc(tcsl)) {
3956             G[0].def_designation = G[0].designation = TX_ASCII;
3957             G[0].init = TRUE;
3958             G[0].def_c1 = G[0].c1 = FALSE;
3959             G[0].size = cs94;
3960             G[0].national = FALSE;
3961         }
3962         for (i = cs_is_nrc(tcsl) ? 0 : 1; i < 4; i++) {
3963             G[i].def_designation = G[i].designation = tcsl;
3964             G[i].init = TRUE;
3965             G[i].def_c1 = G[i].c1 = FALSE;
3966             switch (cs_size(G[i].designation)) { /* 94, 96, or 128 */
3967             case 128:
3968             case 96:
3969                 G[i].size = G[i].def_size = cs96;
3970                 break;
3971             case 94:
3972                 G[i].size = G[i].def_size = cs94;
3973                 break;
3974             default:
3975                 G[i].size = G[i].def_size = csmb;
3976                 break;
3977             }
3978             G[i].national = cs_is_nrc(x);
3979         }
3980 #else /* CKOUNI */
3981         tcsr = tcsl;            /* Make both sets the same */
3982         for (i = 0; i < 4; i++) {
3983             G[i].def_designation = G[i].designation = FC_TRANSP;
3984             G[i].init = FALSE;
3985             G[i].size = G[i].def_size = cs96;
3986             G[i].c1 = G[i].def_c1 = FALSE;
3987             G[i].rtoi = NULL;
3988             G[i].itol = NULL;
3989             G[i].ltoi = NULL;
3990             G[i].itor = NULL;
3991             G[i].national = FALSE;
3992         }
3993 #endif /* CKOUNI */
3994 #endif /* OS2 */
3995         return;
3996     }
3997 #ifdef OS2
3998 #ifdef CKOUNI
3999     else if (x == TX_UTF8) {
4000         tcs_transp = 0;
4001         tt_utf8 = 1;            /* Turn it on if we are UTF8 */
4002         return;
4003     }
4004 #endif /* CKOUNI */
4005     else {
4006         tcs_transp = 0;
4007         tcsr = x;                       /* Remote character set */
4008 #ifdef CKOUNI
4009         tt_utf8 = 0;                    /* Turn off UTF8 flag */
4010 #endif /* CKOUNI */
4011
4012         if (z == TT_GR_ALL) {
4013             int i;
4014 #ifdef UNICODE
4015             dec_kbd = x;
4016 #endif /* UNICODE */
4017             for (i = 0; i < 4; i++) {
4018                 G[i].init = TRUE;
4019                 if ( i == 0 && !cs_is_nrc(x) ) {
4020                     G[0].designation = G[0].def_designation = FC_USASCII;
4021                     G[0].size = G[0].def_size = cs94;
4022                     G[0].national = 1;
4023                 } else {
4024                     G[i].def_designation = G[i].designation = x;
4025                     switch (cs_size(x)) {       /* 94, 96, or 128 */
4026                     case 128:
4027                     case 96:
4028                         G[i].size = G[i].def_size = cs96;
4029                         break;
4030                     case 94:
4031                         G[i].size = G[i].def_size = cs94;
4032                         break;
4033                     default:
4034                         G[i].size = G[i].def_size = csmb;
4035                         break;
4036                     }
4037                     G[i].national = cs_is_nrc(x);
4038                 }
4039                 G[i].c1 = G[i].def_c1 = x != tcsl && cs_is_std(x);
4040             }
4041 #ifdef UNICODE
4042         } else if (z == TT_GR_KBD) {    /* Keyboard only */
4043             dec_kbd = x;
4044 #endif /* UNICODE */
4045         } else {                        /* Specific Gn */
4046             G[z].def_designation = G[z].designation = x;
4047             G[z].init = TRUE;
4048             switch (cs_size(x)) {       /* 94, 96, or 128 */
4049             case 128:
4050             case 96:
4051                 G[z].size = G[z].def_size = cs96;
4052                 break;
4053             case 94:
4054                 G[z].size = G[z].def_size = cs94;
4055                 break;
4056             default:
4057                 G[z].size = G[z].def_size = csmb;
4058                 break;
4059             }
4060             G[z].c1 = G[z].def_c1 = x != tcsl && cs_is_std(x);
4061             G[z].national = cs_is_nrc(x);
4062         }
4063     }
4064 #else /* not OS2 */
4065     tcsr = x;                   /* Remote character set */
4066 #endif /* OS2 */
4067 }
4068 #endif /* NOCSETS */
4069
4070 VOID
4071 setcmask(x) int x; {
4072     if (x == 7) {
4073         cmask = 0177;
4074     } else if (x == 8) {
4075         cmask = 0377;
4076         parity = 0;
4077     }
4078 #ifdef KUI      
4079     KuiSetProperty(KUI_TERM_CMASK,x,0);
4080 #endif /* KUI */
4081 }
4082
4083 #ifdef CK_AUTODL
4084 VOID
4085 setautodl(x,y) int x,y; {
4086     autodl = x;
4087     adl_ask = y;
4088 #ifdef KUI      
4089     KuiSetProperty(KUI_TERM_AUTODOWNLOAD,x?(y?2:1):0,0);
4090 #endif /* KUI */
4091 }
4092 #endif /* CK_AUTODL */
4093
4094 #ifdef OS2
4095 VOID
4096 seturlhl(int x) {
4097     tt_url_hilite = x;
4098 #ifdef KUI      
4099     KuiSetProperty(KUI_TERM_URL_HIGHLIGHT,x,0);
4100 #endif /* KUI */
4101 }
4102
4103 VOID
4104 setaprint(int x) {
4105     extern int aprint;
4106     aprint = x;
4107 #ifdef KUI
4108     KuiSetProperty(KUI_TERM_PRINTERCOPY,x,0);
4109 #endif /* KUI */
4110 }
4111 #endif /* OS2 */
4112
4113 int
4114 settrm() {
4115     int i = 0;
4116 #ifdef OS2
4117     extern int colorreset, user_erasemode;
4118 #endif /* OS2 */
4119     if ((y = cmkey(trmtab,ntrm,"", "",xxstring)) < 0) return(y);
4120 #ifdef MAC
4121     printf("\n?Sorry, not implemented yet.  Please use the Settings menu.\n");
4122     return(-9);
4123 #else
4124 #ifdef IKSD
4125     if (inserver) {
4126         if ((y = cmcfm()) < 0) return(y);
4127         printf("?Sorry, command disabled.\r\n");
4128         return(success = 0);
4129     }
4130 #endif /* IKSD */
4131
4132     switch (y) {
4133       case XYTBYT:                      /* SET TERMINAL BYTESIZE */
4134         if ((y = cmnum("bytesize for terminal connection","8",10,&x,
4135                        xxstring)) < 0)
4136           return(y);
4137         if (x != 7 && x != 8) {
4138             printf("\n?The choices are 7 and 8\n");
4139             return(success = 0);
4140         }
4141         if ((y = cmcfm()) < 0) return(y);
4142         setcmask(x);
4143 #ifdef OS2
4144         if (IS97801(tt_type_mode))
4145           SNI_bitmode(x);
4146 #endif /* OS2 */
4147         return(success = 1);
4148
4149       case XYTSO:                       /* SET TERMINAL LOCKING-SHIFT */
4150         return(seton(&sosi));
4151
4152       case XYTNL:                       /* SET TERMINAL NEWLINE-MODE */
4153         return(seton(&tnlm));
4154
4155 #ifdef OS2
4156       case XYTCOL:
4157         if ((x = cmkey(ttycoltab,ncolors,"","terminal",xxstring)) < 0)
4158           return(x);
4159         else if (x == TTCOLRES) {
4160             if ((y = cmkey(ttcolmodetab,ncolmode,
4161                            "","default-color",xxstring)) < 0)
4162               return(y);
4163             if ((z = cmcfm()) < 0)
4164               return(z);
4165             colorreset = y;
4166             return(success = 1);
4167         } else if (x == TTCOLERA) {
4168             if ((y = cmkey(ttcolmodetab,ncolmode,"",
4169                            "current-color",xxstring)) < 0)
4170               return(y);
4171             if ((z = cmcfm()) < 0)
4172               return(z);
4173             user_erasemode = y;
4174             return(success=1);
4175         } else {                        /* No parse error */
4176             int fg = 0, bg = 0;
4177             fg = cmkey(ttyclrtab, nclrs,
4178                        (x == TTCOLBOR ?
4179                         "color for screen border" :
4180                         "foreground color and then background color"),
4181                        "lgray", xxstring);
4182             if (fg < 0)
4183               return(fg);
4184             if (x != TTCOLBOR) {
4185                 if ((bg = cmkey(ttyclrtab,nclrs,
4186                                 "background color","blue",xxstring)) < 0)
4187                   return(bg);
4188             }
4189             if ((y = cmcfm()) < 0)
4190               return(y);
4191             switch (x) {
4192               case TTCOLNOR:
4193                 colornormal = fg | bg << 4;
4194                 fgi = fg & 0x08;
4195                 bgi = bg & 0x08;
4196                 break;
4197               case TTCOLREV:
4198                 colorreverse = fg | bg << 4;
4199                 break;
4200               case TTCOLITA:
4201                 coloritalic = fg | bg << 4;
4202                 break;
4203               case TTCOLUND:
4204                 colorunderline = fg | bg << 4;
4205                 break;
4206               case TTCOLGRP:
4207                 colorgraphic = fg | bg << 4;
4208                 break;
4209               case TTCOLDEB:
4210                 colordebug = fg | bg << 4;
4211                 break;
4212               case TTCOLSTA:
4213                 colorstatus = fg | bg << 4;
4214                 break;
4215               case TTCOLHLP:
4216                 colorhelp = fg | bg << 4;
4217                 break;
4218               case TTCOLBOR:
4219                 colorborder = fg;
4220                 break;
4221               case TTCOLSEL:
4222                 colorselect = fg | bg << 4;
4223                 break;
4224               default:
4225                 printf("%s - invalid\n",cmdbuf);
4226                 return(-9);
4227                 break;
4228             }
4229             scrninitialized[VTERM] = 0;
4230             VscrnInit(VTERM);
4231         }
4232         return(success = 1);
4233
4234       case XYTCUR: {                    /* SET TERMINAL CURSOR */
4235           extern int cursorena[];
4236           extern int cursoron[] ;       /* Cursor state on/off       */
4237           if ((x = cmkey(ttycurtab,ncursors,"","underline",xxstring)) < 0)
4238             return(x);
4239           if ((z = cmkey(curontab,ncuron,"","on",xxstring)) < 0)
4240             return(z);
4241           if ((y = cmcfm()) < 0) return(y);
4242           tt_cursor = tt_cursor_usr = x;
4243           if ( z == 2 ) {
4244               cursorena[VTERM] = tt_cursorena_usr = 1;
4245               tt_cursor_blink = 0;
4246           } else {
4247               cursorena[VTERM] = tt_cursorena_usr = z;/* turn cursor on/off */
4248               tt_cursor_blink = 1;
4249           }
4250           cursoron[VTERM] = FALSE; /* Force newcursor to restore the cursor */
4251           return(success = 1);
4252       }
4253 #endif /* OS2 */
4254
4255       case XYTTYP:                      /* SET TERMINAL TYPE */
4256         return(settrmtyp());
4257
4258 #ifdef OS2
4259       case XYTARR:                      /* SET TERMINAL ARROW-KEYS */
4260         if ((x = cmkey(akmtab,2,"","",xxstring)) < 0) return(x);
4261         if ((y = cmcfm()) < 0) return(y);
4262         tt_arrow = x;                   /* TTK_NORM / TTK_APPL; see ckuusr.h */
4263         return(success = 1);
4264
4265       case XYTKPD:                      /* SET TERMINAL KEYPAD-MODE */
4266         if ((x = cmkey(kpmtab,2,"","",xxstring)) < 0) return(x);
4267         if ((y = cmcfm()) < 0) return(y);
4268         tt_keypad = x;                  /* TTK_NORM / TTK_APPL; see ckuusr.h */
4269         return(success = 1);
4270
4271       case XYTUNX: {                    /* SET TERM UNIX-MODE (DG) */
4272         extern int dgunix,dgunix_usr;
4273         x = seton(&dgunix);
4274         dgunix_usr = dgunix;
4275         return(x);
4276       }
4277       case XYTKBMOD: {                  /* SET TERM KEYBOARD MODE */
4278           extern int tt_kb_mode;
4279           if ((x = cmkey(kbmodtab,
4280                          nkbmodtab,
4281                          "normal",
4282                          "special keyboard mode for terminal emulation",
4283                          xxstring)
4284                ) < 0)
4285             return(x);
4286           if ((y = cmcfm()) < 0) return(y);
4287           tt_kb_mode = x;
4288           return(success = 1);
4289       }
4290
4291       case XYTWRP:                      /* SET TERMINAL WRAP */
4292         return(seton(&tt_wrap));
4293
4294       case XYSCRS:
4295         if ((y = cmnum("CONNECT scrollback buffer size, lines","2000",10,&x,
4296                        xxstring)) < 0)
4297           return(y);
4298         /* The max number of lines is the RAM  */
4299         /* we can actually dedicate to a       */
4300         /* scrollback buffer given the maximum */
4301         /* process memory space of 512MB       */
4302         if (x < 256 || x > 2000000L) {
4303             printf("\n?The size must be between 256 and 2,000,000.\n");
4304             return(success = 0);
4305         }
4306         if ((y = cmcfm()) < 0) return(y);
4307         tt_scrsize[VTERM] = x;
4308         VscrnInit(VTERM);
4309         return(success = 1);
4310 #endif /* OS2 */
4311
4312 #ifndef NOCSETS
4313       case XYTCS: {                     /* SET TERMINAL CHARACTER-SET */
4314         int eol;
4315           /* set terminal character-set <remote> <local> */
4316         if ((x = cmkey(
4317 #ifdef CKOUNI
4318                        txrtab,ntxrtab,
4319 #else  /* CKOUNI */
4320                        ttcstab,ntermc,
4321 #endif /* CKOUNI */
4322                        "remote terminal character-set","",xxstring)) < 0)
4323           return(x);
4324
4325 #ifdef UNICODE
4326         if (x == TX_TRANSP
4327 #ifdef CKOUNI
4328             || x == TX_UTF8
4329 #endif /* CKOUNI */
4330            ) {
4331               if ((y = cmcfm()) < 0)    /* Confirm the command */
4332                   return(y);
4333 #ifdef OS2
4334             if ( isunicode() && x == TX_TRANSP ) {
4335                 /* If we are in unicode display mode then transparent
4336                  * only affects the output direction.  We need to know
4337                  * the actual remote character set in order to perform
4338                  * the tcsr -> ucs2 translation for display.
4339                  */
4340                 x = y = tcsl;
4341             } else
4342 #endif /* OS2 */
4343                 y = x;
4344         }
4345 #else /* UNICODE */
4346         if (x == FC_TRANSP) {
4347             if ((y = cmcfm()) < 0)      /* Confirm the command */
4348                 return(y);
4349             y = x;
4350         }
4351 #endif /* UNICODE */
4352
4353         /* Not transparent or UTF8, so get local set to translate it into */
4354         s = "";
4355 #ifdef OS2
4356         y = os2getcp();                 /* Default is current code page */
4357         switch (y) {
4358           case 437: s = "cp437"; break;
4359           case 850: s = "cp850"; break;
4360           case 852: s = "cp852"; break;
4361           case 857: s = "cp857"; break;
4362           case 858: s = "cp858"; break;
4363           case 862: s = "cp862"; break;
4364           case 866: s = "cp866"; break;
4365           case 869: s = "cp869"; break;
4366           case 1250: s = "cp1250"; break;
4367           case 1251: s = "cp1251"; break;
4368           case 1252: s = "cp1252"; break;
4369           case 1253: s = "cp1253"; break;
4370           case 1254: s = "cp1254"; break;
4371           case 1255: s = "cp1255"; break;
4372           case 1256: s = "cp1256"; break;
4373           case 1257: s = "cp1257"; break;
4374           case 1258: s = "cp1258"; break;
4375         }
4376 #ifdef PCFONTS
4377 /*
4378    If the user has loaded a font with SET TERMINAL FONT then we want
4379    to change the default code page to the font that was loaded.
4380 */
4381         if (tt_font != TTF_ROM) {
4382             for (y = 0; y < ntermfont; y++ ) {
4383                 if (term_font[y].kwval == tt_font) {
4384                     s = term_font[y].kwd;
4385                     break;
4386                 }
4387             }
4388         }
4389 #endif /* PCFONTS */
4390 #else  /* Not K95... */
4391         s = fcsinfo[fcharset].keyword;
4392 #endif /* OS2 */
4393
4394         if ((y = cmkey(
4395 #ifdef CKOUNI
4396                        txrtab,ntxrtab,
4397 #else /* CKOUNI */
4398                        ttcstab,ntermc,
4399 #endif /* CKOUNI */
4400                        "local character-set",s,xxstring)) < 0)
4401           return(y);
4402
4403 #ifdef UNICODE
4404         if (y == TX_UTF8) {
4405             printf("?UTF8 may not be used as a local character set.\r\n");
4406             return(-9);
4407         }
4408 #endif /* UNICODE */
4409 #ifdef OS2
4410         if ((z = cmkey(graphsettab,ngraphset,
4411                        "DEC VT intermediate graphic set","all",xxstring)) < 0)
4412             return(z);
4413 #endif /* OS2 */
4414         if ((eol = cmcfm()) < 0)
4415             return(eol); /* Confirm the command */
4416
4417         /* End of command parsing - actions begin */
4418         setlclcharset(y);
4419         setremcharset(x,z);
4420         return(success = 1);
4421       }
4422 #endif /* NOCSETS */
4423
4424 #ifndef NOCSETS
4425       case XYTLCS:                      /* SET TERMINAL LOCAL-CHARACTER-SET */
4426         /* set terminal character-set <local> */
4427         s = getdcset();                 /* Get display character-set name */
4428         if ((y = cmkey(
4429 #ifdef CKOUNI
4430                        txrtab,ntxrtab,
4431 #else /* CKOUNI */
4432                        fcstab,nfilc,
4433 #endif /* CKOUNI */
4434                        "local character-set",s,xxstring)) < 0)
4435           return(y);
4436
4437 #ifdef UNICODE
4438           if (y == TX_UTF8) {
4439               printf("?UTF8 may not be used as a local character set.\r\n");
4440               return(-9);
4441           }
4442 #endif /* UNICODE */
4443           if ((z = cmcfm()) < 0) return(z); /* Confirm the command */
4444
4445           /* End of command parsing - action begins */
4446
4447         setlclcharset(y);
4448         return(success = 1);
4449 #endif /* NOCSETS */
4450
4451 #ifndef NOCSETS
4452 #ifdef UNICODE
4453       case XYTUNI:                      /* SET TERMINAL UNICODE */
4454         return(seton(&tt_unicode));
4455 #endif /* UNICODE */
4456
4457       case XYTRCS:                      /* SET TERMINAL REMOTE-CHARACTER-SET */
4458         /* set terminal character-set <remote> <Graphic-set> */
4459         if ((x = cmkey(
4460 #ifdef CKOUNI
4461                 txrtab, ntxrtab,
4462 #else /* CKOUNI */
4463                 ttcstab,ntermc,
4464 #endif /* CKOUNI */
4465                        "remote terminal character-set","",xxstring)) < 0)
4466           return(x);
4467
4468 #ifdef UNICODE
4469         if (x == TX_TRANSP
4470 #ifdef CKOUNI
4471             || x == TX_UTF8
4472 #endif /* CKOUNI */
4473            ) {
4474               if ((y = cmcfm()) < 0)    /* Confirm the command */
4475                   return(y);
4476 #ifdef OS2
4477             if ( isunicode() && x == TX_TRANSP ) {
4478                 /* If we are in unicode display mode then transparent
4479                  * only affects the output direction.  We need to know
4480                  * the actual remote character set in order to perform
4481                  * the tcsr -> ucs2 translation for display.
4482                  */
4483                 x = tcsl;
4484             }
4485 #endif /* OS2 */
4486         }
4487 #else /* UNICODE */
4488         if (x == FC_TRANSP) {
4489           if ((y = cmcfm()) < 0)        /* Confirm the command */
4490             return(y);
4491         }
4492 #endif /* UNICODE */
4493         else {
4494 #ifdef OS2
4495           if ((z = cmkey(graphsettab,ngraphset,
4496                       "DEC VT intermediate graphic set","all",xxstring)) < 0)
4497             return(z);
4498 #endif /* OS2 */
4499           if ((y = cmcfm()) < 0)        /* Confirm the command */
4500             return(y);
4501         }
4502         /* Command parsing ends here */
4503
4504         setremcharset(x,z);
4505         return(success = 1);
4506 #endif /* NOCSETS */
4507
4508       case XYTEC:                       /* SET TERMINAL ECHO */
4509         if ((x = cmkey(rltab,nrlt,"which side echos during CONNECT",
4510                        "remote", xxstring)) < 0) return(x);
4511         if ((y = cmcfm()) < 0) return(y);
4512 #ifdef NETCONN
4513         oldplex = x;
4514 #endif /* NETCONN */
4515         duplex = x;
4516         return(success = 1);
4517
4518       case XYTESC:                      /* SET TERM ESC */
4519         if ((x = cmkey(nabltab,nnabltab,"","enabled",xxstring)) < 0)
4520           return(x);
4521         if ((y = cmcfm()) < 0) return(y);
4522         tt_escape = x;
4523         return(1);
4524
4525       case XYTCRD:                      /* SET TERMINAL CR-DISPLAY */
4526         if ((x = cmkey(crdtab,2,"", "normal", xxstring)) < 0) return(x);
4527         if ((y = cmcfm()) < 0) return(y);
4528         tt_crd = x;
4529         return(success = 1);
4530
4531 #ifdef OS2
4532       case XYTANS: {                    /* SET TERMINAL ANSWERBACK */
4533 /*
4534   NOTE: We let them enable and disable the answerback sequence, but we
4535   do NOT let them change it, and we definitely do not let the host set it.
4536   This is a security feature.
4537
4538   As of 1.1.8 we allow the SET TERM ANSWERBACK MESSAGE <string> to be
4539   used just as MS-DOS Kermit does.  C0 and C1 controls as well as DEL
4540   are not allowed to be used as characters.  They are translated to
4541   underscore.  This may not be set by APC.
4542 */
4543           if ((x = cmkey(anbktab,nansbk,"", "off", xxstring)) < 0)
4544             return(x);
4545           if (x < 2) {
4546               if ((y = cmcfm()) < 0)
4547                 return(y);
4548               tt_answer = x;
4549               return(success = 1);
4550           } else if ( x == 2 || x == 3) {
4551               int len = 0;
4552               extern int safeanswerbk;
4553               extern char useranswerbk[];
4554               if ((y = cmtxt("Answerback extension","",&s,xxstring)) < 0)
4555                 return(y);
4556               if (apcactive == APC_LOCAL ||
4557                   (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)))
4558                 return(success = 0);
4559               len = strlen(s);
4560               if (x == 2) {
4561                   /* Safe Answerback's don't have C0/C1 chars */
4562                   for (z = 0; z < len; z++) {
4563                       if ((s[z] & 0x7F) <= SP || (s[z] & 0x7F) == DEL)
4564                         useranswerbk[z] = '_';
4565                       else
4566                         useranswerbk[z] = s[z];
4567                   }
4568                   useranswerbk[z] = '\0';
4569                   safeanswerbk = 1 ;    /* TRUE */
4570               } else {
4571                   ckstrncpy(useranswerbk,s,60); /* (see ckocon.c) */
4572                   safeanswerbk = 0;     /* FALSE */
4573               }
4574               updanswerbk();
4575               return(success = 1);
4576           } else
4577             return(success = 0);
4578       }
4579 #endif /* OS2 */
4580
4581 #ifdef CK_APC
4582       case XYTAPC:
4583         if ((y = cmkey(apctab,napctab,
4584                        "application program command execution","",
4585                        xxstring)) < 0)
4586           return(y);
4587         if ((x = cmcfm()) < 0)
4588           return(x);
4589         if (apcactive == APC_LOCAL ||
4590             (apcactive == APC_REMOTE && !(apcstatus & APC_UNCH)))
4591           return(success = 0);
4592         apcstatus = y;
4593         return(success = 1);
4594
4595 #ifdef CK_AUTODL
4596       case XYTAUTODL:                   /* AUTODOWNLOAD */
4597         if ((y = cmkey(adltab,nadltab,"Auto-download options","",
4598                        xxstring)) < 0)
4599           return(y);
4600         switch (y) {
4601           case TAD_ON:
4602           case TAD_OFF:
4603             if ((x = cmcfm()) < 0)
4604               return(x);
4605             setautodl(y,0);
4606             break;
4607           case TAD_ASK:
4608             if ((x = cmcfm()) < 0)
4609               return(x);
4610             setautodl(TAD_ON,1);
4611             break;
4612           case TAD_ERR:
4613             if ((y = cmkey(adlerrtab,nadlerrtab,"","", xxstring)) < 0)
4614               return(y);
4615             if ((x = cmcfm()) < 0)
4616               return(x);
4617             adl_err = y;
4618             break;
4619 #ifdef OS2
4620           case TAD_K:
4621             if ((y = cmkey(adlxtab,nadlxtab,"","", xxstring)) < 0)
4622               return(y);
4623             switch (y) {
4624               case TAD_X_C0:
4625                 if ((y = cmkey(adlc0tab,nadlc0tab,"",
4626                                "processed-by-emulator",xxstring)) < 0)
4627                   return(y);
4628                 if ((x = cmcfm()) < 0)
4629                   return(x);
4630                 adl_kc0 = y;
4631                 break;
4632               case TAD_X_DETECT:
4633                 if ((y = cmkey(adldtab,nadldtab,"","packet",xxstring)) < 0)
4634                   return(y);
4635                 if ((x = cmcfm()) < 0)
4636                   return(x);
4637                 adl_kmode = y;
4638                 break;
4639               case TAD_X_STR:
4640                 if ((y = cmtxt("Kermit start string","KERMIT READY TO SEND...",
4641                                &s,xxstring)) < 0)
4642                   return(y);
4643                 free(adl_kstr);
4644                 adl_kstr = strdup(s);
4645                 break;
4646             }
4647             break;
4648
4649           case TAD_Z:
4650             if ((y = cmkey(adlxtab,nadlxtab,"","",xxstring)) < 0)
4651               return(y);
4652             switch (y) {
4653               case TAD_X_C0:
4654                 if ((y = cmkey(adlc0tab,nadlc0tab,"",
4655                                "processed-by-emulator",xxstring)) < 0)
4656                   return(y);
4657                 if ((x = cmcfm()) < 0)
4658                   return(x);
4659                 adl_zc0 = y;
4660                 break;
4661               case TAD_X_DETECT:
4662                 if ((y = cmkey(adldtab,nadldtab,"","packet",xxstring)) < 0)
4663                   return(y);
4664                 if ((x = cmcfm()) < 0)
4665                   return(x);
4666                 adl_zmode = y;
4667                 break;
4668               case TAD_X_STR:
4669                 if ((y = cmtxt("","rz\\{13}",&s,xxstring)) < 0)
4670                   return(y);
4671                 free(adl_zstr);
4672                 adl_zstr = strdup(s);
4673                 break;
4674             }
4675             break;
4676 #endif /* OS2 */
4677         }
4678         return(success = 1);
4679
4680 #endif /* CK_AUTODL */
4681 #endif /* CK_APC */
4682
4683 #ifdef OS2
4684       case XYTBEL:
4685         return(success = setbell());
4686
4687       case XYTMBEL:                     /* MARGIN-BELL */
4688         if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
4689         if (y) {                        /* ON */
4690             if ((z = cmnum("Column at which to set margin bell",
4691                            "72",10,&x,xxstring)) < 0)
4692               return(z);
4693         }
4694         if ((z = cmcfm()) < 0) return(z);
4695         marginbell = y;
4696         marginbellcol = x;
4697         return(success = 1);
4698 #endif /* OS2 */
4699
4700 #ifdef CKTIDLE
4701       case XYTIDLE:                     /* IDLE-SEND */
4702       case XYTITMO:                     /* IDLE-TIMEOUT */
4703         if ((z = cmnum("seconds of idle time to wait, or 0 to disable",
4704                        "0",10,&x,xxstring)) < 0)
4705           return(z);
4706         if (y == XYTIDLE) {
4707             if ((y = cmtxt("string to send, may contain kverbs and variables",
4708                            "\\v(newline)",&s,xxstring)) < 0)
4709               return(y);
4710             tt_idlesnd_tmo = x;         /* (old) */
4711             tt_idlelimit = x;           /* (new) */
4712             makestr(&tt_idlestr,brstrip(s)); /* (new) */
4713             tt_idlesnd_str = tt_idlestr; /* (old) */
4714             tt_idleact = IDLE_OUT;      /* (new) */
4715         } else {
4716             if ((y = cmcfm()) < 0)
4717               return(y);
4718             tt_idlelimit = x;
4719         }
4720 #ifdef OS2
4721         puterror(VTERM);
4722 #endif /* OS2 */
4723         return(success = 1);
4724
4725       case XYTIACT: {                   /* SET TERM IDLE-ACTION */
4726           if ((y = cmkey(idlacts,nidlacts,"","",xxstring)) < 0)
4727             return(y);
4728           if (y == IDLE_OUT) {
4729               if ((x = cmtxt("string to send, may contain kverbs and variables"
4730                              , "\\v(newline)",&s,xxstring)) < 0)
4731                 return(x);
4732               makestr(&tt_idlestr,brstrip(s)); /* (new) */
4733               tt_idlesnd_str = tt_idlestr; /* (old) */
4734           } else {
4735               if ((x = cmcfm()) < 0)
4736                 return(x);
4737           }
4738           tt_idleact = y;
4739           return(success = 1);
4740       }
4741 #endif /* CKTIDLE */
4742
4743       case XYTDEB:                      /* TERMINAL DEBUG */
4744         y = seton(&x);                  /* Go parse ON or OFF */
4745         if (y > 0)                      /* Command succeeded? */
4746           setdebses(x);
4747         return(y);
4748
4749 #ifdef OS2
4750       case XYTASCRL:                    /* SET TERMINAL AUTOSCROLL */
4751           y = seton(&autoscroll);
4752           return(y);
4753
4754       case XYTAPAGE:                    /* SET TERMINAL AUTOPAGE */
4755           y = seton(&wy_autopage);
4756           return(y);
4757
4758       case XYTROL:                      /* SET TERMINAL ROLL */
4759         if ((y = cmkey(rolltab,nroll,"scrollback mode","insert",xxstring))<0)
4760           return(y);
4761         if (y == TTR_KEYS) {
4762             if ((x = cmkey(rollkeytab,nrollkey,"","send",xxstring))<0)
4763               return(x);
4764             if ((z = cmcfm()) < 0) return(z);
4765             tt_rkeys[VTERM] = x;
4766         } else {
4767             if ((x = cmcfm()) < 0) return(x);
4768             tt_roll[VTERM] = y;
4769         }
4770         return(success = 1);
4771
4772       case XYTCTS:                      /* SET TERMINAL TRANSMIT-TIMEOUT */
4773         y = cmnum("Maximum seconds to allow CTS off during CONNECT",
4774                   "5",10,&x,xxstring);
4775         return(setnum(&tt_ctstmo,x,y,10000));
4776
4777       case XYTCPG: {                    /* SET TERMINAL CODE-PAGE */
4778         int i;
4779         int cp = -1;
4780         y = cmnum("PC code page to use during terminal emulation",
4781                   ckitoa(os2getcp()),10,&x,xxstring);
4782         if ((x = setnum(&cp,x,y,11000)) < 0) return(x);
4783         if (os2setcp(cp) != 1) {
4784 #ifdef NT
4785             if (isWin95())
4786               printf(
4787                  "Sorry, Windows 95 does not support code page switching\n");
4788             else
4789 #endif /* NT */
4790               printf(
4791                  "Sorry, %d is not a valid code page for this system.\n",cp);
4792             return(-9);
4793         }
4794     /* Force the terminal character-sets conversions to be updated */
4795         for ( i = 0; i < 4; i++ )
4796           G[i].init = TRUE;
4797         return(1);
4798     }
4799
4800       case XYTPAC:                      /* SET TERMINAL OUTPUT-PACING */
4801         y = cmnum(
4802            "Pause between sending each character during CONNECT, milliseconds",
4803                   "-1",10,&x,xxstring);
4804         return(setnum(&tt_pacing,x,y,10000));
4805
4806 #ifdef OS2MOUSE
4807       case XYTMOU: {                    /* SET TERMINAL MOUSE */
4808           int old_mou = tt_mouse;
4809           if ((x = seton(&tt_mouse)) < 0)
4810             return(x);
4811           if (tt_mouse != old_mou)
4812             if (tt_mouse)
4813               os2_mouseon();
4814             else
4815               os2_mouseoff();
4816           return(1);
4817       }
4818 #endif /* OS2MOUSE */
4819 #endif /* OS2 */
4820
4821       case XYTWID: {
4822           if ((y = cmnum(
4823 #ifdef OS2
4824                          "number of columns in display window during CONNECT",
4825 #else
4826                          "number of columns on your screen",
4827 #endif /* OS2 */
4828                          "80",10,&x,xxstring)) < 0)
4829             return(y);
4830           if ((y = cmcfm()) < 0) return(y);
4831 #ifdef OS2
4832           return(success = os2_settermwidth(x));
4833 #else  /* Not OS/2 */
4834           tt_cols = x;
4835           return(success = 1);
4836 #endif /* OS2 */
4837       }
4838
4839       case XYTHIG:
4840         if ((y = cmnum(
4841 #ifdef OS2
4842  "number of rows in display window during CONNECT, not including status line",
4843  tt_status[VTERM]?"24":"25",
4844 #else
4845  "24","number of rows on your screen",
4846 #endif /* OS2 */
4847                        10,&x,xxstring)) < 0)
4848           return(y);
4849         if ((y = cmcfm()) < 0) return(y);
4850
4851 #ifdef OS2
4852         return (success = os2_settermheight(x));
4853 #else  /* Not OS/2 */
4854         tt_rows = x;
4855         return(success = 1);
4856 #endif /* OS2 */
4857
4858 #ifdef OS2
4859       case XYTPRN: {                    /* Print Mode */
4860           extern bool xprint, aprint, cprint, uprint;
4861           if ((y = cmkey(prnmtab,nprnmtab,"","off", xxstring)) < 0) return(y);
4862           if ((x = cmcfm()) < 0) return(x);
4863           switch (y) {
4864             case 0:
4865               if (cprint || uprint || aprint || xprint)
4866                 printeroff();
4867               cprint = xprint = uprint = 0;
4868               setaprint(0);
4869               break;
4870             case 1:
4871               if (!(cprint || uprint || aprint || xprint))
4872                 printeron();
4873               setaprint(1);
4874               cprint = xprint = uprint = 0;
4875               break;
4876             case 2:
4877               if (!(cprint || uprint || aprint || xprint))
4878                 printeron();
4879               cprint = 1;
4880               setaprint(0);
4881               xprint = uprint = 0;
4882               break;
4883             case 3:
4884               if (!(cprint || uprint || aprint || xprint))
4885                 printeron();
4886               uprint = 1;
4887               setaprint(0);
4888               xprint = cprint = 0;
4889               break;
4890           }
4891           return(1);
4892       }
4893 #else
4894 #ifdef XPRINT
4895       case XYTPRN: {
4896           extern int tt_print;
4897           if ((x = seton(&tt_print)) < 0)
4898             return(x);
4899           return(success = 1);
4900       }
4901 #endif /* XPRINT */
4902 #endif /* OS2 */
4903
4904 #ifdef OS2
4905       case XYTSCNM: {
4906           extern int decscnm, decscnm_usr;
4907           if ((y = cmkey(normrev,4,"",
4908                          decscnm_usr?"reverse":"normal",
4909                          xxstring)
4910                ) < 0)
4911             return(y);
4912           if ((x = cmcfm()) < 0) return(x);
4913           decscnm_usr = y;
4914           if (decscnm != decscnm_usr)
4915             flipscreen(VTERM);
4916           return(1);
4917     }
4918     case XYTOPTI:
4919         if ((y = cmkey(onoff,2,"",tt_diff_upd?"on":"off",
4920                         xxstring)) < 0) return(y);
4921         if ((x = cmcfm()) < 0) return(x);
4922         tt_diff_upd = y;
4923         return(1);
4924     case XYTUPD: {
4925         int mode, delay;
4926         if ((mode = cmkey(scrnupd,nscrnupd,"","fast",xxstring)) < 0) {
4927             return(mode);
4928         } else {
4929             y = cmnum(
4930             "Pause between FAST screen updates in CONNECT mode, milliseconds",
4931                       "100",10,&x,xxstring
4932                       );
4933             if (x < 0 || x > 1000 ) {
4934                 printf(
4935             "\n?The update rate must be between 0 and 1000 milliseconds.\n"
4936                        );
4937                 return(success = 0);
4938             }
4939             if ((y = cmcfm()) < 0) return(y);
4940
4941             updmode = tt_updmode = mode;
4942             return(setnum(&tt_update,x,y,10000));
4943         }
4944     }
4945     case XYTCTRL:
4946           if ((x = cmkey(termctrl,ntermctrl,"","7",xxstring)) < 0) {
4947               return(x);
4948           } else {
4949               if ((y = cmcfm()) < 0)
4950                   return(y);
4951               switch ( x ) {
4952               case 8:
4953                   send_c1 = send_c1_usr = TRUE;
4954                   break;
4955               case 7:
4956               default:
4957                   send_c1 = send_c1_usr = FALSE;
4958                   break;
4959               }
4960           }
4961           return(success = TRUE);
4962           break;
4963
4964 #ifdef PCFONTS
4965       case XYTFON:
4966         if ( !IsOS2FullScreen() ) {
4967             printf(
4968         "\n?SET TERMINAL FONT is only supported in Full Screen sessions.\n");
4969             return(success = FALSE);
4970         }
4971
4972         if ((x = cmkey(term_font,ntermfont,"","default",xxstring)) < 0) {
4973             return(x);
4974         } else {
4975             if ((y = cmcfm()) < 0) return(y);
4976             if ( !os2LoadPCFonts() ) {
4977                 tt_font = x;
4978                 return(success = TRUE);
4979             } else {
4980                 printf(
4981       "\n?PCFONTS.DLL is not available in CKERMIT executable directory.\n");
4982                 return(success = FALSE);
4983             }
4984         }
4985         break;
4986 #else /* PCFONTS */
4987 #ifdef NT
4988 #ifdef KUI
4989     case XYTFON:
4990         return(setguifont());           /* ckuus3.c */
4991 #endif /* KUI */
4992 #endif /* NT */
4993 #endif /* PCFONTS */
4994
4995       case XYTVCH: {
4996           extern int pheight, marginbot, cmd_rows, cmd_cols;
4997           if ((x = cmkey(tvctab,ntvctab,"",isWin95()?"win95-safe":"enabled",
4998                          xxstring)) < 0)
4999             return(x);
5000           if ((y = cmcfm()) < 0) return(y);
5001 #ifndef KUI
5002           if (x != tt_modechg) {
5003               switch (x) {
5004                 case TVC_DIS:
5005                   /* When disabled the heights of all of the virtual screens */
5006                   /* must be equal to the physical height of the console     */
5007                   /* window and may not be changed.                          */
5008                   /* The width of the window may not be altered.             */
5009                   tt_modechg = TVC_ENA;                 /* Temporary */
5010                   if (marginbot > pheight-(tt_status[VTERM]?1:0))
5011                     marginbot = pheight-(tt_status[VTERM]?1:0);
5012                   tt_szchng[VCMD] = 1 ;
5013                   tt_rows[VCMD] = pheight;
5014                   VscrnInit(VCMD);
5015                   SetCols(VCMD);
5016                   cmd_rows = y;
5017
5018                   tt_szchng[VTERM] = 2 ;
5019                   tt_rows[VTERM] = pheight - (tt_status[VTERM]?1:0);
5020                   VscrnInit(VTERM);
5021
5022                   break;
5023
5024                 case TVC_ENA:
5025                   /* When enabled the physical height of the console windows */
5026                   /* should be adjusted to the height of the virtual screen  */
5027                   /* The width may be set to anything.                       */
5028                   /* nothing to do                                           */
5029                   break;
5030
5031               case TVC_W95:
5032                   /* Win95-safe mode allows the physical height to change    */
5033                   /* but restricts it to a width of 80 and a height equal to */
5034                   /* 25, 43, or 50.  Must be adjusted now.                   */
5035                   /* The virtual heights must be equal to the above.         */
5036                   if (pheight != 25 && pheight != 43 && pheight != 50) {
5037                       if (pheight < 25)
5038                         y = 25;
5039                       else if (pheight < 43)
5040                         y = 43;
5041                       else
5042                         y = 50;
5043                   } else
5044                     y = pheight;
5045
5046                   tt_modechg = TVC_ENA; /* Temporary */
5047
5048                   tt_szchng[VCMD] = 1;
5049                   tt_rows[VCMD] = y;
5050                   tt_cols[VCMD] = 80;
5051                   VscrnInit(VCMD);
5052                   SetCols(VCMD);
5053                   cmd_rows = y;
5054                   cmd_cols = 80;
5055
5056                   marginbot = y-(tt_status[VTERM]?1:0);
5057                   tt_szchng[VTERM] = 2;
5058                   tt_rows[VTERM] = y - (tt_status[VTERM]?1:0);
5059                   tt_cols[VTERM] = 80;
5060                   VscrnInit(VTERM);
5061                   break;
5062               }
5063               tt_modechg = x;
5064           }
5065           return(success = 1);
5066 #else
5067           return(success = 0);
5068 #endif /* KUI */
5069       }
5070       case XYTSTAT: {
5071           extern int marginbot;
5072           if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
5073           if ((x = cmcfm()) < 0) return(x);
5074           if (y != tt_status[VTERM] || y != tt_status_usr[VTERM]) {
5075               /* Might need to fixup the margins */
5076               if ( marginbot == VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) )
5077                 if (y) {
5078                     marginbot--;
5079                 } else {
5080                     marginbot++;
5081                 }
5082               tt_status_usr[VTERM] = tt_status[VTERM] = y;
5083               if (y) {
5084                     tt_szchng[VTERM] = 2;
5085                     tt_rows[VTERM]--;
5086                     VscrnInit(VTERM);  /* Height set here */
5087 #ifdef TNCODE
5088                     if (TELOPT_ME(TELOPT_NAWS))
5089                       tn_snaws();
5090 #endif /* TNCODE */
5091 #ifdef RLOGCODE
5092                     if (TELOPT_ME(TELOPT_NAWS))
5093                       rlog_naws();
5094 #endif /* RLOGCODE */
5095 #ifdef SSHBUILTIN
5096                     if (TELOPT_ME(TELOPT_NAWS))
5097                       ssh_snaws();
5098 #endif /* SSHBUILTIN */
5099               } else {
5100                   tt_szchng[VTERM] = 1;
5101                   tt_rows[VTERM]++;
5102                   VscrnInit(VTERM);     /* Height set here */
5103 #ifdef TNCODE
5104                   if (TELOPT_ME(TELOPT_NAWS))
5105                     tn_snaws();
5106 #endif /* TNCODE */
5107 #ifdef RLOGCODE
5108                   if (TELOPT_ME(TELOPT_NAWS))
5109                     rlog_naws();
5110 #endif /* RLOGCODE */
5111 #ifdef SSHBUILTIN
5112                   if (TELOPT_ME(TELOPT_NAWS))
5113                     ssh_snaws();
5114 #endif /* SSHBUILTIN */
5115               }
5116           }
5117           return(1);
5118       }
5119 #endif /* OS2 */
5120
5121 #ifdef NT
5122       case XYTATTBUG:
5123         if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
5124         if ((x = cmcfm()) < 0) return(x);
5125         tt_attr_bug = y;
5126         return(1);
5127 #endif /* NT */
5128
5129 #ifdef OS2
5130       case XYTSGRC:
5131         if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
5132         if ((x = cmcfm()) < 0) return(x);
5133         sgrcolors = y;
5134         return(1);
5135
5136       case XYTSEND:
5137           if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
5138           if ((x = cmcfm()) < 0) return(x);
5139           tt_senddata = y;
5140           return(1);
5141
5142       case XYTSEOB:
5143           if ((y = cmkey(ttyseobtab,2,"","us_cr",xxstring)) < 0) return(y);
5144           if ((x = cmcfm()) < 0) return(x);
5145           wy_blockend = y;
5146           return(1);
5147
5148       case XYTURLHI: {
5149           int done = 0, attr = VT_CHAR_ATTR_NORMAL;
5150
5151           if ((x = cmkey(onoff,2,"","on",xxstring)) < 0)
5152             return(x);
5153           if (x) {
5154               z = 0;
5155               while (!done) {
5156                   if ((y = cmkey(ttyprotab,nprotect,"",
5157                                  z?"done":"reverse",xxstring)) < 0)
5158                     return(y);
5159                   switch (y) {
5160                     case TTATTDONE:
5161                       done = TRUE;
5162                       break;
5163                     case TTATTBLI:
5164                       attr |= VT_CHAR_ATTR_BLINK;
5165                       break;
5166                     case TTATTREV:
5167                       attr |= VT_CHAR_ATTR_REVERSE;
5168                       break;
5169                     case TTATTITA:
5170                       attr |= VT_CHAR_ATTR_ITALIC;
5171                       break;
5172                     case TTATTUND:
5173                       attr |= VT_CHAR_ATTR_UNDERLINE;
5174                       break;
5175                     case TTATTBLD:
5176                       attr |= VT_CHAR_ATTR_BOLD;
5177                       break;
5178                     case TTATTDIM:
5179                       attr |= VT_CHAR_ATTR_DIM;
5180                       break;
5181                     case TTATTINV:
5182                       attr |= VT_CHAR_ATTR_INVISIBLE;
5183                       break;
5184                     case TTATTNOR:
5185                       break;
5186                   }
5187                   z = 1;                /* One attribute has been chosen */
5188               }
5189           }
5190           if ((z = cmcfm()) < 0) return(z);
5191           seturlhl(x);
5192           if (x)
5193             tt_url_hilite_attr = attr;
5194           return(1);
5195       }
5196       case XYTATTR:
5197         if ((x = cmkey(ttyattrtab,nattrib,"","underline",xxstring)) < 0)
5198           return(x);
5199         switch (x) {
5200           case TTATTBLI:
5201             if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
5202             if ((x = cmcfm()) < 0) return(x);
5203             trueblink = y;
5204 #ifndef KUI
5205             if ( !trueblink && trueunderline ) {
5206                 trueunderline = 0;
5207                 printf("Warning: Underline being simulated by color.\n");
5208             }
5209
5210 #endif /* KUI */
5211             break;
5212
5213           case TTATTDIM:
5214             if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
5215             if ((x = cmcfm()) < 0) return(x);
5216             truedim = y;
5217             break;
5218
5219           case TTATTREV:
5220             if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
5221             if ((x = cmcfm()) < 0) return(x);
5222             truereverse = y;
5223             break;
5224
5225           case TTATTUND:
5226             if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
5227             if ((x = cmcfm()) < 0) return(x);
5228             trueunderline = y;
5229 #ifndef KUI
5230             if (!trueblink && trueunderline) {
5231                 trueblink = 1;
5232                 printf("Warning: True blink mode is active.\n");
5233             }
5234 #endif /* KUI */
5235             break;
5236
5237           case TTATTITA:
5238               if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
5239               if ((x = cmcfm()) < 0) return(x);
5240               trueitalic = y;
5241             break;
5242
5243           case TTATTPRO: {      /* Set default Protected Character attribute */
5244               extern vtattrib WPattrib;    /* current WP Mode Attrib */
5245               extern vtattrib defWPattrib; /* default WP Mode Attrib */
5246               vtattrib wpa = {0,0,0,0,0,1,0,0,0,0,0};   /* Protected */
5247               int done = 0;
5248
5249               x = 0;
5250               while (!done) {
5251                   if ((y = cmkey(ttyprotab,nprotect,"",
5252                                  x?"done":"dim",xxstring)) < 0)
5253                     return(y);
5254                   switch (y) {
5255                     case TTATTNOR:
5256                       break;
5257                     case TTATTBLI:      /* Blinking doesn't work */
5258                       wpa.blinking = TRUE;
5259                       break;
5260                     case TTATTREV:
5261                       wpa.reversed = TRUE;
5262                       break;
5263                     case TTATTITA:
5264                       wpa.italic = TRUE;
5265                       break;
5266                     case TTATTUND:
5267                       wpa.underlined = TRUE;
5268                       break;
5269                     case TTATTBLD:
5270                       wpa.bold = TRUE;
5271                       break;
5272                     case TTATTDIM:
5273                       wpa.dim = TRUE;
5274                       break;
5275                     case TTATTINV:
5276                       wpa.invisible = TRUE ;
5277                       break;
5278                     case TTATTDONE:
5279                       done = TRUE;
5280                       break;
5281                   }
5282                   x = 1;                /* One attribute has been chosen */
5283               }
5284               if ((x = cmcfm()) < 0) return(x);
5285               WPattrib = defWPattrib = wpa;
5286               break;
5287           }
5288         }
5289         return(1);
5290
5291       case XYTKEY: {                    /* SET TERMINAL KEY */
5292           int t, x, y;
5293           int clear = 0, deflt = 0;
5294           int confirmed = 0;
5295           int flag = 0;
5296           int kc = -1;                  /* Key code */
5297           int litstr = 0;               /* Literal String? */
5298           char *s = NULL;               /* Key binding */
5299 #ifndef NOKVERBS
5300           char *p = NULL;               /* Worker */
5301 #endif /* NOKVERBS */
5302           con_event defevt;
5303           extern int os2gks;
5304           extern int mskkeys;
5305           extern int initvik;
5306           struct FDB kw,sw,nu,cm;
5307
5308           defevt.type = error;
5309
5310           if ((t = cmkey(ttkeytab,nttkey,"","",xxstring)) < 0)
5311             return(t);
5312           cmfdbi(&nu,                   /* First FDB - command switches */
5313                  _CMNUM,                /* fcode */
5314                  "/literal, keycode, or action",
5315                  "",                    /* default */
5316                  "",                    /* addtl string data */
5317                  10,                    /* addtl numeric data 1: radix */
5318                  0,                     /* addtl numeric data 2: 0 */
5319                  xxstring,              /* Processing function */
5320                  NULL,                  /* Keyword table */
5321                  &sw                    /* Pointer to next FDB */
5322                  );                     /*  */
5323           cmfdbi(&sw,                   /* Second FDB - switches */
5324                  _CMKEY,                /* fcode */
5325                  "",
5326                  "",                    /* default */
5327                  "",                    /* addtl string data */
5328                  nstrmswitab,           /* addtl numeric data 1: tbl size */
5329                  4,                     /* addtl numeric data 2: 4 = cmswi */
5330                  xxstring,              /* Processing function */
5331                  strmswitab,            /* Keyword table */
5332                  &kw                    /* Pointer to next FDB */
5333                  );
5334           cmfdbi(&kw,                   /* Third FDB - command switches */
5335                  _CMKEY,                /* fcode */
5336                  "/literal, keycode, or action",
5337                  "",                    /* default */
5338                  "",                    /* addtl string data */
5339                  nstrmkeytab,           /* addtl numeric data 1: tbl size */
5340                  0,                     /* addtl numeric data 2 */
5341                  xxstring,              /* Processing function */
5342                  strmkeytab,            /* Keyword table */
5343                  &cm                    /* Pointer to next FDB */
5344                  );
5345           cmfdbi(&cm,                   /* Final FDB - Confirmation */
5346                  _CMCFM,                /* fcode */
5347                  "",
5348                  "",                    /* default */
5349                  "",                    /* addtl string data */
5350                  0,                     /* addtl numeric data 1: tbl size */
5351                  0,                     /* addtl numeric data 2: 4 = cmswi */
5352                  xxstring,              /* Processing function */
5353                  NULL,                  /* Keyword table */
5354                  NULL                   /* Pointer to next FDB */
5355                  );
5356           while (kc < 0) {
5357               x = cmfdb(&nu);           /* Parse something */
5358               if (x < 0)
5359                 return(x);
5360
5361               switch (cmresult.fcode) {
5362                 case _CMCFM:
5363                   printf(" Press key to be defined: ");
5364                   conbin((char)escape); /* Put terminal in binary mode */
5365                   os2gks = 0;           /* Turn off Kverb preprocessing */
5366                   kc = congks(0);       /* Get character or scan code */
5367                   os2gks = 1;           /* Turn on Kverb preprocessing */
5368                   concb((char)escape);  /* Restore terminal to cbreak mode */
5369                   if (kc < 0) {         /* Check for error */
5370                       printf("?Error reading key\n");
5371                       return(0);
5372                   }
5373                   shokeycode(kc,t);     /* Show current definition */
5374                   flag = 1;             /* Remember it's a multiline command */
5375                   break;
5376                 case _CMNUM:
5377                   kc = cmresult.nresult;
5378                   break;
5379                 case _CMKEY:
5380                   if (cmresult.fdbaddr == &sw) { /* Switch */
5381                       if (cmresult.nresult == 0)
5382                         litstr = 1;
5383                   } else if (cmresult.fdbaddr == &kw) { /* Keyword */
5384                       if (cmresult.nresult == 0)
5385                         clear = 1;
5386                       else
5387                         deflt = 1;
5388                       if ((x = cmcfm()) < 0)
5389                         return(x);
5390                       if (clear)
5391                         clearkeymap(t);
5392                       else if (deflt)
5393                         defaultkeymap(t);
5394                       initvik = 1;
5395                       return(1);
5396                   }
5397               }
5398           }
5399
5400     /* Normal SET TERMINAL KEY <terminal> <scancode> <value> command... */
5401
5402           if (mskkeys)
5403             kc = msktock(kc);
5404
5405           if (kc < 0 || kc >= KMSIZE) {
5406               printf("?key code must be between 0 and %d\n", KMSIZE - 1);
5407               return(-9);
5408           }
5409           if (kc == escape) {
5410               printf("Sorry, %d is the CONNECT-mode escape character\n",kc);
5411               return(-9);
5412           }
5413           wideresult = -1;
5414           if (flag) {
5415               cmsavp(psave,PROMPTL);
5416               cmsetp(" Enter new definition: ");
5417               cmini(ckxech);
5418           }
5419         def_again:
5420           if (flag) prompt(NULL);
5421           if ((y = cmtxt("key definition,\n\
5422  or Ctrl-C to cancel this command,\n\
5423  or Enter to restore default definition",
5424                          "",&s,NULL)) < 0) {
5425               if (flag)                 /* Handle parse errors */
5426                 goto def_again;
5427               else
5428                 return(y);
5429           }
5430           s = brstrip(s);
5431 #ifndef NOKVERBS
5432           p = s;                        /* Save this place */
5433 #endif /* NOKVERBS */
5434 /*
5435   If the definition included any \Kverbs, quote the backslash so the \Kverb
5436   will still be in the definition when the key is pressed.  We don't do this
5437   in zzstring(), because \Kverbs are valid only in this context and nowhere
5438   else.
5439
5440   We use this code active for all versions that support SET KEY, even if they
5441   don't support \Kverbs, because otherwise \K would behave differently for
5442   different versions.
5443 */
5444           for (x = 0, y = 0; s[x]; x++, y++) { /* Convert \K to \\K */
5445               if ((x > 0) &&
5446                   (s[x] == 'K' || s[x] == 'k')
5447                   ) {                   /* Have K */
5448
5449                   if ((x == 1 && s[x-1] == CMDQ) ||
5450                       (x > 1 && s[x-1] == CMDQ && s[x-2] != CMDQ)) {
5451                       line[y++] = CMDQ; /* Make it \\K */
5452                   }
5453                   if (x > 1 && s[x-1] == '{' && s[x-2] == CMDQ) {
5454                       line[y-1] = CMDQ; /* Have \{K */
5455                       line[y++] = '{';  /* Make it \\{K */
5456                   }
5457               }
5458               line[y] = s[x];
5459           }
5460           line[y++] = NUL;              /* Terminate */
5461           s = line + y + 1;             /* Point to after it */
5462           x = LINBUFSIZ - (int) strlen(line) - 1; /* Get remaining space */
5463           if ((x < (LINBUFSIZ / 2)) ||
5464               (zzstring(line, &s, &x) < 0)) { /* Expand variables, etc. */
5465               printf("?Key definition too long\n");
5466               if (flag) cmsetp(psave);
5467               return(-9);
5468           }
5469           s = line + y + 1;             /* Point to result. */
5470
5471 #ifndef NOKVERBS
5472 /*
5473   Special case: see if the definition starts with a \Kverb.
5474   If it does, point to it with p, otherwise set p to NULL.
5475 */
5476           p = s;
5477           if (*p++ == CMDQ) {
5478               if (*p == '{') p++;
5479               p = (*p == 'k' || *p == 'K') ? p + 1 : NULL;
5480           }
5481 #endif /* NOKVERBS */
5482
5483           switch (strlen(s)) {          /* Action depends on length */
5484             case 0:                     /* Clear individual key def */
5485               deletekeymap(t,kc);
5486               break;
5487             case 1:
5488               if (!litstr) {
5489                   defevt.type = key;    /* Single character */
5490                   defevt.key.scancode = *s;
5491                   break;
5492               }
5493             default:                    /* Character string */
5494 #ifndef NOKVERBS
5495               if (p) {
5496                   y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */
5497                   /* Need exact match */
5498                   debug(F101,"set key kverb lookup",0,y);
5499                   if (y > -1) {
5500                       defevt.type = kverb;
5501                       defevt.kverb.id = y;
5502                       break;
5503                   }
5504               }
5505 #endif /* NOKVERBS */
5506               if (litstr) {
5507                   defevt.type = literal;
5508                   defevt.literal.string = (char *) malloc(strlen(s)+1);
5509                   if (defevt.literal.string)
5510                     strcpy(defevt.literal.string, s); /* safe */
5511               } else {
5512                   defevt.type = macro;
5513                   defevt.macro.string = (char *) malloc(strlen(s)+1);
5514                   if (defevt.macro.string)
5515                     strcpy(defevt.macro.string, s); /* safe */
5516               }
5517               break;
5518           }
5519           insertkeymap(t, kc, defevt);
5520           if (flag)
5521             cmsetp(psave);
5522           initvik = 1;                  /* Update VIK table */
5523           return(1);
5524       }
5525
5526 #ifdef PCTERM
5527       case XYTPCTERM:                   /* PCTERM Keyboard Mode */
5528         if ((x = seton(&tt_pcterm)) < 0) return(x);
5529         return(success = 1);
5530 #endif /* PCTERM */
5531 #endif /* OS2 */
5532
5533 #ifdef CK_TRIGGER
5534       case XYTRIGGER:
5535         if ((y = cmtxt("String to trigger automatic return to command mode",
5536                        "",&s,xxstring)) < 0)
5537           return(y);
5538         makelist(s,tt_trigger,TRIGGERS);
5539         return(1);
5540 #endif /* CK_TRIGGER */
5541
5542 #ifdef OS2
5543       case XYTSAC:
5544         if ((y = cmnum("ASCII value to use for spacing attributes",
5545                        "32",10,&x,xxstring)) < 0)
5546           return(y);
5547         if ((y = cmcfm()) < 0) return(y);
5548         tt_sac = x;
5549         return(success = 1);
5550
5551       case XYTKBDGL: {      /* SET TERM KBD-FOLLOWS-GL/GR */
5552           extern int tt_kb_glgr;        /* from ckoco3.c */
5553           if ((x = seton(&tt_kb_glgr)) < 0)
5554               return(x);
5555           return(success = 1);
5556       }
5557 #ifndef NOCSETS
5558       case XYTVTLNG:        /* SET TERM DEC-LANGUAGE */
5559         if ((y = cmkey(vtlangtab,nvtlangtab,"VT language",
5560                        IS97801(tt_type_mode)?"german":"north-american",
5561                        xxstring)) < 0)
5562           return(y);
5563         if ((x = cmcfm()) < 0) return(x);
5564
5565         /* A real VT terminal would use the language to set the   */
5566         /* default keyboard language for both 8-bit multinational */
5567         /* and 7-bit national modes.  For 8-bit mode it would     */
5568         /* set the terminal character-set to the ISO set if it    */
5569         /* is not already set.                                    */
5570         /* Latin-1 can be replaced by DEC Multinational           */
5571         switch (y) {
5572           case VTL_NORTH_AM:  /* North American */
5573             /* Multinational: Latin-1   */
5574             /* National:      US_ASCII  */
5575             dec_lang = y;
5576             dec_nrc = TX_ASCII;
5577             dec_kbd = TX_8859_1;
5578             break;
5579           case VTL_BRITISH :
5580             /* Multinational: Latin-1   */
5581             /* National:      UK_ASCII  */
5582             dec_lang = y;
5583             dec_nrc = TX_BRITISH;
5584             dec_kbd = TX_8859_1;
5585             break;
5586           case VTL_FRENCH  :
5587           case VTL_BELGIAN :
5588           case VTL_CANADIAN:
5589             /* Multinational: Latin-1   */
5590             /* National:      FR_ASCII  */
5591             dec_lang = y;
5592             dec_nrc = TX_FRENCH;
5593             dec_kbd = TX_8859_1;
5594             break;
5595           case VTL_FR_CAN  :
5596             /* Multinational: Latin-1   */
5597             /* National:      FC_ASCII  */
5598             dec_lang = y;
5599             dec_nrc = TX_CN_FRENCH;
5600             dec_kbd = TX_8859_1;
5601             break;
5602           case VTL_DANISH  :
5603           case VTL_NORWEGIA:
5604             /* Multinational: Latin-1   */
5605             /* National:      NO_ASCII  */
5606             dec_lang = y;
5607             dec_nrc = TX_NORWEGIAN;
5608             dec_kbd = TX_8859_1;
5609             break;
5610           case VTL_FINNISH :
5611             /* Multinational: Latin-1   */
5612             /* National:      FI_ASCII  */
5613             dec_lang = y;
5614             dec_nrc = TX_FINNISH;
5615             dec_kbd = TX_8859_1;
5616             break;
5617           case VTL_GERMAN  :
5618             /* Multinational: Latin-1   */
5619             /* National:      GR_ASCII  */
5620             dec_lang = y;
5621             dec_nrc = TX_GERMAN;
5622             dec_kbd = TX_8859_1;
5623             break;
5624           case VTL_DUTCH   :
5625             /* Multinational: Latin-1   */
5626             /* National:      DU_ASCII  */
5627             dec_lang = y;
5628             dec_nrc = TX_DUTCH;
5629             dec_kbd = TX_8859_1;
5630             break;
5631           case VTL_ITALIAN :
5632             /* Multinational: Latin-1   */
5633             /* National:      IT_ASCII  */
5634             dec_lang = y;
5635             dec_nrc = TX_ITALIAN;
5636             dec_kbd = TX_8859_1;
5637             break;
5638           case VTL_SW_FR   :
5639           case VTL_SW_GR   :
5640             /* Multinational: Latin-1   */
5641             /* National:      CH_ASCII  */
5642             dec_lang = y;
5643             dec_nrc = TX_SWISS;
5644             dec_kbd = TX_8859_1;
5645             break;
5646           case VTL_SWEDISH :
5647             /* Multinational: Latin-1   */
5648             /* National:      SW_ASCII  */
5649             dec_lang = y;
5650             dec_nrc = TX_SWEDISH;
5651             dec_kbd = TX_8859_1;
5652             break;
5653           case VTL_SPANISH :
5654             /* Multinational: Latin-1   */
5655             /* National:      SP_ASCII  */
5656             dec_lang = y;
5657             dec_nrc = TX_SPANISH;
5658             dec_kbd = TX_8859_1;
5659             break;
5660           case VTL_PORTUGES:
5661             /* Multinational: Latin-1   */
5662             /* National:      Portugese ASCII  */
5663             dec_lang = y;
5664             dec_nrc = TX_PORTUGUESE;
5665             dec_kbd = TX_8859_1;
5666             break;
5667           case VTL_HEBREW  :
5668             /* Multinational: Latin-Hebrew / DEC-Hebrew  */
5669             /* National:      DEC 7-bit Hebrew  */
5670             dec_lang = y;
5671             dec_nrc = TX_HE7;
5672             dec_kbd = TX_8859_8;
5673             break;
5674           case VTL_GREEK   :
5675             /* Multinational: Latin-Greek / DEC-Greek   */
5676             /* National:      DEC Greek NRC             */
5677             /* is ELOT927 equivalent to DEC Greek????   */
5678             dec_lang = y;
5679             dec_nrc = TX_ELOT927;
5680             dec_kbd = TX_8859_7;
5681             break;
5682 #ifdef COMMENT
5683           case VTL_TURK_Q  :
5684           case VTL_TURK_F  :
5685             /* Multinational: Latin-Turkish / DEC-Turkish   */
5686             /* National:      DEC 7-bit Turkish             */
5687             break;
5688 #endif /* COMMENT */
5689           case VTL_HUNGARIA:
5690             /* Multinational: Latin-2   */
5691             /* National:      no national mode  */
5692             dec_lang = y;
5693             dec_nrc = TX_HUNGARIAN;
5694             dec_kbd = TX_8859_2;
5695             break;
5696           case VTL_SLOVAK  :
5697           case VTL_CZECH   :
5698           case VTL_POLISH  :
5699           case VTL_ROMANIAN:
5700             /* Multinational: Latin-2   */
5701             /* National:      no national mode  */
5702             dec_lang = y;
5703             dec_nrc = TX_ASCII;
5704             dec_kbd = TX_8859_2;
5705             break;
5706           case VTL_RUSSIAN :
5707             /* Multinational: Latin-Cyrillic / KOI-8   */
5708             /* National:      DEC Russian NRC  */
5709             dec_lang = y;
5710             dec_nrc = TX_KOI7;
5711             dec_kbd = TX_8859_5;
5712             break;
5713           case VTL_LATIN_AM:
5714             /* Multinational: not listed in table   */
5715             /* National:      not listed in table  */
5716             dec_lang = y;
5717             dec_nrc = TX_ASCII;
5718             dec_kbd = TX_8859_1;
5719             break;
5720 #ifdef COMMENT
5721           case VTL_SCS     :
5722             /* Multinational: Latin-2   */
5723             /* National:      SCS NRC   */
5724             break;
5725 #endif /* COMMENT */
5726           default:
5727             return(success = 0);
5728         }
5729         if (IS97801(tt_type_mode)) {
5730             SNI_bitmode(cmask == 0377 ? 8 : 7);
5731         }
5732         return(success = 1);
5733 #endif /* NOCSETS */
5734
5735       case XYTVTNRC: {                  /* SET TERM DEC-NRC-MODE */
5736           extern int decnrcm_usr, decnrcm;        /* from ckoco3.c */
5737           if ((x = seton(&decnrcm_usr)) < 0)
5738             return(x);
5739           decnrcm = decnrcm_usr;
5740           return(success = 1);
5741       }
5742       case XYTSNIPM: {                  /* SET TERM SNI-PAGEMODE */
5743           extern int sni_pagemode, sni_pagemode_usr;
5744           if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
5745           if ((x = cmcfm()) < 0) return(x);
5746           sni_pagemode_usr = sni_pagemode = y;
5747           return(success = 1);
5748       }
5749       case XYTSNISM: {                  /* SET TERM SNI-SCROLLMODE */
5750           extern int sni_scroll_mode, sni_scroll_mode_usr;
5751           if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
5752           if ((x = cmcfm()) < 0) return(x);
5753           sni_scroll_mode_usr = sni_scroll_mode = y;
5754           return(success = 1);
5755       }
5756       case XYTSNICC: {  /* SET TERM SNI-CH.CODE */
5757           extern int sni_chcode_usr;
5758           if ((y = cmkey(onoff,2,"","on",xxstring)) < 0) return(y);
5759           if ((x = cmcfm()) < 0) return(x);
5760           sni_chcode_usr = y;
5761           SNI_chcode(y);
5762           return(success = 1);
5763       }
5764       case XYTSNIFV: {  /* SET TERM SNI-FIRMWARE-VERSIONS */
5765           extern CHAR sni_kbd_firmware[], sni_term_firmware[];
5766           CHAR kbd[7],term[7];
5767
5768           if ((x = cmfld("Keyboard Firmware Version",sni_kbd_firmware,
5769                          &s, xxstring)) < 0)
5770             return(x);
5771           if ((int)strlen(s) != 6) {
5772               printf("?Sorry - the firmware version must be 6 digits long\n");
5773               return(-9);
5774           }
5775           for (i = 0; i < 6; i++) {
5776               if (!isdigit(s[i])) {
5777    printf("?Sorry - the firmware version can only contain digits [0-9]\n");
5778                   return(-9);
5779               }
5780           }
5781           ckstrncpy(kbd,s,7);
5782
5783           if ((x = cmfld("Terminal Firmware Version",sni_term_firmware,
5784                          &s, xxstring)) < 0)
5785             return(x);
5786           if ((int)strlen(s) != 6) {
5787               printf("?Sorry - the firmware version must be 6 digits long\n");
5788               return(-9);
5789           }
5790           for (i = 0; i < 6; i++) {
5791               if (!isdigit(s[i])) {
5792    printf("?Sorry - the firmware version can only contain digits [0-9]\n");
5793                    return(-9);
5794               }
5795           }
5796           ckstrncpy(term,s,7);
5797           if ((x = cmcfm()) < 0) return(x);
5798
5799           ckstrncpy(sni_kbd_firmware,kbd,7);
5800           ckstrncpy(sni_term_firmware,term,7);
5801           return(success = 1);
5802     }
5803
5804     case XYTLSP: {              /* SET TERM LINE-SPACING */
5805         if ((x = cmfld("Line Spacing","1",&s, xxstring)) < 0)
5806           return(x);
5807         if (isfloat(s,0) < 1) {         /* (sets floatval) */
5808             printf("?Integer or floating-point number required\n");
5809             return(-9);
5810         }
5811         if (floatval < 1.0 || floatval > 3.0) {
5812             printf("?Value must within the range 1.0 and 3.0 (inclusive)\n");
5813             return(-9);
5814         }
5815         if ((x = cmcfm()) < 0) return(x);
5816 #ifdef KUI
5817         tt_linespacing[VCMD] = tt_linespacing[VTERM] = floatval;
5818         return(success = 1);
5819 #else /* KUI */
5820         printf("?Sorry, Line-spacing is only supported in K95G.EXE.\n");
5821         return(success = 0);
5822 #endif /* KUI */
5823     }
5824 #endif /* OS2 */
5825
5826       default:                          /* Shouldn't get here. */
5827         return(-2);
5828     }
5829 #endif /* MAC */
5830 #ifdef COMMENT
5831     /*
5832       This was supposed to shut up picky compilers but instead it makes
5833       most compilers complain about "statement not reached".
5834     */
5835     return(-2);
5836 #endif /* COMMENT */
5837 #ifdef OS2
5838 return(-2);
5839 #endif /* OS2 */
5840 }
5841
5842 #ifdef OS2
5843 int
5844 settitle(void) {
5845     extern char usertitle[];
5846     if ((y = cmtxt("title text","",&s,xxstring)) < 0)
5847       return(y);
5848 #ifdef IKSD
5849     if (inserver) {
5850         printf("?Sorry, command disabled.\r\n");
5851         return(success = 0);
5852     }
5853 #endif /* IKSD */
5854     s = brstrip(s);
5855     ckstrncpy(usertitle,s,64);
5856     os2settitle("",1);
5857     return(1);
5858 }
5859
5860 static struct keytab dialertab[] = {    /* K95 Dialer types */
5861     "backspace",        0, 0,
5862     "enter",            1, 0
5863 };
5864 static int ndialer = 2;
5865
5866 int
5867 setdialer(void) {
5868     int t, x, y;
5869     int clear = 0, deflt = 0;
5870     int kc;                             /* Key code */
5871     char *s = NULL;                     /* Key binding */
5872 #ifndef NOKVERBS
5873     char *p = NULL;                     /* Worker */
5874 #endif /* NOKVERBS */
5875     con_event defevt;
5876     extern int os2gks;
5877     extern int mskkeys;
5878     extern int initvik;
5879
5880     defevt.type = error;
5881
5882     if (( x = cmkey(dialertab, ndialer,
5883                     "Kermit-95 dialer work-arounds",
5884                     "", xxstring)) < 0 )
5885       return(x);
5886     switch (x) {
5887       case 0:                           /* Backspace */
5888         kc = 264;
5889         break;
5890       case 1:                           /* Enter */
5891         kc = 269;
5892         break;
5893       default:
5894         printf("Illegal value in setdialer()\n");
5895         return(-9);
5896     }
5897     if ((y = cmtxt("Key definition","",&s,xxstring)) < 0)
5898       return(y);
5899
5900 #ifdef IKSD
5901     if (inserver) {
5902         printf("?Sorry, command disabled.\r\n");
5903         return(success = 0);
5904     }
5905 #endif /* IKSD */
5906     s = brstrip(s);
5907 #ifndef NOKVERBS
5908     p = s;                              /* Save this place */
5909 #endif /* NOKVERBS */
5910 /*
5911   If the definition included any \Kverbs, quote the backslash so the \Kverb
5912   will still be in the definition when the key is pressed.  We don't do this
5913   in zzstring(), because \Kverbs are valid only in this context and nowhere
5914   else.
5915
5916   We use this code active for all versions that support SET KEY, even if they
5917   don't support \Kverbs, because otherwise \K would behave differently for
5918   different versions.
5919 */
5920     for (x = 0, y = 0; s[x]; x++, y++) { /* Convert \K to \\K */
5921         if ((x > 0) &&
5922             (s[x] == 'K' || s[x] == 'k')
5923             ) {                         /* Have K */
5924
5925             if ((x == 1 && s[x-1] == CMDQ) ||
5926                 (x > 1 && s[x-1] == CMDQ && s[x-2] != CMDQ)) {
5927                 line[y++] = CMDQ;       /* Make it \\K */
5928             }
5929             if (x > 1 && s[x-1] == '{' && s[x-2] == CMDQ) {
5930                 line[y-1] = CMDQ;       /* Have \{K */
5931                 line[y++] = '{';        /* Make it \\{K */
5932             }
5933         }
5934         line[y] = s[x];
5935     }
5936     line[y++] = NUL;                    /* Terminate */
5937     s = line + y + 1;                   /* Point to after it */
5938     x = LINBUFSIZ - (int) strlen(line) - 1; /* Calculate remaining space */
5939     if ((x < (LINBUFSIZ / 2)) ||
5940         (zzstring(line, &s, &x) < 0)) { /* Expand variables, etc. */
5941         printf("?Key definition too long\n");
5942         return(-9);
5943     }
5944     s = line + y + 1;                   /* Point to result. */
5945
5946 #ifndef NOKVERBS
5947 /*
5948   Special case: see if the definition starts with a \Kverb.
5949   If it does, point to it with p, otherwise set p to NULL.
5950 */
5951     p = s;
5952     if (*p++ == CMDQ) {
5953         if (*p == '{') p++;
5954         p = (*p == 'k' || *p == 'K') ? p + 1 : NULL;
5955     }
5956 #endif /* NOKVERBS */
5957
5958     /* Clear the definition for SET KEY */
5959     if (macrotab[kc]) {                 /* Possibly free old macro from key. */
5960         free((char *)macrotab[kc]);
5961         macrotab[kc] = NULL;
5962     }
5963     keymap[kc] = (KEY) kc;
5964
5965     /* Now reprogram the default value for all terminal types */
5966     /* remember to treat Wyse and Televideo terminals special */
5967     /* because of their use of Kverbs for Backspace and Enter */
5968     for (t = 0; t <= TT_MAX; t++) {
5969         if ( ISDG200(t) && kc == 264) {
5970             extern char * udkfkeys[] ;
5971             if (kc == 264) {            /* \Kdgbs */
5972                 if (udkfkeys[83])
5973                   free(udkfkeys[83]);
5974                 udkfkeys[83] = strdup(s);
5975             }
5976         } else if (ISWYSE(t) || ISTVI(t)) {
5977             extern char * udkfkeys[] ;
5978             if (kc == 264) {            /* \Kwybs or \Ktvibs */
5979                 if (udkfkeys[32])
5980                   free(udkfkeys[32]);
5981                 udkfkeys[32] = strdup(s);
5982             }
5983             if (kc == 269) {            /* \Kwyenter and \Kwyreturn */
5984                 if (udkfkeys[39])       /* \Ktvienter and \Ktvireturn */
5985                   free(udkfkeys[39]);
5986                 udkfkeys[39] = strdup(s);
5987                 if (udkfkeys[49])
5988                   free(udkfkeys[49]);
5989                 udkfkeys[49] = strdup(s);
5990             }
5991         } else {
5992             switch (strlen(s)) {        /* Action depends on length */
5993               case 0:                   /* Clear individual key def */
5994                 deletekeymap(t,kc);
5995                 break;
5996               case 1:
5997                 defevt.type = key;      /* Single character */
5998                 defevt.key.scancode = *s;
5999                 break;
6000               default:                  /* Character string */
6001 #ifndef NOKVERBS
6002                 if (p) {
6003                     y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */
6004                     /* Exact match req'd */
6005                     debug(F101,"set key kverb lookup",0,y);
6006                     if (y > -1) {
6007                         defevt.type = kverb;
6008                         defevt.kverb.id = y;
6009                         break;
6010                     }
6011                 }
6012 #endif /* NOKVERBS */
6013                 defevt.type = macro;
6014                 defevt.macro.string = (char *) malloc(strlen(s)+1);
6015                 if (defevt.macro.string)
6016                   strcpy(defevt.macro.string, s); /* safe */
6017                 break;
6018             }
6019             insertkeymap( t, kc, defevt ) ;
6020             initvik = 1;                /* Update VIK table */
6021         }
6022     }
6023     return(1);
6024 }
6025 #endif /* OS2 */
6026
6027 #ifdef NT
6028 int
6029 setwin95( void ) {
6030     int x, y, z;
6031
6032     if (( y = cmkey(win95tab, nwin95,
6033                     "Windows 95 specific work-arounds",
6034                     "keyboard-translation",
6035                     xxstring)) < 0 )
6036         return (y);
6037     switch (y) {
6038       case XYWPOPUP:
6039         if ((y = cmkey(onoff,2,"popups are used to prompt the user for data",
6040                        "on",xxstring)) < 0)
6041           return(y);
6042         if ((x = cmcfm()) < 0) return(x);
6043         win95_popup = y;
6044         return(1);
6045
6046       case XYW8_3:
6047         if ((y = cmkey(onoff,2,"8.3 FAT file names","off",xxstring)) < 0)
6048           return(y);
6049         if ((x = cmcfm()) < 0) return(x);
6050         win95_8_3 = y;
6051         return(1);
6052
6053       case XYWSELECT:
6054         if ((y = cmkey(onoff,2,"\"select()\" fails on write","off",
6055              xxstring)) < 0)
6056           return(y);
6057         if ((x = cmcfm()) < 0) return(x);
6058         win95selectbug = y;
6059         return(1);
6060
6061       case XYWAGR:
6062         if ((y = cmkey(onoff,2,"Right-Alt is Alt-Gr","off",xxstring)) < 0)
6063           return(y);
6064         if ((x = cmcfm()) < 0) return(x);
6065         win95altgr = y;
6066         return(1);
6067
6068       case XYWOIO:
6069         if ((y = cmkey(onoff,2,"Use Overlapped I/O","on",xxstring)) < 0)
6070           return(y);
6071         if (y) {
6072             if ((x = cmnum("Maximum number of outstanding I/O requests",
6073                            "10",10,&z,xxstring)) < 0)
6074               return(x);
6075             if (z < 1 || z > 7) {
6076                 printf(
6077 "?Maximum outstanding I/O requests must be between 1 and 7.\n");
6078                 return(-9);
6079             }
6080         } else
6081           z = 1;
6082         if ((x = cmcfm()) < 0) return(x);
6083         owwait = !y;
6084         maxow = maxow_usr = z;
6085         return(1);
6086
6087       case XYWKEY:
6088 #ifndef COMMENT
6089         printf("\n?\"Keyboard-Translation\" is no longer required.\n");
6090         return(-9);
6091 #else /* COMMENT */
6092         if (( z = cmkey(tcstab, ntcs,
6093                         "Keyboard Character Set",
6094                         "latin1-iso",
6095                         xxstring)) < 0)
6096           return (z);
6097         if ((x = cmcfm()) < 0)
6098           return(x);
6099
6100         win95kcsi = z;
6101         win95kl2 = (win95kcsi == TC_2LATIN);
6102
6103         if (win95kcsi == TC_TRANSP) {
6104             win95kcs = NULL;
6105         } else {
6106 #ifdef UNICODE
6107             win95kcs = xlr[win95kcsi][tx2fc(tcsl)];
6108 #else /* UNICODE */
6109             win95kcs = xlr[win95kcsi][tcsl];
6110 #endif /* UNICODE */
6111         }
6112         return(1);
6113 #endif /* COMMENT */
6114
6115       case XYWLUC:
6116         if ((y = cmkey(onoff,2,"Unicode-to-Lucida-Console substitutions",
6117                        "on",xxstring)) < 0)
6118           return(y);
6119         if ((x = cmcfm()) < 0) return(x);
6120         win95lucida = y;
6121         return(1);
6122
6123       case XYWHSL:
6124         if ((y = cmkey(onoff,2,"Horizontal Scan Line substitutions",
6125                        "on",xxstring)) < 0)
6126           return(y);
6127         if ((x = cmcfm()) < 0) return(x);
6128         win95hsl = y;
6129         return(1);
6130
6131       default:
6132         printf("Illegal value in setwin95()\n");
6133         return(-9);
6134     }
6135 }
6136 #endif /* NT */
6137
6138 #ifdef OS2
6139 int
6140 setprty (
6141 #ifdef CK_ANSIC
6142     void
6143 #endif /* CK_ANSIC */
6144 /* setprty */ ) {
6145     int x, y, z;
6146
6147     if (( y = cmkey(prtytab, nprty,
6148                     "priority level of terminal and communication threads",
6149                     "foreground-server",
6150                     xxstring)) < 0 )
6151       return (y);
6152
6153     if ((x = cmcfm()) < 0)
6154       return (x);
6155 #ifdef IKSD
6156     if (inserver &&
6157 #ifdef IKSDCONF
6158          iksdcf
6159 #else
6160          1
6161 #endif /* IKSDCONF */
6162     ) {
6163         if ((y = cmcfm()) < 0) return(y);
6164         printf("?Sorry, command disabled.\r\n");
6165         return(success = 0);
6166     }
6167 #endif /* IKSD */
6168     priority = y;
6169     return(TRUE);
6170 }
6171 #endif /* OS2 */
6172
6173 int
6174 setbell() {
6175     int y, x;
6176 #ifdef OS2
6177     int z;
6178 #endif /* OS2 */
6179
6180     if ((y = cmkey(beltab,nbeltab,
6181 #ifdef OS2
6182         "how console and terminal bells should\nbe generated", "audible",
6183 #else
6184         "Whether Kermit should ring the terminal bell (beep)", "on",
6185 #endif /* OS2 */
6186                    xxstring)) < 0)
6187           return(y);
6188
6189 #ifdef IKSD
6190     if (inserver) {
6191         if ((y = cmcfm()) < 0) return(y);
6192         printf("?Sorry, command disabled.\r\n");
6193         return(success = 0);
6194     }
6195 #endif /* IKSD */
6196
6197     switch (y) {                        /* SET BELL */
6198       case XYB_NONE:
6199 #ifdef OS2
6200       case XYB_VIS:
6201 #endif /* OS2 */
6202         if ((x = cmcfm()) < 0)
6203           return(x);
6204 #ifdef OS2
6205         tt_bell = y;
6206 #else
6207         tt_bell = 0;
6208 #endif /* OS2 */
6209         break;
6210
6211       case XYB_AUD:
6212 #ifdef OS2
6213         if ((x = cmkey(audibletab, naudibletab,
6214                "how audible console and terminal\nbells should be generated",
6215                        "beep",xxstring))<0)
6216           return(x);
6217         if ((z = cmcfm()) < 0)
6218           return(z);
6219         tt_bell = y | x;
6220 #else
6221         /* This lets C-Kermit accept but ignore trailing K95 keywords */
6222         if ((x = cmtxt("Confirm with carriage return","",&s,xxstring)) < 0)
6223           return(x);
6224         tt_bell = 1;
6225 #endif /* OS2 */
6226         break;
6227     }
6228     return(1);
6229 }
6230
6231 #ifdef OS2MOUSE
6232 int
6233 setmou(
6234 #ifdef CK_ANSIC
6235        void
6236 #endif /* CK_ANSIC */
6237  /* setmou */ ) {
6238     extern int initvik;
6239     int button = 0, event = 0;
6240     char * p;
6241
6242     if ((y = cmkey(mousetab,nmtab,"","",xxstring)) < 0)
6243       return(y);
6244
6245 #ifdef IKSD
6246     if (inserver) {
6247         if ((y = cmcfm()) < 0) return(y);
6248         printf("?Sorry, command disabled.\r\n");
6249         return(success = 0);
6250     }
6251 #endif /* IKSD */
6252
6253     if (y == XYM_ON) {                  /* MOUSE ACTIVATION */
6254         int old_mou = tt_mouse;
6255         if ((x = seton(&tt_mouse)) < 0)
6256             return(x);
6257         if (tt_mouse != old_mou)
6258           if (tt_mouse)
6259             os2_mouseon();
6260           else
6261             os2_mouseoff();
6262         return(1);
6263     }
6264
6265     if (y == XYM_DEBUG) {               /* MOUSE DEBUG */
6266         extern int MouseDebug;
6267         if ((x = seton(&MouseDebug)) < 0)
6268             return(x);
6269         return(1);
6270     }
6271
6272     if (y == XYM_CLEAR) {               /* Reset Mouse Defaults */
6273         if ((x = cmcfm()) < 0) return(x);
6274         mousemapinit(-1,-1);
6275         initvik = 1;                    /* Update VIK Table */
6276         return 1;
6277     }
6278     if (y != XYM_BUTTON) {              /* Shouldn't happen. */
6279         printf("Internal parsing error\n");
6280         return(-9);
6281     }
6282
6283     /* MOUSE EVENT ... */
6284
6285     if ((button = cmkey(mousebuttontab,nmbtab,
6286                         "Button number","1",
6287                         xxstring)) < 0)
6288       return(button);
6289
6290     if ((y =  cmkey(mousemodtab,nmmtab,
6291                     "Keyboard modifier","none",
6292                     xxstring)) < 0)
6293       return(y);
6294
6295     event |= y;                         /* OR in the bits */
6296
6297     if ((y =  cmkey(mclicktab,nmctab,"","click",xxstring)) < 0)
6298       return(y);
6299
6300     /* Two bits are assigned, if neither are set then it is button one */
6301
6302     event |= y;                 /* OR in the bit */
6303
6304     wideresult = -1;
6305
6306     if ((y = cmtxt("definition,\n\
6307 or Ctrl-C to cancel this command,\n\
6308 or Enter to restore default definition",
6309                    "",&s,NULL)) < 0) {
6310         return(y);
6311     }
6312     s = brstrip(s);
6313     p = s;                              /* Save this place */
6314 /*
6315   If the definition included any \Kverbs, quote the backslash so the \Kverb
6316   will still be in the definition when the key is pressed.  We don't do this
6317   in zzstring(), because \Kverbs are valid only in this context and nowhere
6318   else.  This code copied from SET KEY, q.v. for addt'l commentary.
6319 */
6320     for (x = 0, y = 0; s[x]; x++, y++) { /* Convert \K to \\K */
6321         if ((x > 0) &&
6322             (s[x] == 'K' || s[x] == 'k')
6323             ) {                         /* Have K */
6324
6325             if ((x == 1 && s[x-1] == CMDQ) ||
6326                 (x > 1 && s[x-1] == CMDQ && s[x-2] != CMDQ)) {
6327                 line[y++] = CMDQ;       /* Make it \\K */
6328             }
6329             if (x > 1 && s[x-1] == '{' && s[x-2] == CMDQ) {
6330                 line[y-1] = CMDQ;       /* Have \{K */
6331                 line[y++] = '{';        /* Make it \\{K */
6332             }
6333         }
6334         line[y] = s[x];
6335     }
6336     line[y++] = NUL;                    /* Terminate */
6337     s = line + y + 1;                   /* Point to after it */
6338     x = LINBUFSIZ - (int) strlen(line) - 1; /* Calculate remaining space */
6339     if ((x < (LINBUFSIZ / 2)) ||
6340         (zzstring(line, &s, &x) < 0)) { /* Expand variables, etc. */
6341         printf("?Key definition too long\n");
6342         return(-9);
6343     }
6344     s = line + y + 1;                   /* Point to result. */
6345
6346 #ifndef NOKVERBS
6347 /*
6348   Special case: see if the definition starts with a \Kverb.
6349   If it does, point to it with p, otherwise set p to NULL.
6350 */
6351     p = s;
6352     if (*p++ == CMDQ) {
6353         if (*p == '{') p++;
6354         p = (*p == 'k' || *p == 'K') ? p + 1 : NULL;
6355     }
6356 #else
6357     p = NULL;
6358 #endif /* NOKVERBS */
6359
6360     /* free the old definition if necessary */
6361     if (mousemap[button][event].type == macro) {
6362         free( mousemap[button][event].macro.string);
6363         mousemap[button][event].macro.string = NULL;
6364     }
6365     switch (strlen(s)) {                /* Action depends on length */
6366       case 0:                           /* Reset to default binding */
6367         mousemapinit( button, event );
6368         break;
6369       case 1:                           /* Single character */
6370             mousemap[button][event].type = key;
6371         mousemap[button][event].key.scancode = *s;
6372         break;
6373       default:                          /* Character string */
6374 #ifndef NOKVERBS
6375         if (p) {
6376             y = xlookup(kverbs,p,nkverbs,&x); /* Look it up */
6377             debug(F101,"set mouse kverb lookup",0,y); /* need exact match */
6378             if (y > -1) {
6379             /* Assign the kverb to the event */
6380             mousemap[button][event].type = kverb;
6381             mousemap[button][event].kverb.id = F_KVERB | y;
6382             break;
6383             }
6384         }
6385 #endif /* NOKVERBS */
6386
6387        /* Otherwise, it's a macro, so assign the macro to the event */
6388        mousemap[button][event].type = macro;
6389        mousemap[button][event].macro.string = (MACRO) malloc(strlen(s)+1);
6390        if (mousemap[button][event].macro.string)
6391          strcpy((char *) mousemap[button][event].macro.string, s); /* safe */
6392         break;
6393     }
6394     initvik = 1;                        /* Update VIK Table */
6395     if ( (button == XYM_B3) && (mousebuttoncount() < 3) && !quiet )
6396     {
6397         printf("?Warning: this machine does not have a three button mouse.\n");
6398         return(0);
6399     }
6400     return(1);
6401 }
6402 #endif /* OS2MOUSE */
6403 #endif /* NOLOCAL */
6404
6405 #ifndef NOXFER
6406 int                                     /* SET SEND/RECEIVE */
6407 setsr(xx, rmsflg) int xx; int rmsflg; {
6408     if (xx == XYRECV)
6409       ckstrncpy(line,"Parameter for inbound packets",LINBUFSIZ);
6410     else
6411       ckstrncpy(line,"Parameter for outbound packets",LINBUFSIZ);
6412
6413     if (rmsflg) {
6414         if ((y = cmkey(rsrtab,nrsrtab,line,"",xxstring)) < 0) {
6415             if (y == -3) {
6416                 printf("?Remote receive parameter required\n");
6417                 return(-9);
6418             } else return(y);
6419         }
6420     } else {
6421         if ((y = cmkey(srtab,nsrtab,line,"",xxstring)) < 0) return(y);
6422     }
6423     switch (y) {
6424       case XYQCTL:                      /* CONTROL-PREFIX */
6425         if ((x = cmnum("ASCII value of control prefix","",10,&y,xxstring)) < 0)
6426           return(x);
6427         if ((x = cmcfm()) < 0) return(x);
6428         if ((y > 32 && y < 63) || (y > 95 && y < 127)) {
6429             if (xx == XYRECV)
6430               ctlq = (CHAR) y;          /* RECEIVE prefix, use with caution! */
6431             else
6432               myctlq = (CHAR) y;        /* SEND prefix, OK to change */
6433             return(success = 1);
6434         } else {
6435             printf("?Illegal value for prefix character\n");
6436             return(-9);
6437         }
6438
6439       case XYEOL:
6440         if ((y = setcc("13",&z)) < 0)
6441             return(y);
6442         if (z > 31) {
6443             printf("Sorry, the legal values are 0-31\n");
6444             return(-9);
6445         }
6446         if (xx == XYRECV)
6447           eol = (CHAR) z;
6448         else
6449           seol = (CHAR) z;
6450         return(success = y);
6451
6452       case XYLEN:
6453         y = cmnum("Maximum number of characters in a packet","90",10,&x,
6454                   xxstring);
6455         if (xx == XYRECV) {             /* Receive... */
6456             if ((y = setnum(&z,x,y,maxrps)) < 0)
6457               return(y);
6458             if (protocol != PROTO_K) {
6459                 printf("?Sorry, this command does not apply to %s protocol.\n",
6460                        ptab[protocol].p_name
6461                        );
6462                 printf("Use SET SEND PACKET-LENGTH for XYZMODEM\n");
6463                 return(-9);
6464             }
6465             if (z < 10) {
6466                 printf("Sorry, 10 is the minimum\n");
6467                 return(-9);
6468             }
6469             if (rmsflg) {
6470                 sstate = setgen('S', "401", ckitoa(z), "");
6471                 return((int) sstate);
6472             } else {
6473                 if (protocol == PROTO_K) {
6474                     if (z > MAXRP) z = MAXRP;
6475                     y = adjpkl(z,wslotr,bigrbsiz);
6476                     if (y != z) {
6477                         urpsiz = y;
6478                         if (!xcmdsrc)
6479                           if (msgflg) printf(
6480 " Adjusting receive packet-length to %d for %d window slots\n",
6481                                              y, wslotr);
6482                     }
6483                     urpsiz = y;
6484                     ptab[protocol].rpktlen = urpsiz;
6485                     rpsiz =  (y > 94) ? 94 : y;
6486                 } else {
6487 #ifdef CK_XYZ
6488                     if ((protocol == PROTO_X || protocol == PROTO_XC) &&
6489                          z != 128 && z != 1024) {
6490                         printf("Sorry, bad packet length for XMODEM.\n");
6491                         printf("Please use 128 or 1024.\n");
6492                         return(-9);
6493                     }
6494 #endif /* CK_XYZ */
6495                     urpsiz = rpsiz = z;
6496                 }
6497             }
6498         } else {                        /* Send... */
6499             if ((y = setnum(&z,x,y,maxsps)) < 0)
6500               return(y);
6501             if (z < 10) {
6502                 printf("Sorry, 10 is the minimum\n");
6503                 return(-9);
6504             }
6505             if (protocol == PROTO_K) {
6506                 if (z > MAXSP) z = MAXSP;
6507                 spsiz = z;              /* Set it */
6508                 y = adjpkl(spsiz,wslotr,bigsbsiz);
6509                 if (y != spsiz && !xcmdsrc)
6510                   if (msgflg)
6511                     printf("Adjusting packet size to %d for %d window slots\n",
6512                            y,wslotr);
6513             } else
6514               y = z;
6515 #ifdef CK_XYZ
6516             if ((protocol == PROTO_X || protocol == PROTO_XC) &&
6517                  z != 128 && z != 1024) {
6518                 printf("Sorry, bad packet length for XMODEM.\n");
6519                 printf("Please use 128 or 1024.\n");
6520                 return(-9);
6521             }
6522 #endif /* CK_XYZ */
6523             spsiz = spmax = spsizr = y; /* Set it and flag that it was set */
6524             spsizf = 1;                 /* to allow overriding Send-Init. */
6525             ptab[protocol].spktflg = spsizf;
6526             ptab[protocol].spktlen = spsiz;
6527         }
6528         if (pflag && protocol == PROTO_K && !xcmdsrc) {
6529             if (z > 94 && !reliable && msgflg) {
6530                 /* printf("Extended-length packets requested.\n"); */
6531                 if (bctr < 2 && z > 200) printf("\
6532 Remember to SET BLOCK 2 or 3 for long packets.\n");
6533             }
6534             if (speed <= 0L) speed = ttgspd();
6535 #ifdef COMMENT
6536 /*
6537   Kermit does this now itself.
6538 */
6539             if (speed <= 0L && z > 200 && msgflg) {
6540                 printf("\
6541 Make sure your timeout interval is long enough for %d-byte packets.\n",z);
6542             }
6543 #endif /* COMMENT */
6544         }
6545         return(success = y);
6546
6547       case XYMARK:
6548 #ifdef DOOMSDAY
6549 /*
6550   Printable start-of-packet works for UNIX and VMS only!
6551 */
6552         x_ifnum = 1;
6553         y = cmnum("Code for packet-start character","1",10,&x,xxstring);
6554         x_ifnum = 0;
6555         if ((y = setnum(&z,x,y,126)) < 0) return(y);
6556 #else
6557         if ((y = setcc("1",&z)) < 0)
6558             return(y);
6559 #endif /* DOOMSDAY */
6560         if (xx == XYRECV)
6561           stchr = (CHAR) z;
6562         else {
6563             mystch = (CHAR) z;
6564 #ifdef IKS_OPTION
6565             /* If IKS negotiation in use   */
6566             if (TELOPT_U(TELOPT_KERMIT) || TELOPT_ME(TELOPT_KERMIT))
6567               tn_siks(KERMIT_SOP);      /* Report change to other side */
6568 #endif /* IKS_OPTION */
6569         }
6570         return(success = y);
6571
6572       case XYNPAD:                      /* PADDING */
6573         y = cmnum("How many padding characters for inbound packets","0",10,&x,
6574                   xxstring);
6575         if ((y = setnum(&z,x,y,94)) < 0) return(y);
6576         if (xx == XYRECV)
6577           mypadn = (CHAR) z;
6578         else
6579           npad = (CHAR) z;
6580         return(success = y);
6581
6582       case XYPADC:                      /* PAD-CHARACTER */
6583         if ((y = setcc("0",&z)) < 0) return(y);
6584         if (xx == XYRECV) mypadc = z; else padch = z;
6585         return(success = y);
6586
6587       case XYTIMO:                      /* TIMEOUT */
6588         if (xx == XYRECV) {
6589             y = cmnum("Packet timeout interval",ckitoa(URTIME),10,&x,xxstring);
6590             if ((y = setnum(&z,x,y,94)) < 0) return(y);
6591
6592             if (rmsflg) {               /* REMOTE SET RECEIVE TIMEOUT */
6593                 sstate = setgen('S', "402", ckitoa(z), "");
6594                 return((int) sstate);
6595             } else {                    /* SET RECEIVE TIMEOUT */
6596                 pkttim = z;             /*   Value to put in my negotiation */
6597             }                           /*   packet for other Kermit to use */
6598
6599         } else {                        /* SET SEND TIMEOUT */
6600 #ifdef CK_TIMERS
6601             extern int rttflg, mintime, maxtime;
6602             int tmin = 0, tmax = 0;
6603 #endif /* CK_TIMERS */
6604             y = cmnum("Packet timeout interval",ckitoa(DMYTIM),10,&x,xxstring);
6605             if (y == -3) {              /* They cancelled a previous */
6606                 x = DMYTIM;             /* SET SEND command, so restore */
6607                 timef = 0;              /* and turn off the override flag */
6608                 y = cmcfm();
6609             }
6610 #ifdef CK_TIMERS
6611             if (y < 0) return(y);
6612             if (x < 0) {
6613                 printf("?Out of range - %d\n",x);
6614                 return(-9);
6615             }
6616             if ((z = cmkey(timotab,2,"","dynamic",xxstring)) < 0) return(z);
6617             if (z) {
6618                 if ((y = cmnum("Minimum timeout to allow",
6619                                "1",10,&tmin,xxstring)) < 0)
6620                   return(y);
6621                 if (tmin < 1) {
6622                     printf("?Out of range - %d\n",tmin);
6623                     return(-9);
6624                 }
6625                 if ((y = cmnum("Maximum timeout to allow",
6626                                "0",10,&tmax,xxstring)) < 0)
6627                   return(y);
6628                 /* 0 means let Kermit choose, < 0 means no maximum */
6629             }
6630             if ((y = cmcfm()) < 0)
6631               return(y);
6632             rttflg = z;                 /* Round-trip timer flag */
6633             z = x;
6634 #else
6635             if ((y = setnum(&z,x,y,94)) < 0)
6636               return(y);
6637 #endif /* CK_TIMERS */
6638             timef = 1;                  /* Turn on the override flag */
6639             timint = rtimo = z;         /* Override value for me to use */
6640 #ifdef CK_TIMERS
6641             if (rttflg) {               /* Lower and upper bounds */
6642                 mintime = tmin;
6643                 maxtime = tmax;
6644             }
6645 #endif /* CK_TIMERS */
6646         }
6647         return(success = 1);
6648
6649       case XYFPATH:                     /* PATHNAMES */
6650         if (xx == XYRECV) {
6651             y = cmkey(rpathtab,nrpathtab,"","auto",xxstring);
6652         } else {
6653             y = cmkey(pathtab,npathtab,"","off",xxstring);
6654         }
6655         if (y < 0) return(y);
6656
6657         if ((x = cmcfm()) < 0) return(x);
6658         if (xx == XYRECV) {             /* SET RECEIVE PATHNAMES */
6659             fnrpath = y;
6660             ptab[protocol].fnrp = fnrpath;
6661         } else {                        /* SET SEND PATHNAMES */
6662             fnspath = y;
6663             ptab[protocol].fnsp = fnspath;
6664         }
6665         return(success = 1);            /* Note: 0 = ON, 1 = OFF */
6666         /* In other words, ON = leave pathnames ON, OFF = take them off. */
6667
6668       case XYPAUS:                      /* SET SEND/RECEIVE PAUSE */
6669         y = cmnum("Milliseconds to pause between packets","0",10,&x,xxstring);
6670         if ((y = setnum(&z,x,y,15000)) < 0)
6671           return(y);
6672         pktpaus = z;
6673         return(success = 1);
6674
6675 #ifdef CKXXCHAR                         /* SET SEND/RECEIVE IGNORE/DOUBLE */
6676       case XYIGN:
6677       case XYDBL: {
6678           int i, zz;
6679           short *p;
6680           extern short dblt[];
6681           extern int dblflag, ignflag;
6682
6683           /* Make space for a temporary copy of the ignore/double table */
6684
6685           zz = y;
6686 #ifdef COMMENT
6687           if (zz == XYIGN && xx == XYSEND) {
6688               blah blah who cares
6689           }
6690           if (zz == XYDBL && xx == XYRECV) {
6691               blah blah
6692           }
6693 #endif /* COMMENT */
6694           p = (short *)malloc(256 * sizeof(short));
6695           if (!p) {
6696               printf("?Internal error - malloc failure\n");
6697               return(-9);
6698           }
6699           for (i = 0; i < 256; i++) p[i] = dblt[i]; /* Copy current table */
6700
6701           while (1) {                   /* Collect a list of numbers */
6702 #ifndef NOSPL
6703               x_ifnum = 1;              /* Turn off complaints from eval() */
6704 #endif /* NOSPL */
6705               if ((x = cmnum(zz == XYDBL ?
6706                              "Character to double" :
6707                              "Character to ignore",
6708                              "",10,&y,xxstring
6709                              )) < 0) {
6710 #ifndef NOSPL
6711                   x_ifnum = 0;
6712 #endif /* NOSPL */
6713                   if (x == -3)          /* Done */
6714                     break;
6715                   if (x == -2) {
6716                       if (p) { free(p); p = NULL; }
6717                       debug(F110,"SET S/R DOUBLE/IGNORE atmbuf",atmbuf,0);
6718                       if (!ckstrcmp(atmbuf,"none",4,0) ||
6719                           !ckstrcmp(atmbuf,"non",3,0) ||
6720                           !ckstrcmp(atmbuf,"no",2,0) ||
6721                           !ckstrcmp(atmbuf,"n",1,0)) {
6722                           if ((x = cmcfm()) < 0) /* Get confirmation */
6723                             return(x);
6724                           for (y = 0; y < 256; y++)
6725                             dblt[y] &= (zz == XYDBL) ? 1 : 2;
6726                           if (zz == XYDBL) dblflag = 0;
6727                           if (zz == XYIGN) ignflag = 0;
6728                           return(success = 1);
6729                       } else {
6730                           printf(
6731                             "?Please specify a number or the word NONE\n");
6732                           return(-9);
6733                       }
6734                   } else {
6735                       free(p);
6736                       p = NULL;
6737                       return(x);
6738                   }
6739               }
6740 #ifndef NOSPL
6741               x_ifnum = 0;
6742 #endif /* NOSPL */
6743               if (y < 0 || y > 255) {
6744                   printf("?Please enter a character code in range 0-255\n");
6745                   free(p);
6746                   p = NULL;
6747                   return(-9);
6748               }
6749               p[y] |= (zz == XYDBL) ? 2 : 1;
6750               if (zz == XYDBL) dblflag = 1;
6751               if (zz == XYIGN) ignflag = 1;
6752           } /* End of while loop */
6753
6754           if ((x = cmcfm()) < 0) return(x);
6755 /*
6756   Get here only if they have made no mistakes.  Copy temporary table back to
6757   permanent one, then free temporary table and return successfully.
6758 */
6759           if (p) {
6760               for (i = 0; i < 256; i++) dblt[i] = p[i];
6761               free(p);
6762               p = NULL;
6763           }
6764           return(success = 1);
6765       }
6766 #endif /* CKXXCHAR */
6767
6768 #ifdef PIPESEND
6769       case XYFLTR: {                    /* SET { SEND, RECEIVE } FILTER */
6770           if ((y = cmtxt((xx == XYSEND) ?
6771                 "Filter program for sending files -\n\
6772  use \\v(filename) to substitute filename" :
6773                 "Filter program for receiving files -\n\
6774  use \\v(filename) to substitute filename",
6775                          "",&s,NULL)) < 0)
6776             return(y);
6777           if (!*s) {                    /* Removing a filter... */
6778               if (xx == XYSEND && sndfilter) {
6779                   makestr(&g_sfilter,NULL);
6780                   makestr(&sndfilter,NULL);
6781               } else if (rcvfilter) {
6782                   makestr(&g_rfilter,NULL);
6783                   makestr(&rcvfilter,NULL);
6784               }
6785               return(success = 1);
6786           }                             /* Adding a filter... */
6787           s = brstrip(s);               /* Strip any braces */
6788           y = strlen(s);
6789           if (xx == XYSEND) {           /* For SEND filter... */
6790               for (x = 0; x < y; x++) { /* make sure they included "\v(...)" */
6791                   if (s[x] != '\\') continue;
6792                   if (s[x+1] == 'v') break;
6793               }
6794               if (x == y) {
6795                   printf(
6796               "?Filter must contain a replacement variable for filename.\n"
6797                          );
6798                   return(-9);
6799               }
6800           }
6801           if (xx == XYSEND) {
6802               makestr(&sndfilter,s);
6803               makestr(&g_sfilter,s);
6804           } else {
6805               makestr(&rcvfilter,s);
6806               makestr(&g_rfilter,s);
6807           }
6808           return(success = 1);
6809       }
6810 #endif /* PIPESEND */
6811
6812       case XYINIL:
6813         y = cmnum("Max length for protocol init string","-1",10,&x,xxstring);
6814         if ((y = setnum(&z,x,y,-1)) < 0)
6815           return(y);
6816         if (xx == XYSEND)
6817           sprmlen = z;
6818         else
6819           rprmlen = z;
6820         return(success = 1);
6821
6822       case 993: {
6823           extern int sendipkts;
6824           if (xx == XYSEND) {
6825               if ((x = seton(&sendipkts)) < 0)
6826                 return(x);
6827           }
6828           return(1);
6829       }
6830 #ifdef CK_PERMS
6831       case 994:
6832         switch(xx) {
6833           case XYSEND:
6834             if ((x = seton(&atlpro)) < 0) return(x);
6835             atgpro = atlpro;
6836             return(1);
6837           case XYRECV:
6838             if ((x = seton(&atlpri)) < 0) return(x);
6839             atgpri = atlpri;
6840             return(1);
6841           default:
6842             return(-2);
6843         }
6844 #endif /* CK_PERMS */
6845
6846 #ifndef NOCSETS
6847       case XYCSET: {                    /* CHARACTER-SET-SELECTION */
6848           extern struct keytab xfrmtab[];
6849           extern int r_cset, s_cset;
6850           if ((y = cmkey(xfrmtab,2,"","automatic",xxstring)) < 0)
6851             return(y);
6852           if ((x = cmcfm()) < 0)
6853             return(x);
6854           if (xx == XYSEND)
6855             s_cset = y;
6856           else
6857             r_cset = y;
6858           return(success = 1);
6859       }
6860 #endif /* NOCSETS */
6861
6862       case XYBUP:
6863         if ((y = cmkey(onoff,2,"","on",xxstring)) < 0)
6864           return(y);
6865         if ((x = cmcfm()) < 0) return(x);
6866         if (xx == XYSEND) {
6867             extern int skipbup;
6868             skipbup = (y == 0) ? 1 : 0;
6869             return(success = 1);
6870         } else {
6871             printf(
6872 "?Please use SET FILE COLLISION to choose the desired action\n");
6873             return(-9);
6874         }
6875
6876       case XYMOVE:
6877 #ifdef COMMENT
6878         y = cmdir("Directory to move file(s) to after successful transfer",
6879                   "",&s,xxstring);
6880 #else
6881         y = cmtxt("Directory to move file(s) to after successful transfer",
6882                   "",&s,xxstring);
6883 #endif /* COMMENT */
6884
6885         if (y < 0 && y != -3)
6886           return(y);
6887         ckstrncpy(line,s,LINBUFSIZ);
6888         s = brstrip(line);
6889
6890 #ifdef COMMENT
6891         /* Only needed for cmdir() */
6892         if ((x = cmcfm()) < 0)
6893           return(x);
6894 #endif /* COMMENT */
6895         
6896         /* Check directory existence if absolute */
6897         /* THIS MEANS IT CAN'T INCLUDE ANY DEFERRED VARIABLES! */
6898         if (s) if (*s) {
6899             if (isabsolute(s) && !isdir(s)) {
6900                 printf("?Directory does not exist - %s\n",s);
6901                 return(-9);
6902             }
6903         }
6904         if (xx == XYSEND) {
6905             if (*s) {
6906 #ifdef COMMENT
6907                 /* Allow it to be relative */
6908                 zfnqfp(s,LINBUFSIZ,line);
6909 #endif /* COMMENT */
6910                 makestr(&snd_move,line);
6911                 makestr(&g_snd_move,line);
6912             } else {
6913                 makestr(&snd_move,NULL);
6914                 makestr(&g_snd_move,NULL);
6915             }
6916         } else {
6917             if (*s) {
6918 #ifdef COMMENT
6919                 /* Allow it to be relative */
6920                 zfnqfp(s,LINBUFSIZ,line);
6921 #endif /* COMMENT */
6922                 makestr(&rcv_move,line);
6923                 makestr(&g_rcv_move,line);
6924             } else {
6925                 makestr(&rcv_move,NULL);
6926                 makestr(&g_rcv_move,NULL);
6927             }
6928         }
6929         return(success = 1);
6930
6931       case XYRENAME:
6932         y = cmtxt("Template to rename file(s) to after successful transfer",
6933                   "",&s,NULL);          /* NOTE: no xxstring */
6934         if (y < 0 && y != -3)           /* Evaluation is deferred */
6935           return(y);
6936         ckstrncpy(line,s,LINBUFSIZ);
6937         s = brstrip(line);
6938         if ((x = cmcfm()) < 0)
6939           return(x);
6940         if (xx == XYSEND) {
6941             if (*s) {
6942                 makestr(&snd_rename,s);
6943                 makestr(&g_snd_rename,s);
6944             } else {
6945                 makestr(&snd_rename,NULL);
6946                 makestr(&g_snd_rename,NULL);
6947             }
6948         } else {
6949             if (*s) {
6950                 makestr(&rcv_rename,s);
6951                 makestr(&g_rcv_rename,s);
6952             } else {
6953                 makestr(&rcv_rename,NULL);
6954                 makestr(&g_rcv_rename,NULL);
6955             }
6956         }
6957         return(success = 1);
6958
6959 #ifdef VMS
6960       case 887:                         /* VERSION-NUMBERS */
6961         if (xx == XYSEND) {
6962             extern int vmssversions;
6963             return(seton(&vmssversions));
6964         } else {
6965             extern int vmsrversions;
6966             return(seton(&vmsrversions));
6967         }
6968 #endif /* VMS */
6969
6970       default:
6971         return(-2);
6972     }                                   /* End of SET SEND/RECEIVE... */
6973 }
6974 #endif /* NOXFER */
6975
6976 #ifndef NOXMIT
6977 int
6978 setxmit() {
6979     if ((y = cmkey(xmitab,nxmit,"","",xxstring)) < 0) return(y);
6980     switch (y) {
6981       case XMITE:                       /* EOF */
6982         y = cmtxt("Characters to send at end of file,\n\
6983  Use backslash codes for control characters","",&s,xxstring);
6984         if (y < 0) return(y);
6985         if ((int)strlen(s) > XMBUFL) {
6986             printf("?Too many characters, %d maximum\n",XMBUFL);
6987             return(-2);
6988         }
6989         ckstrncpy(xmitbuf,s,XMBUFL);
6990         return(success = 1);
6991
6992       case XMITF:                       /* Fill */
6993         y = cmnum("Numeric code for blank-line fill character","0",10,&x,
6994                   xxstring);
6995         if ((y = setnum(&z,x,y,127)) < 0) return(y);
6996         xmitf = z;
6997         return(success = 1);
6998       case XMITL:                       /* Linefeed */
6999         return(seton(&xmitl));
7000       case XMITS:                       /* Locking-Shift */
7001         return(seton(&xmits));
7002       case XMITP:                       /* Prompt */
7003         y = cmnum("Numeric code for host's prompt character, 0 for none",
7004                   "10",10,&x,xxstring);
7005         if ((y = setnum(&z,x,y,127)) < 0) return(y);
7006         xmitp = z;
7007         return(success = 1);
7008       case XMITX:                       /* Echo */
7009         return(seton(&xmitx));
7010       case XMITW:                       /* Pause */
7011         y = cmnum("Number of milliseconds to pause between binary characters\n\
7012 or text lines during transmission","0",10,&x,xxstring);
7013         if ((y = setnum(&z,x,y,1000)) < 0) return(y);
7014         xmitw = z;
7015         return(success = 1);
7016       case XMITT:                       /* Timeout */
7017         y = cmnum("Seconds to wait for each character to echo",
7018                   "1",10,&x,xxstring);
7019         if ((y = setnum(&z,x,y,1000)) < 0) return(y);
7020         xmitt = z;
7021         return(success = 1);
7022       default:
7023         return(-2);
7024     }
7025 }
7026 #endif /* NOXMIT */
7027
7028 #ifndef NOXFER
7029 /*  D O R M T  --  Do a remote command  */
7030
7031 VOID
7032 rmsg() {
7033     if (pflag && !quiet && fdispla != XYFD_N)
7034       printf(
7035 #ifdef CK_NEED_SIG
7036        " Type your escape character, %s, followed by X or E to cancel.\n",
7037        dbchr(escape)
7038 #else
7039        " Press the X or E key to cancel.\n"
7040 #endif /* CK_NEED_SIG */
7041       );
7042 }
7043
7044 static int xzcmd = 0;                   /* Global copy of REMOTE cmd index */
7045
7046 /*  R E M C F M  --  Confirm a REMOTE command  */
7047 /*
7048   Like cmcfm(), but allows for a redirection indicator on the end,
7049   like "> filename" or "| command".  Returns what cmcfm() would have
7050   returned: -1 if reparse needed, etc etc blah blah.  On success,
7051   returns 1 with:
7052
7053     char * remdest containing the name of the file or command.
7054     int remfile set to 1 if there is to be any redirection.
7055     int remappd set to 1 if output file is to be appended to.
7056     int rempipe set to 1 if remdest is a command, 0 if it is a file.
7057 */
7058 static int
7059 remcfm() {
7060     int x;
7061     char *s;
7062     char c;
7063
7064     remfile = 0;
7065     rempipe = 0;
7066     remappd = 0;
7067
7068     if ((x = cmtxt(
7069              "> filename, | command,\n\
7070 or type carriage return to confirm the command",
7071                    "",&s,xxstring)) < 0)
7072       return(x);
7073     if (remdest) {
7074         free(remdest);
7075         remdest = NULL;
7076     }
7077     debug(F101,"remcfm local","",local);
7078     debug(F110,"remcfm s",s,0);
7079     debug(F101,"remcfm cmd","",xzcmd);
7080
7081     if (!*s) {                          /* No redirection indicator */
7082         if (!local &&
7083             (xzcmd == XZDIR || xzcmd == XZTYP ||
7084              xzcmd == XZXIT || xzcmd == XZSPA ||
7085              xzcmd == XZHLP || xzcmd == XZPWD ||
7086              xzcmd == XZLGI || xzcmd == XZLGO ||
7087              xzcmd == XZWHO || xzcmd == XZHOS)) {
7088             printf("?\"%s\" has no effect in remote mode\n",cmdbuf);
7089             return(-9);
7090         } else
7091           return(1);
7092     }
7093     c = *s;                             /* We have something */
7094     if (c != '>' && c != '|') {         /* Is it > or | ? */
7095         printf("?Not confirmed\n");     /* No */
7096         return(-9);
7097     }
7098     s++;                                /* See what follows */
7099     if (c == '>' && *s == '>') {        /* Allow for ">>" too */
7100         s++;
7101         remappd = 1;                    /* Append to output file */
7102     }
7103     while (*s == SP || *s == HT) s++;   /* Strip intervening whitespace */
7104     if (!*s) {
7105         printf("?%s missing\n", c == '>' ? "Filename" : "Command");
7106         return(-9);
7107     }
7108     if (c == '>' && zchko(s) < 0) {     /* Check accessibility */
7109         printf("?Access denied - %s\n", s);
7110         return(-9);
7111     }
7112     remfile = 1;                        /* Set global results */
7113     rempipe = (c == '|');
7114     if (rempipe
7115 #ifndef NOPUSH
7116         && nopush
7117 #endif /* NOPUSH */
7118         ) {
7119         printf("?Sorry, access to external commands is disabled.\n");
7120         return(-9);
7121     }
7122     makestr(&remdest,s);
7123 #ifndef NODEBUG
7124     if (deblog) {
7125         debug(F101,"remcfm remfile","",remfile);
7126         debug(F101,"remcfm remappd","",remappd);
7127         debug(F101,"remcfm rempipe","",rempipe);
7128         debug(F110,"remcfm remdest",remdest, 0);
7129     }
7130 #endif /* NODEBUG */
7131     return(1);
7132 }
7133
7134 /*  R E M T X T  --  Like remcfm()...  */
7135 /*
7136    ... but for REMOTE commands that end with cmtxt().
7137    Here we must decipher braces to discover whether the trailing
7138    redirection indicator is intended for local use, or to be sent out
7139    to the server, as in:
7140
7141      remote host blah blah > file                 This end
7142      remote host { blah blah } > file             This end
7143      remote host { blah blah > file }             That end
7144      remote host { blah blah > file } > file      Both ends
7145
7146    Pipes too:
7147
7148      remote host blah blah | cmd                  This end
7149      remote host { blah blah } | cmd              This end
7150      remote host { blah blah | cmd }              That end
7151      remote host { blah blah | cmd } | cmd        Both ends
7152
7153    Or both:
7154
7155      remote host blah blah | cmd > file           This end, etc etc...
7156
7157    Note: this really only makes sense for REMOTE HOST, but why be picky?
7158    Call after calling cmtxt(), with pointer to string that cmtxt() parsed,
7159    as in "remtxt(&s);".
7160
7161    Returns:
7162     1 on success with braces & redirection things removed & pointer updated,
7163    -9 on failure (bad indirection), after printing error message.
7164 */
7165 int
7166 remtxt(p) char ** p; {
7167     int i, x, bpos, ppos;
7168     char c, *s, *q;
7169
7170     remfile = 0;                        /* Initialize global results */
7171     rempipe = 0;
7172     remappd = 0;
7173     if (remdest) {
7174         free(remdest);
7175         remdest = NULL;
7176     }
7177     s = *p;
7178     if (!s)                             /* No redirection indicator */
7179       s = "";
7180     if (!*s) {                          /* Ditto */
7181         if (!local &&
7182             (xzcmd == XZDIR || xzcmd == XZTYP ||
7183              xzcmd == XZXIT || xzcmd == XZSPA ||
7184              xzcmd == XZHLP || xzcmd == XZPWD ||
7185              xzcmd == XZLGI || xzcmd == XZLGO ||
7186              xzcmd == XZWHO || xzcmd == XZHOS)) {
7187             printf("?\"%s\" has no effect in remote mode\n",cmdbuf);
7188             if (hints) {
7189                 printf("Hint: Try again with an output redirector.\n");
7190             }
7191             return(-9);
7192         } else
7193           return(1);
7194     }
7195     bpos = -1;                          /* Position of > (bracket) */
7196     ppos = -1;                          /* Position of | (pipe) */
7197     x = strlen(s);                      /* Length of cmtxt() string */
7198
7199     for (i = x-1; i >= 0; i--) {        /* Search right to left. */
7200         c = s[i];
7201         if (c == '}')                   /* Break on first right brace */
7202           break;                        /* Don't look at contents of braces */
7203         else if (c == '>')              /* Record position of > */
7204           bpos = i;
7205         else if (c == '|')              /* and of | */
7206           ppos = i;
7207     }
7208     if (bpos < 0 && ppos < 0) {         /* No redirectors. */
7209         if (!local &&
7210             (xzcmd == XZDIR || xzcmd == XZTYP ||
7211              xzcmd == XZXIT || xzcmd == XZSPA ||
7212              xzcmd == XZHLP || xzcmd == XZPWD ||
7213              xzcmd == XZLGI || xzcmd == XZLGO ||
7214              xzcmd == XZWHO || xzcmd == XZHOS)) {
7215             printf("?\"%s\" has no effect in remote mode\n",cmdbuf);
7216             if (hints) {
7217                 printf("Hint: Try again with an output redirector.\n");
7218             }
7219             return(-9);
7220         }
7221         s = brstrip(s);                 /* Remove outer braces if any. */
7222         *p = s;                         /* Point to result */
7223         return(1);                      /* and return. */
7224     }
7225     remfile = 1;                        /* It's | or > */
7226     i = -1;                             /* Get leftmost symbol */
7227     if (bpos > -1)                      /* Bracket */
7228       i = bpos;
7229     if (ppos > -1 && (ppos < bpos || bpos < 0)) { /* or pipe */
7230         i = ppos;
7231         rempipe = 1;
7232     }
7233     if (rempipe
7234 #ifndef NOPUSH
7235         && nopush
7236 #endif /* NOPUSH */
7237         ) {
7238         printf("?Sorry, access to external commands is disabled.\n");
7239         return(-9);
7240     }
7241     c = s[i];                           /* Copy of symbol */
7242
7243     if (c == '>' && s[i+1] == '>')      /* ">>" for append? */
7244       remappd = 1;                     /* It's not just a flag it's a number */
7245
7246     q = s + i + 1 + remappd;            /* Point past symbol in string */
7247     while (*q == SP || *q == HT) q++;   /* and any intervening whitespace */
7248     if (!*q) {
7249         printf("?%s missing\n", c == '>' ? "Filename" : "Command");
7250         return(-9);
7251     }
7252     if (c == '>' && zchko(q) < 0) {     /* (Doesn't work for | cmd > file) */
7253         printf("?Access denied - %s\n", q);
7254         return(-9);
7255     }
7256     makestr(&remdest,q);                /* Create the destination string */
7257     q = s + i - 1;                      /* Point before symbol */
7258     while (q > s && (*q == SP || *q == HT)) /* Strip trailing whitespace */
7259       q--;
7260     *(q+1) = NUL;                       /* Terminate the string. */
7261     s = brstrip(s);                     /* Remove any braces */
7262     *p = s;                             /* Set return value */
7263
7264 #ifndef NODEBUG
7265     if (deblog) {
7266         debug(F101,"remtxt remfile","",remfile);
7267         debug(F101,"remtxt remappd","",remappd);
7268         debug(F101,"remtxt rempipe","",rempipe);
7269         debug(F110,"remtxt remdest",remdest, 0);
7270         debug(F110,"remtxt command",s,0);
7271     }
7272 #endif /* NODEBUG */
7273
7274     return(1);
7275 }
7276
7277 int
7278 plogin(xx) int xx; {
7279     char *p1 = NULL, *p2 = NULL, *p3 = NULL;
7280     int psaved = 0, rc = 0;
7281 #ifdef CK_RECALL
7282     extern int on_recall;               /* around Password prompting */
7283 #endif /* CK_RECALL */
7284     debug(F101,"plogin local","",local);
7285
7286     if (!local || (network && ttchk() < 0)) {
7287         printf("?No connection\n");
7288         return(-9);
7289     }
7290     if ((x = cmfld("User ID","",&s,xxstring)) < 0) { /* Get User ID */
7291         if (x != -3) return(x);
7292     }
7293     y = strlen(s);
7294     if (y > 0) {
7295         if ((p1 = malloc(y + 1)) == NULL) {
7296             printf("?Internal error: malloc\n");
7297             rc = -9;
7298             goto XZXLGI;
7299         } else
7300           strcpy(p1,s);                 /* safe */
7301         if ((rc = cmfld("Password","",&s,xxstring)) < 0)
7302           if (rc != -3) goto XZXLGI;
7303         y = strlen(s);
7304         if (y > 0) {
7305             if ((p2 = malloc(y + 1)) == NULL) {
7306                 printf("?Internal error: malloc\n");
7307                 rc = -9;
7308                 goto XZXLGI;
7309             } else
7310               strcpy(p2,s);             /* safe */
7311             if ((rc = cmfld("Account","",&s,xxstring)) < 0)
7312               if (rc != -3) goto XZXLGI;
7313             y = strlen(s);
7314             if (y > 0) {
7315                 if ((p3 = malloc(y + 1)) == NULL) {
7316                     printf("?Internal error: malloc\n");
7317                     rc = -9;
7318                     goto XZXLGI;
7319                 } else
7320                   strcpy(p3,s);         /* safe */
7321             }
7322         }
7323     }
7324     if ((rc = remtxt(&s)) < 0)          /* Confirm & handle redirectors */
7325       goto XZXLGI;
7326
7327     if (!p1) {                          /* No Userid specified... */
7328         debok = 0;                      /* Don't log this */
7329         /* Prompt for username, password, and account */
7330 #ifdef CK_RECALL
7331         on_recall = 0;
7332 #endif /* CK_RECALL */
7333         cmsavp(psave,PROMPTL);          /* Save old prompt */
7334         psaved = 1;
7335         debug(F110,"REMOTE LOGIN saved",psave,0);
7336
7337         cmsetp("Username: ");           /* Make new prompt */
7338         concb((char)escape);            /* Put console in cbreak mode */
7339         cmini(1);
7340         prompt(xxstring);
7341         rc = -9;
7342         for (x = -1; x < 0; ) {         /* Prompt till they answer */
7343             cmres();                    /* Reset the parser */
7344             x = cmtxt("","",&s,NULL);   /* Get a literal line of text */
7345         }
7346         y = strlen(s);
7347         if (y < 1) {
7348             printf("?Canceled\n");
7349             goto XZXLGI;
7350         }
7351         if ((p1 = malloc(y + 1)) == NULL) {
7352             printf("?Internal error: malloc\n");
7353             goto XZXLGI;
7354         } else
7355           strcpy(p1,s);                 /* safe */
7356
7357         cmsetp("Password: ");           /* Make new prompt */
7358         concb((char)escape);            /* Put console in cbreak mode */
7359         cmini(0);                       /* No echo */
7360         prompt(xxstring);
7361         debok = 0;
7362         for (x = -1; x < 0 && x != -3; ) { /* Get answer */
7363             cmres();                    /* Reset the parser */
7364             x = cmtxt("","",&s,NULL);   /* Get literal line of text */
7365         }
7366         if ((p2 = malloc((int)strlen(s) + 1)) == NULL) {
7367             printf("?Internal error: malloc\n");
7368             goto XZXLGI;
7369         } else
7370           strcpy(p2,s);                 /* safe */
7371         printf("\r\n");
7372         if ((rc = cmcfm()) < 0)
7373           goto XZXLGI;
7374     }
7375     sstate = setgen('I',p1,p2,p3);      /* Get here with at least user ID */
7376     rc = 0;
7377
7378   XZXLGI:                               /* Common exit point */
7379     if (psaved)
7380       cmsetp(psave);                    /* Restore original prompt */
7381     if (p3) { free(p3); p3 = NULL; }    /* Free malloc'd storage */
7382     if (p2) { free(p2); p2 = NULL; }
7383     if (p1) { free(p1); p1 = NULL; }
7384     if (rc > -1) {
7385         if (local && rc > -1)           /* If local, flush tty input buffer */
7386           ttflui();
7387     }
7388     return(rc);
7389 }
7390
7391 #ifdef OS2
7392 #ifndef NOLOCAL
7393 int
7394 dormt(xx) int xx; {
7395     int rc = 0;
7396     extern int term_io;
7397     int term_io_sav = term_io;
7398 #ifdef NEWFTP
7399     extern int ftpget, ftpisopen();
7400     if ((ftpget == 1) || ((ftpget == 2) && ftpisopen()))
7401       return(doftprmt(xx,0));
7402 #endif /* NEWFTP */
7403     term_io = 0;
7404     rc = xxdormt(xx);
7405     term_io = term_io_sav;
7406     return rc;
7407 }
7408
7409
7410 int
7411 xxdormt(xx) int xx;
7412 #else /* NOLOCAL */
7413 int
7414 dormt(xx) int xx;
7415 #endif /* NOLOCAL */
7416 #else /* OS2 */
7417 int
7418 dormt(xx) int xx;
7419 #endif /* OS2 */
7420 {                                       /* REMOTE commands */
7421     int x, y, retcode;
7422     char *s, sbuf[50], *s2;
7423
7424 #ifdef NEWFTP
7425     extern int ftpget, ftpisopen();
7426     if ((ftpget == 1) || ((ftpget == 2) && ftpisopen()))
7427       return(doftprmt(xx,0));
7428 #endif /* NEWFTP */
7429
7430     remfile = 0;                        /* Clear these */
7431     rempipe = 0;
7432     remappd = 0;
7433
7434     if (xx < 0) return(xx);             /* REMOTE what? */
7435
7436     xzcmd = xx;                         /* Make global copy of arg */
7437
7438     if (xx == XZSET) {                  /* REMOTE SET */
7439         if ((y = cmkey(rmstab,nrms,"","",xxstring)) < 0) {
7440             if (y == -3) {
7441                 printf("?Parameter name required\n");
7442                 return(-9);
7443             } else return(y);
7444         }
7445         return(doprm(y,1));
7446     }
7447
7448     switch (xx) {                       /* Others... */
7449
7450       case XZCDU:
7451         if ((x = cmcfm()) < 0) return(x);
7452         printf("?Sorry, REMOTE CDUP not supported yet\n");
7453         return(-9);
7454
7455       case XZCWD:                       /* CWD (CD) */
7456         if ((x = cmtxt("Remote directory name","",&s,xxstring)) < 0)
7457           return(x);
7458         if ((x = remtxt(&s)) < 0)
7459           return(x);
7460         debug(F111,"XZCWD: ",s,x);
7461         *sbuf = NUL;
7462         s2 = sbuf;
7463 /*
7464   The following is commented out because since the disappearance of the
7465   DECSYSTEM-20 from the planet, no known computer requires a password for
7466   changing directory.
7467 */
7468 #ifdef DIRPWDPR
7469         if (*s != NUL) {                /* If directory name given, */
7470                                         /* get password on separate line. */
7471             if (tlevel > -1) {          /* From take file... */
7472
7473                 if (fgets(sbuf,50,tfile[tlevel]) == NULL)
7474                   fatal("take file ends prematurely in 'remote cwd'");
7475                 debug(F110," pswd from take file",s2,0);
7476                 for (x = (int)strlen(sbuf);
7477                      x > 0 && (sbuf[x-1] == NL || sbuf[x-1] == CR);
7478                      x--)
7479                   sbuf[x-1] = '\0';
7480
7481             } else {                    /* From terminal... */
7482
7483                 printf(" Password: ");  /* get a password */
7484 #ifdef IKSD
7485                 if (!local && inserver) {
7486                     x = coninc(0);
7487                 } else
7488 #endif /* IKSD */
7489 #ifdef OS2
7490                   x = is_a_tty(0) ? coninc(0) : /* with no echo ... */
7491                     getchar();
7492 #else /* OS2 */
7493                 x = getchar();
7494 #endif /* OS2 */
7495                 while ((x != NL) && (x != CR)) {
7496                     if ((x &= 0177) == '?') {
7497                         printf("? Password of remote directory\n Password: ");
7498                         s2 = sbuf;
7499                         *sbuf = NUL;
7500                     } else if (x == ESC) /* Mini command line editor... */
7501                       bleep(BP_WARN);
7502                     else if (x == BS || x == 0177)
7503                       s2--;
7504                     else if (x == 025) {        /* Ctrl-U */
7505                         s2 = sbuf;
7506                         *sbuf = NUL;
7507                     } else
7508                       *s2++ = x;
7509
7510                     /* Get the next character */
7511 #ifdef IKSD
7512                     if (!local && inserver) {
7513                         x = coninc(0);
7514                     } else
7515 #endif /* IKSD */
7516 #ifdef OS2
7517                     x = is_a_tty(0) ? coninc(0) : /* with no echo ... */
7518                       getchar();
7519 #else /* OS2 */
7520                     x = getchar();
7521 #endif /* OS2 */
7522                 }
7523                 *s2 = NUL;
7524                 putchar('\n');
7525             }
7526             s2 = sbuf;
7527         } else s2 = "";
7528 #endif /* DIRPWDPR */
7529
7530         debug(F110," password",s2,0);
7531         rcdactive = 1;
7532         sstate = setgen('C',s,s2,"");
7533         retcode = 0;
7534         break;
7535
7536       case XZDEL:                               /* Delete */
7537         if ((x = cmtxt("Name of remote file(s) to delete",
7538                        "",&s,xxstring)) < 0) {
7539             if (x == -3) {
7540                 printf("?Name of remote file(s) required\n");
7541                 return(-9);
7542             } else return(x);
7543         }
7544         if ((x = remtxt(&s)) < 0)
7545           return(x);
7546         if (local) ttflui();            /* If local, flush tty input buffer */
7547         retcode = sstate = rfilop(s,'E');
7548         break;
7549
7550       case XZDIR:                       /* Directory */
7551         if ((x = cmtxt("Remote directory or file specification","",&s,
7552                        xxstring)) < 0)
7553           return(x);
7554         if ((x = remtxt(&s)) < 0)
7555           return(x);
7556         if (local) ttflui();            /* If local, flush tty input buffer */
7557         rmsg();
7558         retcode = sstate = setgen('D',s,"","");
7559         break;
7560
7561       case XZHLP:                       /* Help */
7562         if ((x = remcfm()) < 0) return(x);
7563         sstate = setgen('H',"","","");
7564         retcode = 0;
7565         break;
7566
7567       case XZHOS:                       /* Host */
7568         if ((x = cmtxt("Command for remote system","",&s,xxstring)) < 0)
7569           return(x);
7570         if ((x = remtxt(&s)) < 0)
7571           return(x);
7572         if ((y = (int)strlen(s)) < 1)
7573           return(x);
7574         ckstrncpy(line,s,LINBUFSIZ);
7575         cmarg = line;
7576         rmsg();
7577         retcode = sstate = 'c';
7578         break;
7579
7580 #ifndef NOFRILLS
7581       case XZKER:
7582         if ((x = cmtxt("Command for remote Kermit","",&s,xxstring)) < 0)
7583           return(x);
7584         if ((x = remtxt(&s)) < 0)
7585           return(x);
7586         if ((int)strlen(s) < 1)  {
7587             if (x == -3) {
7588                 printf("?Remote Kermit command required\n");
7589                 return(-9);
7590             } else return(x);
7591         }
7592         ckstrncpy(line,s,LINBUFSIZ);
7593         cmarg = line;
7594         retcode = sstate = 'k';
7595         rmsg();
7596         break;
7597
7598       case XZLGI:                       /* Login */
7599         rcdactive = 1;                  /* Suppress "Logged in" msg if quiet */
7600         return(plogin(XXREM));
7601
7602       case XZLGO: {                     /* Logout */
7603           extern int bye_active;
7604           if ((x = remcfm()) < 0) return(x);
7605           sstate = setgen('I',"","","");
7606           retcode = 0;
7607           bye_active = 1;               /* Close connection when done */
7608           break;
7609       }
7610
7611       case XZPRI:                       /* Print */
7612         if (!atdiso || !atcapr) {       /* Disposition attribute off? */
7613             printf("?Disposition Attribute is Off\n");
7614             return(-2);
7615         }
7616         cmarg = "";
7617         cmarg2 = "";
7618         if ((x = cmifi("Local file(s) to print on remote printer","",&s,&y,
7619                        xxstring)) < 0) {
7620             if (x == -3) {
7621                 printf("?Name of local file(s) required\n");
7622                 return(-9);
7623             }
7624             return(x);
7625         }
7626         ckstrncpy(line,s,LINBUFSIZ);    /* Make a safe copy of filename */
7627         *optbuf = NUL;                  /* Wipe out any old options */
7628         if ((x = cmtxt("Options for remote print command","",&s,xxstring)) < 0)
7629           return(x);
7630         if ((x = remtxt(&s)) < 0)
7631           return(x);
7632         if ((int)strlen(optbuf) > 94) { /* Make sure this is legal */
7633             printf("?Option string too long\n");
7634             return(-9);
7635         }
7636         ckstrncpy(optbuf,s,OPTBUFLEN);  /* Make a safe copy of options */
7637         nfils = -1;                     /* Expand file list internally */
7638         cmarg = line;                   /* Point to file list. */
7639         rprintf = 1;                    /* REMOTE PRINT modifier for SEND */
7640         sstate = 's';                   /* Set start state to SEND */
7641         if (local) displa = 1;
7642         retcode = 0;
7643         break;
7644 #endif /* NOFRILLS */
7645
7646       case XZSPA:                       /* Space */
7647         if ((x = cmtxt("Confirm, or remote directory name",
7648                        "",&s,xxstring)) < 0)
7649           return(x);
7650         if ((x = remtxt(&s)) < 0)
7651           return(x);
7652         retcode = sstate = setgen('U',s,"","");
7653         break;
7654
7655 #ifndef NOFRILLS
7656       case XZTYP:                       /* Type */
7657         if ((x = cmtxt("Remote file specification","",&s,xxstring)) < 0)
7658           return(x);
7659         if ((int)strlen(s) < 1) {
7660             printf("?Remote filename required\n");
7661             return(-9);
7662         }
7663         if ((x = remtxt(&s)) < 0)
7664           return(x);
7665         rmsg();
7666         retcode = sstate = rfilop(s,'T');
7667         break;
7668 #endif /* NOFRILLS */
7669
7670 #ifndef NOFRILLS
7671       case XZWHO:
7672         if ((x = cmtxt("Remote user name, or carriage return",
7673                        "",&s,xxstring)) < 0)
7674           return(x);
7675         if ((x = remtxt(&s)) < 0)
7676           return(x);
7677         retcode = sstate = setgen('W',s,"","");
7678         break;
7679 #endif /* NOFRILLS */
7680
7681       case XZPWD:                       /* PWD */
7682         if ((x = remcfm()) < 0) return(x);
7683         sstate = setgen('A',"","","");
7684         retcode = 0;
7685         break;
7686
7687 #ifndef NOSPL
7688       case XZQUE: {                     /* Query */
7689           char buf[2];
7690           extern char querybuf[], * qbufp;
7691           extern int qbufn;
7692           if ((y = cmkey(vartyp,nvartyp,"","",xxstring)) < 0)
7693             return(y);
7694           if ((x = cmtxt(y == 'F' ? "Remote function invocation" :
7695                          ('K' ? "Remote variable name or function":
7696                          "Remote variable name"),
7697                          "",
7698                          &s,
7699                          (y == 'K') ? xxstring : NULL
7700                          )) < 0)        /* Don't evaluate */
7701             return(x);
7702           if ((x = remtxt(&s)) < 0)
7703             return(x);
7704           query = 1;                    /* QUERY is active */
7705           qbufp = querybuf;             /* Initialize query response buffer */
7706           qbufn = 0;
7707           querybuf[0] = NUL;
7708           buf[0] = (char) (y & 127);
7709           buf[1] = NUL;
7710           retcode = sstate = setgen('V',"Q",(char *)buf,s);
7711           break;
7712       }
7713
7714       case XZASG: {                     /* Assign */
7715           char buf[VNAML];
7716           if ((y = cmfld("Remote variable name","",&s,NULL)) < 0) /* No eval */
7717             return(y);
7718           if ((int)strlen(s) >= VNAML) {
7719               printf("?Too long\n");
7720               return(-9);
7721           }
7722           ckstrncpy(buf,s,VNAML);
7723           if ((x = cmtxt("Assignment for remote variable",
7724                    "",&s,xxstring)) < 0) /* Evaluate this one */
7725             return(x);
7726           if ((x = remtxt(&s)) < 0)
7727             return(x);
7728 #ifdef COMMENT
7729 /*
7730   Server commands can't be long packets.  In principle there's no reason
7731   why they shouldn't be, except that we don't know at this point if the
7732   server is capable of accepting long packets because we haven't started
7733   the protocol yet.  In practice, allowing a long packet here breaks a lot
7734   of assumptions, causes buffer overruns and crashes, etc.  To be fixed
7735   later.  (But since this is commented out, evidently I fixed it later...)
7736 */
7737           if ((int)strlen(s) > 85) {    /* Allow for encoding expansion */
7738               printf("?Sorry, value is too long - 85 characters max\n");
7739               return(-9);
7740           }
7741 #endif /* COMMENT */
7742           retcode = sstate = setgen('V',"S",(char *)buf,s);
7743           break;
7744       }
7745 #endif /* NOSPL */
7746
7747       case XZCPY: {                     /* COPY */
7748           char buf[TMPBUFSIZ];
7749           buf[TMPBUFSIZ-1] = '\0';
7750           if ((x = cmfld("Name of remote file to copy","",&s,xxstring)) < 0) {
7751               if (x == -3) {
7752                   printf("?Name of remote file required\n");
7753                   return(-9);
7754               }
7755               else
7756                 return(x);
7757           }
7758           ckstrncpy(buf,s,TMPBUFSIZ);
7759           if ((x = cmfld("Name of remote destination file or directory",
7760                          "",&s, xxstring)) < 0) {
7761               if (x == -3) {
7762                   printf("?Name of remote file or directory required\n");
7763                   return(-9);
7764               } else return(x);
7765           }
7766           ckstrncpy(tmpbuf,s,TMPBUFSIZ);
7767           if ((x = remcfm()) < 0)
7768             return(x);
7769           if (local) ttflui();          /* If local, flush tty input buffer */
7770           retcode = sstate = setgen('K',buf,tmpbuf,"");
7771           break;
7772       }
7773       case XZREN: {                     /* Rename */
7774           char buf[TMPBUFSIZ];
7775           buf[TMPBUFSIZ-1] = '\0';
7776           if ((x = cmfld("Name of remote file to rename",
7777                          "",&s,xxstring)) < 0) {
7778               if (x == -3) {
7779                   printf("?Name of remote file required\n");
7780                   return(-9);
7781               } else return(x);
7782           }
7783           ckstrncpy(buf,s,TMPBUFSIZ);
7784           if ((x = cmfld("New name of remote file","",&s, xxstring)) < 0) {
7785               if (x == -3) {
7786                   printf("?Name of remote file required\n");
7787                   return(-9);
7788               } else return(x);
7789           }
7790           ckstrncpy(tmpbuf,s,TMPBUFSIZ);
7791           if ((x = remcfm()) < 0)
7792             return(x);
7793           if (local) ttflui();          /* If local, flush device buffer */
7794           retcode = sstate = setgen('R',buf,tmpbuf,"");
7795           break;
7796       }
7797       case XZMKD:                       /* mkdir */
7798       case XZRMD:                       /* rmdir */
7799         if ((x = cmtxt((xx == XZMKD) ?
7800                        "Name of remote directory to create" :
7801                        "Name of remote directory to delete",
7802                        "",
7803                        &s,
7804                        xxstring
7805                        )) < 0) {
7806             if (x == -3) {
7807                 printf("?Name required\n");
7808                 return(-9);
7809             } else return(x);
7810         }
7811         if ((x = remtxt(&s)) < 0)
7812           return(x);
7813         if (local) ttflui();            /* If local, flush tty input buffer */
7814         retcode = sstate = rfilop(s, (char)(xx == XZMKD ? 'm' : 'd'));
7815         break;
7816
7817       case XZXIT:                       /* Exit */
7818         if ((x = remcfm()) < 0) return(x);
7819         sstate = setgen('X',"","","");
7820         retcode = 0;
7821         break;
7822
7823       default:
7824         if ((x = remcfm()) < 0) return(x);
7825         printf("?Not implemented - %s\n",cmdbuf);
7826         return(-2);
7827     }
7828     if (local && retcode > -1)          /* If local, flush tty input buffer */
7829       ttflui();
7830     return(retcode);
7831 }
7832
7833
7834 /*  R F I L O P  --  Remote File Operation  */
7835
7836 CHAR
7837 #ifdef CK_ANSIC
7838 rfilop(char * s, char t)
7839 #else
7840 rfilop(s,t) char *s, t;
7841 #endif /* CK_ANSIC */
7842 /* rfilop */ {
7843     if (*s == NUL) {
7844         printf("?File specification required\n");
7845         return((CHAR) 0);
7846     }
7847     debug(F111,"rfilop",s,t);
7848     return(setgen(t,s,"",""));
7849 }
7850 #endif /* NOXFER */
7851
7852 #ifdef ANYX25
7853 int
7854 setx25() {
7855     if ((y = cmkey(x25tab,nx25,"X.25 call options","",xxstring)) < 0)
7856       return(y);
7857     switch (y) {
7858       case XYUDAT:
7859         if ((z = cmkey(onoff,2,"X.25 call user data","",xxstring))
7860             < 0) return(z);
7861         if (z == 0) {
7862             if ((z = cmcfm()) < 0) return(z);
7863             cudata = 0;             /* disable call user data */
7864             return (success = 1);
7865         }
7866         if ((x = cmtxt("X.25 call user data string","",&s,xxstring)) < 0)
7867           return(x);
7868         if ((int)strlen(s) == 0) {
7869             return (-3);
7870         } else if ((int)strlen(s) > MAXCUDATA) {
7871             printf("?The length must be > 0 and <= %d\n",MAXCUDATA);
7872             return(-2);
7873         }
7874         if ((y = cmcfm()) < 0) return(y);
7875         ckstrncpy(udata,s,MAXCUDATA);
7876         cudata = 1;                     /* X.25 call user data specified */
7877         return (success = 1);
7878       case XYCLOS:
7879         if ((z = cmkey(onoff,2,"X.25 closed user group call","",xxstring))
7880             < 0) return(z);
7881         if (z == 0) {
7882             if ((z = cmcfm()) < 0) return(z);
7883             closgr = -1;                /* disable closed user group */
7884             return (success = 1);
7885         }
7886         if ((y = cmnum("0 <= cug index >= 99","",10,&x,xxstring)) < 0)
7887           return(y);
7888         if (x < 0 || x > 99) {
7889             printf("?The choices are 0 <= cug index >= 99\n");
7890             return(-2);
7891         }
7892         if ((y = cmcfm()) < 0) return(y);
7893         closgr = x;                     /* closed user group selected */
7894         return (success = 1);
7895
7896       case XYREVC:
7897         if((z = cmkey(onoff,2,"X.25 reverse charge call","",xxstring)) < 0)
7898           return(z);
7899         if ((x = cmcfm()) < 0) return(x);
7900         revcall = z;
7901         return (success = 1);
7902     }
7903 }
7904
7905 #ifndef IBMX25
7906 int
7907 setpadp() {
7908     if ((y = cmkey(padx3tab,npadx3,"PAD X.3 parameter name","",xxstring)) < 0)
7909       return(y);
7910     x = y;
7911     switch (x) {
7912       case PAD_BREAK_CHARACTER:
7913         if ((y = cmnum("PAD break character value","",10,&z,xxstring)) < 0)
7914           return(y);
7915         if ((y = cmcfm()) < 0) return(y);
7916         break;
7917       case PAD_ESCAPE:
7918         if ((y = cmnum("PAD escape","",10,&z,xxstring)) < 0) return(y);
7919         if (z != 0 && z != 1) {
7920             printf("?The choices are 0 or 1\n");
7921             return(-2);
7922         }
7923         if ((y = cmcfm()) < 0) return(y);
7924         break;
7925       case PAD_ECHO:
7926         if ((y = cmnum("PAD echo","",10,&z,xxstring)) < 0) return(y);
7927         if (z != 0 && z != 1) {
7928             printf("?The choices are 0 or 1\n");
7929             return(-2);
7930         }
7931         if ((y = cmcfm()) < 0) return(y);
7932         break;
7933       case PAD_DATA_FORWARD_CHAR:
7934         if ((y = cmnum("PAD data forward char","",10,&z,xxstring)) < 0)
7935           return(y);
7936         if (z != 0 && z != 2) {
7937             printf("?The choices are 0 or 2\n");
7938             return(-2);
7939         }
7940         if ((y = cmcfm()) < 0) return(y);
7941         break;
7942       case PAD_DATA_FORWARD_TIMEOUT:
7943         if ((y = cmnum("PAD data forward timeout","",10,&z,xxstring)) < 0)
7944             return(y);
7945         if (z < 0 || z > 255) {
7946             printf("?The choices are 0 or 1 <= timeout <= 255\n");
7947             return(-2);
7948         }
7949         if ((y = cmcfm()) < 0) return(y);
7950         break;
7951       case PAD_FLOW_CONTROL_BY_PAD:
7952         if ((y = cmnum("PAD pad flow control","",10,&z,xxstring)) < 0)
7953           return(y);
7954         if (z != 0 && z != 1) {
7955             printf("?The choices are 0 or 1\n");
7956             return(-2);
7957         }
7958         if ((y = cmcfm()) < 0) return(y);
7959         break;
7960       case PAD_SUPPRESSION_OF_SIGNALS:
7961         if ((y = cmnum("PAD service","",10,&z,xxstring)) < 0) return(y);
7962         if (z != 0 && z != 1) {
7963             printf("?The choices are 0 or 1\n");
7964             return(-2);
7965         }
7966         if ((y = cmcfm()) < 0) return(y);
7967         break;
7968
7969       case PAD_BREAK_ACTION:
7970         if ((y = cmnum("PAD break action","",10,&z,xxstring)) < 0) return(y);
7971         if (z != 0 && z != 1 && z != 2 && z != 5 && z != 8 && z != 21) {
7972             printf("?The choices are 0, 1, 2, 5, 8 or 21\n");
7973             return(-2);
7974         }
7975         if ((y = cmcfm()) < 0) return(y);
7976         break;
7977
7978       case PAD_SUPPRESSION_OF_DATA:
7979         if ((y = cmnum("PAD data delivery","",10,&z,xxstring)) < 0) return(y);
7980         if (z != 0 && z != 1) {
7981             printf("?The choices are 0 or 1\n");
7982             return(-2);
7983         }
7984         if ((y = cmcfm()) < 0) return(y);
7985         break;
7986
7987       case PAD_PADDING_AFTER_CR:
7988         if ((y = cmnum("PAD crpad","",10,&z,xxstring)) < 0) return(y);
7989         if (z < 0 || z > 7) {
7990             printf("?The choices are 0 or 1 <= crpad <= 7\n");
7991             return(-2);
7992         }
7993         if ((y = cmcfm()) < 0) return(y);
7994         break;
7995
7996       case PAD_LINE_FOLDING:
7997         if ((y = cmnum("PAD linefold","",10,&z,xxstring)) < 0) return(y);
7998         if (z < 0 || z > 255) {
7999             printf("?The choices are 0 or 1 <= linefold <= 255\n");
8000             return(-2);
8001         }
8002         if ((y = cmcfm()) < 0) return(y);
8003         break;
8004
8005       case PAD_LINE_SPEED:
8006         if ((y = cmnum("PAD baudrate","",10,&z,xxstring)) < 0) return(y);
8007         if (z < 0 || z > 18) {
8008             printf("?The choices are 0 <= baudrate <= 18\n");
8009             return(-2);
8010         }
8011         if ((y = cmcfm()) < 0) return(y);
8012         break;
8013
8014       case PAD_FLOW_CONTROL_BY_USER:
8015         if ((y = cmnum("PAD terminal flow control","",10,&z,xxstring)) < 0)
8016             return(y);
8017         if (z != 0 && z != 1) {
8018             printf("?The choices are 0 or 1\n");
8019             return(-2);
8020         }
8021         if ((y = cmcfm()) < 0) return(y);
8022         break;
8023
8024       case PAD_LF_AFTER_CR:
8025         if ((y = cmnum("PAD crpad","",10,&z,xxstring)) < 0) return(y);
8026         if (z < 0 || z == 3 || z > 7) {
8027             printf("?The choices are 0, 1, 2, 4, 5, 6 or 7\n");
8028             return(-2);
8029         }
8030         if ((y = cmcfm()) < 0) return(y);
8031         break;
8032
8033       case PAD_PADDING_AFTER_LF:
8034         if ((y = cmnum("PAD lfpad","",10,&z,xxstring)) < 0) return(y);
8035         if (z < 0 || z > 7) {
8036             printf("?The choices are 0 or 1 <= lfpad <= 7\n");
8037             return(-2);
8038         }
8039         if ((y = cmcfm()) < 0) return(y);
8040         break;
8041
8042       case PAD_EDITING:
8043         if ((y = cmnum("PAD edit control","",10,&z,xxstring)) < 0) return(y);
8044         if (z != 0 && z != 1) {
8045             printf("?The choices are 0 or 1\n");
8046             return(-2);
8047         }
8048         if ((y = cmcfm()) < 0) return(y);
8049         break;
8050
8051       case PAD_CHAR_DELETE_CHAR:
8052         if ((y = cmnum("PAD char delete char","",10,&z,xxstring)) < 0)
8053             return(y);
8054         if (z < 0 || z > 127) {
8055             printf("?The choices are 0 or 1 <= chardelete <= 127\n");
8056             return(-2);
8057         }
8058         if ((y = cmcfm()) < 0) return(y);
8059         break;
8060
8061       case PAD_BUFFER_DELETE_CHAR:
8062         if ((y = cmnum("PAD buffer delete char","",10,&z,xxstring)) < 0)
8063             return(y);
8064         if (z < 0 || z > 127) {
8065             printf("?The choices are 0 or 1 <= bufferdelete <= 127\n");
8066             return(-2);
8067         }
8068         if ((y = cmcfm()) < 0) return(y);
8069         break;
8070
8071       case PAD_BUFFER_DISPLAY_CHAR:
8072         if ((y = cmnum("PAD display line char","",10,&z,xxstring)) < 0)
8073             return(y);
8074         if (z < 0 || z > 127) {
8075             printf("?The choices are 0 or 1 <= displayline <= 127\n");
8076             return(-2);
8077         }
8078         if ((y = cmcfm()) < 0) return(y);
8079         break;
8080     }
8081     padparms[x] = z;
8082     return(success = 1);
8083 }
8084 #endif /* IBMX25 */
8085 #endif /* ANYX25 */
8086
8087 #ifndef NOXFER
8088 int
8089 setat(rmsflg) int rmsflg; {
8090     int xx;
8091     if ((y = cmkey(attrtab,natr,"File Attribute packets","",xxstring)) < 0)
8092       return(y);
8093     if (y == AT_XALL) {                 /* ATTRIBUTES ALL ON or ALL OFF */
8094         if ((z = seton(&xx)) < 0) return(z);
8095         if (rmsflg) {
8096             printf("Sorry, command not available\n");
8097             return(-9);
8098         } else {
8099             atenci = xx;                /* Encoding in */
8100             atenco = xx;                /* Encoding out */
8101             atdati = xx;                /* Date in */
8102             atdato = xx;                /* Date out */
8103             atdisi = xx;                /* Disposition in/out */
8104             atdiso = xx;
8105             atleni = xx;                /* Length in/out (both kinds) */
8106             atleno = xx;
8107             atblki = xx;                /* Blocksize in/out */
8108             atblko = xx;
8109             attypi = xx;                /* File type in/out */
8110             attypo = xx;
8111             atsidi = xx;                /* System ID in/out */
8112             atsido = xx;
8113             atsysi = xx;                /* System-dependent params in/out */
8114             atsyso = xx;
8115 #ifdef CK_PERMS                         /* Protection */
8116             atlpri = xx;                /* Local in */
8117             atlpro = xx;                /* Local out */
8118             atgpri = xx;                /* Generic in */
8119             atgpro = xx;                /* Generic out */
8120 #endif /* CK_PERMS */
8121 #ifdef STRATUS
8122             atfrmi = xx;                /* Format in/out */
8123             atfrmo = xx;
8124             atcrei = xx;                /* Creator id in/out */
8125             atcreo = xx;
8126             atacti = xx;                /* Account in/out */
8127             atacto = xx;
8128 #endif /* STRATUS */
8129         }
8130         return(z);
8131     } else if (y == AT_ALLY || y == AT_ALLN) { /* ATTRIBUTES ON or OFF */
8132         if ((x = cmcfm()) < 0) return(x);
8133         atcapr = (y == AT_ALLY) ? 1 : 0;
8134         if (rmsflg) {
8135             sstate = setgen('S', "132", atcapr ? "1" : "0", "");
8136             return((int) sstate);
8137         } else return(success = 1);
8138     }
8139     /* Otherwise, it's an individual attribute that wants turning off/on */
8140
8141     if ((z = cmkey(onoff,2,"","",xxstring)) < 0) return(z);
8142     if ((x = cmcfm()) < 0) return(x);
8143
8144 /* There are better ways to do this... */
8145 /* The real problem is that we're not separating the in and out cases */
8146 /* and so we have to arbitrarily pick the "in" case, i.e tell the remote */
8147 /* server to ignore incoming attributes of the specified type, rather */
8148 /* than telling it not to send them.  The protocol does not (yet) define */
8149 /* codes for "in-and-out-at-the-same-time". */
8150
8151     switch (y) {
8152 #ifdef CK_PERMS
8153 /* We're lumping local and generic protection together for now... */
8154       case AT_LPRO:
8155       case AT_GPRO:
8156         if (rmsflg) {
8157             sstate = setgen('S', "143", z ? "1" : "0", "");
8158             return((int) sstate);
8159         }
8160         atlpri = atlpro = atgpri = atgpro = z; break;
8161 #endif /* CK_PERMS */
8162       case AT_DISP:
8163         if (rmsflg) {
8164             sstate = setgen('S', "142", z ? "1" : "0", "");
8165             return((int) sstate);
8166         }
8167         atdisi = atdiso = z; break;
8168       case AT_ENCO:
8169         if (rmsflg) {
8170             sstate = setgen('S', "141", z ? "1" : "0", "");
8171             return((int) sstate);
8172         }
8173         atenci = atenco = z; break;
8174       case AT_DATE:
8175         if (rmsflg) {
8176             sstate = setgen('S', "135", z ? "1" : "0", "");
8177             return((int) sstate);
8178         }
8179         atdati = atdato = z; break;
8180       case AT_LENB:
8181       case AT_LENK:
8182         if (rmsflg) {
8183             sstate = setgen('S', "133", z ? "1" : "0", "");
8184             return((int) sstate);
8185         }
8186         atleni = atleno = z; break;
8187       case AT_BLKS:
8188         if (rmsflg) {
8189             sstate = setgen('S', "139", z ? "1" : "0", "");
8190             return((int) sstate);
8191         }
8192         atblki = atblko = z; break;
8193       case AT_FTYP:
8194         if (rmsflg) {
8195             sstate = setgen('S', "134", z ? "1" : "0", "");
8196             return((int) sstate);
8197         }
8198         attypi = attypo = z; break;
8199 #ifdef STRATUS
8200       case AT_CREA:
8201         if (rmsflg) {
8202             sstate = setgen('S', "136", z ? "1" : "0", "");
8203             return((int) sstate);
8204         }
8205         atcrei = atcreo = z; break;
8206       case AT_ACCT:
8207         if (rmsflg) {
8208             sstate = setgen('S', "137", z ? "1" : "0", "");
8209             return((int) sstate);
8210         }
8211         atacti = atacto = z; break;
8212 #endif /* STRATUS */
8213       case AT_SYSI:
8214         if (rmsflg) {
8215             sstate = setgen('S', "145", z ? "1" : "0", "");
8216             return((int) sstate);
8217         }
8218         atsidi = atsido = z; break;
8219       case AT_RECF:
8220         if (rmsflg) {
8221             sstate = setgen('S', "146", z ? "1" : "0", "");
8222             return((int) sstate);
8223         }
8224         atfrmi = atfrmo = z; break;
8225       case AT_SYSP:
8226         if (rmsflg) {
8227             sstate = setgen('S', "147", z ? "1" : "0", "");
8228             return((int) sstate);
8229         }
8230         atsysi = atsyso = z; break;
8231       default:
8232         printf("?Not available\n");
8233         return(-2);
8234     }
8235     return(1);
8236 }
8237 #endif /* NOXFER */
8238
8239 #ifndef NOSPL
8240 int
8241 setinp() {
8242     if ((y = cmkey(inptab,ninp,"","",xxstring)) < 0) return(y);
8243     switch (y) {
8244 #ifdef OS2
8245       case IN_PAC:                      /* SET INPUT PACING */
8246         z = cmnum("milliseconds","0",10,&x,xxstring);
8247         return(setnum(&tt_inpacing,x,z,1000));
8248       case IN_TRM:                      /* SET INPUT TERMINAL */
8249         return(seton(&interm));
8250 #endif /* OS2 */
8251       case IN_DEF:                      /* SET INPUT DEFAULT-TIMEOUT */
8252         z = cmnum("Positive number","",10,&x,xxstring);
8253         return(setnum(&indef,x,z,94));
8254 #ifdef CKFLOAT
8255       case IN_SCA:                      /* SET INPUT SCALE-FACTOR */
8256         if ((x = cmfld("Number such as 2 or 0.5","1.0",&s, xxstring)) < 0)
8257           return(x);
8258         if (isfloat(s,0)) {             /* A floating-point number? */
8259             extern char * inpscale;
8260             inscale = floatval;         /* Yes, get its value */
8261             makestr(&inpscale,s);       /* Save it as \v(inscale) */
8262             return(success = 1);
8263         } else {
8264             return(-2);
8265         }
8266 #endif  /* CKFLOAT */
8267       case IN_TIM:                      /* SET INPUT TIMEOUT-ACTION */
8268         if ((z = cmkey(intimt,2,"","",xxstring)) < 0) return(z);
8269         if ((x = cmcfm()) < 0) return(x);
8270         intime[cmdlvl] = z;
8271         return(success = 1);
8272       case IN_CAS:                      /* SET INPUT CASE */
8273         if ((z = cmkey(incast,2,"","",xxstring)) < 0) return(z);
8274         if ((x = cmcfm()) < 0) return(x);
8275         inpcas[cmdlvl] = z;
8276         return(success = 1);
8277       case IN_ECH:                      /* SET INPUT ECHO */
8278         return(seton(&inecho));
8279       case IN_SIL:                      /* SET INPUT SILENCE */
8280         z = cmnum("Seconds of inactivity before INPUT fails","",10,&x,
8281                   xxstring);
8282         return(setnum(&insilence,x,z,-1));
8283
8284       case IN_BUF:                      /* SET INPUT BUFFER-SIZE */
8285         if ((z = cmnum("Number of bytes in INPUT buffer",
8286                        ckitoa(INPBUFSIZ),10,&x, xxstring)) < 0)
8287           return(z);
8288         if ((y = cmcfm()) < 0) return(y);
8289         inbufsize = 0;
8290         if (inpbuf) {
8291             free(inpbuf);
8292             inpbuf = NULL;
8293             inpbp = NULL;
8294         }
8295         if (!(s = (char *)malloc(x + 1)))
8296           return(0);
8297         inpbuf = s;
8298         inpbp = s;
8299         inbufsize = x;
8300         for (x = 0; x <= inbufsize; x++)
8301           inpbuf[x] = NUL;
8302         return(success = 1);
8303
8304 #ifdef CK_AUTODL
8305       case IN_ADL:                      /* AUTODOWNLOAD */
8306         return(seton(&inautodl));
8307 #endif /* CK_AUTODL */
8308
8309       case IN_CAN:                      /* SET INPUT INTERRUPTS */
8310         return(seton(&inintr));
8311     }
8312     return(0);
8313 }
8314 #endif /* NOSPL */
8315
8316 #ifdef NETCONN
8317 VOID
8318 ndreset() {
8319 #ifndef NODIAL                          /* This depends on DIAL... */
8320     int i=0, j=0;
8321     if (!ndinited)                      /* Don't free garbage... */
8322       return;
8323     for (i = 0; i < nhcount; i++) {     /* Clean out previous list */
8324         if (nh_p[i])
8325           free(nh_p[i]);
8326         nh_p[i] = NULL;
8327         if (nh_p2[i])
8328           free(nh_p2[i]);
8329         nh_p2[i] = NULL;
8330         for (j = 0; j < 4; j++) {
8331             if (nh_px[j][i])
8332               free(nh_px[j][i]);
8333             nh_px[j][i] = NULL;
8334         }
8335     }
8336 #endif /* NODIAL */
8337 }
8338
8339 VOID
8340 ndinit() {                              /* Net directory pointers */
8341 #ifndef NODIAL                          /* This depends on DIAL... */
8342     int i, j;
8343     if (ndinited++)                     /* Don't do this more than once. */
8344       return;
8345     for (i = 0; i < MAXDDIR; i++) {     /* Init all pointers to NULL */
8346         netdir[i] = NULL;
8347     }
8348     for (i = 0; i < MAXDNUMS; i++) {
8349         nh_p[i] = NULL;
8350         nh_p2[i] = NULL;
8351         for (j = 0; j < 4; j++)
8352           nh_px[j][i] = NULL;
8353     }
8354 #endif /* NODIAL */
8355 }
8356
8357 #ifndef NODIAL
8358 #ifdef NETCONN
8359 VOID                                    /* Get net defaults from environment */
8360 getnetenv() {
8361     char *p = NULL;
8362
8363     makestr(&p,getenv("K_NET_DIRECTORY")); /* Dialing directories */
8364     if (p) {
8365         int i;
8366         xwords(p,MAXDDIR,netdir,0);
8367         for (i = 0; i < MAXDDIR; i++) { /* Fill in any gaps... */
8368             if (!netdir[i+1])
8369               break;
8370             else
8371               netdir[i] = netdir[i+1];
8372             debug(F111,"netdir[i]",netdir[i],i);
8373         }
8374         nnetdir = i;
8375     }
8376 }
8377 #endif /* NETCONN */
8378 #endif /* NODIAL */
8379
8380 int
8381 #ifdef CK_ANSIC
8382 lunet(char *s)                          /* s = name to look up   */
8383 #else
8384 lunet(s) char *s;
8385 #endif /* CK_ANSIC */
8386 /* lunet */ {
8387 #ifndef NODIAL                          /* This depends on DIAL... */
8388     int n, n1, t, dd = 0;
8389     int ambiguous = 0;
8390     FILE * f;
8391     char *line = NULL;
8392     extern int dialdpy;
8393     int netdpy = dialdpy;
8394     char *info[8];
8395
8396     nhcount = 0;                        /* Set this before returning */
8397
8398     if (!s || nnetdir < 1)              /* Validate arguments */
8399       return(-1);
8400
8401     if (isdigit(*s) || *s == '*' || *s == '.')
8402       return(0);
8403
8404     if ((n1 = (int) strlen(s)) < 1)     /* Length of string to look up */
8405       return(-1);
8406
8407     if (!(line = malloc(1024)))         /* Allocate input buffer */
8408       return(-1);
8409
8410   lu_again:
8411     f = NULL;                           /* Network directory file descriptor */
8412     t = nhcount = 0;                    /* Match count */
8413     dd = 0;                             /* Directory counter */
8414
8415     dirline = 0;
8416     while (1) {                         /* We make one pass */
8417         if (!f) {                       /* Directory not open */
8418             if (dd >= nnetdir)          /* No directories left? */
8419               break;                    /* Done. */
8420             if ((f = fopen(netdir[dd],"r")) == NULL) { /* Open it */
8421                 perror(netdir[dd]);     /* Can't, print message saying why */
8422                 dd++;
8423                 continue;               /* But go on to next one. */
8424             }
8425             if (netdpy)
8426               printf("Opening %s...\n",netdir[dd]);
8427             dd++;
8428         }
8429         line[0] = NUL;
8430         if (getnct(line,1023,f,1) < 0) { /* Read a line */
8431             if (f) {                    /* f can be clobbered! */
8432                 fclose(f);              /* Close the file */
8433                 f = NULL;               /* Indicate next one needs opening */
8434             }
8435             continue;
8436         }
8437         if (!line[0])                   /* Empty line */
8438           continue;
8439
8440         xwords(line,7,info,0);          /* Parse it */
8441
8442         if (!info[1] || !info[2] || !info[3]) /* Required fields */
8443           continue;
8444         if (*info[1] == ';')            /* Full-line comment */
8445           continue;
8446         if ((n = (int) strlen(info[1])) < 1) /* Length of name-tag */
8447           continue;
8448         if (n < n1)                     /* Search name is longer */
8449           continue;                     /* Can't possibly match */
8450         if (ambiguous && n != n1)
8451           continue;
8452         if (ckstrcmp(s,info[1],n1,0))   /* Compare using length of */
8453           continue;                     /* search string s. */
8454
8455         /* Have a match */
8456
8457         makestr(&(nh_p[nhcount]), info[3]);    /* address */
8458         makestr(&(nh_p2[nhcount]),info[2]);    /* net type */
8459         makestr(&(nh_px[0][nhcount]),info[4]); /* net-specific stuff... */
8460         makestr(&(nh_px[1][nhcount]),info[5]);
8461         makestr(&(nh_px[2][nhcount]),info[6]);
8462         makestr(&(nh_px[3][nhcount]),info[7]);
8463
8464         nhcount++;                      /* Count this match */
8465         if (nhcount > MAXDNUMS) {       /* Watch out for too many */
8466             printf("Warning: %d matches found, %d max\n",
8467                    nhcount,
8468                    MAXDNUMS
8469                    );
8470             nhcount = MAXDNUMS;
8471             break;
8472         }
8473         if (nhcount == 1) {             /* First one - save entry name */
8474             if (n_name) {               /* Free the one from before if any */
8475                 free(n_name);
8476                 n_name = NULL;
8477             }
8478             if (!(n_name = (char *)malloc(n + 1))) { /* Allocate new storage */
8479                 printf("?memory allocation error - lunet:3\n");
8480                 if (line) {
8481                     free(line);
8482                     line = NULL;
8483                 }
8484                 nhcount = 0;
8485                 return(-1);
8486             }
8487             t = n;                      /* Remember its length */
8488             strcpy(n_name,info[1]);     /* safe */
8489         } else {                        /* Second or subsequent one */
8490             if ((int) strlen(info[1]) == t) /* Lengths compare */
8491               if (!ckstrcmp(n_name,info[1],t,0)) /* Caseless compare OK */
8492                 continue;
8493
8494             /* Name given by user matches entries with different names */
8495
8496             if (ambiguous)              /* Been here before */
8497               break;
8498
8499             ambiguous = 1;              /* Now an exact match is required */
8500             ndreset();                  /* Clear out previous list */
8501             goto lu_again;              /* Do it all over again. */
8502         }
8503     }
8504     if (line) {
8505         free(line);
8506         line = NULL;
8507     }
8508     if (nhcount == 0 && ambiguous)
8509       printf("?\"%s\" - ambiguous in network directory\n",s);
8510 #else
8511     nhcount = 0;
8512 #endif /* NODIAL */
8513     return(nhcount);
8514 }
8515 #endif /* NETCONN */
8516
8517 #ifndef NOLOCAL
8518 /*  C L S C O N N X  --  Close connection  */
8519
8520 int
8521 clsconnx(ask) int ask; {
8522     int x, rc = 0;
8523 #ifdef NEWFTP
8524     extern int ftpget, ftpisopen(), ftpbye();
8525     if ((ftpget == 1) || ((ftpget == 2) && !local && ftpisopen()))
8526       return(success = ftpbye());
8527 #endif /* NEWFTP */
8528     debug(F101,"clsconnx local","",local);
8529     if (local) {
8530         x = ask ? hupok(1) : 1;         /* Make sure it's OK to close */
8531         if (!x) {
8532             rc = -1;
8533             debug(F101,"clsconnx hupok says no","",rc);
8534             return(rc);
8535         }
8536         ttflui();                       /* Clear away buffered up junk */
8537 #ifndef NODIAL
8538 #ifdef OS2ONLY
8539 /* Don't hangup a line that is shared with the SLIP or PPP driver */
8540         if (!ttslip && !ttppp)
8541 #endif /* OS2ONLY */
8542           mdmhup();
8543 #endif /* NODIAL */
8544         if (network && msgflg)
8545           printf(" Closing connection\n");
8546         ttclos(0);                      /* Close old connection, if any */
8547         rc = 1;
8548         {
8549             extern int wasclosed, whyclosed;
8550             if (wasclosed) {
8551                 whyclosed = WC_CLOS;
8552 #ifndef NOSPL
8553                 if (nmac) {             /* Any macros defined? */
8554                     int k;              /* Yes */
8555                     /* printf("ON_CLOSE CLSCONNX\n"); */
8556                     wasclosed = 0;
8557                     k = mlook(mactab,"on_close",nmac);  /* Look this up */
8558                     if (k >= 0) {                       /* If found, */
8559                         if (dodo(k,ckitoa(whyclosed),0) > -1) /* set it up, */
8560                           parser(1);                    /* and execute it */
8561                     }
8562                 }
8563 #endif /* NOSPL */
8564                 whyclosed = WC_REMO;
8565                 wasclosed = 0;
8566             }
8567         }
8568     }
8569 #ifdef VMS                              /* Or maybe #ifndef UNIX? */
8570     else {                              /* Need to do this in VMS to */
8571         ttclos(0);                      /* free the tty channel number */
8572         rc = 1;                         /* obtained in ttopen() or else */
8573     }                                   /* subsequent ttopen's won't work */
8574 #endif /* VMS */
8575     dologend();
8576     haveline = 0;
8577     if (mdmtyp < 0) {                   /* Switching from net to async? */
8578         if (mdmsav > -1)                /* Restore modem type from last */
8579           mdmtyp = mdmsav;              /* SET MODEM command, if any. */
8580         else
8581           mdmtyp = 0;
8582         mdmsav = -1;
8583     }
8584     if (network)
8585       network = 0;
8586 #ifdef NETCONN
8587     if (oldplex > -1) {                 /* Restore previous duplex setting. */
8588         duplex = oldplex;
8589         oldplex = -1;
8590     }
8591 #endif /* NETCONN */
8592 #ifndef MAC
8593     ckstrncpy(ttname,dftty,TTNAMLEN);   /* Restore default communication */
8594 #endif /* MAC */
8595     local = dfloc;                      /* device and local/remote status */
8596     if (local) {
8597         cxtype = CXT_DIRECT;            /* Something reasonable */
8598         speed = ttgspd();               /* Get the current speed */
8599     } else {
8600         cxtype = CXT_REMOTE;
8601         speed = -1L;
8602     }
8603 #ifndef NOXFER
8604     if (xreliable > -1 && !setreliable) {
8605         reliable = xreliable;
8606         debug(F101,"clsconnx reliable A","",reliable);
8607     } else if (!setreliable) {
8608         reliable = SET_AUTO;
8609         debug(F101,"clsconnx reliable B","",reliable);
8610     }
8611 #endif /* NOXFER */
8612     setflow();                          /* Revert flow control */
8613     return(rc);
8614 }
8615
8616 int
8617 clskconnx(x) int x; {                   /* Close Kermit connection only */
8618     int t, rc;                          /* (not FTP) */
8619 #ifdef NEWFTP
8620     extern int ftpget;
8621     t = ftpget;
8622     ftpget = 0;
8623 #endif /* NEWFTP */
8624     rc = clsconnx(x);
8625 #ifdef NEWFTP
8626     ftpget = t;
8627 #endif /* NEWFTP */
8628     return(rc);
8629 }
8630
8631 /* May 2002: setlin() decomposition starts here ... */
8632
8633 #ifdef OS2
8634 #define SRVBUFSIZ PIPENAML
8635 #else /* OS2 */
8636 #define SRVBUFSIZ 63
8637 #endif /* OS2 */
8638 #define HOSTNAMLEN 15*65
8639
8640 int netsave = -1;
8641 static char * tmpstring = NULL;
8642 static char * tmpusrid = NULL;
8643
8644 #ifdef SSHCMD
8645 char * sshcmd = NULL;
8646 char * defsshcmd = "ssh -e none";
8647 #else
8648 #ifdef SSHBUILTIN
8649 char * sshrcmd = NULL;
8650 char * sshtmpcmd = NULL;
8651 #endif /* SSHBUILTIN */
8652 #endif /* SSHCMD */
8653
8654 /* c x _ f a i l  --  Common error exit routine for cx_net, cx_line */
8655
8656 int
8657 cx_fail(msg, text) int msg; char * text; {
8658     makestr(&slmsg,text);               /* For the record (or GUI) */
8659     if (msg)                            /* Not GUI, not quiet, etc */
8660       printf("?%s\n",text);             /* Print error message */
8661     slrestor();                         /* Restore LINE/HOST to known state */
8662     return(msg ? -9 : (success = 0));   /* Return appropriate code */
8663 }
8664
8665 #ifdef NETCONN
8666 /* c x _ n e t  --  Make a network connection */
8667
8668 /*
8669   Call with:
8670     net      = network type
8671     protocol = protocol type
8672     host     = string pointer to host name.
8673     svc      = string pointer to service or port on host.
8674     username = username for connection
8675     password = password for connection
8676     command  = command to execute
8677     param1   = Telnet: Authentication type
8678                SSH:    Version
8679     param2   = Telnet: Encryption type
8680                SSH:    Command as Subsystem
8681     param3   = Telnet: 1 to wait for negotiations, 0 otherwise
8682                SSH:    X11 Forwarding
8683     cx       = 1 to automatically enter Connect mode, 0 otherwise.
8684     sx       = 1 to automatically enter Server mode, 0 otherwise.
8685     flag     = if no host name given, 1 = close current connection, 0 = resume
8686     gui      = 1 if called from GUI dialog, 0 otherwise.
8687   Returns:
8688     1 on success
8689     0 on failure and no message printed, slmsg set to failure message.
8690    -9 on failure and message printed, ditto.
8691 */
8692 int
8693 #ifdef CK_ANSIC
8694 cx_net( int net, int protocol, char * xhost, char * svc, 
8695         char * username, char * password, char * command,
8696         int param1, int param2, int param3, int cx, int sx, int flag, int gui)
8697 #else /* CK_ANSIC */
8698 cx_net(net, protocol, xhost, svc,
8699        username, password, command,
8700        param1, param2, param3, cx, sx, flag, gui)
8701     char * xhost, * svc, * username, *password, *command; 
8702     int net, protocol, cx, sx, flag, param1, param2, param3, gui; 
8703 #endif /* CK_ANSIC */
8704 /* cx_net */ {
8705
8706     int i, n, x, msg;
8707     int _local = -1;
8708
8709     extern char pwbuf[], * g_pswd;
8710     extern int pwflg, pwcrypt, g_pflg, g_pcpt, nolocal;
8711
8712     char srvbuf[SRVBUFSIZ+1];           /* Service */
8713     char hostbuf[HOSTNAMLEN];           /* Host buffer to manipulate */
8714     char hostname[HOSTNAMLEN];          /* Copy of host parameter */
8715     char * host = hostbuf;              /* Pointer to copy of host param */
8716
8717     if (!xhost) xhost = "";             /* Watch out for null pointers */
8718     if (!svc) svc = "";
8719     ckstrncpy(host,xhost,HOSTNAMLEN);   /* Avoid buffer confusion */
8720
8721     debug(F110,"cx_net host",host,0);
8722     debug(F111,"cx_net service",svc,SRVBUFSIZ);
8723     debug(F101,"cx_net network type","",net);
8724
8725     msg = (gui == 0) && msgflg;         /* Whether to print messages */
8726
8727 #ifndef NODIAL
8728     debug(F101,"cx_net nnetdir","",nnetdir);
8729     x = 0;                              /* Look up in network directory */
8730     if (*host == '=') {                 /* If number starts with = sign */
8731         host++;                         /* strip it */
8732         while (*host == SP) host++;     /* and any leading spaces */
8733         debug(F110,"cx_net host 2",host,0);
8734         nhcount = 0;
8735     } else if (*host) {                 /* We want to look it up. */
8736         if (nnetdir > 0)                /* If there is a directory... */
8737           x = lunet(host);              /* (sets nhcount) */
8738         else                            /* otherwise */
8739           nhcount = 0;                  /* we didn't find any there */
8740         if (x < 0)                      /* Internal error? */
8741           return(cx_fail(msg,"Network directory lookup error"));
8742         debug(F111,"cx_net lunet nhcount",host,nhcount);
8743     }
8744 #endif /* NODIAL */
8745
8746     /* New connection wanted.  Make a copy of the host name/address... */
8747
8748     if (clskconnx(1) < 0)               /* Close current Kermit connection */
8749       return(cx_fail(msg,"Error closing previous connection"));
8750
8751     if (*host) {                        /* They gave a hostname */
8752         _local = 1;                     /* Network connection always local */
8753         if (mdmsav < 0)
8754           mdmsav = mdmtyp;              /* Remember old modem type */
8755         mdmtyp = -net;                  /* Special code for network */
8756     } else {                            /* They just said "set host" */
8757         host = dftty;                   /* So go back to normal */
8758         _local = dfloc;                 /* default tty, location, */
8759         if (flag) {                     /* Close current connection */
8760             setflow();                  /* Maybe change flow control */
8761             haveline = 1;               /* (* is this right? *) */
8762             dologend();
8763 #ifndef NODIAL
8764             dialsta = DIA_UNK;
8765 #endif /* NODIAL */
8766 #ifdef LOCUS
8767             if (autolocus) {
8768                 setlocus(1,1);
8769             }
8770 #endif /* LOCUS */
8771             /* XXX - Is this right? */
8772             /* Should we be returning without doing anything ? */
8773             /* Yes it's right -- we closed the old connection just above. */
8774             return(success = 1);        
8775         }
8776     }
8777     success = 0;
8778     if (host != line)                   /* line[] is a global */
8779       ckstrncpy(line,host,LINBUFSIZ);
8780     ckstrncpy(hostname,host,HOSTNAMLEN);
8781     ckstrncpy(srvbuf,svc,SRVBUFSIZ+1);
8782
8783 #ifndef NODIAL
8784     if ((nhcount > 1) && msg) {
8785         int k;
8786         printf("%d entr%s found for \"%s\"%s\n",
8787                nhcount,
8788                (nhcount == 1) ? "y" : "ies",
8789                s,
8790                (nhcount > 0) ? ":" : "."
8791                );
8792         for (i = 0; i < nhcount; i++) {
8793                 printf("%3d. %-12s => %-9s %s",
8794                        i+1,n_name,nh_p2[i],nh_p[i]);
8795             for (k = 0; k < 4; k++) { /* Also list net-specific items */
8796                 if (nh_px[k][i])      /* free format... */
8797                   printf(" %s",nh_px[k][i]);
8798                 else
8799                   break;
8800             }
8801             printf("\n");
8802         }
8803     }
8804     if (nhcount == 0)
8805       n = 1;
8806     else
8807       n = nhcount;
8808 #else
8809     n = 1;
8810     nhcount = 0;
8811 #endif /* NODIAL */
8812
8813     for (i = 0; i < n; i++) {           /* Loop for each entry found */
8814         debug(F101,"cx_net loop i","",i);
8815 #ifndef NODIAL
8816         if (nhcount > 0) {              /* If we found at least one entry... */
8817             ckstrncpy(line,nh_p[i],LINBUFSIZ); /* Copy current entry */
8818             if (lookup(netcmd,nh_p2[i],nnets,&x) > -1) { /* Net type */
8819                 int xx;
8820                 xx = netcmd[x].kwval;
8821                 /* User specified SSH so don't let net directory override */
8822                 if (net != NET_SSH || xx != NET_TCPB) {
8823                     net = xx;
8824                     mdmtyp  = 0 - net;
8825                 }
8826             } else {
8827                 makestr(&slmsg,"Network type not supported");
8828                 if (msg)
8829                   printf("Error - network type \"%s\" not supported\n",
8830                          nh_p2[i]
8831                          );
8832                 continue;
8833             }
8834             switch (net) {              /* Net-specific directory things */
8835 #ifdef SSHBUILTIN
8836               case NET_SSH:             /* SSH */
8837                 /* Any SSH specific network directory stuff? */
8838                 break;                  /* NET_SSH */
8839 #endif /* SSHBUILTIN */
8840
8841               case NET_TCPB: {          /* TCP/IP TELNET,RLOGIN,... */
8842 #ifdef TCPSOCKET
8843                   char *q;
8844                   int flag = 0;
8845
8846                   /* Extract ":service", if any, from host string */
8847                   debug(F110,"cx_net service 1",line,0);
8848                   for (q = line; (*q != '\0') && (*q != ':'); q++)
8849                     ;
8850                   if (*q == ':') { *q++ = NUL; flag = 1; }
8851                   debug(F111,"cx_net service 2",line,flag);
8852
8853                   /* Get service, if any, from directory entry */
8854
8855                   if (!*srvbuf) {
8856                       if (nh_px[0][i]) {
8857                           ckstrncpy(srvbuf,nh_px[0][i],SRVBUFSIZ);
8858                           debug(F110,"cx_net service 3",srvbuf,0);
8859                       }
8860                       if (flag) {
8861                           ckstrncpy(srvbuf,q,SRVBUFSIZ);
8862                           debug(F110,"cx_net service 4",srvbuf,0);
8863                       }
8864                   }
8865                   ckstrncpy(hostname,line,HOSTNAMLEN);
8866
8867                   /* If we have a service, append to host name/address */
8868                   if (*srvbuf) {
8869                       ckstrncat(line, ":", LINBUFSIZ);
8870                       ckstrncat(line, srvbuf, LINBUFSIZ);
8871                       debug(F110,"cx_net service 5",line,0);
8872                   }
8873 #ifdef RLOGCODE
8874                   /* If no service given but command was RLOGIN */
8875                   else if (ttnproto == NP_RLOGIN) { /* add this... */
8876                       ckstrncat(line, ":login",LINBUFSIZ);
8877                       debug(F110,"cx_net service 6",line,0);
8878                   }
8879 #ifdef CK_AUTHENTICATION
8880 #ifdef CK_KERBEROS
8881                   else if (ttnproto == NP_K4LOGIN ||
8882                            ttnproto == NP_K5LOGIN) { /* add this... */
8883                       ckstrncat(line, ":klogin",LINBUFSIZ);
8884                       debug(F110,"cx_net service 7",line,0);
8885                   }
8886                   else if (ttnproto == NP_EK4LOGIN ||
8887                            ttnproto == NP_EK5LOGIN) { /* add this... */
8888                       ckstrncat(line, ":eklogin",LINBUFSIZ);
8889                       debug(F110,"cx_net service 8",line,0);
8890                   }
8891 #endif /* CK_KERBEROS */
8892 #endif /* CK_AUTHENTICATION */
8893 #endif /* RLOGCODE */
8894                   else {                /* Otherwise, add ":telnet". */
8895                       ckstrncat(line, ":telnet", LINBUFSIZ);
8896                       debug(F110,"cx_net service 9",line,0);
8897                   }
8898                   if (username) {       /* This is a parameter... */
8899                       ckstrncpy(uidbuf,username,UIDBUFLEN);
8900                       uidflag = 1;
8901                   }
8902                   /* Fifth field, if any, is user ID (for rlogin) */
8903
8904                   if (nh_px[1][i] && !uidflag)
8905                     ckstrncpy(uidbuf,username,UIDBUFLEN);
8906 #ifdef RLOGCODE
8907                   if (IS_RLOGIN() && !uidbuf[0])
8908                     return(cx_fail(msg,"Username required"));
8909 #endif /* RLOGCODE */
8910 #endif /* TCPSOCKET */
8911                   break;
8912               }
8913               case NET_PIPE:            /* Pipe */
8914 #ifdef NPIPE
8915                 if (!pipename[0]) { /* User didn't give a pipename */
8916                     if (nh_px[0][i]) { /* But directory entry has one */
8917                         if (strcmp(pipename,"\\pipe\\")) {
8918                             ckstrncpy(pipename,"\\pipe\\",LINBUFSIZ);
8919                             ckstrncat(srvbuf,nh_px[0][i],PIPENAML-6);
8920                         } else {
8921                             ckstrncpy(pipename,nh_px[0][i],PIPENAML);
8922                         }
8923                         debug(F110,"cx_net pipeneme",pipename,0);
8924                     }
8925                 }
8926 #endif /* NPIPE */
8927                 break;
8928
8929               case NET_SLAT:            /* LAT / CTERM */
8930 #ifdef SUPERLAT
8931                 if (!slat_pwd[0]) { /* User didn't give a password */
8932                     if (nh_px[0][i]) { /* But directory entry has one */
8933                         ckstrncpy(slat_pwd,nh_px[0][i],18);
8934                         debug(F110,"cx_net SuperLAT password",slat_pwd,0);
8935                     }
8936                 }
8937 #endif /* SUPERLAT */
8938                 break;
8939
8940               case NET_SX25:        /* X.25 keyword parameters */
8941               case NET_IX25:
8942               case NET_VX25: {
8943 #ifdef ANYX25
8944                   int k;            /* Cycle through the four fields */
8945                   for (k = 0; k < 4; k++) {
8946                       if (!nh_px[k][i]) /* Bail out if none left */
8947                         break;
8948                       if (!ckstrcmp(nh_px[k][i],"cug=",4,0)) {
8949                           closgr = atoi(nh_px[k][i]+4);
8950                           debug(F101,"X25 CUG","",closgr);
8951                       } else if (!ckstrcmp(nh_px[k][i],"cud=",4,0)) {
8952                           cudata = 1;
8953                           ckstrncpy(udata,nh_px[k][i]+4,MAXCUDATA);
8954                           debug(F110,"X25 CUD",cudata,0);
8955                       } else if (!ckstrcmp(nh_px[k][i],"rev=",4,0)) {
8956                           revcall = !ckstrcmp(nh_px[k][i]+4,"=on",3,0);
8957                           debug(F101,"X25 REV","",revcall);
8958 #ifndef IBMX25
8959                       } else if (!ckstrcmp(nh_px[k][i],"pad=",4,0)) {
8960                           int x3par, x3val;
8961                           char *s1, *s2;
8962                           s1 = s2 = nh_px[k][i]+4; /* PAD parameters */
8963                           while (*s2) {            /* Pick them apart */
8964                               if (*s2 == ':') {
8965                                   *s2 = NUL;
8966                                   x3par = atoi(s1);
8967                                   s1 = ++s2;
8968                                   continue;
8969                               } else if (*s2 == ',') {
8970                                   *s2 = NUL;
8971                                   x3val = atoi(s1);
8972                                   s1 = ++s2;
8973                                   debug(F111,"X25 PAD",x3par,x3val);
8974                                   if (x3par > -1 &&
8975                                       x3par <= MAXPADPARMS)
8976                                     padparms[x3par] = x3val;
8977                                   continue;
8978                               } else
8979                                 s2++;
8980                           }
8981 #endif /* IBMX25 */
8982                       }
8983                   }
8984 #endif /* ANYX25 */
8985                   break;
8986               }
8987               default:                  /* Nothing special for other nets */
8988                 break;
8989             }
8990         } else
8991 #endif /* NODIAL */
8992         {                               /* No directory entries found. */
8993             ckstrncpy(line,hostname,LINBUFSIZ); /* Put this back... */
8994             /* If the user gave a TCP service */
8995             if (net == NET_TCPB || net == NET_SSH)
8996               if (*srvbuf) {            /* Append it to host name/address */
8997                   ckstrncat(line, ":", LINBUFSIZ);
8998                   ckstrncat(line, srvbuf,LINBUFSIZ);
8999               }
9000         }
9001         /*
9002            Get here with host name/address and all net-specific
9003            parameters set, ready to open the connection.
9004         */
9005         mdmtyp = -net;                  /* This should have been done */
9006                                         /* already but just in case ... */
9007
9008         debug(F110,"cx_net net line[] before ttopen",line,0);
9009         debug(F101,"cx_net net mdmtyp before ttopen","",mdmtyp);
9010         debug(F101,"cx_net net ttnproto","",ttnproto);
9011
9012 #ifdef SSHBUILTIN
9013         if (net == NET_SSH) {
9014             makestr(&ssh_hst,hostname);        /* Stash everything */
9015             if (username) {
9016                 if (!sl_uid_saved) {
9017                     ckstrncpy(sl_uidbuf,uidbuf,UIDBUFLEN);
9018                     sl_uid_saved = 1;
9019                 }
9020                 ckstrncpy(uidbuf,username,UIDBUFLEN);
9021             }
9022             if (srvbuf[0]) {
9023                 makestr(&ssh_prt,srvbuf);
9024             } else
9025                 makestr(&ssh_prt,NULL);
9026
9027             if (command) {
9028                 makestr(&ssh_cmd,brstrip(command));
9029                 ssh_cas = param2;
9030             } else
9031                 makestr(&ssh_cmd,NULL);
9032
9033             if (param1 > -1) {
9034 #ifndef SSHTEST
9035                 if (!sl_ssh_ver_saved) {
9036                     sl_ssh_ver = ssh_ver;
9037                     sl_ssh_ver_saved = 1;
9038                 }
9039 #endif /* SSHTEST */
9040                 ssh_ver = param1;
9041             }
9042             if (param3 > -1) {
9043 #ifndef SSHTEST
9044                 if (!sl_ssh_xfw_saved) {
9045                     sl_ssh_xfw = ssh_xfw;
9046                     sl_ssh_xfw_saved = 1;
9047                 }
9048 #endif /* SSHTEST */
9049                 ssh_xfw = param3;
9050             }
9051         } else                          /* NET_SSH */
9052 #endif /* SSHBUILTIN */
9053 #ifdef TCPSOCKET
9054           if (net == NET_TCPB) {
9055             switch (protocol) {
9056 #ifdef CK_SSL
9057               case NP_SSL:
9058                 ttnproto = protocol;
9059                 ssl_only_flag = 1;
9060                 tls_only_flag = 0;
9061                 break;
9062
9063               case NP_TLS:
9064                 ttnproto = protocol;
9065                 ssl_only_flag = 0;
9066                 tls_only_flag = 1;
9067                 break;
9068
9069               case NP_SSL_TELNET:
9070                 ttnproto = NP_TELNET;
9071                 ssl_only_flag = 1;
9072                 tls_only_flag = 0;
9073                 break;
9074
9075               case NP_TLS_TELNET:
9076                 ttnproto = NP_TELNET;
9077                 ssl_only_flag = 0;
9078                 tls_only_flag = 1;
9079                 break;
9080 #endif /* CK_SSL */
9081               case NP_NONE:
9082               case NP_TCPRAW:
9083               case NP_RLOGIN:
9084               case NP_K4LOGIN:
9085               case NP_K5LOGIN:
9086               case NP_EK4LOGIN:
9087               case NP_EK5LOGIN:
9088               case NP_TELNET:
9089               case NP_KERMIT:
9090               default:
9091                 ttnproto = protocol;
9092 #ifdef CK_SSL
9093                 ssl_only_flag = 0;
9094                 tls_only_flag = 0;
9095 #endif /* CK_SSL */
9096                 break;
9097             }
9098 #ifdef CK_AUTHENTICATION
9099             if ((ttnproto == NP_TELNET || ttnproto == NP_KERMIT) &&
9100                 param1 > -1) {
9101             if (!sl_auth_saved) {
9102                 int x;
9103                 for (x = 0; x < AUTHTYPLSTSZ; x++)
9104                   sl_auth_type_user[x] = auth_type_user[x];
9105                 sl_auth_saved = 1;
9106             }
9107             if (!sl_topt_a_s_saved) {
9108                 sl_topt_a_su = TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION);
9109                 sl_topt_a_s_saved = 1;
9110             }
9111             if (!sl_topt_a_c_saved) {
9112                 sl_topt_a_cm = TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION);
9113                 sl_topt_a_c_saved = 1;
9114             }
9115             switch (param1) {
9116               case AUTHTYPE_AUTO:
9117                 auth_type_user[0] = AUTHTYPE_AUTO;
9118                 TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_RQ;
9119                 TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_RQ;
9120                 break;
9121               case AUTHTYPE_NULL:
9122                 auth_type_user[0] = AUTHTYPE_NULL;
9123                 TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_RF;
9124                 TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_RF;
9125                 break;
9126 #ifdef CK_SRP
9127               case AUTHTYPE_SRP:
9128                 auth_type_user[0] = AUTHTYPE_SRP;
9129                 auth_type_user[1] = AUTHTYPE_NULL;
9130                 TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
9131                 TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
9132                 break;
9133 #endif /* CK_SRP */
9134 #ifdef CK_SSL
9135               case AUTHTYPE_SSL:
9136                 auth_type_user[0] = AUTHTYPE_SSL;
9137                 auth_type_user[1] = AUTHTYPE_NULL;
9138                 TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
9139                 TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
9140                 break;
9141 #endif /* CK_SSL */
9142 #ifdef NT
9143               case AUTHTYPE_NTLM:
9144                 auth_type_user[0] = AUTHTYPE_NTLM;
9145                 auth_type_user[1] = AUTHTYPE_NULL;
9146                 TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
9147                 TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
9148                 break;
9149 #endif /* NT */
9150 #ifdef CK_KERBEROS
9151               case AUTHTYPE_KERBEROS_V4:
9152                 auth_type_user[0] = AUTHTYPE_KERBEROS_V4;
9153                 auth_type_user[1] = AUTHTYPE_NULL;
9154                 TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
9155                 TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
9156                 break;
9157
9158               case AUTHTYPE_KERBEROS_V5:
9159                 auth_type_user[0] = AUTHTYPE_KERBEROS_V5;
9160                 auth_type_user[1] = AUTHTYPE_NULL;
9161                 TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
9162                 TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_MU;
9163                 break;
9164 #endif /* CK_KERBEROS */
9165             }
9166         }
9167         /*
9168            If the user requires a particular type of Kerberos connection,
9169            make sure we have a valid TGT.
9170         */
9171         makestr(&slmsg,"Authentication failure");
9172         if ((ttnproto == NP_TELNET || ttnproto == NP_KERMIT) &&
9173             (line[0] == '*' &&
9174              TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) == TN_NG_MU ||
9175              line[0] != '*' &&
9176              TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) == TN_NG_MU)
9177             ) {
9178 #ifdef CK_KERBEROS
9179             if ( auth_type_user[0] == AUTHTYPE_KERBEROS_V4 ) {
9180                 extern int krb4_autoget;
9181                 if (!ck_krb4_is_installed())
9182                   return(cx_fail(msg,
9183               "Required authentication method (Kerberos 4) is not installed"));
9184 #ifdef COMMENT
9185                 /* This code results in false failures when using */
9186                 /* kerberos to machines in realms other than the  */
9187                 /* default since we don't know the realm of the   */
9188                 /* other machine until perform the reverse DNS    */
9189                 /* lookup.                                        */
9190                 else if (line[0] != '*' && !ck_krb4_is_tgt_valid() &&
9191                            (!krb4_autoget ||
9192                             krb4_autoget && !ck_krb4_autoget_TGT(NULL))) {
9193                     return(cx_fail(msg,
9194                            "Kerberos 4: Ticket Getting Ticket not valid"));
9195                 }
9196 #endif /* COMMENT */
9197             } else if (auth_type_user[0] == AUTHTYPE_KERBEROS_V5) {
9198                 extern int krb5_autoget;
9199                 if (!ck_krb5_is_installed()) {
9200                     return(cx_fail(msg,
9201            "Required authentication method (Kerberos 5) is not installed"));
9202                 }
9203 #ifdef COMMENT
9204                 /* This code results in false failures when using */
9205                 /* kerberos to machines in realms other than the  */
9206                 /* default since we don't know the realm of the   */
9207                 /* other machine until perform the reverse DNS    */
9208                 /* lookup.                                        */
9209                 else if (line[0] != '*' && !ck_krb5_is_tgt_valid() &&
9210                            (!krb5_autoget ||
9211                             krb5_autoget && !ck_krb5_autoget_TGT(NULL))) {
9212                     return(cx_fail(msg,
9213                          "Kerberos 5: Ticket Getting Ticket not valid."));
9214                 }
9215 #endif /* COMMENT */
9216             }
9217 #endif /* CK_KERBEROS */
9218 #ifdef NT
9219             if (auth_type_user[0] == AUTHTYPE_NTLM) {
9220                 if (!ck_ntlm_is_installed()) {
9221                     return(cx_fail(msg,
9222                    "Required authentication method (NTLM) is not installed"));
9223                 } else if (line[0] != '*' && !ck_ntlm_is_valid(0)) {
9224                     return(cx_fail(msg,"NTLM: Credentials are unavailable."));
9225                 }
9226             }
9227 #endif /* NT */
9228 #ifdef CK_SSL
9229             if (auth_type_user[0] == AUTHTYPE_SSL) {
9230                 if (!ck_ssleay_is_installed()) {
9231                     return(cx_fail(msg,
9232                      "Required authentication method (SSL) is not installed"));
9233                 }
9234             }
9235 #endif /* CK_SSL */
9236 #ifdef CK_SRP
9237             if (auth_type_user[0] == AUTHTYPE_SRP) {
9238                 if (!ck_srp_is_installed()) {
9239                     return(cx_fail(msg,
9240                      "Required authentication method (SRP) is not installed"));
9241                 }
9242             }
9243 #endif /* CK_SRP */
9244         }
9245 #endif /* CK_AUTHENTICATION */
9246 #ifdef CK_ENCRYPTION
9247         if ((ttnproto == NP_TELNET || ttnproto == NP_KERMIT) &&
9248              param2 > -1) {
9249             if (!sl_cx_saved) {
9250                 sl_cx_type = cx_type;
9251                 sl_cx_saved = 1;
9252             }
9253             if (!sl_topt_e_s_saved) {
9254                 sl_topt_e_su = TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION);
9255                 sl_topt_e_sm = TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION);
9256                 sl_topt_e_s_saved = 1;
9257             }
9258             if (!sl_topt_e_c_saved) {
9259                 sl_topt_e_cu = TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION);
9260                 sl_topt_e_cm = TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION);
9261                 sl_topt_e_c_saved = 1;
9262             }
9263             cx_type = param2;
9264             if (cx_type == CX_AUTO) {
9265                 TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
9266                 TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
9267                 TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
9268                 TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ;
9269             } else if (cx_type == CX_NONE) {
9270                 TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
9271                 TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
9272                 TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
9273                 TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF;
9274             } else {
9275                 TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
9276                 TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
9277                 TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
9278                 TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_MU;
9279             }
9280         }
9281         if (ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN ||
9282             (ttnproto == NP_TELNET || ttnproto == NP_KERMIT) &&
9283             ((line[0] == '*' &&
9284               TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) == TN_NG_MU &&
9285               TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_MU) ||
9286              (line[0] != '*' &&
9287               TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) == TN_NG_MU &&
9288               TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) == TN_NG_MU))
9289             ) {
9290             if (!ck_crypt_is_installed()) {
9291                 return(cx_fail(msg,
9292                   "Required Encryption methods are not installed"));
9293             }
9294         }
9295 #endif /* CK_ENCRYPTION */
9296 #ifdef RLOGCODE
9297 #ifdef CK_KERBEROS
9298 #ifdef KRB4
9299         if (ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN) {
9300             extern int krb4_autoget;
9301             char tgt[256];
9302             char * realm;
9303
9304             /* We don't have the full hostname at yet so  */
9305             /* we do a DNS lookup before calling ttopen() */ 
9306
9307             realm = ck_krb4_realmofhost(ckgetfqhostname(hostname));
9308             ckmakmsg(tgt,256,"krbtgt.",realm,"@",realm);
9309             if (!ck_krb4_is_installed()) {
9310                 return(cx_fail(msg,
9311                  "Required authentication method (Kerberos 4) is not installed"
9312                                ));
9313             } else {
9314                 if ((ck_krb4_tkt_isvalid(tgt) <= 0) &&
9315                     (!krb4_autoget ||
9316                      krb4_autoget && !ck_krb4_autoget_TGT(realm))) {
9317                     return(cx_fail(msg,
9318                            "Kerberos 4: Ticket Getting Ticket not valid"));
9319                 }
9320             }
9321         }
9322 #endif /* KRB4 */
9323 #ifdef KRB5
9324         if (ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN ||
9325             ttnproto == NP_K5U2U)
9326         {
9327             extern int krb5_autoget;
9328             char tgt[256];
9329             char * realm;
9330
9331             /* Must get full hostname before calling ttopen() */
9332
9333             realm = ck_krb5_realmofhost(ckgetfqhostname(hostname));
9334             ckmakmsg(tgt,256,"krbtgt/",realm,"@",realm);
9335
9336             if (!ck_krb5_is_installed()) {
9337                 return(cx_fail(msg,
9338                  "Required authentication method (Kerberos 5) not installed"));
9339             } else if (!((ck_krb5_tkt_isvalid(NULL,tgt) > 0) ||
9340                           ck_krb5_is_tgt_valid()) &&
9341                        (!krb5_autoget ||
9342                         krb5_autoget && !ck_krb5_autoget_TGT(realm))) {
9343                 return(cx_fail(msg,
9344                        "Kerberos 5: Ticket Getting Ticket not valid."));
9345             }
9346         }
9347 #endif /* KRB5 */
9348 #endif /* CK_KERBEROS */
9349 #endif /* RLOGCODE */
9350
9351 #ifndef NOSPL
9352 #ifdef RLOGCODE
9353         if (username) {
9354             if (!sl_uid_saved) {
9355                 ckstrncpy(sl_uidbuf,uidbuf,UIDBUFLEN);
9356                 sl_uid_saved = 1;
9357             }
9358             ckstrncpy(uidbuf,username,UIDBUFLEN);
9359             uidflag = 1;
9360         }
9361 #endif /* RLOGCODE */
9362 #ifdef TNCODE
9363         if (!sl_tn_saved) {
9364             sl_tn_wait = tn_wait_flg;
9365             sl_tn_saved = 1;
9366         }
9367         tn_wait_flg = param3;
9368 #endif /* TNCODE */
9369 #endif /* NOSPL */
9370         } /* if (net == NET_TCPB) */
9371 #endif /* TCPSOCKET */
9372
9373 #ifndef NOSPL
9374 #ifdef CK_SECURITY
9375         if (password) {
9376             if (password[0]) {
9377                 ckstrncpy(pwbuf,password,PWBUFL+1);
9378                 pwflg = 1;
9379                 pwcrypt = 0;
9380             } else
9381                 pwflg = 0;
9382         }
9383 #endif /* CK_SECURITY */
9384 #endif /* NOSPL */
9385
9386         /* Try to open - network */
9387         ckstrncpy(ttname,line,TTNAMLEN);
9388         y = ttopen(line, &_local, mdmtyp, 0 );
9389
9390 #ifndef NOHTTP
9391         /*  If the connection failed and we are using an HTTP Proxy
9392          *  and the reason for the failure was an authentication
9393          *  error, then we need to give the user to ability to
9394          *  enter a username and password, just like a browser.
9395          *
9396          *  I tried to do all of this within the netopen() call
9397          *  but it is much too much work.
9398          */
9399         while (y < 0 && tcp_http_proxy != NULL ) {
9400
9401             if (tcp_http_proxy_errno == 401 ||
9402                 tcp_http_proxy_errno == 407 ) {
9403                 char uid[UIDBUFLEN];
9404                 char pwd[256];
9405                 struct txtbox tb[2];
9406                 int ok;
9407
9408                 tb[0].t_buf = uid;
9409                 tb[0].t_len = UIDBUFLEN;
9410                 tb[0].t_lbl = "Proxy Userid: ";
9411                 tb[0].t_dflt = NULL;
9412                 tb[0].t_echo = 1;
9413                 tb[1].t_buf = pwd;
9414                 tb[1].t_len = 256;
9415                 tb[1].t_lbl = "Proxy Passphrase: ";
9416                 tb[1].t_dflt = NULL;
9417                 tb[1].t_echo = 2;
9418
9419                 ok = uq_mtxt("Proxy Server Authentication Required\n",
9420                               NULL, 2, tb);
9421
9422                 if (ok && uid[0]) {
9423                     char * proxy_user, * proxy_pwd;
9424
9425                     proxy_user = tcp_http_proxy_user;
9426                     proxy_pwd  = tcp_http_proxy_pwd;
9427
9428                     tcp_http_proxy_user = uid;
9429                     tcp_http_proxy_pwd = pwd;
9430
9431                     ckstrncpy(ttname,line,TTNAMLEN);
9432                     y = ttopen(line, &_local, mdmtyp, 0);
9433                     memset(pwd,0,sizeof(pwd));
9434                     tcp_http_proxy_user = proxy_user;
9435                     tcp_http_proxy_pwd = proxy_pwd;
9436                 } else
9437                   break;
9438             } else
9439               break;
9440         }
9441 #endif /* NOHTTP */
9442         if (y < 0) {
9443             slrestor();
9444             makestr(&slmsg,"Network connection failure");
9445 #ifdef VMS
9446             if (msg && hints && !xcmdsrc && IS_RLOGIN()) {
9447                 makestr(&slmsg,"RLOGIN failure");
9448                 if  (socket_errno == EACCES) {
9449                     printf("*************************\n");
9450                     printf(
9451            "Hint: RLOGIN requires privileges to open an outbound port.\n");
9452                     printf(
9453                     "(Use SET HINTS OFF to suppress future hints.)\n");
9454                     printf("*************************\n");
9455                 }
9456             }
9457 #else  /* Not VMS... */
9458             if (errno) {
9459                 int x;
9460                 debug(F111,"set host line, errno","",errno);
9461                 makestr(&slmsg,ck_errstr());
9462                 if (msg) {
9463 #ifdef OS2
9464                     printf("Can't connect to %s\n",line);
9465 #else /* OS2 */
9466 #ifdef UNIX
9467                     if (hints && !xcmdsrc && IS_RLOGIN()) {
9468                         makestr(&slmsg,"RLOGIN failure");
9469                         printf("*************************\n");
9470                         printf(
9471          "Hint: RLOGIN requires privileges to open an outbound port.\n");
9472                         printf(
9473          "(Use SET HINTS OFF to suppress future hints.)\n");
9474                         printf("*************************\n");
9475                     }
9476 #endif /* UNIX */
9477 #endif /* OS2 */
9478                 } else printf("Can't connect to %s\n",line);
9479             } else
9480 #endif /* VMS */
9481               if (msg) printf("Can't open connection to %s\n",line);
9482             continue;
9483         } else {
9484             success = 1;
9485 #ifndef NODIAL
9486             dialsta = DIA_UNK;
9487 #endif /* NODIAL */
9488             switch (net) {
9489               case NET_TCPA:
9490               case NET_TCPB:
9491                 cxtype = CXT_TCPIP;
9492 #ifdef COMMENT
9493 /* This works but it messes up interactive anonymous login */
9494 #ifndef NOXFER
9495 #ifdef IKS_OPTION
9496                 /* If we have connected to an Internet Kermit service */
9497                 /* and a /USER: switch was given, then log in. */
9498
9499                 if (TELOPT_U(TELOPT_KERMIT) || TELOPT_ME(TELOPT_KERMIT)) {
9500                     debug(F111,"cx_net IKSD /USER:",uidbuf,haveuser);
9501                     if (haveuser /* && cx == 0 */ ) { /* /USER: given */
9502                         char * psw = pwbuf; /* Do we have a password? */
9503                         if (!*psw) {        /* No... */
9504                             if (!strcmp(uidbuf,"anonymous") ||
9505                                 !strcmp(uidbuf,"ftp")) {
9506                                 extern char myhost[];
9507                                 char * u = (char *)sl_uidbuf;
9508                                 char * h = (char *)myhost;
9509                                 if (!*u) u = "nobody";
9510                                 if (!*h) h = "nowhere";
9511                                 ckmakmsg(tmpbuf,TMPBUFSIZ,u,"@",h,NULL);
9512                                 psw = tmpbuf;
9513                                 debug(F110,"cx_net IKSD anon",psw,0);
9514                             } else {
9515                                 readpass(" Password: ",pwbuf,PWBUFL);
9516                             }
9517                         }
9518                         sstate = setgen('I',uidbuf,psw,"");
9519                     }
9520                 }
9521 #endif /* IKS_OPTION */
9522 #endif /* NOXFER */
9523 #endif /* COMMENT */
9524                 break;
9525               case NET_SSH:
9526                 cxtype = CXT_SSH;
9527                 duplex = 0;         /* Remote echo */
9528                 break;
9529               case NET_SLAT:
9530                 cxtype = CXT_LAT;
9531                 break;
9532               case NET_SX25:
9533               case NET_IX25:
9534               case NET_HX25:
9535               case NET_VX25:
9536                 cxtype = CXT_X25;
9537                 break;
9538               case NET_BIOS:
9539                 cxtype = CXT_NETBIOS;
9540                 break;
9541               case NET_FILE:
9542               case NET_PIPE:
9543               case NET_CMD:
9544               case NET_DLL:
9545               case NET_PTY:
9546                 cxtype = CXT_PIPE;
9547                 break;
9548               default:
9549                 cxtype = CXT_PIPE;
9550                 break;
9551             }
9552             break;
9553         }
9554     } /* for-loop */
9555     s = line;
9556
9557     debug(F101,"cx_net post ttopen success","",success);
9558     if (!success) {
9559         local = dfloc;                  /* Go back to normal */
9560 #ifndef MAC
9561         ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default tty name */
9562 #endif /* MAC */
9563         speed = ttgspd();
9564         network = 0;                    /* No network connection active */
9565         haveline = 0;
9566         if (mdmtyp < 0) {               /* Switching from net to async? */
9567             if (mdmsav > -1)            /* Restore modem type from last */
9568               mdmtyp = mdmsav;          /* SET MODEM command, if any. */
9569             else
9570               mdmtyp = 0;
9571             mdmsav = -1;
9572         }
9573         return(0);                      /* Return failure */
9574     }
9575     if (_local > -1) local = _local;    /* Opened ok, set local/remote. */
9576     makestr(&slmsg,NULL);
9577     network = (mdmtyp < 0);             /* Remember connection type. */
9578     ckstrncpy(ttname,s,TTNAMLEN);       /* Copy name into real place. */
9579     debug(F110,"cx_net ok",ttname,0);
9580     debug(F101,"cx_net network","",network);
9581 #ifndef NOXFER
9582     if ((reliable != SET_OFF || !setreliable)) /* Assume not reliable. */
9583       reliable = SET_OFF;
9584 #endif /* NOXFER */
9585     if (!network || istncomport())      
9586       speed = ttgspd();                 /* Get the current speed. */
9587     debug(F101,"cx_net local","",local);
9588     if (network) {
9589         debug(F101,"cx_net net","",net);
9590 #ifndef NOXFER
9591         /* Force prefixing of 255 on TCP/IP connections... */
9592         if (net == NET_TCPB
9593 #ifdef SSHBUILTIN
9594              || net == NET_SSH
9595 #endif /* SSHBUILTIN */
9596              ) {
9597             debug(F101,"cx_net reliable A","",reliable);
9598 #ifdef CK_SPEED
9599             ctlp[(unsigned)255] = 1;
9600 #endif /* CK_SPEED */
9601             if ((reliable != SET_OFF || !setreliable)) {
9602 #ifdef TN_COMPORT
9603                 if (istncomport()) {    /* Telnet communication port */
9604                     reliable = SET_OFF; /* Transport is not reliable */
9605                     debug(F101,"cx_net reliable istncomport()","",1);
9606                 } else {
9607                     reliable = SET_ON;  /* Transport is reliable end to end */
9608                     debug(F101,"cx_net reliable istncomport()","",0);
9609                 }
9610 #else
9611                 reliable = SET_ON;      /* Transport is reliable end to end */
9612 #endif /* ifdef TN_COMPORT */
9613             }
9614             debug(F101,"cx_net reliable B","",reliable);
9615         } else if (net == NET_SX25 ||
9616                    net == NET_VX25 ||
9617                    net == NET_IX25 ||
9618                    net == NET_HX25) {
9619             duplex = 1;                 /* Local echo for X.25 */
9620             if (reliable != SET_OFF || !setreliable)
9621               reliable = SET_ON;        /* Transport is reliable end to end */
9622         }
9623 #endif /* NOXFER */
9624     }
9625 #ifndef NOXFER
9626     debug(F101,"cx_net reliable","",reliable);
9627 #endif /* NOXFER */
9628 #ifdef OS2
9629     if (mdmtyp <= 0)                    /* Network or Direct Connection */
9630       DialerSend(OPT_KERMIT_CONNECT, 0);
9631 #endif /* OS2 */
9632
9633   xcx_net:
9634
9635     setflow();                          /* Set appropriate flow control */
9636
9637     haveline = 1;
9638 #ifdef CKLOGDIAL
9639     dolognet();
9640 #endif /* CKLOGDIAL */
9641
9642 #ifndef NOSPL
9643     if (local) {
9644         if (nmac) {                     /* Any macros defined? */
9645             int k;                      /* Yes */
9646             k = mlook(mactab,"on_open",nmac);   /* Look this up */
9647             if (k >= 0) {                       /* If found, */
9648                 if (dodo(k,ttname,0) > -1)      /* set it up, */
9649                   parser(1);                    /* and execute it */
9650             }
9651         }
9652     }
9653 #endif /* NOSPL */
9654
9655     if (local && (cx || sx)) {          /* /CONNECT or /SERVER switch given */
9656         if (cx) {                       /* /CONNECT */
9657             if (!gui) {
9658                 /* Command was confirmed so we can pre-pop command level.  */
9659                 /* This is so CONNECT module won't think we're executing a */
9660                 /* script if CONNECT was the final command in the script.  */
9661                 if (cmdlvl > 0)
9662                   prepop();
9663             }
9664 #ifndef NODIAL
9665             dialsta = DIA_UNK;
9666 #endif /* NODIAL */
9667 #ifdef LOCUS
9668             if (autolocus) {
9669                 setlocus(1,1);
9670             }
9671 #endif /* LOCUS */
9672             success = doconect(0, cmdlvl == 0 ? 1 : 0);
9673             if (ttchk() < 0)
9674               dologend();
9675             debug(F101,"cx_net post doconect success","",success);
9676             return(success);
9677 #ifndef NOXFER
9678         } else if (sx) {                /* /SERVER */
9679             sstate = 'x';
9680 #ifdef MAC
9681             what = W_RECV;
9682             scrcreate();
9683 #endif /* MAC */
9684             if (local) displa = 1;
9685 #ifdef AMIGA
9686             reqoff();                   /* No DOS requestors while server */
9687 #endif /* AMIGA */
9688 #endif /* NOXFER */
9689         }
9690     }
9691 #ifndef NODIAL
9692     dialsta = DIA_UNK;
9693 #endif /* NODIAL */
9694 #ifdef LOCUS
9695     if (autolocus) {
9696         setlocus(1,1);
9697     }
9698 #endif /* LOCUS */
9699     return(success = 1);
9700 }
9701 #endif /* NETCONN */
9702
9703 /* c x _ s e r i a l  --  Make a serial connection */
9704
9705 /*
9706   Call with:
9707     device  = string pointer to device name.
9708     cx      = 1 to automatically enter Connect mode, 0 otherwise.
9709     sx      = 1 to automatically enter Server mode, 0 otherwise.
9710     shr     = 1 if device should be opened in shareable mode, 0 otherwise.
9711     flag    = if no dev name given: 1 = close current connection, 0 = resume.
9712     gui     = 1 if called from GUI dialog, 0 otherwise.
9713   Returns:
9714     1 on success
9715     0 on failure and no message printed, slmsg set to failure message.
9716    -9 on failure and message printed, ditto.
9717 */
9718
9719 /* these are bit flags */
9720 #define CX_TAPI 1
9721 #define CX_PPP  2
9722 #define CX_SLIP 4
9723
9724 int
9725 #ifdef CK_ANSIC
9726 cx_serial(char *device, 
9727           int cx, int sx, int shr, int flag, int gui, int special)
9728 #else /* CK_ANSIC */
9729 cx_serial(device, cx, sx, shr, flag, gui, special)
9730     char * device; int cx, sx, shr, flag, gui, special; 
9731 #endif /* CK_ANSIC */
9732 /* cx_serial */ {
9733     int i, n, x, y, msg;
9734     int _local = -1;
9735     char *s;
9736
9737     debug(F110,"cx_serial device",device,0);
9738     s = device;
9739     msg = (gui == 0) && msgflg;         /* Whether to print messages */
9740     success = 0;
9741
9742 #ifndef NODIAL
9743     dialsta = DIA_UNK;
9744 #endif /* NODIAL */
9745     debug(F101,"cx_serial mdmtyp","",mdmtyp);
9746     if (clskconnx(1) < 0)               /* Close the Kermit connection */
9747       return(success = 0);
9748     if (*s) {                           /* They gave a device name */
9749         _local = -1;                    /* Let ttopen decide about it */
9750     } else {                            /* They just said "set line" */
9751         s = dftty;                      /* so go back to normal tty */
9752         _local = dfloc;                 /* and mode. */
9753     }
9754 #ifdef VMS
9755     {
9756         extern int ok_to_share;
9757         ok_to_share = shr;
9758     }
9759 #endif /* VMS */
9760
9761 #ifdef OS2                              /* Must wait until after ttclos() */
9762 #ifdef NT                               /* to change these settings       */
9763 #ifdef CK_TAPI
9764     tttapi = special & CX_TAPI;
9765 #endif /* CK_TAPI */
9766 #else
9767     ttslip = special & CX_SLIP;
9768     ttppp  = special & CX_PPP;
9769 #endif /* NT */
9770     ttshare = shr;                      /* Shareable device ? */
9771     debug(F110,"OS2 SET PORT final s",s,"");
9772 #endif /* OS2 */
9773
9774     /* Open the new line */        
9775
9776     ckstrncpy(ttname,s,TTNAMLEN);
9777     if ((y = ttopen(s,&_local,mdmtyp,cdtimo)) > -1) {
9778         cxtype = (mdmtyp > 0) ? CXT_MODEM : CXT_DIRECT;
9779 #ifndef NODIAL
9780         dialsta = DIA_UNK;
9781 #ifdef CK_TAPI
9782         /* if the line is a tapi device, then we need to auto-execute */
9783         /* SET MODEM TYPE TAPI - which we do the equivalent of here.  */
9784         if (tttapi) {
9785             extern int usermdm;
9786             usermdm = 0;
9787             initmdm(38);                /* From ckudia.c n_TAPI == 38 */
9788         }
9789 #endif /* CK_TAPI */
9790 #endif /* NODIAL */
9791         success = 1;
9792     } else {                            /* Failed */
9793 #ifdef OS2ONLY
9794         if (!strcmp(s,dftty))   /* Do not generate an error with dftty */
9795           ;
9796         else if (y == -6 && ttslip) {
9797             makestr(&slmsg,"Can't access SLIP driver");
9798             if (msg) printf("?%s\n",slmsg);
9799         } else if (y == -6 && ttppp) {
9800             makestr(&slmsg,"Can't access PPP driver");
9801             if (msg) printf("?%s\n",slmsg);
9802         } else
9803 #endif /* OS2ONLY */
9804           if (y == -2) {
9805               makestr(&slmsg,"Timed out - no carrier");
9806               if (msg) {
9807                   printf("?%s\n",slmsg);
9808                   if (hints) {
9809                       printf("\n*************************\n");
9810                       printf(
9811                        "HINT (Use SET HINTS OFF to suppress future hints):\n");
9812                       printf(
9813                           "Try SET CARRIER OFF and SET LINE again, or else\n");
9814                       printf("SET MODEM, SET LINE, and then DIAL.\n");
9815                       printf("*************************\n\n");
9816                   }
9817               }
9818           } else if (y == -3) {
9819               makestr(&slmsg,"Access to lock denied");
9820               if (msg) {
9821 #ifdef UNIX
9822                   printf(
9823                    "Sorry, write access to UUCP lockfile directory denied.\n");
9824 #ifndef NOHINTS
9825                   if (hints) {
9826                       printf("\n*************************\n");
9827                       printf(
9828                        "HINT (Use SET HINTS OFF to suppress future hints):\n");
9829                       printf(
9830           "Please read the installation instructions file, %sckuins.txt,\n",
9831                              k_info_dir ? k_info_dir : ""
9832                              );
9833                       printf(
9834           "or the UNIX appendix of the manual, \"Using C-Kermit\"\n"
9835                              );
9836                       printf(
9837           "or visit http://www.columbia.edu/kermit/ckuins.html \n"
9838                              );
9839                       printf("*************************\n\n");
9840                   }
9841 #endif /* NOHINTS */
9842 #else
9843                   printf("Sorry, access to lock denied: %s\n",s);
9844 #endif /* UNIX */
9845               }
9846           } else if (y == -4) {
9847               makestr(&slmsg,"Access to device denied");
9848               if (msg) {
9849                   printf("Sorry, access to device denied: %s\n",s);
9850 #ifdef UNIX
9851 #ifndef NOHINTS
9852                   if (hints) {
9853                       printf("\n*************************\n");
9854                       printf(
9855                       "HINT (Use SET HINTS OFF to suppress future hints):\n");
9856                       printf(
9857             "Please read the installation instructions file, %sckuins.txt,\n",
9858                              k_info_dir ? k_info_dir : ""
9859                              );
9860                       printf(
9861             "or the UNIX appendix of the manual, \"Using C-Kermit\".\n"
9862                              );
9863                       printf("*************************\n\n");
9864                   }
9865 #endif /* NOHINTS */
9866 #endif /* UNIX */
9867               }
9868           } else if (y == -5) {
9869               makestr(&slmsg,"Device is in use or unavailable");
9870               if (msg)
9871 #ifdef VMS
9872                 printf(
9873                   "Sorry, device is in use or otherwise unavailable: %s\n",s);
9874 #else
9875               printf("Sorry, device is in use: %s\n",s);
9876 #endif /* VMS */
9877           } else {                      /* Other error. */
9878               makestr(&slmsg,"Device open failed");
9879               if (
9880 #ifdef VMS
9881                   1
9882 #else
9883                   errno
9884 #endif /* VMS */
9885                   ) {
9886                   int x;                /* Find a safe, long buffer */
9887                   makestr(&slmsg,ck_errstr());
9888 #ifndef VMS
9889                   debug(F111,"cx_serial serial errno",slmsg,errno);
9890 #endif /* VMS */
9891                   if (msg)
9892                     printf("Connection to %s failed: %s\n",s,slmsg);
9893               } else if (msg)
9894                 printf("Sorry, can't open connection: %s\n",s);
9895           }
9896     }
9897     network = 0;                        /* No network connection active */
9898     speed = ttgspd();
9899     if (!success) {
9900         local = dfloc;                  /* Go back to normal */
9901 #ifndef MAC
9902         ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default tty name */
9903 #endif /* MAC */
9904         haveline = 0;
9905         if (mdmtyp < 0) {               /* Switching from net to async? */
9906             if (mdmsav > -1)            /* Restore modem type from last */
9907               mdmtyp = mdmsav;          /* SET MODEM command, if any. */
9908             else
9909               mdmtyp = 0;
9910             mdmsav = -1;
9911         }
9912         return(msg ? -9 : 0);           /* Return failure */
9913     }
9914     if (_local > -1)
9915       local = _local;                   /* Opened ok, set local/remote. */
9916     makestr(&slmsg,NULL);               /* Erase SET LINE message */
9917     ckstrncpy(ttname,s,TTNAMLEN);       /* Copy name into real place. */
9918     debug(F110,"cx_serial ok",ttname,0);
9919 #ifndef NOXFER
9920     if ((reliable != SET_OFF || !setreliable)) /* Assume not reliable. */
9921       reliable = SET_OFF;
9922 #endif /* NOXFER */
9923
9924   xcx_serial:
9925     setflow();                          /* Set appropriate flow control */
9926     haveline = 1;
9927 #ifdef CKLOGDIAL
9928       dologline();
9929 #endif /* CKLOGDIAL */
9930
9931 #ifndef NOSPL
9932     if (local) {
9933         if (nmac) {                     /* Any macros defined? */
9934             int k;                      /* Yes */
9935             k = mlook(mactab,"on_open",nmac);   /* Look this up */
9936             if (k >= 0) {                       /* If found, */
9937                 if (dodo(k,ttname,0) > -1)      /* set it up, */
9938                   parser(1);                    /* and execute it */
9939             }
9940         }
9941     }
9942 #endif /* NOSPL */
9943
9944     if (local && (cx || sx)) {          /* /CONNECT or /SERVER switch given */
9945         extern int carrier;
9946         if (carrier != CAR_OFF) {       /* Looking for carrier? */
9947             /* Open() turns on DTR -- wait up to a second for CD to come up */
9948             int i, x;
9949             for (i = 0; i < 10; i++) {  /* WAIT 1 CD... */
9950                 x = ttgmdm();
9951                 if (x < 0 || x & BM_DCD)
9952                   break;
9953                 msleep(100);
9954             }
9955         }
9956         if (cx) {                       /* /CONNECT */
9957             /* Command was confirmed so we can pre-pop command level. */
9958             /* This is so CONNECT module won't think we're executing a */
9959             /* script if CONNECT was the final command in the script. */
9960
9961             if (cmdlvl > 0)
9962               prepop();
9963 #ifndef NODIAL
9964             dialsta = DIA_UNK;
9965 #endif /* NODIAL */
9966 #ifdef LOCUS
9967             if (autolocus) {
9968                 setlocus(1,1);
9969             }
9970 #endif /* LOCUS */
9971             success = doconect(0, cmdlvl == 0 ? 1 : 0);
9972             if (ttchk() < 0)
9973               dologend();
9974             return(success);
9975 #ifndef NOXFER
9976         } else if (sx) {                /* /SERVER */
9977             sstate = 'x';
9978 #ifdef MAC
9979             what = W_RECV;
9980             scrcreate();
9981 #endif /* MAC */
9982             if (local) displa = 1;
9983 #ifdef AMIGA
9984             reqoff();                   /* No DOS requestors while server */
9985 #endif /* AMIGA */
9986 #endif /* NOXFER */
9987         }
9988     }
9989 #ifndef NODIAL
9990     dialsta = DIA_UNK;
9991 #endif /* NODIAL */
9992 #ifdef LOCUS
9993     if (autolocus) {
9994         setlocus(1,1);
9995     }
9996 #endif /* LOCUS */
9997     return(success = 1);
9998 }
9999
10000
10001 /* S E T L I N -- parse name of and then open communication device. */
10002 /*
10003   Call with:
10004     xx == XYLINE for a serial (tty) line, XYHOST for a network host,
10005     zz == 0 means if user doesn't give a device name, continue current
10006             active connection (if any);
10007     zz != 0 means if user doesn't give a device name, then close the
10008             current connection and restore the default communication device.
10009     fc == 0 to just make the connection, 1 to also CONNECT (e.g. "telnet").
10010 */
10011 int
10012 setlin(xx, zz, fc) 
10013     int xx, zz, fc; 
10014 {
10015     extern char pwbuf[], * g_pswd;
10016     extern int pwflg, pwcrypt, g_pflg, g_pcpt, nolocal;
10017     int wait;
10018     /* int tn_wait_sv; */
10019     int mynet;
10020     int _local = -1;
10021     int c, i, haveswitch = 0;
10022     int haveuser = 0;
10023     int getval = 0;
10024     int wild = 0;                       /* Filespec has wildcards */
10025     int cx = 0;                         /* Connect after */
10026     int sx = 0;                         /* Become server after */
10027     int a_type = -1;                    /* Authentication type */
10028     int e_type = -1;                    /* Telnet /ENCRYPT type */
10029 #ifdef CK_ENCRYPTION
10030     int encrypt = 0;                    /* Encrypted? */
10031 #endif /* CK_ENCRYPTION */
10032     int shr = 0;                        /* Share serial device */
10033     int confirmed = 0;                  /* Command has been entered */
10034     struct FDB sw, tx, nx;
10035 #ifdef OS2
10036     struct FDB fl;
10037 #endif /* OS2 */
10038
10039     char * ss;
10040 #ifdef TCPSOCKET
10041     int rawflg = 0;
10042 #endif /* TCPSOCKET */
10043
10044     char srvbuf[SRVBUFSIZ+1];
10045
10046 #ifdef OS2
10047 #ifdef NT
10048     int xxtapi = 0;
10049 #else
10050     int xxslip = 0, xxppp = 0;
10051 #endif /* NT */
10052 #endif /* OS2 */
10053
10054     int dossh = 0;
10055
10056     debug(F101,"setlin fc","",fc);
10057     debug(F101,"setlin zz","",zz);
10058     debug(F101,"setlin xx","",xx);
10059
10060 #ifdef SSHCMD
10061     if (xx == XXSSH) {                  /* SSH becomes PTY SSH ... */
10062         dossh = 1;
10063         xx = XYHOST;
10064     }
10065 #endif /* SSHCMD */
10066
10067 #ifdef TNCODE
10068     /* tn_wait_sv = tn_wait_flg; */
10069     wait = tn_wait_flg;
10070 #else
10071     /* tn_wait_sv = 0; */
10072     wait = 0;
10073 #endif /* TNCODE */
10074
10075     mynet = nettype;
10076
10077     if (nolocal) {
10078         makestr(&slmsg,"Making connections is disabled");
10079         printf("?Sorry, making connections is disabled\n");
10080         return(-9);
10081     }
10082     if (netsave > -1)
10083       nettype = netsave;
10084
10085     if (fc != 0 || zz == 0)             /* Preset /CONNECT switch */
10086       cx = 1;
10087
10088     debug(F101,"setlin cx","",cx);
10089
10090     *srvbuf = NUL;
10091
10092     line[0] = NUL;
10093     s = line;
10094
10095 #ifdef NETCONN
10096 #ifdef CK_SECURITY
10097     if (tmpstring)
10098         makestr(&tmpstring,NULL);
10099 #endif /* CK_SECURITY */
10100     if (tmpusrid)
10101         makestr(&tmpusrid,NULL);
10102 #endif /* NETCONN */
10103
10104     autoflow = 1;                       /* Enable automatic flow setting */
10105
10106     if (xx == XYHOST) {                 /* SET HOST <hostname> */
10107 #ifndef NETCONN
10108         makestr(&slmsg,"Network connections not supported");
10109         printf("?%s\n",slmsg);
10110         return(-9);
10111 #else /* NETCONN */
10112 #ifndef NOPUSH
10113         if ((mynet == NET_CMD || mynet == NET_PTY || dossh) && nopush) {
10114             makestr(&slmsg,"Access to external commands is disabled");
10115             printf("?Sorry, access to external commands is disabled\n");
10116             return(-9);
10117         }
10118 #endif /* NOPUSH */
10119
10120 #ifdef SSHCMD
10121         if (dossh) {                    /* SSH connection via pty */
10122             int k;
10123             k = ckstrncpy(line, sshcmd ? sshcmd : defsshcmd, LINBUFSIZ);
10124             debug(F111,"setlin sshcmd 1",line,k);
10125             if ((x = cmtxt("Optional switches and hostname","",&s,xxstring))<0)
10126               return(x);
10127             if (!*s) {
10128                 printf("?SSH to where?\n");
10129                 return(-9);
10130             }
10131             if (k < LINBUFSIZ) {
10132                 line[k++] = SP;
10133                 line[k] = NUL;
10134                 debug(F111,"setlin sshcmd 2",line,k);
10135             } if (k < LINBUFSIZ) {
10136                 ckstrncpy(&line[k],s,LINBUFSIZ-k);
10137                 debug(F111,"setlin sshcmd 3",line,k);
10138             } else {
10139                 printf("?Too long\n");
10140                 return(-9);
10141             }
10142             x = cx_net( NET_PTY,                /* network type */
10143                         0,                      /* protocol (not used) */
10144                         line,                   /* host */
10145                         NULL,                   /* service (not used) */
10146                         NULL,                   /* username (not used) */
10147                         NULL,                   /* password (not used) */
10148                         NULL,                   /* command (not used) */
10149                         -1,-1,-1,               /* params 1-3 (not used) */
10150                         1,                      /* connect immediately */
10151                         sx,                     /* server? */
10152                         zz,                     /* close current? */
10153                         0);                     /* not gui */
10154             debug(F111,"setlin cx_net",line,x);
10155             return(x);
10156         }
10157 #endif /* SSHCMD */
10158
10159 /*
10160   Here we parse optional switches and then the hostname or whatever,
10161   which depends on the network type.  The tricky part is, the network type
10162   can be set by a switch.
10163 */
10164 #ifndef NOSPL
10165         makestr(&g_pswd,pwbuf);         /* Save global pwbuf */
10166         g_pflg = pwflg;                 /* and flag */
10167         g_pcpt = pwcrypt;
10168 #endif /* NOSPL */
10169
10170         confirmed = 0;
10171         haveswitch = 0;
10172 #ifdef NETFILE
10173         if (mynet != NET_FILE) {
10174 #endif /* NETFILE */
10175             ss = (mynet == NET_CMD || mynet == NET_PTY) ?
10176               "Command, or switch" :
10177                 (mynet == NET_TCPA || mynet == NET_TCPB
10178                   || mynet == NET_SSH) ?
10179                   "Hostname, ip-address, or switch" :
10180                     "Host or switch";
10181             if (fc) {
10182                 if (mynet == NET_TCPB &&
10183                     (ttnproto == NP_TELNET || ttnproto == NP_KERMIT)) {
10184                     if (nshteltab) {
10185                         haveswitch++;
10186                         cmfdbi(&sw,_CMKEY,ss,"","",nshteltab,4,xxstring,
10187                              shteltab,&nx);
10188                     }
10189                 }
10190 #ifdef RLOGCODE
10191                 else if (mynet == NET_TCPB && ttnproto == NP_RLOGIN) {
10192                     if (nshrlgtab) {
10193                         haveswitch++;
10194                         cmfdbi(&sw,_CMKEY,ss,"","",nshrlgtab,4,xxstring,
10195                                shrlgtab,&nx);
10196                     }
10197                 }
10198 #endif /* RLOGCODE */
10199             } else {
10200                 haveswitch++;
10201                 cmfdbi(&sw,_CMKEY,ss,"","",nshtab,4,xxstring,shtab,&nx);
10202             }
10203 #ifdef NETFILE
10204         }
10205 #endif /* NETFILE */
10206         if (mynet == NET_TCPB || mynet == NET_SLAT ||
10207             mynet == NET_SSH  || mynet == NET_DEC) {
10208             cmfdbi(&nx,_CMFLD,"Host","","",0,0,xxstring,NULL,NULL);
10209 #ifdef NETFILE
10210         } else if (mynet == NET_FILE) {
10211             cmfdbi(&nx,_CMIFI,"Filename","","",0,0,xxstring,NULL,NULL);
10212 #endif /* NETFILE */
10213 #ifdef PTYORPIPE
10214         } else if (mynet == NET_CMD || mynet == NET_PTY) {
10215             cmfdbi(&nx,_CMTXT,"Command","","",0,0,xxstring,NULL,NULL);
10216 #endif /* PTYORPIPE */
10217         } else {
10218             cmfdbi(&nx,_CMTXT,"Host","","",0,0,xxstring,NULL,NULL);
10219         }
10220         while (1) {
10221             x = cmfdb(haveswitch ? &sw : &nx);
10222             debug(F101,"setlin cmfdb","",x);
10223             if (x < 0)
10224               if (x != -3)
10225                 return(x);
10226             if (x == -3) {
10227                 if ((x = cmcfm()) < 0) {
10228                     return(x);
10229                 } else {
10230                     confirmed = 1;
10231                     break;
10232                 }
10233             }
10234             if (cmresult.fcode != _CMKEY) {    /* Not a switch */
10235                 ckstrncpy(line,cmresult.sresult,LINBUFSIZ); /* Save the data */
10236                 s = line;                      /* that was parsed... */
10237                 if (cmresult.fcode == _CMIFI) {
10238                     wild = cmresult.nresult;
10239                 } else if (cmresult.fcode == _CMTXT) {
10240                     confirmed = 1;
10241                 }
10242                 break;                  /* and break out of this loop */
10243             }
10244             c = cmgbrk();               /* Have switch - get break character */
10245             getval = (c == ':' || c == '='); /* Must parse an agument? */
10246             if (getval && !(cmresult.kflags & CM_ARG)) {
10247                 printf("?This switch does not take arguments\n");
10248                 return(-9);
10249             }
10250             if (!getval && (cmgkwflgs() & CM_ARG)) {
10251                 printf("?This switch requires an argument\n");
10252                 return(-9);
10253             }
10254             switch (cmresult.nresult) { /* It's a switch.. */
10255               case SL_CNX:              /* /CONNECT */
10256                 cx = 1;
10257                 sx = 0;
10258                 break;
10259               case SL_SRV:              /* /SERVER */
10260                 cx = 0;
10261                 sx = 1;
10262                 break;
10263 #ifdef NETCMD
10264               case SL_CMD:              /* /COMMAND */
10265                 netsave = mynet;
10266                 mynet = NET_CMD;
10267                 break;
10268 #endif /* NETCMD */
10269 #ifdef NETPTY
10270               case SL_PTY:              /* /PTY */
10271                 netsave = mynet;
10272                 mynet = NET_PTY;
10273                 break;
10274 #endif /* NETPTY */
10275               case SL_NET:              /* /NETWORK-TYPE */
10276                 if ((x = cmkey(netcmd,nnets,"","",xxstring)) < 0)
10277                   return(x);
10278                 mynet = x;
10279                 break;
10280
10281 #ifdef CK_SECURITY
10282               case SL_PSW:              /* /PASSWORD: */
10283                 if (!getval)
10284                   break;
10285                 debok = 0;
10286                 if ((x = cmfld("Password","",&s,xxstring)) < 0) {
10287                     if (x == -3) {
10288                         makestr(&tmpstring,"");
10289                     } else {
10290                         return(x);
10291                     }
10292                 } else {
10293                     s = brstrip(s);
10294                     if ((x = (int)strlen(s)) > PWBUFL) {
10295                         makestr(&slmsg,"Internal error");
10296                         printf("?Sorry, too long - max = %d\n",PWBUFL);
10297                         return(-9);
10298                     }
10299                     makestr(&tmpstring,s);
10300                 }
10301                 break;
10302 #endif /* CK_SECURITY */
10303
10304               case SL_UID:              /* /USERID: */
10305                 if (!getval)
10306                   break;
10307                 if ((x = cmfld("Userid","",&s,xxstring)) < 0) {
10308                     if (x == -3) {
10309                         makestr(&tmpusrid,"");
10310                     } else {
10311                         return(x);
10312                     }
10313                 } else {
10314                     s = brstrip(s);
10315                     if ((x = (int)strlen(s)) > 63) {
10316                         makestr(&slmsg,"Internal error");
10317                         printf("?Sorry, too long - max = %d\n",63);
10318                         return(-9);
10319                     }
10320                     makestr(&tmpusrid,s);
10321                     haveuser = 1;
10322                 }
10323                 break;
10324
10325 #ifdef CK_AUTHENTICATION
10326 #ifdef CK_SRP
10327               case SL_SRP:
10328                 a_type = AUTHTYPE_SRP;
10329                 break;
10330 #endif /* CK_SRP */
10331 #ifdef CK_SSL
10332               case SL_SSL:
10333                 a_type = AUTHTYPE_SSL;
10334                 break;
10335 #endif /* CK_SSL */
10336 #ifdef NT
10337               case SL_NTLM:
10338                 a_type = AUTHTYPE_NTLM;
10339                 break;
10340 #endif /* NT */
10341 #ifdef CK_KERBEROS
10342               case SL_KRB4:
10343                 a_type = AUTHTYPE_KERBEROS_V4;
10344                 if (ttnproto == NP_RLOGIN)
10345                   ttnproto =
10346 #ifdef CK_ENCRYPTION
10347                     encrypt ? NP_EK4LOGIN :
10348 #endif /* CK_ENCRYPTION */
10349                       NP_K4LOGIN;
10350                 else if (ttnproto == NP_K5LOGIN)
10351                   ttnproto = NP_K4LOGIN;
10352 #ifdef CK_ENCRYPTION
10353                 else if (ttnproto == NP_EK5LOGIN)
10354                   ttnproto = NP_EK4LOGIN;
10355 #endif /* CK_ENCRYPTION */
10356                 break;
10357               case SL_KRB5:
10358                 a_type = AUTHTYPE_KERBEROS_V5;
10359                 if (ttnproto == NP_RLOGIN)
10360                   ttnproto =
10361 #ifdef CK_ENCRYPTION
10362                     encrypt ? NP_EK5LOGIN :
10363 #endif /* CK_ENCRYPTION */
10364                       NP_K5LOGIN;
10365                 else if (ttnproto == NP_K4LOGIN)
10366                   ttnproto = NP_K5LOGIN;
10367 #ifdef CK_ENCRYPTION
10368                 else if (ttnproto == NP_EK4LOGIN)
10369                   ttnproto = NP_EK5LOGIN;
10370 #endif /* CK_ENCRYPTION */
10371                 break;
10372 #endif /* CK_KERBEROS */
10373               case SL_AUTH: {
10374                   extern struct keytab autyptab[];
10375                   extern int nautyp;
10376                   if ((x = cmkey(autyptab,nautyp,"type of authentication",
10377                                  "automatic",xxstring)) < 0)
10378                     return(x);
10379                   a_type = x;
10380                   break;
10381               }
10382 #endif /* CK_AUTHENTICATION */
10383 #ifdef CK_ENCRYPTION
10384               case SL_ENC:
10385                 switch (ttnproto) {
10386                   case NP_K4LOGIN:
10387                     ttnproto = NP_EK4LOGIN;
10388                     encrypt = 1;
10389                     break;
10390                   case NP_K5LOGIN:
10391                     ttnproto = NP_EK5LOGIN;
10392                     encrypt = 1;
10393                     break;
10394                   case NP_KERMIT:
10395                   case NP_TELNET: {
10396                       static struct keytab * tnetbl = NULL;
10397                       static int ntnetbl = 0;
10398                       x = ck_get_crypt_table(&tnetbl,&ntnetbl);
10399                       debug(F101,"ck_get_crypt_table x","",x);
10400                       debug(F101,"ck_get_crypt_table n","",ntnetbl);
10401                       if (x < 1 || !tnetbl || ntnetbl < 1) /* Didn't get it */
10402                         x = 0;
10403                       if (!x) {
10404                           makestr(&slmsg,"Internal error");
10405                           printf("?Oops, types not loaded\n");
10406                           return(-9);
10407                       }
10408                       if ((x = cmkey(tnetbl,ntnetbl,"type of encryption",
10409                                      "automatic",xxstring)) < 0)
10410                         return(x);
10411                       e_type = x;
10412                       break;
10413                   }
10414                 }
10415                 break;
10416 #endif /* CK_ENCRYPTION */
10417               case SL_WAIT:
10418                 wait = 1;
10419                 break;
10420               case SL_NOWAIT:
10421                 wait = 0;
10422                 break;
10423             }
10424         }
10425
10426 #ifdef NETFILE
10427         if (mynet == NET_FILE) {        /* Parsed by cmifi() */
10428             if ((x = cmcfm()) < 0)      /* Needs confirmation */
10429               return(x);
10430             x = cx_net(mynet,           /* nettype */
10431                        0,               /* protocol (not used) */
10432                        line,            /* host */
10433                        "",              /* port */
10434                        NULL,            /* alternate username */
10435                        NULL,            /* password */
10436                        NULL,            /* command to execute */
10437                        0,               /* param1 */
10438                        0,               /* param2 */
10439                        0,               /* param3 */
10440                        cx,              /* enter CONNECT mode */
10441                        sx,              /* enter SERVER mode */
10442                        zz,              /* close connection if open */
10443                        0                /* gui */
10444                        );
10445         }
10446 #endif /* NETFILE */
10447
10448 #ifdef NETCMD
10449         if (mynet == NET_CMD || mynet == NET_PTY) {
10450             char *p = NULL;
10451             if (!confirmed) {
10452                 if ((x = cmtxt("Rest of command","",&s,xxstring)) < 0)
10453                   return(x);
10454                 if (*s) {
10455                     strncat(line," ",LINBUFSIZ);
10456                     strncat(line,s,LINBUFSIZ);
10457                 }
10458                 s = line;
10459             }
10460             /* s == line - so we must protect the line buffer */
10461             s = brstrip(s);
10462             makestr(&p,s);
10463             ckstrncpy(line,p,LINBUFSIZ);
10464             makestr(&p,NULL);
10465
10466             x = cx_net( mynet,                  /* nettype */
10467                         0,                      /* protocol (not used) */
10468                         line,                   /* host */
10469                         "",                     /* port */
10470                         NULL,                   /* alternate username */
10471                         NULL,                   /* password */
10472                         NULL,                   /* command to execute */
10473                         0,                      /* param1 */
10474                         0,                      /* param2 */
10475                         0,                      /* param3 */
10476                         cx,                     /* enter CONNECT mode */
10477                         sx,                     /* enter SERVER mode */
10478                         zz,                     /* close connection if open */
10479                         0                       /* gui */
10480                         );
10481         }
10482 #endif /* NETCMD */
10483
10484 #ifdef NPIPE                            /* Named pipe */
10485         if (mynet == NET_PIPE) {        /* Needs backslash twiddling */
10486             if (line[0]) {
10487                 if (strcmp(line,"*")) {    /* If remote, begin with */
10488                     char * p = NULL;
10489                     makestr(&p,line);      
10490                     ckstrncpy(line,"\\\\",LINBUFSIZ); /* server name */
10491                     ckstrncat(line,p,LINBUFSIZ);
10492                     makestr(&p,NULL);      
10493                 } else {
10494                     line[0]='\0';
10495                 }
10496                 ckstrncat(line,"\\pipe\\", LINBUFSIZ); /* Make pipe name */
10497                 ckstrncat(line,pipename, LINBUFSIZ); /* Add name of pipe */
10498
10499                 x = cx_net(mynet,       /* nettype */
10500                            0,           /* protocol (not used) */
10501                            line,        /* host */
10502                            "",          /* port */
10503                            NULL,        /* alternate username */
10504                            NULL,        /* password */
10505                            NULL,        /* command to execute */
10506                            0,           /* param1 */
10507                            0,           /* param2 */
10508                            0,           /* param3 */
10509                            cx,          /* enter CONNECT mode */
10510                            sx,          /* enter SERVER mode */
10511                            zz,          /* close connection if open */
10512                            0            /* gui */
10513                            );
10514             }
10515         }
10516 #endif /* NPIPE */
10517
10518 #ifdef SUPERLAT
10519         if (mynet == NET_SLAT) {        /* Needs password, etc. */
10520             slat_pwd[0] = NUL;          /* Erase any previous password */
10521             debok = 0;
10522             if (*line) {                /* If they gave a host name... */
10523                 if ((x = cmfld(
10524                      "password,\n or carriage return if no password required",
10525                                "",
10526                                &s,
10527                                xxstring
10528                                )) < 0 && x != -3)
10529                   return(x);
10530                 ckstrncpy(slat_pwd,s,18); /* Set the password, if any */
10531             }
10532             if ((x = cmcfm()) < 0) return(x); /* Confirm the command */
10533
10534             x = cx_net(mynet,           /* nettype */
10535                        0,               /* protocol (not used) */
10536                        line,            /* host */
10537                        "",              /* port */
10538                        NULL,            /* alternate username */
10539                        NULL,            /* password */
10540                        NULL,            /* command to execute */
10541                        0,               /* param1 */
10542                        0,               /* param2 */
10543                        0,               /* param3 */
10544                        cx,              /* enter CONNECT mode */
10545                        sx,              /* enter SERVER mode */
10546                        zz,              /* close connection if open */
10547                        0                /* gui */
10548                        );
10549         }
10550 #endif /* SUPERLAT */
10551
10552 #ifdef DECNET
10553         if (mynet == NET_DEC) {  
10554             if (!line[0]) {                   /* If they gave a host name... */
10555                 printf("?hostname required\n");
10556                 return(-3);
10557             }
10558             if ((x = cmcfm()) < 0) return(x); /* Confirm the command */
10559
10560             x = cx_net(mynet,           /* nettype */
10561                        0,               /* protocol (not used) */
10562                        line,            /* host */
10563                        "",              /* port */
10564                        NULL,            /* alternate username */
10565                        NULL,            /* password */
10566                        NULL,            /* command to execute */
10567                        0,               /* param1 */
10568                        0,               /* param2 */
10569                        0,               /* param3 */
10570                        cx,              /* enter CONNECT mode */
10571                        sx,              /* enter SERVER mode */
10572                        zz,              /* close connection if open */
10573                        0                /* gui */
10574                        );
10575         }
10576 #endif /* DECNET */
10577
10578 #ifdef SSHBUILTIN
10579         if (mynet == NET_SSH) {         /* SSH connection */
10580             int k, havehost = 0, trips = 0;
10581             int    tmpver = -1, tmpxfw = -1, tmpssh_cas;
10582 #ifndef SSHTEST
10583             extern int sl_ssh_xfw, sl_ssh_xfw_saved;
10584             extern int sl_ssh_ver, sl_ssh_ver_saved;
10585 #endif /* SSHTEST */
10586             extern struct keytab sshopnsw[];
10587             extern int nsshopnsw;
10588             extern char *ssh_tmpcmd, *ssh_tmpport;
10589             struct FDB sw, kw, fl;
10590
10591             debug(F110,"setlin SSH service 0",srvbuf,0);
10592             debug(F110,"setlin SSH host s 2",s,0);
10593             if (*s) {           /* If they gave a host name... */
10594                 debug(F110,"setlin SSH host s 1",s,0);
10595                 if (*s == '*') {
10596                     makestr(&slmsg,"Incoming connections not supported");
10597                     printf(
10598      "?Sorry, incoming connections not supported for SSH.\n"
10599                            );
10600                     return(-9);
10601                 }
10602                 ckstrncpy(line,s,LINBUFSIZ);
10603             } else {
10604                 printf("?hostname required\n");
10605                 return(-3);
10606             }
10607
10608             /* Parse [ port ] [ switches ] */
10609             cmfdbi(&kw,                 /* Switches */
10610                     _CMKEY,
10611                     "Port number or service name,\nor switch",
10612                     "",
10613                     "",
10614                     nsshopnsw,
10615                     4,
10616                     xxstring,
10617                     sshopnsw,
10618                     &fl
10619                     );
10620             cmfdbi(&fl,                 /* Port number or service name */
10621                     _CMFLD,
10622                     "",
10623                     "",
10624                     "",
10625                     0,
10626                     0,
10627                     xxstring,
10628                     NULL,
10629                     NULL
10630                     );
10631             trips = 0;                  /* Explained below */
10632             while (1) {                 /* Parse port and switches */
10633                 y = cmfdb(&kw);         /* Get a field */
10634                 if (y == -3)            /* User typed CR so quit from loop */
10635                     break;
10636                 if (y < 0)              /* Other parse error, pass it back */
10637                     return(y);
10638                 switch (cmresult.fcode) { /* Field or Keyword? */
10639                 case _CMFLD:              /* Field */
10640                     ckstrncpy(srvbuf,cmresult.sresult,SRVBUFSIZ);
10641                     break;
10642                 case _CMKEY:            /* Keyword */
10643                     switch (cmresult.nresult) { /* Which one? */
10644                     case SSHSW_PWD:
10645                         if (!cmgbrk()) {
10646                             printf("?This switch requires an argument\n");
10647                             return(-9);
10648                         }
10649                         debok = 0;
10650                         if ((y = cmfld("Password","",&s,xxstring)) < 0) {
10651                             if (y == -3) {
10652                                 makestr(&tmpstring,"");
10653                             } else {
10654                                 return(y);
10655                             }
10656                         } else {
10657                             s = brstrip(s);
10658                             if ((y = (int)strlen(s)) > PWBUFL) {
10659                                 makestr(&slmsg,"Internal error");
10660                                 printf("?Sorry, too long - max = %d\n",PWBUFL);
10661                                 return(-9);
10662                             }
10663                             makestr(&tmpstring,s);
10664                         }
10665                         break;
10666                     case SSHSW_USR:             /* /USER: */
10667                         if (!cmgbrk()) {
10668                             printf("?This switch requires an argument\n");
10669                             return(-9);
10670                         }
10671                         if ((y = cmfld("Username","",&s,xxstring)) < 0)
10672                             return(y);
10673                         s = brstrip(s);
10674                         makestr(&tmpusrid,s);
10675                         break;
10676                     case SSHSW_VER:
10677                         if ((y = cmnum("Number","",10,&z,xxstring)) < 0)
10678                             return(y);
10679                         if (z < 1 || z > 2) {
10680                             printf("?Out of range: %d\n",z);
10681                             return(-9);
10682                         }
10683                         tmpver = z;
10684                         break;
10685                     case SSHSW_CMD:
10686                     case SSHSW_SUB:
10687                         if ((y = cmfld("Text","",&s,xxstring)) < 0)
10688                           return(y);
10689                         makestr(&ssh_tmpcmd,s);
10690                         tmpssh_cas = (cmresult.nresult == SSHSW_SUB);
10691                         break;
10692                     case SSHSW_X11:
10693                         if ((y = cmkey(onoff,2,"","on",xxstring)) < 0)
10694                             return(y);
10695                         tmpxfw = y;
10696                         break;
10697                     default:
10698                         return(-2);
10699                     }
10700                 }
10701                 if (trips++ == 0) {     /* After first time through */
10702                     cmfdbi(&kw,         /* only parse switches, not port. */
10703                             _CMKEY,
10704                             "Switch",
10705                             "",
10706                             "",
10707                             nsshopnsw,
10708                             4,
10709                             xxstring,
10710                             sshopnsw,
10711                             NULL
10712                             );
10713                 }
10714             }
10715             if ((y = cmcfm()) < 0)      /* Get confirmation */
10716                 return(y);
10717
10718             debug(F110,"setlin pre-cx_net line",line,0);
10719             debug(F110,"setlin pre-cx_net srvbuf",srvbuf,0);
10720             x = cx_net( mynet,                  /* nettype */
10721                         0,                      /* protocol (not used) */
10722                         line,                   /* host */
10723                         srvbuf,                 /* port */
10724                         tmpusrid,               /* alternate username */
10725                         tmpstring,              /* password */
10726                         ssh_tmpcmd,             /* command to execute */
10727                         tmpver,                 /* param1 - ssh version */
10728                         tmpssh_cas,             /* param2 - ssh cas  */
10729                         tmpxfw,                 /* param3 - ssh x11fwd */
10730                         cx,                     /* enter CONNECT mode */
10731                         sx,                     /* enter SERVER mode */
10732                         zz,                     /* close connection if open */
10733                         0                       /* gui */
10734                         );
10735             if (tmpusrid)
10736                 makestr(&tmpusrid,NULL);
10737             if (ssh_tmpcmd)
10738                 makestr(&ssh_tmpcmd,NULL);
10739         }
10740 #endif /* SSHBUILTIN */
10741
10742 #ifdef TCPSOCKET
10743         if (mynet == NET_TCPB) {        /* TCP/IP connection */
10744             debug(F110,"setlin service 0",srvbuf,0);
10745             debug(F110,"setlin host s 2",s,0);
10746             if (*s) {                   /* If they gave a host name... */
10747                 debug(F110,"setlin host s 1",s,0);
10748 #ifdef NOLISTEN
10749                 if (*s == '*') {
10750                     makestr(&slmsg,"Incoming connections not supported");
10751                     printf(
10752      "?Sorry, incoming connections not supported in this version of Kermit.\n"
10753                            );
10754                     return(-9);
10755                 }
10756 #endif /* NOLISTEN */
10757 #ifdef RLOGCODE
10758                 /* Allow a username if rlogin is requested */
10759                 if (mynet == NET_TCPB &&
10760                     (ttnproto == NP_RLOGIN || ttnproto == NP_K5LOGIN ||
10761                      ttnproto == NP_EK5LOGIN || ttnproto == NP_K4LOGIN ||
10762                      ttnproto == NP_EK4LOGIN
10763                     )) {
10764                     int y;
10765                     uidflag = 0;
10766                     /* Check for "host:service" */
10767                     for ( ; (*s != '\0') && (*s != ':'); s++) ;
10768                     if (*s) {   /* Service, save it */
10769                         *s = NUL;
10770                         ckstrncpy(srvbuf,++s,SRVBUFSIZ);
10771                     } else {            /* No :service, then use default. */
10772 #ifdef VMS
10773                         switch (ttnproto) {
10774                           case NP_RLOGIN:
10775                             ckstrncpy(srvbuf,"513",SRVBUFSIZ); /* "login" */
10776                             break;
10777                           case NP_K4LOGIN:
10778                           case NP_K5LOGIN:
10779                             ckstrncpy(srvbuf,"543",SRVBUFSIZ); /* "klogin" */
10780                             break;
10781                           case NP_EK4LOGIN:
10782                           case NP_EK5LOGIN:
10783                             ckstrncpy(srvbuf,"2105",SRVBUFSIZ); /* "eklogin" */
10784                             break;
10785                         }
10786 #else /* VMS */
10787                         switch (ttnproto) {
10788                           case NP_RLOGIN:
10789                             ckstrncpy(srvbuf,"login",SRVBUFSIZ);
10790                             break;
10791                           case NP_K4LOGIN:
10792                           case NP_K5LOGIN:
10793                             ckstrncpy(srvbuf,"klogin",SRVBUFSIZ);
10794                             break;
10795                           case NP_EK4LOGIN:
10796                           case NP_EK5LOGIN:
10797                             ckstrncpy(srvbuf,"eklogin",SRVBUFSIZ);
10798                             break;
10799                         }
10800 #endif /* VMS */
10801                     }
10802                     if (!confirmed) {
10803                         y = cmfld("Userid on remote system",
10804                                   uidbuf,&s,xxstring);
10805                         if (y < 0 && y != -3)
10806                           return(y);
10807                         if ((int)strlen(s) > 63) {
10808                             makestr(&slmsg,"Internal error");
10809                             printf("Sorry, too long\n");
10810                             return(-9);
10811                         }
10812                         makestr(&tmpusrid,s);
10813                     }
10814                 } else {        /* TELNET or SET HOST */
10815 #endif /* RLOGCODE */
10816                     /* Check for "host:service" */
10817                     for ( ; (*s != '\0') && (*s != ':'); s++) ;
10818                     if (*s) {   /* Service, save it */
10819                         *s = NUL;
10820                         ckstrncpy(srvbuf,++s,SRVBUFSIZ);
10821                     } else if (!confirmed) {
10822                         /* No :service, let them type one. */
10823                         if (*line != '*') { /* Not incoming */
10824                             if (mynet == NET_TCPB && ttnproto == NP_KERMIT) {
10825                                 if ((x = cmfld(
10826                                                "TCP service name or number",
10827                                                "kermit",&s,xxstring)
10828                                      ) < 0 && x != -3)
10829                                   return(x);
10830 #ifdef RLOGCODE
10831                             } else if (mynet == NET_TCPB &&
10832                                        ttnproto == NP_RLOGIN) {
10833                                 if ((x = cmfld(
10834   "TCP service name or number,\n or carriage return for rlogin (513)",
10835                                                "login",&s,xxstring)
10836                                      ) < 0 && x != -3)
10837                                   return(x);
10838 #ifdef CK_AUTHENTICATION
10839 #ifdef CK_KERBEROS
10840                             } else if (mynet == NET_TCPB &&
10841                                        (ttnproto == NP_K4LOGIN ||
10842                                        ttnproto == NP_K5LOGIN)) {
10843                                 if ((x = cmfld(
10844   "TCP service name or number,\n or carriage return for klogin (543)",
10845                                                "klogin",&s,xxstring)
10846                                      ) < 0 && x != -3)
10847                                   return(x);
10848                             } else if (mynet == NET_TCPB &&
10849                                        (ttnproto == NP_EK4LOGIN ||
10850                                         ttnproto == NP_EK5LOGIN)) {
10851                                 if ((x = cmfld(
10852   "TCP service name or number,\n or carriage return for eklogin (2105)",
10853                                                "eklogin",&s,xxstring)
10854                                      ) < 0 && x != -3)
10855                                   return(x);
10856 #endif /* CK_KERBEROS */
10857 #endif /* CK_AUTHENTICATION */
10858 #endif /* RLOGCODE */
10859                             } else {
10860                                 /* Do not set a default value in this call */
10861                                 /* If you do then it will prevent entries  */
10862                                 /* in the network directory from accessing */
10863                                 /* alternate ports.                        */
10864
10865                                 if ((x = cmfld(
10866                                                "TCP service name or number",
10867                                                "",&s,xxstring)
10868                                      ) < 0 && x != -3)
10869                                   return(x);
10870                             }
10871                         } else { /* Incoming connection */
10872                             if ((x = cmfld("TCP service name or number",
10873                                            "",&s,xxstring)
10874                                  ) < 0 && x != -3)
10875                               return(x);
10876                         }
10877                         if (*s)         /* If they gave a service, */
10878                           ckstrncpy(srvbuf,s,SRVBUFSIZ); /* copy it */
10879                         debug(F110,"setlin service 0.5",srvbuf,0);
10880                     }
10881 #ifdef RLOGCODE
10882                 }
10883 #endif /* RLOGCODE */
10884                 if (!confirmed) {
10885                     char * defproto;
10886                     switch (ttnproto) {
10887                       case NP_RLOGIN:
10888                         defproto = "/rlogin";
10889                         break;
10890                       case NP_K4LOGIN:
10891                         defproto = "/k4login";
10892                         break;
10893                       case NP_K5LOGIN:
10894                         defproto = "/k5login";
10895                         break;
10896                       case NP_EK4LOGIN:
10897                         defproto = "/ek4login";
10898                         break;
10899                       case NP_EK5LOGIN:
10900                         defproto = "/ek5login";
10901                         break;
10902                       case NP_KERMIT:
10903                       case NP_TELNET:
10904                         defproto = "/telnet";
10905                         break;
10906                       default:
10907                         defproto = "/default";
10908                     }
10909                     if ((x = cmkey(tcprawtab,ntcpraw,"Switch",defproto,
10910                                    xxstring)) < 0) {
10911                         if (x != -3)
10912                           return(x);
10913                         else if ((x = cmcfm()) < 0)
10914                           return(x);
10915                     } else {
10916                         rawflg = x;
10917                         if ((x = cmcfm()) < 0)
10918                           return(x);
10919                     }
10920                 }
10921             }
10922             debug(F110,"setlin pre-cx_net line",line,0);
10923             debug(F110,"setlin pre-cx_net srvbuf",srvbuf,0);
10924             x = cx_net( mynet,                  /* nettype */
10925                         rawflg                  /* protocol */,
10926                         line,                   /* host */
10927                         srvbuf,                 /* port */
10928                         tmpusrid,               /* alternate username */
10929                         tmpstring,              /* password */
10930                         NULL,                   /* command to execute */
10931                         a_type,                 /* param1 - telnet authtype */
10932                         e_type,                 /* param2 - telnet enctype  */
10933                         wait,                   /* param3 - telnet wait */
10934                         cx,                     /* enter CONNECT mode */
10935                         sx,                     /* enter SERVER mode */
10936                         zz,                     /* close connection if open */
10937                         0                       /* gui */
10938                         );
10939         }
10940 #endif /* TCPSOCKET */
10941
10942 #ifdef CK_SECURITY
10943         if (tmpstring)
10944             makestr(&tmpstring,NULL);
10945 #endif /* CK_SECURITY */
10946         if (tmpusrid)
10947             makestr(&tmpusrid,NULL);
10948         debug(F111,"setlin cx_net",line,x);
10949         return(x);
10950 #endif /* NETCONN */
10951     }
10952
10953 /* Serial tty device, possibly modem, connection... */
10954
10955 #ifdef OS2
10956 /*
10957   User can type:
10958     COM1..COM8 = Regular COM port
10959     1..8       = Synonym for COM1..COM8, is translated to COM1..COM8
10960     _n         = (n is a number) = open file handle
10961     string     = any text string = name of some other kind of device,
10962                  taken literally, as given.
10963 */
10964     s = "Communication device name";
10965
10966 #ifdef CK_TAPI
10967     if (TAPIAvail)
10968       cktapiBuildLineTable(&tapilinetab, &_tapilinetab, &ntapiline);
10969     if (!(tapilinetab && _tapilinetab && ntapiline > 0) &&
10970         xx == XYTAPI_LIN ) {
10971         makestr(&slmsg,"TAPI device not configured");
10972         printf("\nNo TAPI Line Devices are configured for this system\n");
10973         return(-9);
10974     }
10975     if (xx == XYTAPI_LIN) {             /* Default (first) TAPI line */
10976         s = "tapi";                     /* (whatever it is) */
10977     } else {                            /* Query the user */
10978 #endif /* CK_TAPI */
10979
10980 /* Now parse optional switches and then device name */
10981
10982         confirmed = 0;
10983         cmfdbi(&sw,_CMKEY,"Device name, or switch",
10984                "","",npsltab,4,xxstring,psltab,&fl);
10985         cmfdbi(&fl,_CMFLD,"",dftty,"",0,0,xxstring,NULL,NULL);
10986         while (1) {
10987             x = cmfdb(&sw);
10988             debug(F101,"setlin cmfdb","",x);
10989             if (x < 0)
10990               if (x != -3)
10991                 return(x);
10992             if (x == -3) {
10993                 if ((x = cmcfm()) < 0) {
10994                     return(x);
10995                 } else {
10996                     confirmed = 1;
10997                     break;
10998                 }
10999             }
11000             if (cmresult.fcode == _CMFLD) {
11001                 s = cmresult.sresult;
11002                 break;
11003             } else if (cmresult.fcode == _CMKEY) {
11004                 switch (cmresult.nresult) {
11005                   case SL_CNX:          /* /CONNECT */
11006                     cx = 1;
11007                     sx = 0;
11008                     break;
11009                   case SL_SRV:          /* /SERVER */
11010                     cx = 0;
11011                     sx = 1;
11012                     break;
11013                   case SL_SHR:          /* /SHARE */
11014                     shr = 1;
11015                     break;
11016                   case SL_NSH:          /* /NOSHARE */
11017                     shr = 0;
11018                     break;
11019                 }
11020             }
11021         }
11022 #ifdef CK_TAPI
11023     }
11024 #endif /* CK_TAPI */
11025
11026     debug(F110,"OS2 SET PORT s",s,0);
11027     y = lookup(os2devtab,s,nos2dev,&x); /* Look up in keyword table */
11028     debug(F101,"OS2 SET PORT x","",x);
11029     debug(F101,"OS2 SET PORT y","",y);
11030     if ((y > -1) && (x >= 0 && x < 8)) { /* User typed a digit 1..8 */
11031         s = os2devtab[x+8].kwd;         /* Substitite its real name */
11032 #ifdef NT
11033         xxtapi = 0;
11034 #else /* NT */
11035         xxslip = xxppp = 0;
11036 #endif /* NT */
11037         debug(F110,"OS2 SET PORT subst s",s,"");
11038 #ifndef NT
11039     } else if ((y >-1) && (x >= 16 && x < 24)) { /* SLIP access */
11040         s = os2devtab[x-8].kwd;         /* Substitite its real name */
11041         debug(F110,"OS2 SET PORT SLIP subst s",s,"");
11042         xxslip = 1;
11043         xxppp  = 0;
11044     } else if ((y >-1) && (x >= 24 && x < 32)) { /* PPP access */
11045         s = os2devtab[x-16].kwd;        /* Substitite its real name */
11046         debug(F110,"OS2 SET PORT PPP subst s",s,"");
11047         xxppp = 1;
11048         xxslip = 0;
11049         if ((y = cmkey(os2ppptab,
11050                        nos2ppp,
11051                        "PPP driver interface",
11052                        "ppp0",
11053                        xxstring)
11054              ) < 0)
11055           return(y);
11056         debug(F101,"OS2 SET PORT PPP INTERFACE y","",y);
11057         xxppp = (y % 10) + 1;
11058 #endif /* NT */
11059     } else if (*s == '_') {             /* User used "_" prefix */
11060         s++;                            /* Remove it */
11061         /* Rest must be numeric */
11062         debug(F110,"OS2 SET PORT HANDLE _subst s",s,0);
11063         if (!rdigits(s)) {
11064             makestr(&slmsg,"Invalid file handle");
11065             printf("?Invalid format for file handle\n");
11066             return(-9);
11067         }
11068 #ifdef NT
11069         xxtapi = 0;
11070 #else /* NT */
11071         xxslip = xxppp = 0;
11072 #endif /* NT */
11073     } else {                            /* A normal COMx port or a string */
11074         s = brstrip(s);                 /* Strip braces if any */
11075 #ifdef NT
11076 #ifdef CK_TAPI
11077         /* Windows TAPI support - Look up in keyword table */
11078         if (tapilinetab && _tapilinetab && ntapiline > 0) {
11079             if (!ckstrcmp(s,"tapi",4,0)) {
11080
11081                 /* Find out what the lowest numbered TAPI device is */
11082                 /* and use it as the default.                       */
11083                 int j = 9999, k = -1;
11084                 for (i = 0; i < ntapiline; i++) {
11085                     if (tapilinetab[i].kwval < j) {
11086                         j = tapilinetab[i].kwval;
11087                         k = i;
11088                     }
11089                 }
11090                 if (k >= 0)
11091                   s = _tapilinetab[k].kwd;
11092                 else
11093                   s = "";
11094
11095                 if ((y = cmkey(_tapilinetab,ntapiline,
11096                                "TAPI device name",s,xxstring)) < 0)
11097                   return(y);
11098
11099                 xxtapi = 1;
11100
11101                 /* Get the non Underscored string */
11102                 for (i = 0; i < ntapiline; i++ ) {
11103                     if (tapilinetab[i].kwval == y) {
11104                         s = tapilinetab[i].kwd;
11105                         break;
11106                     }
11107                 }
11108             } else
11109               xxtapi = 0;
11110         }
11111 #endif /* CK_TAPI */
11112 #else /* NT */
11113         /* not OS/2 SLIP or PPP */
11114         xxslip = xxppp = 0;
11115 #endif /* NT */
11116     }
11117     ckstrncpy(tmpbuf,s,TMPBUFSIZ);      /* Copy to a safe place */
11118     s = tmpbuf;
11119     if ((x = cmcfm()) < 0)
11120       return(x);
11121
11122 #else /* !OS2 */
11123
11124     cmfdbi(&sw,_CMKEY,"Device name, or switch",
11125            "","",npsltab,4,xxstring,psltab,&tx);
11126     cmfdbi(&tx,_CMTXT,"",dftty,"",0,0,xxstring,NULL,NULL);
11127     while (!confirmed) {
11128         x = cmfdb(&sw);
11129         debug(F101,"setlin cmfdb","",x);
11130         if (x < 0)
11131           if (x != -3)
11132             return(x);
11133         if (x == -3) {
11134             if ((x = cmcfm()) < 0) {
11135                 return(x);
11136             } else {
11137                 confirmed = 1;
11138                 break;
11139             }
11140         }
11141         switch (cmresult.fcode) {
11142           case _CMTXT:
11143             ckstrncpy(tmpbuf,cmresult.sresult,TMPBUFSIZ);
11144             s = tmpbuf;
11145             debug(F110,"setlin CMTXT",tmpbuf,0);
11146             confirmed = 1;
11147             break;
11148           case _CMKEY:                  /* Switch */
11149             debug(F101,"setlin CMKEY",tmpbuf,cmresult.nresult);
11150             switch (cmresult.nresult) {
11151               case SL_CNX:              /* /CONNECT */
11152                 cx = 1;
11153                 sx = 0;
11154                 break;
11155               case SL_SRV:              /* /SERVER */
11156                 cx = 0;
11157                 sx = 1;
11158                 break;
11159 #ifdef VMS
11160               case SL_SHR:              /* /SHARE */
11161                 shr = 1;
11162                 break;
11163               case SL_NSH:              /* /NOSHARE */
11164                 shr = 0;
11165                 break;
11166 #endif /* VMS */
11167             }
11168             continue;
11169           default:
11170             debug(F101,"setlin bad cmfdb result","",cmresult.fcode);
11171             makestr(&slmsg,"Internal error");
11172             printf("?Internal parsing error\n");
11173             return(-9);
11174         }
11175     }
11176 #endif /* OS2 */
11177     if (!confirmed)
11178       if ((x = cmcfm()) < 0)
11179         return(x);
11180
11181     debug(F110,"setlin pre-cx_serial s",s,0);
11182     debug(F110,"setlin pre-cx_serial line",line,0);
11183     x = cx_serial(s,cx,sx,shr,zz,0,
11184 #ifdef OS2
11185 #ifdef NT
11186                    (xxtapi ? CX_TAPI : 0)
11187 #else
11188                    (xxslip ? CX_SLIP : 0) | (xxppp ? CX_PPP : 0)
11189 #endif /* NT */
11190 #else /* OS2 */
11191                    0
11192 #endif /* OS2 */
11193                    );
11194     debug(F111,"setlin cx_serial",line,x);
11195     return(x);
11196 }
11197 #endif /* NOLOCAL */
11198
11199 #ifdef CKCHANNELIO
11200 /*
11201   C-Library based file-i/o package for scripts.  This should be portable to
11202   all C-Kermit versions since it uses the same APIs we have always used for
11203   processing command files.  The entire channel i/o package is contained
11204   herein, apart from some keyword table entries in the main keyword table
11205   and the help text in the HELP command module.
11206
11207   On platforms like VMS and VOS, this package handles only UNIX-style
11208   stream files.  If desired, it can be replaced for those platforms by
11209   <#>ifdef'ing out this code and adding the equivalent replacement routines
11210   to the ck?fio.c module, e.g. for RMS-based file i/o in ckvfio.c.
11211 */
11212
11213 /* Define NOSTAT if the <#>include causes trouble. */
11214
11215 #ifndef NOSTAT
11216 #ifdef VMS
11217 #ifdef VAXC                             /* As it does in VAX C */
11218 #define NOSTAT
11219 #endif /* VAXC */
11220 #endif /* VMS */
11221 #endif /* NOSTAT */
11222
11223 #ifndef NOSTAT
11224 #include <sys/stat.h>
11225 #endif /* NOSTAT */
11226
11227 #ifdef NLCHAR
11228 static int z_lt = 1;                    /* Length of line terminator */
11229 #else
11230 static int z_lt = 2;
11231 #endif /* NLCHAR */
11232
11233 struct ckz_file {                       /* C-Kermit file struct */
11234     FILE * z_fp;                        /* Includes the C-Lib file struct */
11235     unsigned int z_flags;               /* Plus C-Kermit mode flags, */
11236     long z_nline;                       /* current line number if known, */
11237     char z_name[CKMAXPATH+2];           /* and the file's name. */
11238 };
11239 static struct ckz_file * z_file = NULL; /* Array of C-Kermit file structs */
11240 static int z_inited = 0;                /* Flag for array initialized */
11241 int z_maxchan = Z_MAXCHAN;              /* Max number of C-Kermit channels */
11242 int z_openmax = CKMAXOPEN;              /* Max number of open files overall */
11243 int z_nopen = 0;                        /* How many channels presently open */
11244 int z_error = 0;                        /* Most recent error */
11245 int z_filcount = -1;                    /* Most recent FILE COUNT result */
11246
11247 #define RD_LINE 0                       /* FILE READ options */
11248 #define RD_CHAR 1
11249 #define RD_SIZE 2
11250 #define RD_TRIM 8                       /* Like Snobol &TRIM = 1 */
11251 #define RD_UNTA 9                       /* Untabify */
11252
11253 #define WR_LINE RD_LINE                 /* FILE WRITE options */
11254 #define WR_CHAR RD_CHAR
11255 #define WR_SIZE RD_SIZE
11256 #define WR_STRI 3
11257 #define WR_LPAD 4
11258 #define WR_RPAD 5
11259
11260 #ifdef UNIX
11261 extern int ckmaxfiles;                  /* Filled in by sysinit(). */
11262 #endif /* UNIX */
11263
11264 /* See ckcker.h for error numbers */
11265 /* See ckcdeb.h for Z_MAXCHAN and CKMAXOPEN definitions */
11266 /* NOTE: For VMS we might be able to fill in ckmaxfiles */
11267 /* from FILLM and CHANNELCNT -- find out about these... */
11268
11269 static char * fopnargs[] = {            /* Mode combinations for fopen() */
11270 #ifdef COMMENT
11271     /* All combinations of rwa */
11272     "",  "r",  "w",  "rw",  "a",  "ra",  "wa",  "rwa", /* Text mode */
11273     "b", "rb", "wb", "rwb", "ab", "rab", "wab", "rwab" /* Binary mode */
11274 #else
11275     /* Combinations and syntax permitted by C libraries... */
11276     "",  "r",  "w",  "r+",  "a",  "",   "a",  "", /* Text mode */
11277 #ifdef OS2
11278     "",  "rb", "wb", "r+b", "ab", "",   "ab", "" /* Binary modes for K95 */
11279 #else
11280 #ifdef VMS
11281     "",  "rb", "wb", "r+b", "ab", "",   "ab", "" /* Binary modes for VMS */
11282 #else
11283     "",  "r",   "w", "r+",  "a",  "",   "a",  "" /* Binary modes for UNIX */
11284 #endif /* VMS */
11285 #endif /* OS2 */
11286 #endif /* COMMENT */
11287 };
11288 static int nfopnargs = sizeof(fopnargs) / sizeof(char *);
11289
11290 char *                                  /* Error messages */
11291 ckferror(n) int n; {
11292     switch (n) {
11293       case FX_NER: return("No error");
11294       case FX_SYS: return(ck_errstr());
11295       case FX_EOF: return("End of file");
11296       case FX_NOP: return("File not open");
11297       case FX_CHN: return("Channel out of range");
11298       case FX_RNG: return("Parameter out of range");
11299       case FX_NMF: return("Too many files open");
11300       case FX_FOP: return("Operation conflicts with OPEN mode");
11301       case FX_NYI: return("OPEN mode not supported");
11302       case FX_BOM: return("Illegal combination of OPEN modes");
11303       case FX_ACC: return("Access denied");
11304       case FX_FNF: return("File not found");
11305       case FX_OFL: return("Buffer overflow");
11306       case FX_LNU: return("Current line number unknown");
11307       case FX_ROO: return("Off limits");
11308       case FX_UNK: return("Operation fails - reason unknown");
11309       default: return("Error number out of range");
11310     }
11311 }
11312
11313 /*
11314   Z _ O P E N --  Open a file for the requested type of access.
11315
11316   Call with:
11317     name:  Name of file to be opened.
11318     flags: Any combination of FM_xxx values except FM_EOF (ckcker.h).
11319   Returns:
11320     >= 0 on success: The assigned channel number
11321     <  0 on failure: A negative FX_xxx error code (ckcker.h).
11322 */
11323 int
11324 z_open(name, flags) char * name; int flags; {
11325     int i, n;
11326     FILE * t;
11327     char * mode;
11328     debug(F111,"z_open",name,flags);
11329     if (!name) name = "";               /* Check name argument */
11330     if (!name[0])
11331       return(z_error = FX_BFN);
11332     if (flags & FM_CMD)                 /* Opening pipes not implemented yet */
11333       return(z_error = FX_NYI);         /* (and not portable either) */
11334     debug(F101,"z_open nfopnargs","",nfopnargs);
11335     if (flags < 0 || flags >= nfopnargs) /* Range check flags */
11336       return(z_error = FX_RNG);
11337     mode = fopnargs[flags];             /* Get fopen() arg */
11338     debug(F111,"z_open fopen args",mode,flags);
11339     if (!mode[0])                       /* Check for illegal combinations */
11340       return(z_error = FX_BOM);
11341     if (!z_inited) {                    /* If file structs not inited */
11342         debug(F101,"z_open z_maxchan 1","",z_maxchan);
11343 #ifdef UNIX
11344         debug(F101,"z_open ckmaxfiles","",ckmaxfiles);
11345         if (ckmaxfiles > 0) {           /* Set in ck?tio.c: sysinit() */
11346             int x;
11347             x = ckmaxfiles - ZNFILS - 5;
11348             if (x > z_maxchan)          /* sysconf() value greater than */
11349               z_maxchan = x;            /* value from header files. */
11350             debug(F101,"z_open z_maxchan 2","",z_maxchan);
11351         }
11352 #endif /* UNIX */
11353         if (z_maxchan < Z_MINCHAN)      /* Allocate at least this many. */
11354           z_maxchan = Z_MINCHAN;
11355         debug(F101,"z_open z_maxchan 3","",z_maxchan);
11356         /* Note: This could be a pretty big chunk of memory */
11357         /* if z_maxchan is a big number.  If this becomes a problem */
11358         /* we'll need to malloc and free each element at open/close time */
11359         if (!(z_file = (struct ckz_file *)
11360               malloc(sizeof(struct ckz_file) * (z_maxchan + 1))))
11361           return(z_error = FX_NMF);
11362         for (i = 0; i < z_maxchan; i++) {
11363             z_file[i].z_fp = NULL;
11364             z_file[i].z_flags = 0;
11365             z_file[i].z_nline = 0;
11366             *(z_file[i].z_name) = '\0';
11367         }
11368         z_inited = 1;                   /* Remember we did */
11369     }
11370     for (n = -1, i = 0; i < z_maxchan; i++) {
11371         if (!z_file[i].z_fp) {
11372             n = i;
11373             break;
11374         }
11375     }
11376     if (n < 0 || n >= z_maxchan)        /* Any free channels? */
11377       return(z_error = FX_NMF);         /* No, fail. */
11378     errno = 0;
11379
11380     z_file[n].z_flags = 0;              /* In case of failure... */
11381
11382     t = fopen(name, mode);              /* Try to open the file. */
11383     if (!t) {                           /* Failed... */
11384         debug(F111,"z_open error",name,errno);
11385 #ifdef EMFILE
11386         if (errno == EMFILE)
11387           return(z_error = FX_NMF);
11388 #endif /* EMFILE */
11389         return(z_error = (errno ?  FX_SYS : FX_UNK)); /* Return error code */
11390     }
11391 #ifdef NT
11392 #ifdef O_SEQUENTIAL
11393     if (t)                              /* Caching hint for NT */
11394       _setmode(_fileno(t),O_SEQUENTIAL);
11395 #endif /* O_SEQUENTIAL */
11396 #endif /* NT */
11397     z_nopen++;                          /* Open, count it. */
11398     z_file[n].z_fp = t;                 /* Stash the file pointer */
11399     z_file[n].z_flags = flags;          /* and the flags */
11400     z_error = 0;
11401     zfnqfp(name,CKMAXPATH,z_file[n].z_name); /* and the file's full name */
11402     return(n);                          /* Return the channel number */
11403 }
11404
11405 int
11406 z_close(channel) int channel; {         /* Close file on given channel */
11407     int x;
11408     FILE * t;
11409     if (!z_inited)                      /* Called before any files are open? */
11410       return(z_error = FX_NOP);
11411     if (channel >= z_maxchan)           /* Channel out of range? */
11412       return(z_error = FX_CHN);
11413     if (!(t = z_file[channel].z_fp))    /* Channel wasn't open? */
11414       return(z_error = FX_NOP);
11415     errno = 0;                          /* Set errno 0 to get a good reading */
11416     x = fclose(t);                      /* Try to close */
11417     if (x == EOF)                       /* On failure */
11418       return(z_error = FX_SYS);         /* indicate system error. */
11419     z_nopen--;                          /* Closed OK, decrement open count */
11420     z_file[channel].z_fp = NULL;        /* Set file pointer to NULL */
11421     z_file[channel].z_nline = 0;        /* Current line number is 0 */
11422     z_file[channel].z_flags = 0;        /* Set flags to 0 */
11423     *(z_file[channel].z_name) = '\0';   /* Clear name */
11424     return(z_error = 0);
11425 }
11426
11427 /*
11428   Z _ O U T  --  Output string to channel.
11429
11430   Call with:
11431     channel:     Channel number to write to.
11432     s:           String to write.
11433     length > -1: How many characters of s to write.
11434     length < 0:  Write entire NUL-terminated string.
11435     flags == 0:  Supply line termination.
11436     flags >  0:  Don't supply line termination.
11437     flags <  0:  Write 'length' NUL characters.
11438   Special case:
11439     If flags > -1 and s is empty or NULL and length == 1, write 1 NUL.
11440   Returns:
11441     Number of characters written to channel on success, or
11442     negative FX_xxx error code on failure.
11443 */
11444 int
11445 z_out(channel,s,length,flags) int channel, flags, length; char * s; {
11446     FILE * t;
11447     int x, n;
11448     char c = '\0';
11449
11450     if (!s) s = "";                     /* Guard against null pointer */
11451 #ifdef DEBUG
11452     if (deblog) {
11453         debug(F111,"z_out",s,channel);
11454         debug(F101,"z_out length","",length);
11455         debug(F101,"z_out flags","",flags);
11456     }
11457 #endif /* DEBUG */
11458     if (!z_inited)                      /* File i/o inited? */
11459       return(z_error = FX_NOP);
11460     if (channel >= z_maxchan)           /* Channel in range? */
11461       return(z_error = FX_CHN);
11462     if (!(t = z_file[channel].z_fp))    /* File open? */
11463       return(z_error = FX_NOP);
11464     if (!((z_file[channel].z_flags) & (FM_WRI|FM_APP))) /* In write mode? */
11465       return(z_error = FX_FOP);
11466     n = length;                         /* Length of string to write */
11467     if (n < 0) {                        /* Negative means get it ourselves */
11468         if (flags < 0)                  /* Except when told to write NULs in */
11469           return(z_error = FX_RNG);     /* which case args are inconsistent */
11470         n = strlen(s);                  /* Get length of string arg */
11471     }
11472     errno = 0;                          /* Reset errno */
11473     debug(F101,"z_out n","",n);
11474     if (flags < 0) {                    /* Writing NULs... */
11475         int i;
11476         for (i = 0; i < n; i++) {
11477             x = fwrite(&c,1,1,t);
11478             if (x < 1)
11479               return(z_error = (errno ? FX_SYS : FX_UNK));
11480         }
11481         z_file[channel].z_nline = -1;   /* Current line no longer known */
11482         z_error = 0;
11483         return(i);
11484     } else {                            /* Writing string arg */
11485         if (n == 1 && !s[0])            /* Writing one char but it's NUL */
11486           x = fwrite(&c,1,1,t);
11487         else                            /* Writing non-NUL char or string */
11488           x = fwrite(s,1,n,t);
11489         debug(F101,"z_out fwrite",ckitoa(x),errno);
11490         if (x < n)                      /* Failure to write requested amount */
11491           return(z_error = (errno ? FX_SYS : FX_UNK)); /* Return error */
11492         if (flags == 0) {               /* If supplying line termination */
11493             if (fwrite("\n",1,1,t))     /* do that  */
11494               x += z_lt;                /* count the terminator */
11495             if (z_file[channel].z_nline > -1) /* count this line */
11496               z_file[channel].z_nline++;
11497         } else {
11498             z_file[channel].z_nline = -1; /* Current line no longer known */
11499         }
11500     }
11501     z_error = 0;
11502     return(x);
11503 }
11504
11505 #define Z_INBUFLEN 64
11506
11507 /*
11508   Z _ I N  --  Multichannel i/o file input function.
11509
11510   Call with:
11511     channel number to read from.
11512     s = address of destination buffer.
11513     buflen = destination buffer length.
11514     length = Number of bytes to read, must be < buflen.
11515     flags: 0 = read a line; nonzero = read the given number of bytes.
11516   Returns:
11517     Number of bytes read into buffer or a negative error code.
11518     A terminating NUL is deposited after the last byte that was read.
11519 */
11520 int
11521 z_in(channel,s,buflen,length,flags)
11522  int channel, buflen, length, flags; char * s;
11523 /* z_in */ {
11524     int i, j, x;
11525     FILE * t;
11526     char * p;
11527
11528     if (!z_inited)                      /* Check everything... */
11529       return(z_error = FX_NOP);
11530     if (channel >= z_maxchan)
11531       return(z_error = FX_CHN);
11532     if (!(t = z_file[channel].z_fp))
11533       return(z_error = FX_NOP);
11534     if (!((z_file[channel].z_flags) & FM_REA))
11535       return(z_error = FX_FOP);
11536     if (!s)                             /* Check destination */
11537      return(z_error = FX_RNG);
11538     s[0] = NUL;
11539     if (length == 0)                    /* Read 0 bytes - easy. */
11540       return(z_error = 0);
11541     debug(F101,"z_in channel","",channel);
11542     debug(F101,"z_in buflen","",buflen);
11543     debug(F101,"z_in length","",length);
11544     debug(F101,"z_in flags","",flags);
11545     if (length < 0 || buflen < 0)       /* Check length args */
11546       return(z_error = FX_RNG);
11547     if (buflen <= length)
11548       return(z_error = FX_RNG);
11549     errno = 0;                          /* Reset errno */
11550     if (flags) {                        /* Read block or byte */
11551         i = fread(s,1,length,t);
11552 #ifdef DEBUG
11553         if (deblog) {
11554             debug(F111,"z_in block",s,i);
11555             debug(F101,"z_in block errno","",errno);
11556             debug(F101,"z_in block ferror","",ferror(t));
11557             debug(F101,"z_in block feof","",feof(t));
11558         }
11559 #endif /* DEBUG */
11560         z_file[channel].z_nline = -1;   /* Current line no longer known */
11561     } else {                            /* Read line */
11562 #ifndef COMMENT
11563         /* This method is used because it's simpler than the others */
11564         /* and also marginally faster. */
11565         debug(F101,"z_in getc loop","",ftell(t));
11566         for (i = 0; i < length; i++) {
11567             if ((x = getc(t)) == EOF) {
11568                 debug(F101,"z_in getc error","",ftell(t));
11569                 s[i] = '\0';
11570                 break;
11571             }
11572             s[i] = x;
11573             if (s[i] == '\n') {
11574                 s[i] = '\0';
11575                 break;
11576             }
11577         }
11578         debug(F111,"z_in line byte loop",ckitoa(errno),i);
11579         debug(F111,"z_in line got",s,z_file[channel].z_nline);
11580         if (z_file[channel].z_nline > -1)
11581           z_file[channel].z_nline++;
11582 #else
11583 #ifdef COMMENT2
11584         /* Straightforward but strlen() slows it down. */
11585         s[0] = '\0';
11586         i = 0;
11587         if (fgets(s,length,t)) {
11588             i = strlen(s);
11589             if (i > 0 && s[i-1] == '\n') i--;
11590         }
11591         debug(F111,"z_in line fgets",ckitoa(errno),i);
11592         if (z_file[channel].z_nline > -1)
11593           z_file[channel].z_nline++;
11594 #else
11595         /* This is a do-it-yourself fgets() with its own readahead and */
11596         /* putback.  It's a bit faster than real fgets() but not enough */
11597         /* to justify the added complexity or the risk of the ftell() and */
11598         /* fseek() calls failing. */
11599         int k, flag = 0;
11600         long pos;
11601         for (i = 0; !flag && i <= (length - Z_INBUFLEN); i += Z_INBUFLEN) {
11602             k = ((length - i) < Z_INBUFLEN) ? length - i : Z_INBUFLEN;
11603             if ((x = fread(s+i,1,k,t)) < 1)
11604               break;
11605             s[i+x] = '\0';
11606             for (j = 0; j < x; j++) {
11607                 if (s[i+j] == '\n') {
11608                     s[i+j] = '\0';
11609                     flag ++;
11610                     pos = ftell(t);
11611                     if (pos > -1) {
11612                         pos -= (x - j - 1);
11613                         x = fseek(t, pos, 0);
11614                         i += j;
11615                         break;
11616                     } else
11617                       return(z_error = FX_SYS);
11618                 }
11619             }
11620         }
11621         if (z_file[channel].z_nline > -1)
11622           z_file[channel].z_nline++;
11623         debug(F111,"z_in line chunk loop",ckitoa(errno),i);
11624 #endif /* COMMENT2 */
11625 #endif /* COMMENT */
11626     }
11627     debug(F111,"z_in i",ckitoa(errno),i);
11628     if (i < 0) i = 0;                   /* NUL-terminate result */
11629     s[i] = '\0';
11630     if (i > 0) {
11631         z_error = 0;
11632         return(i);
11633     }
11634     if (i == 0 && feof(t))              /* EOF on reading? */
11635       return(z_error = FX_EOF);         /* Return EOF code */
11636     return(errno ? (z_error = -1) : i); /* Return length or system error */
11637 }
11638
11639 int
11640 z_flush(channel) int channel; {         /* Flush output channel */
11641     FILE * t;
11642     int x;
11643     if (!z_inited)                      /* Regular checks */
11644       return(z_error = FX_NOP);
11645     if (channel >= z_maxchan)
11646       return(z_error = FX_CHN);
11647     if (!(t = z_file[channel].z_fp))
11648       return(z_error = FX_NOP);
11649     if (!((z_file[channel].z_flags) & (FM_WRI|FM_APP))) /* Write access? */
11650       return(z_error = FX_FOP);
11651     errno = 0;                          /* Reset errno */
11652     x = fflush(t);                      /* Try to flush */
11653     return(x ? (z_error = FX_SYS) : 0); /* Return system error or 0 if OK */
11654 }
11655
11656 int
11657 #ifdef CK_ANSIC
11658 z_seek(int channel, long pos)           /* Move file pointer to byte */
11659 #else
11660 z_seek(channel,pos) int channel; long pos; /* (seek to given position) */
11661 #endif /* CK_ANSIC */
11662 {
11663     int i, x = 0, rc;
11664     FILE * t;
11665     if (!z_inited)                      /* Check... */
11666       return(z_error = FX_NOP);
11667     if (channel >= z_maxchan)
11668       return(z_error = FX_CHN);
11669     if (!(t = z_file[channel].z_fp))
11670       return(z_error = FX_NOP);
11671     if (pos < 0L) {
11672         x = 2;
11673         pos = (pos == -2) ? -1L : 0L;
11674     }
11675     errno = 0;
11676     rc = fseek(t,pos,x);                /* Try to seek */
11677     debug(F111,"z_seek",ckitoa(errno),rc);
11678     if (rc < 0)                         /* OK? */
11679       return(z_error = FX_SYS); /* No. */
11680     z_file[channel].z_nline = ((pos || x) ? -1 : 0);
11681     return(z_error = 0);
11682 }
11683
11684 int
11685 #ifdef CK_ANSIC
11686 z_line(int channel, long pos)           /* Move file pointer to line */
11687 #else
11688 z_line(channel,pos) int channel; long pos; /* (seek to given position) */
11689 #endif /* CK_ANSIC */
11690 {
11691     int i, len, x = 0;
11692     long current = 0L, prev = -1L, old = -1L;
11693     FILE * t;
11694     char tmpbuf[256];
11695     if (!z_inited)                      /* Check... */
11696       return(z_error = FX_NOP);
11697     if (channel >= z_maxchan)
11698       return(z_error = FX_CHN);
11699     if (!(t = z_file[channel].z_fp))
11700       return(z_error = FX_NOP);
11701     debug(F101,"z_line pos","",pos);
11702     if (pos < 0L) {                     /* EOF wanted */
11703         long n;
11704         n = z_file[channel].z_nline;
11705         debug(F101,"z_line n","",n);
11706         if (n < 0 || pos < 0) {
11707             rewind(t);
11708             n = 0;
11709         }
11710         while (1) {                     /* This could take a while... */
11711             if ((x = getc(t)) == EOF)
11712               break;
11713             if (x == '\n') {
11714                 n++;
11715                 if (pos == -2) {
11716                     old = prev;
11717                     prev = ftell(t);
11718                 }
11719             }
11720         }
11721         debug(F101,"z_line old","",old);
11722         debug(F101,"z_line prev","",prev);
11723         if (pos == -2) {
11724             if ((x = z_seek(channel,old)) < 0)
11725               return(z_error = x);
11726             else
11727               n--;
11728         }
11729         z_file[channel].z_nline = n;
11730         return(z_error = 0);
11731     }
11732     if (pos == 0L) {                    /* Rewind wanted */
11733         z_file[channel].z_nline = 0L;
11734         rewind(t);
11735         debug(F100,"z_line rewind","",0);
11736         return(0L);
11737     }
11738     tmpbuf[255] = NUL;                  /* Make sure buf is NUL terminated */
11739     current = z_file[channel].z_nline;  /* Current line */
11740     /*
11741       If necessary the following could be optimized, e.g. for positioning
11742       to a previous line in a large file without starting over.
11743     */
11744     if (current < 0 || pos < current) { /* Not known or behind us... */
11745         debug(F101,"z_line rewinding","",pos);
11746         if ((x = z_seek(channel, 0L)) < 0) /* Rewind */
11747           return(z_error = x);
11748         if (pos == 0)                   /* If 0th line wanted we're done */
11749           return(z_error = 0);
11750         current = 0;
11751     }
11752     while (current < pos) {             /* Search for specified line */
11753         if (fgets(tmpbuf,255,t)) {
11754             len = strlen(tmpbuf);
11755             if (len > 0 && tmpbuf[len-1] == '\n') {
11756                 current++;
11757                 debug(F111,"z_line read",ckitoa(len),current);
11758             } else if (len == 0) {
11759                 return(z_error = FX_UNK);
11760             }
11761         } else {
11762             z_file[channel].z_nline = -1L;
11763             debug(F101,"z_line premature EOF","",current);
11764             return(z_error = FX_EOF);
11765         }
11766     }
11767     z_file[channel].z_nline = current;
11768     debug(F101,"z_line result","",current);
11769     z_error = 0;
11770     return(current);
11771 }
11772
11773 char *
11774 z_getname(channel) int channel; {       /* Return name of file on channel */
11775     FILE * t;
11776     if (!z_inited) {
11777         z_error = FX_NOP;
11778         return(NULL);
11779     }
11780     if (channel >= z_maxchan) {
11781         z_error = FX_CHN;
11782         return(NULL);
11783     }
11784     if (!(t = z_file[channel].z_fp)) {
11785         z_error = FX_NOP;
11786         return(NULL);
11787     }
11788     return((char *)(z_file[channel].z_name));
11789 }
11790
11791 int
11792 z_getmode(channel) int channel; {       /* Return OPEN modes of channel */
11793     FILE * t;                           /* 0 if file not open */
11794 #ifndef NOSTAT
11795 #ifdef NT
11796     struct _stat statbuf;
11797 #else /* NT */
11798     struct stat statbuf;
11799 #endif /* NT */
11800 #endif /* NOSTAT */
11801     int x;
11802     if (!z_inited)
11803       return(0);
11804     if (channel >= z_maxchan)
11805       return(z_error = FX_CHN);
11806     if (!(t = z_file[channel].z_fp))
11807       return(0);
11808     x = z_file[channel].z_flags;
11809     if (feof(t)) {                      /* This might not work for */
11810         x |= FM_EOF;                    /* output files */
11811 #ifndef NOSTAT
11812     /* But this does if we can use it. */
11813     } else if (stat(z_file[channel].z_name,&statbuf) > -1) {
11814         if (ftell(t) == statbuf.st_size)
11815           x |= FM_EOF;
11816 #endif /* NOSTAT */
11817     }
11818     return(x);
11819 }
11820
11821 long
11822 z_getpos(channel) int channel; {        /* Get file pointer position */
11823     FILE * t;                           /* on this channel */
11824     long x;
11825     if (!z_inited)
11826       return(z_error = FX_NOP);
11827     if (channel >= z_maxchan)
11828       return(z_error = FX_CHN);
11829     if (!(t = z_file[channel].z_fp))
11830       return(z_error = FX_NOP);
11831     x = ftell(t);
11832     return((x < 0L) ? (z_error = FX_SYS) : x);
11833 }
11834
11835 long
11836 z_getline(channel) int channel; {       /* Get current line number */
11837     FILE * t;                           /* in file on this channel */
11838     long rc;
11839     if (!z_inited)
11840       return(z_error = FX_NOP);
11841     if (channel >= z_maxchan)
11842       return(z_error = FX_CHN);
11843     if (!(t = z_file[channel].z_fp))
11844       return(z_error = FX_NOP);
11845     debug(F101,"z_getline","",z_file[channel].z_nline);
11846     rc = z_file[channel].z_nline;
11847     return((rc < 0) ? (z_error = FX_LNU) : rc);
11848 }
11849
11850 int
11851 z_getfnum(channel) int channel; {       /* Get file number / handle */
11852     FILE * t;                           /* for file on this channel */
11853     if (!z_inited)
11854       return(z_error = FX_NOP);
11855     if (channel >= z_maxchan)
11856       return(z_error = FX_CHN);
11857     if (!(t = z_file[channel].z_fp))
11858       return(z_error = FX_NOP);
11859     z_error = 0;
11860     return(fileno(t));
11861 }
11862
11863 /*
11864   Line-oriented counts and seeks are as dumb as they can be at the moment.
11865   Later we can speed them up by building little indexes.
11866 */
11867 long
11868 z_count(channel, what) int channel, what; { /* Count bytes or lines in file */
11869     FILE * t;
11870     int i, x;
11871     long pos, count = 0L;
11872     if (!z_inited)                      /* Check stuff... */
11873       return(z_error = FX_NOP);
11874     if (channel >= z_maxchan)
11875       return(z_error = FX_CHN);
11876     if (!(t = z_file[channel].z_fp))
11877       return(z_error = FX_NOP);
11878     pos = ftell(t);                     /* Save current file pointer */
11879     errno = 0;
11880     z_error = 0;
11881     if (what == RD_CHAR) {              /* Size in bytes requested */
11882         if (!fseek(t,0L,2)) {           /* Seek to end */
11883             count = ftell(t);           /* Get file pointer */
11884             fseek(t,pos,0);             /* Restore file file pointer */
11885             return(count);
11886         } else                          /* Fallback in case seek fails */
11887           return(zgetfs(z_file[channel].z_name));
11888     }
11889     rewind(t);                          /* Line count requested - rewind. */
11890     while (1) {                         /* Count lines. */
11891         if ((x = getc(t)) == EOF)       /* Stupid byte loop */
11892           break;                        /* but it works as well as anything */
11893         if (x == '\n')                  /* else... */
11894           count++;
11895     }
11896     x = fseek(t,pos,0);                 /* Restore file pointer */
11897     return(count);
11898 }
11899
11900 /* User interface for generalized channel-oriented file i/o */
11901
11902 struct keytab fctab[] = {               /* FILE subcommands */
11903     { "close",      FIL_CLS, 0 },
11904     { "count",      FIL_COU, 0 },
11905     { "flush",      FIL_FLU, 0 },
11906     { "list",       FIL_LIS, 0 },
11907     { "open",       FIL_OPN, 0 },
11908     { "read",       FIL_REA, 0 },
11909     { "rewind",     FIL_REW, 0 },
11910     { "seek",       FIL_SEE, 0 },
11911     { "status",     FIL_STA, 0 },
11912     { "write",      FIL_WRI, 0 }
11913 };
11914 int nfctab = (sizeof (fctab) / sizeof (struct keytab));
11915
11916 static struct keytab fcswtab[] = {      /* OPEN modes */
11917     { "/append",    FM_APP,  0 },
11918     { "/binary",    FM_BIN,  0 },
11919 #ifdef COMMENT
11920     { "/command",   FM_CMD,  0 },       /* Not implemented */
11921 #endif /* COMMENT */
11922     { "/read",      FM_REA,  0 },
11923     { "/write",     FM_WRI,  0 }
11924 };
11925 static int nfcswtab = (sizeof (fcswtab) / sizeof (struct keytab));
11926
11927 static struct keytab fclkwtab[] = {     /* CLOSE options */
11928     { "all",        1,       0 }
11929 };
11930
11931 static struct keytab fsekwtab[] = {     /* SEEK symbols */
11932     { "eof",        1,       0 },
11933     { "last",       2,       0 }
11934 };
11935 static int nfsekwtab = (sizeof (fsekwtab) / sizeof (struct keytab));
11936
11937 #define SEE_LINE  RD_LINE               /* SEEK options */
11938 #define SEE_CHAR  RD_CHAR
11939 #define SEE_REL   3
11940 #define SEE_ABS   4
11941
11942 static struct keytab fskswtab[] = {
11943     { "/absolute",  SEE_ABS,  0 },
11944     { "/byte",      SEE_CHAR, 0 },
11945     { "/character", SEE_CHAR, CM_INV },
11946     { "/line",      SEE_LINE, 0 },
11947     { "/relative",  SEE_REL,  0 }
11948 };
11949 static int nfskswtab = (sizeof (fskswtab) / sizeof (struct keytab));
11950
11951 #define COU_LINE  RD_LINE               /* COUNT options */
11952 #define COU_CHAR  RD_CHAR
11953 #define COU_LIS   3
11954 #define COU_NOL   4
11955
11956 static struct keytab fcoswtab[] = {
11957     { "/bytes",     COU_CHAR, 0      },
11958     { "/characters",COU_CHAR, CM_INV },
11959     { "/lines",     COU_LINE, 0      },
11960     { "/list",      COU_LIS,  0      },
11961     { "/nolist",    COU_NOL,  0      },
11962     { "/quiet",     COU_NOL,  CM_INV }
11963 };
11964 static int nfcoswtab = (sizeof (fcoswtab) / sizeof (struct keytab));
11965
11966 static struct keytab frdtab[] = {       /* READ types */
11967     { "/block",     RD_SIZE, CM_INV|CM_ARG },
11968     { "/byte",      RD_CHAR, CM_INV },
11969     { "/character", RD_CHAR, 0      },
11970     { "/line",      RD_LINE, 0      },
11971     { "/size",      RD_SIZE, CM_ARG },
11972     { "/trim",      RD_TRIM, 0      },
11973     { "/untabify",  RD_UNTA, 0      }
11974 };
11975 static int nfrdtab = (sizeof (frdtab) / sizeof (struct keytab));
11976
11977 static struct keytab fwrtab[] = {       /* WRITE types */
11978     { "/block",     WR_SIZE, CM_INV|CM_ARG },
11979     { "/byte",      WR_CHAR, CM_INV },
11980     { "/character", WR_CHAR, 0      },
11981     { "/line",      WR_LINE, 0      },
11982     { "/lpad",      WR_LPAD, CM_ARG },
11983     { "/rpad",      WR_RPAD, CM_ARG },
11984     { "/size",      WR_SIZE, CM_ARG },
11985     { "/string",    WR_STRI, 0      }
11986 };
11987 static int nfwrtab = (sizeof (fwrtab) / sizeof (struct keytab));
11988
11989 static char blanks[] = "\040\040\040\040"; /* Some blanks for formatting */
11990
11991 int
11992 dofile(op) int op; {                    /* Do the FILE command */
11993     char vnambuf[VNAML];                /* Buffer for variable names */
11994     char *vnp = NULL;                   /* Pointer to same */
11995     char zfilnam[CKMAXPATH+2];
11996     char * p;
11997     struct FDB fl, sw, nu;
11998     long z;
11999     int rsize, filmode = 0, relative = -1, eofflg = 0;
12000     int rc, x, y, cx, n, getval, dummy, confirmed, listing = -1;
12001     int charflag = 0, sizeflag = 0;
12002     int pad = 32, wr_lpad = 0, wr_rpad = 0, rd_trim = 0, rd_untab = 0;
12003
12004     if (op == XXFILE) {                 /* FILE command was given */
12005         /* Get subcommand */
12006         if ((cx = cmkey(fctab,nfctab,"Operation","",xxstring)) < 0) {
12007             if (cx == -3) {
12008                 printf("?File operation required\n");
12009                 x = -9;
12010             }
12011             return(cx);
12012         }
12013     } else {                            /* Shorthand command was given */
12014         switch (op) {
12015           case XXF_CL: cx = FIL_CLS; break; /* FCLOSE */
12016           case XXF_FL: cx = FIL_FLU; break; /* FFLUSH */
12017           case XXF_LI: cx = FIL_LIS; break; /* FLIST */
12018           case XXF_OP: cx = FIL_OPN; break; /* etc... */
12019           case XXF_RE: cx = FIL_REA; break;
12020           case XXF_RW: cx = FIL_REW; break;
12021           case XXF_SE: cx = FIL_SEE; break;
12022           case XXF_ST: cx = FIL_STA; break;
12023           case XXF_WR: cx = FIL_WRI; break;
12024           case XXF_CO: cx = FIL_COU; break;
12025           default: return(-2);
12026         }
12027     }
12028     switch (cx) {                       /* Do requested subcommand */
12029       case FIL_OPN:                     /* OPEN */
12030         cmfdbi(&sw,                     /* Switches */
12031                _CMKEY,                  /* fcode */
12032                "Variable or switch",    /* hlpmsg */
12033                "",                      /* default */
12034                "",                      /* addtl string data */
12035                nfcswtab,                /* addtl numeric data 1: tbl size */
12036                4,                       /* addtl numeric data 2: 4 = cmswi */
12037                xxstring,                /* Processing function */
12038                fcswtab,                 /* Keyword table */
12039                &fl                      /* Pointer to next FDB */
12040                );
12041         cmfdbi(&fl,                     /* Anything that doesn't match */
12042                _CMFLD,                  /* fcode */
12043                "Variable",              /* hlpmsg */
12044                "",
12045                "",
12046                0,
12047                0,
12048                NULL,
12049                NULL,
12050                NULL
12051                );
12052         while (1) {
12053             x = cmfdb(&sw);             /* Parse something */
12054             if (x < 0) {
12055                 if (x == -3) {
12056                     printf("?Variable name and file name required\n");
12057                     x = -9;
12058                 }
12059                 return(x);
12060             }
12061             if (cmresult.fcode == _CMFLD)
12062               break;
12063             else if (cmresult.fcode == _CMKEY) {
12064                 char c;
12065                 c = cmgbrk();
12066                 if ((getval =
12067                      (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
12068                     printf("?This switch does not take an argument\n");
12069                     return(-9);
12070                 }
12071 #ifdef COMMENT
12072                 /* Uncomment if we add any switches ere that take args */
12073                 if (!getval && (cmgkwflgs() & CM_ARG)) {
12074                     printf("?This switch requires an argument\n");
12075                     return(-9);         /* (none do...) */
12076                 }
12077 #endif /* COMMENT */
12078                 filmode |= cmresult.nresult; /* OR in the file mode */
12079             } else
12080               return(-2);
12081         }
12082         /* Not a switch - get the string */
12083         ckstrncpy(vnambuf,cmresult.sresult,VNAML);
12084         if (!vnambuf[0] || chknum(vnambuf)) { /* (if there is one...) */
12085             printf("?Variable name required\n");
12086             return(-9);
12087         }
12088         vnp = vnambuf;                  /* Check variable-name syntax */
12089         if (vnambuf[0] == CMDQ &&
12090             (vnambuf[1] == '%' || vnambuf[1] == '&'))
12091           vnp++;
12092         y = 0;
12093         if (*vnp == '%' || *vnp == '&') {
12094             if ((y = parsevar(vnp,&x,&dummy)) < 0) {
12095                 printf("?Syntax error in variable name\n");
12096                 return(-9);
12097             }
12098         }
12099         if (!(filmode & FM_RWA))        /* If no access mode specified */
12100           filmode |= FM_REA;            /* default to /READ. */
12101
12102         y = 0;                          /* Now parse the filename */
12103         if ((filmode & FM_RWA) == FM_WRI)
12104           x = cmofi("Name of new file","",&s,xxstring);
12105         else if ((filmode & FM_RWA) == FM_REA)
12106           x = cmifi("Name of existing file","",&s,&y,xxstring);
12107         else {
12108             x = cmiofi("Filename","",&s,&y,xxstring);
12109             debug(F101,"fopen /append x","",x);
12110         }
12111         if (x == -9) {
12112             if (zchko(s) < 0) {
12113                 printf("Can't create \"%s\"\n",s);
12114                 return(x);
12115             }
12116         } else if (x < 0) {
12117             if (x == -3) {
12118                 printf("?Filename required\n");
12119                 x = -9;
12120             }
12121             return(x);
12122         }
12123         if (y) {                        /* No wildcards */
12124             printf("?Wildcards not allowed here\n");
12125             return(-9);
12126         }
12127         if (filmode & (FM_APP|FM_WRI)) { /* Check output access */
12128 #ifndef VMS
12129             if (zchko(s) < 0) {          /* and set error code if denied */
12130                 z_error = FX_ACC;
12131                 printf("?Write access denied - \"%s\"\n",s);
12132                 return(-9);
12133             }
12134 #endif /* VMS */
12135         }
12136         ckstrncpy(zfilnam,s,CKMAXPATH); /* Is OK - make safe copy */
12137         if ((x = cmcfm()) < 0)          /* Get confirmation of command */
12138           return(x);
12139         if ((n = z_open(zfilnam,filmode)) < 0) {
12140             printf("?OPEN failed - %s: %s\n",zfilnam,ckferror(n));
12141             return(-9);
12142         }
12143         addmac(vnambuf,ckitoa(n));      /* Assign channel number to variable */
12144         return(success = 1);
12145
12146       case FIL_REW:                     /* REWIND */
12147         if ((x = cmnum("Channel number","",10,&n, xxstring)) < 0) {
12148             if (x == -3) {
12149                 printf("?Channel number required\n");
12150                 x = -9;
12151             }
12152             return(x);
12153         }
12154         if ((x = cmcfm()) < 0)
12155           return(x);
12156         if ((rc = z_seek(n,0L)) < 0) {
12157             printf("?REWIND failed - Channel %d: %s\n",n,ckferror(rc));
12158             return(-9);
12159         }
12160         return(success = 1);
12161
12162       case FIL_CLS:                     /* CLOSE */
12163           cmfdbi(&sw,                   /* Second FDB - switches */
12164                  _CMKEY,                /* fcode */
12165                  "Channel number; or keyword",
12166                  "",
12167                  "",                    /* addtl string data */
12168                  1,                     /* addtl numeric data 1: tbl size */
12169                  0,                     /* addtl numeric data 2: 4 = cmswi */
12170                  xxstring,              /* Processing function */
12171                  fclkwtab,              /* Keyword table */
12172                  &nu                    /* Pointer to next FDB */
12173                  );
12174           cmfdbi(&nu,                   /* First FDB - command switches */
12175                  _CMNUM,                /* fcode */
12176                  "",
12177                  "",                    /* default */
12178                  "",                    /* addtl string data */
12179                  10,                    /* addtl numeric data 1: radix */
12180                  0,                     /* addtl numeric data 2: 0 */
12181                  xxstring,              /* Processing function */
12182                  NULL,                  /* Keyword table */
12183                  NULL                   /* Pointer to next FDB */
12184                  );                     /*  */
12185         x = cmfdb(&sw);                 /* Parse something */
12186         if (x < 0) {
12187             if (x == -3) {
12188                 printf("?Channel number or ALL required\n");
12189                 x = -9;
12190             }
12191             return(x);
12192         }
12193         if (cmresult.fcode == _CMNUM)
12194           n = cmresult.nresult;
12195         else if (cmresult.fcode == _CMKEY)
12196           n = -1;
12197         if ((x = cmcfm()) < 0)
12198           return(x);
12199         rc = 1;
12200         if (n < 0) {
12201             int count = 0;
12202             int i;
12203             for (i = 0; i < z_maxchan; i++) {
12204                 x = z_close(i);
12205                 if (x == FX_SYS) {
12206                     printf("?CLOSE failed - Channel %d: %s\n",n,ckferror(x));
12207                     rc = 0;
12208                 } else if (x > -1)
12209                   count++;
12210             }
12211             debug(F101,"FILE CLOSE ALL","",count);
12212         } else if ((x = z_close(n)) < 0) {
12213             printf("?CLOSE failed - Channel %d: %s\n",n,ckferror(x));
12214             return(-9);
12215         }
12216         return(success = rc);
12217
12218       case FIL_REA:                     /* READ */
12219       case FIL_WRI:                     /* WRITE */
12220         rsize = 0;
12221         cmfdbi(&sw,                     /* Switches */
12222                _CMKEY,                  /* fcode */
12223                "Channel or switch",     /* hlpmsg */
12224                "",                      /* default */
12225                "",                      /* addtl string data */
12226                (cx == FIL_REA) ? nfrdtab : nfwrtab,
12227                4,                       /* addtl numeric data 2: 4 = cmswi */
12228                xxstring,                /* Processing function */
12229                (cx == FIL_REA) ? frdtab : fwrtab, /* Keyword table */
12230                &nu                      /* Pointer to next FDB */
12231                );
12232         cmfdbi(&nu,                     /* Channel number */
12233                _CMNUM,                  /* fcode */
12234                "Channel",
12235                "",                      /* default */
12236                "",                      /* addtl string data */
12237                10,                      /* addtl numeric data 1: radix */
12238                0,                       /* addtl numeric data 2: 0 */
12239                xxstring,                /* Processing function */
12240                NULL,                    /* Keyword table */
12241                NULL                     /* Pointer to next FDB */
12242                );
12243         do {
12244             x = cmfdb(&sw);             /* Parse something */
12245             if (x < 0) {
12246                 if (x == -3) {
12247                     printf("?Channel number required\n");
12248                     x = -9;
12249                 }
12250                 return(x);
12251             }
12252             if (cmresult.fcode == _CMNUM) /* Channel number */
12253               break;
12254             else if (cmresult.fcode == _CMKEY) { /* Switch */
12255                 char c;
12256                 c = cmgbrk();
12257                 if ((getval =
12258                      (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
12259                     printf("?This switch does not take an argument\n");
12260                     return(-9);
12261                 }
12262                 if (!getval && (cmgkwflgs() & CM_ARG)) {
12263                     printf("?This switch requires an argument\n");
12264                     return(-9);
12265                 }
12266                 switch (cmresult.nresult) {
12267                   case WR_LINE:
12268                     charflag = 0;
12269                     sizeflag = 0;
12270                     rsize = 0;
12271                     break;
12272                   case WR_CHAR:
12273                     rsize = 1;
12274                     charflag = 1;
12275                     sizeflag = 1;
12276                     break;
12277                   case WR_SIZE:
12278                     if ((x = cmnum("Bytes","",10,&rsize, xxstring)) < 0) {
12279                         if (x == -3) {
12280                             printf("?Number required\n");
12281                             x = -9;
12282                         }
12283                         return(x);
12284                     }
12285                     charflag = 0;
12286                     sizeflag = 1;
12287                     break;
12288                   case WR_STRI:
12289                     rsize = 1;
12290                     charflag = 0;
12291                     sizeflag = 0;
12292                     break;
12293                   case WR_LPAD:
12294                   case WR_RPAD:
12295                     if ((x = cmnum("Numeric ASCII character value",
12296                                    "32",10,&pad, xxstring)) < 0)
12297                       return(x);
12298                     if (cmresult.nresult == WR_LPAD)
12299                       wr_lpad = 1;
12300                     else
12301                       wr_rpad = 1;
12302                     break;
12303                   case RD_TRIM:
12304                     rd_trim = 1;
12305                     break;
12306                   case RD_UNTA:
12307                     rd_untab = 1;
12308                     break;
12309                 }
12310                 debug(F101,"FILE READ rsize 2","",rsize);
12311             } else
12312               return(-2);
12313         } while
12314           (cmresult.fcode == _CMKEY);
12315
12316         n = cmresult.nresult;           /* Channel */
12317         debug(F101,"FILE READ/WRITE channel","",n);
12318
12319         if (cx == FIL_WRI) {            /* WRITE */
12320             int len = 0;
12321             if ((x = cmtxt("Text","",&s,xxstring)) < 0)
12322               return(x);
12323             ckstrncpy(line,s,LINBUFSIZ); /* Make a safe copy */
12324             s = line;
12325             s = brstrip(s);             /* Strip braces */
12326             if (charflag) {             /* Write one char */
12327                 len = 1;                /* So length = 1 */
12328                 rsize = 1;              /* Don't supply terminator */
12329             } else if (!sizeflag) {     /* Write a string */
12330                 len = -1;               /* So length is unspecified */
12331             } else {                    /* Write a block of given size */
12332                 int i, k, xx;
12333                 if (rsize > TMPBUFSIZ) {
12334                     z_error = FX_OFL;
12335                     printf("?Buffer overflow\n");
12336                     return(-9);
12337                 }
12338                 len = rsize;            /* rsize is really length */
12339                 rsize = 1;              /* Don't supply a terminator */
12340                 xx = strlen(s);         /* Size of given string */
12341                 if (xx >= len) {        /* Bigger or equal */
12342                     s[len] = NUL;
12343                 } else if (wr_lpad) {   /* Smaller, left-padding requested */
12344                     for (i = 0; i < len - xx; i++) /* Must make a copy */
12345                       tmpbuf[i] = pad;
12346                     ckstrncpy(tmpbuf+i,s,TMPBUFSIZ-i);
12347                     tmpbuf[len] = NUL;
12348                     s = tmpbuf;         /* Redirect write source */
12349                 } else if (wr_rpad) {   /* Smaller with right-padding */
12350                     for (i = xx; i < len; i++)
12351                       s[i] = pad;
12352                     s[len] = NUL;
12353                 }
12354             }
12355             if ((rc = z_out(n,s,len,rsize)) < 0) { /* Try to write */
12356                 printf("?Channel %d WRITE error: %s\n",n,ckferror(rc));
12357                 return(-9);
12358             }
12359         } else {                        /* FIL_REA READ */
12360             confirmed = 0;
12361             vnambuf[0] = NUL;
12362             x = cmfld("Variable name","",&s,NULL);
12363             debug(F111,"FILE READ cmfld",s,x);
12364             if (x < 0) {
12365                 if (x == -3 || !*s) {
12366                     if ((x = cmcfm()) < 0)
12367                       return(x);
12368                     else
12369                       confirmed++;
12370                 } else
12371                   return(x);
12372             }
12373             ckstrncpy(vnambuf,s,VNAML);
12374             debug(F111,"FILE READ vnambuf",vnambuf,confirmed);
12375             if (vnambuf[0]) {           /* Variable name given, check it */
12376                 if (!confirmed) {
12377                     x = cmcfm();
12378                     if (x < 0)
12379                       return(x);
12380                     else
12381                       confirmed++;
12382                 }
12383                 vnp = vnambuf;
12384                 if (vnambuf[0] == CMDQ &&
12385                     (vnambuf[1] == '%' || vnambuf[1] == '&'))
12386                   vnp++;
12387                 y = 0;
12388                 if (*vnp == '%' || *vnp == '&') {
12389                     if ((y = parsevar(vnp,&x,&dummy)) < 0) {
12390                         printf("?Syntax error in variable name\n");
12391                         return(-9);
12392                     }
12393                 }
12394             }
12395             debug(F111,"FILE READ variable",vnambuf,confirmed);
12396
12397             if (!confirmed)
12398               if ((x = cmcfm()) < 0)
12399                 return(x);
12400
12401             line[0] = NUL;              /* Clear destination buffer */
12402             if (rsize >= LINBUFSIZ)     /* Don't overrun it */
12403               rsize = LINBUFSIZ - 1;
12404
12405             if (rsize == 0) {           /* Read a line */
12406                 rc = z_in(n,line,LINBUFSIZ,LINBUFSIZ-1,0);
12407             } else {
12408                 rc = z_in(n,line,LINBUFSIZ,rsize,1); /* Read a block */
12409             }
12410             if (rc < 0) {               /* Error... */
12411                 debug(F101,"FILE READ error","",rc);
12412                 debug(F101,"FILE READ errno","",errno);
12413                 if (rc == FX_EOF) {     /* EOF - fail but no error message */
12414                     return(success = 0);
12415                 } else {                /* Other error - fail and print msg */
12416                     printf("?READ error: %s\n",ckferror(rc));
12417                     return(-9);
12418                 }
12419             }
12420             if (rsize == 0) {           /* FREAD /LINE postprocessing */
12421                 if (rd_trim) {          /* Trim */
12422                     int i, k;
12423                     k = strlen(line);
12424                     if (k > 0) {
12425                         for (i = k-1; i > 0; i--) {
12426                             if (line[i] == SP || line[i] == '\t')
12427                               line[i] = NUL;
12428                             else
12429                               break;
12430                         }
12431                     }
12432                 }
12433                 if (rd_untab) {         /* Untabify */
12434                     if (untabify(line,tmpbuf,TMPBUFSIZ) > -1)
12435                       ckstrncpy(line,tmpbuf,LINBUFSIZ);
12436                 }
12437             }
12438             debug(F110,"FILE READ data",line,0);
12439             if (vnambuf[0])             /* Read OK - If variable name given */
12440               addmac(vnambuf,line);     /* Assign result to variable */
12441             else                        /* otherwise */
12442               printf("%s\n",line);      /* just print it */
12443         }
12444         return(success = 1);
12445
12446       case FIL_SEE:                     /* SEEK */
12447       case FIL_COU:                     /* COUNT */
12448         rsize = RD_CHAR;                /* Defaults to /BYTE */
12449         cmfdbi(&sw,                     /* Switches */
12450                _CMKEY,                  /* fcode */
12451                "Channel or switch",     /* hlpmsg */
12452                "",                      /* default */
12453                "",                      /* addtl string data */
12454                ((cx == FIL_SEE) ? nfskswtab : nfcoswtab),
12455                4,                       /* addtl numeric data 2: 4 = cmswi */
12456                xxstring,                /* Processing function */
12457                ((cx == FIL_SEE) ? fskswtab : fcoswtab),
12458                &nu                      /* Pointer to next FDB */
12459                );
12460         cmfdbi(&nu,                     /* Channel number */
12461                _CMNUM,                  /* fcode */
12462                "Channel",
12463                "",                      /* default */
12464                "",                      /* addtl string data */
12465                10,                      /* addtl numeric data 1: radix */
12466                0,                       /* addtl numeric data 2: 0 */
12467                xxstring,                /* Processing function */
12468                NULL,                    /* Keyword table */
12469                NULL                     /* Pointer to next FDB */
12470                );
12471         do {
12472             x = cmfdb(&sw);             /* Parse something */
12473             if (x < 0) {
12474                 if (x == -3) {
12475                     printf("?Channel number required\n");
12476                     x = -9;
12477                 }
12478                 return(x);
12479             }
12480             if (cmresult.fcode == _CMNUM) /* Channel number */
12481               break;
12482             else if (cmresult.fcode == _CMKEY) { /* Switch */
12483                 char c;
12484                 c = cmgbrk();
12485                 if ((getval =
12486                      (c == ':' || c == '=')) && !(cmgkwflgs() & CM_ARG)) {
12487                     printf("?This switch does not take an argument\n");
12488                     return(-9);
12489                 }
12490                 if (cx == FIL_SEE) {
12491                     switch (cmresult.nresult) {
12492                       case SEE_REL: relative = 1; break;
12493                       case SEE_ABS: relative = 0; break;
12494                       default: rsize = cmresult.nresult;
12495                     }
12496                 } else if (cx == FIL_COU) {
12497                     switch (cmresult.nresult) {
12498                       case COU_LIS: listing = 1; break;
12499                       case COU_NOL: listing = 0; break;
12500                       default: rsize = cmresult.nresult;
12501                     }
12502                 }
12503             }
12504         } while
12505           (cmresult.fcode == _CMKEY);
12506
12507         n = cmresult.nresult;           /* Channel */
12508         debug(F101,"FILE SEEK/COUNT channel","",n);
12509         if (cx == FIL_COU) {
12510             if ((x = cmcfm()) < 0)
12511               return(x);
12512             z_filcount = z_count(n,rsize);
12513             if (z_filcount < 0) {
12514                 rc = z_filcount;
12515                 printf("?COUNT error: %s\n",ckferror(rc));
12516                 return(-9);
12517             }
12518             if (listing < 0)
12519               listing = !xcmdsrc;
12520             if (listing)
12521               printf(" %ld %s%s\n",
12522                      z_filcount,
12523                      ((rsize == RD_CHAR) ? "byte" : "line"),
12524                      ((z_filcount == 1L) ? "" : "s")
12525                      );
12526             return(success = (z_filcount > -1) ? 1 : 0);
12527         }
12528         cmfdbi(&sw,                     /* SEEK symbolic targets (EOF) */
12529                _CMKEY,                  /* fcode */
12530                "Channel number;\n or keyword",
12531                "",
12532                "",                      /* addtl string data */
12533                nfsekwtab,               /* addtl numeric data 1: table size */
12534                0,                       /* addtl numeric data 2: 4 = cmswi */
12535                xxstring,                /* Processing function */
12536                fsekwtab,                /* Keyword table */
12537                &nu                      /* Pointer to next FDB */
12538                );
12539         cmfdbi(&nu,                     /* Channel number */
12540                _CMNUM,                  /* fcode */
12541                "",
12542                "",                      /* default */
12543                "",                      /* addtl string data */
12544                10,                      /* addtl numeric data 1: radix */
12545                0,                       /* addtl numeric data 2: 0 */
12546                xxstring,                /* Processing function */
12547                NULL,                    /* Keyword table */
12548                NULL                     /* Pointer to next FDB */
12549                );
12550         x = cmfdb(&sw);                 /* Parse something */
12551         if (x < 0) {
12552             if (x == -3) {
12553                 printf("?Channel number or EOF required\n");
12554                 x = -9;
12555             }
12556             return(x);
12557         }
12558         if (cmresult.fcode == _CMNUM) {
12559             y = cmresult.nresult;
12560             debug(F110,"FILE SEEK atmbuf",atmbuf,0);
12561             if (relative < 0) {
12562                 if (cx == FIL_SEE && (atmbuf[0] == '+' || atmbuf[0] == '-'))
12563                   relative = 1;
12564                 else
12565                   relative = 0;
12566             }
12567         } else if (cmresult.fcode == _CMKEY) {
12568             eofflg = cmresult.nresult;
12569             relative = 0;
12570             y = 0 - eofflg;
12571         }
12572         if ((x = cmcfm()) < 0)
12573           return(x);
12574         z = y;                          /* Convert to long */
12575         y = 1;                          /* Recycle this */
12576         z_flush(n);
12577         debug(F101,"FILE SEEK relative","",relative);
12578         debug(F101,"FILE SEEK rsize","",rsize);
12579
12580         if (rsize == RD_CHAR) {         /* Seek to byte position */
12581             if (relative > 0) {
12582                 long pos;
12583                 pos = z_getpos(n);
12584                 if (pos < 0L) {
12585                     rc = pos;
12586                     printf("?Relative SEEK failed: %s\n",ckferror(rc));
12587                     return(-9);
12588                 }
12589                 z += pos;
12590             } else {
12591                 if (z < 0 && !eofflg) { /* Negative arg but not relative */
12592                     y = 0;              /* Remember this was bad */
12593                     z = 0;              /* but substitute 0 */
12594                 }
12595             }
12596             debug(F101,"FILE SEEK /CHAR z","",z);
12597             if (z < 0 && !eofflg) {
12598                 z_error = FX_RNG;
12599                 return(success = 0);
12600             }
12601             if ((rc = z_seek(n,z)) < 0) {
12602                 if (rc == FX_EOF) return(success = 0);
12603                 printf("?SEEK /BYTE failed - Channel %d: %s\n",n,ckferror(rc));
12604                 return(-9);
12605             }
12606         } else {                        /* Seek to line */
12607             if (relative > 0) {
12608                 long pos;
12609                 pos = z_getline(n);
12610                 debug(F101,"FILE SEEK /LINE pos","",pos);
12611                 if (pos < 0L) {
12612                     rc = pos;
12613                     printf("?Relative SEEK failed: %s\n",ckferror(rc));
12614                     return(-9);
12615                 }
12616                 z += pos;
12617             }
12618             debug(F101,"FILE SEEK /LINE z","",z);
12619             debug(F101,"FILE SEEK /LINE eofflg","",eofflg);
12620             if (z < 0 && !eofflg) {
12621                 z_error = FX_RNG;
12622                 return(success = 0);
12623             }
12624             if ((rc = z_line(n,z)) < 0) {
12625                 if (rc == FX_EOF) return(success = 0);
12626                 printf("?SEEK /LINE failed - Channel %d: %s\n",n,ckferror(rc));
12627                 return(-9);
12628             }
12629         }
12630         return(success = y);
12631
12632       case FIL_LIS: {                   /* LIST open files */
12633 #ifdef CK_TTGWSIZ
12634           extern int cmd_rows, cmd_cols;
12635 #endif /* CK_TTGWSIZ */
12636           extern int xaskmore;
12637           int i, x, n = 0, paging = 0;
12638           char * s;
12639
12640           if ((x = cmcfm()) < 0)
12641             return(x);
12642
12643 #ifdef CK_TTGWSIZ
12644           if (cmd_rows > 0 && cmd_cols > 0)
12645 #endif /* CK_TTGWSIZ */
12646             paging = xaskmore;
12647
12648           printf("System open file limit: %4d\n", z_openmax);
12649           printf("Maximum for FILE OPEN:  %4d\n", z_maxchan);
12650           printf("Files currently open:   %4d\n\n", z_nopen);
12651           n = 4;
12652           for (i = 0; i < z_maxchan; i++) {
12653               s = z_getname(i);         /* Got one? */
12654               if (s) {                  /* Yes */
12655                   char m[8];
12656                   m[0] = NUL;
12657                   printf("%2d. %s",i,s); /* Print name */
12658                   n++;                   /* Count it */
12659                   x = z_getmode(i);      /* Get modes & print them */
12660                   if (x > -1) {
12661                       if (x & FM_REA) ckstrncat(m,"R",8);
12662                       if (x & FM_WRI) ckstrncat(m,"W",8);
12663                       if (x & FM_APP) ckstrncat(m,"A",8);
12664                       if (x & FM_BIN) ckstrncat(m,"B",8);
12665                       if (m[0])
12666                         printf(" (%s)",m);
12667                       if (x & FM_EOF)
12668                         printf(" [EOF]");
12669                       else
12670                         printf(" %ld",z_getpos(i)); /* And file position too */
12671                   }
12672                   printf("\n");
12673 #ifdef CK_TTGWSIZ
12674                   if (paging > 0) {     /* Pause at end of screen */
12675                       if (n > cmd_rows - 3) {
12676                           if (!askmore())
12677                             break;
12678                           else
12679                             n = 0;
12680                       }
12681                   }
12682 #endif /* CK_TTGWSIZ */
12683               }
12684           }
12685           return(success = 1);
12686       }
12687
12688       case FIL_FLU:                     /* FLUSH */
12689         if ((x = cmnum("Channel number","",10,&n, xxstring)) < 0) {
12690             if (x == -3) {
12691                 printf("?Channel number required\n");
12692                 x = -9;
12693             }
12694             return(x);
12695         }
12696         if ((x = cmcfm()) < 0)
12697           return(x);
12698         if ((rc = z_flush(n)) < 0) {
12699             printf("?FLUSH failed - Channel %d: %s\n",n,ckferror(rc));
12700             return(-9);
12701         }
12702         return(success = 1);
12703
12704       case FIL_STA:                     /* STATUS */
12705         if ((x = cmnum("Channel number","",10,&n, xxstring)) < 0) {
12706             if (x == -3) {
12707                 printf("?Channel number required\n");
12708                 x = -9;
12709             }
12710             return(x);
12711         }
12712         if ((x = cmcfm()) < 0)
12713           return(x);
12714         p = blanks + 3;                 /* Tricky formatting... */
12715         if (n < 1000) p--;
12716         if (n < 100) p--;
12717         if (n < 10) p--;
12718         if ((rc = z_getmode(n)) < 0) {
12719             printf("Channel %d:%s%s\n",n,p,ckferror(rc));
12720             return(success = 0);
12721         } else if (!rc) {
12722             printf("Channel %d:%sNot open\n",n,p);
12723             return(success = 0);
12724         } else {
12725             long xx;
12726             s = z_getname(n);
12727             if (!s) s = "(name unknown)";
12728             printf("Channel %d:%sOpen\n",n,p);
12729             printf(" File:        %s\n Modes:      ",s);
12730             if (rc & FM_REA) printf(" /READ");
12731             if (rc & FM_WRI) printf(" /WRITE");
12732             if (rc & FM_APP) printf(" /APPEND");
12733             if (rc & FM_BIN) printf(" /BINARY");
12734             if (rc & FM_CMD) printf(" /COMMAND");
12735             if (rc & FM_EOF) printf(" [EOF]");
12736             printf("\n Size:        %ld\n",z_count(n,RD_CHAR));
12737             printf(" At byte:     %ld\n",z_getpos(n));
12738             xx = z_getline(n);
12739             if (xx > -1)
12740               printf(" At line:     %ld\n",xx);
12741             return(success = 1);
12742         }
12743       default:
12744         return(-2);
12745     }
12746 }
12747 #endif /* CKCHANNELIO */
12748
12749 #ifndef NOSETKEY
12750 /* Save Key maps and in OS/2 Mouse maps */
12751 int
12752 savkeys(name,disp) char * name; int disp; {
12753     char *tp;
12754     static struct filinfo xx;
12755     int savfil, i, j, k;
12756     char buf[1024];
12757
12758     zclose(ZMFILE);
12759
12760     if (disp) {
12761         xx.bs = 0; xx.cs = 0; xx.rl = 0; xx.org = 0; xx.cc = 0;
12762         xx.typ = 0; xx.dsp = XYFZ_A; xx.os_specific = "";
12763         xx.lblopts = 0;
12764         savfil = zopeno(ZMFILE,name,NULL,&xx);
12765     } else savfil = zopeno(ZMFILE,name,NULL,NULL);
12766
12767     if (savfil) {
12768 #ifdef OS2
12769         ztime(&tp);
12770         zsout(ZMFILE, "; Kermit 95 SAVE KEYMAP file: ");
12771         zsoutl(ZMFILE,tp);
12772         if (mskkeys) {
12773             zsoutl(ZMFILE,
12774          "if eq \"\\v(program)\" \"C-Kermit\" set mskermit keycodes on");
12775         } else {
12776             zsoutl(ZMFILE,
12777          "if NOT eq \"\\v(program)\" \"C-Kermit\" stop 1 C-Kermit required.");
12778             zsoutl(ZMFILE,"set mskermit keycodes off");
12779         }
12780         zsoutl(ZMFILE,"");
12781 #else /* OS2 */
12782         ztime(&tp);
12783         zsout(ZMFILE, "; C-Kermit SAVE KEYMAP file: ");
12784         zsoutl(ZMFILE,tp);
12785 #endif /* OS2 */
12786
12787         zsoutl(ZMFILE,"; Clear previous keyboard mappings ");
12788         zsoutl(ZMFILE,"set key clear");
12789 #ifdef OS2
12790         for (k = 0; k < nttkey; k++) {
12791             if (!ttkeytab[k].flgs) {
12792                 ckmakmsg(buf,1024,
12793                          "set terminal key ",
12794                          ttkeytab[k].kwd,
12795                          " clear",
12796                          NULL
12797                          );
12798                 zsoutl(ZMFILE,buf);
12799             }
12800         }
12801 #endif /* OS2 */
12802         zsoutl(ZMFILE,"");
12803
12804         for (i = 0; i < KMSIZE; i++) {
12805             if (macrotab[i]) {
12806                 int len = strlen((char *)macrotab[i]);
12807 #ifdef OS2
12808                 ckmakmsg(buf,
12809                          1024,
12810                          "set key \\",
12811                          ckitoa(mskkeys ? cktomsk(i) : i),
12812                          " ",
12813                          NULL
12814                          );
12815 #else /* OS2 */
12816                 ckmakmsg(buf,
12817                          1024,
12818                          "set key \\",
12819                          ckitoa(i),
12820                          NULL,NULL
12821                          );
12822 #endif /* OS2 */
12823                 zsout(ZMFILE,buf);
12824
12825                 for (j = 0; j < len; j++) {
12826                     char ch = macrotab[i][j];
12827                     if (ch <= SP || ch >= DEL ||
12828                          ch == '-' || ch == ',' ||
12829                          ch == '{' || ch == '}' ||
12830                          ch == ';' || ch == '?' ||
12831                          ch == '.' || ch == '\'' ||
12832                          ch == '\\' || ch == '/' ||
12833                          ch == '#') {
12834                         ckmakmsg(buf,1024,"\\{",ckitoa((int)ch),"}",NULL);
12835                         zsout(ZMFILE,buf);
12836                     } else {
12837                         ckmakmsg(buf,1024,ckctoa((char)ch),NULL,NULL,NULL);
12838                         zsout(ZMFILE,buf);
12839                     }
12840                 }
12841 #ifdef OS2
12842                 ckmakmsg(buf,1024,"\t; ",keyname(i),NULL,NULL);
12843                 zsoutl(ZMFILE,buf);
12844 #else
12845                 zsoutl(ZMFILE,"");
12846 #endif /* OS2 */
12847             } else if ( keymap[i] != i ) {
12848 #ifndef NOKVERBS
12849                 if (IS_KVERB(keymap[i])) {
12850                     for (j = 0; j < nkverbs; j++)
12851                       if (kverbs[j].kwval == (keymap[i] & ~F_KVERB))
12852                         break;
12853                     if (j != nkverbs) {
12854 #ifdef OS2
12855 #ifdef COMMENT
12856                         sprintf(buf, "set key \\%d \\K%s\t; %s",
12857                                 mskkeys ? cktomsk(i) : i,
12858                                 kverbs[j].kwd, keyname(i)
12859                                 );
12860 #else
12861                         ckmakxmsg(buf,  /* 12 string args */
12862                                   1024,
12863                                   "set key \\",
12864                                   ckitoa(mskkeys ? cktomsk(i) : i),
12865                                   " \\K",
12866                                   kverbs[j].kwd,
12867                                   "\t; ",
12868                                   keyname(i),
12869                                   NULL, NULL, NULL, NULL, NULL, NULL);
12870 #endif /* COMMENT */
12871                         zsoutl(ZMFILE,buf);
12872 #else
12873 #ifdef COMMENT
12874                         sprintf(buf, "set key \\%d \\K%s", i, kverbs[j].kwd);
12875 #else
12876                         ckmakmsg(buf,1024,
12877                                  "set key \\",
12878                                  ckitoa(i),
12879                                  " \\K",
12880                                  kverbs[j].kwd
12881                                  );
12882 #endif /* COMMENT */
12883                         zsoutl(ZMFILE,buf);
12884 #endif
12885                     }
12886                 } else
12887 #endif /* NOKVERBS */
12888                   {
12889 #ifdef OS2
12890 #ifdef COMMENT
12891                       sprintf(buf, "set key \\%d \\{%d}\t; %s",
12892                               mskkeys ? cktomsk(i) : i,
12893                               keymap[i],
12894                               keyname(i)
12895                               );
12896 #else
12897                       ckmakxmsg(buf,    /* 8 string args */
12898                                 1024,
12899                                 "set key \\",
12900                                 ckitoa(mskkeys ? cktomsk(i) : i),
12901                                 " \\{",
12902                                 ckitoa(keymap[i]),
12903                                 "}\t; ",
12904                                 keyname(i),
12905                                 NULL,NULL,NULL,NULL,NULL,NULL);
12906 #endif /* COMMENT */
12907                       zsoutl(ZMFILE,buf);
12908 #else
12909 #ifdef COMMENT
12910                       sprintf(buf, "set key \\%d \\{%d}", i, keymap[i]);
12911 #else
12912                       ckmakxmsg(buf,1024,
12913                                "set key \\",
12914                                ckitoa(i),
12915                                " \\{",
12916                                ckitoa(keymap[i]),
12917                                "}",
12918                                NULL,NULL,NULL,NULL,NULL,NULL,NULL);
12919 #endif /* COMMENT */
12920                       zsoutl(ZMFILE,buf);
12921 #endif /* OS2 */
12922                   }
12923             }
12924         }
12925 #ifdef OS2
12926         /* OS/2 also has the SET TERMINAL KEY <termtype> defines */
12927         for (k = 0; k < nttkey; k++) {
12928             extern struct keynode * ttkeymap[];
12929             struct keynode * pnode = NULL;
12930
12931             if (ttkeytab[k].flgs)       /* Don't process CM_INV or CM_ABR */
12932               continue;
12933
12934             zsoutl(ZMFILE,"");
12935             ckmakmsg(buf,1024,"; SET TERMINAL KEY ",ttkeytab[k].kwd,NULL,NULL);
12936             zsoutl(ZMFILE,buf);
12937
12938             for (pnode = ttkeymap[ttkeytab[k].kwval];
12939                  pnode;
12940                  pnode = pnode->next
12941                  ) {
12942                 switch (pnode->def.type) {
12943                   case key:
12944 #ifdef COMMENT
12945                     sprintf(buf, "set terminal key %s \\%d \\{%d}\t; %s",
12946                             ttkeytab[k].kwd,
12947                             mskkeys ? cktomsk(pnode->key) : pnode->key,
12948                             pnode->def.key.scancode,
12949                             keyname(pnode->key)
12950                             );
12951 #else
12952                     ckmakxmsg(buf,
12953                               1024,
12954                               "set terminal key ",
12955                               ttkeytab[k].kwd,
12956                               " \\",
12957                               ckitoa(mskkeys ?
12958                                      cktomsk(pnode->key) :
12959                                      pnode->key),
12960                               " \\{",
12961                               ckitoa(pnode->def.key.scancode),
12962                               "}\t; ",
12963                               keyname(pnode->key),
12964                               NULL,NULL,NULL,NULL
12965                               );
12966 #endif /* COMMENT */
12967                     zsoutl(ZMFILE,buf);
12968                     break;
12969                   case kverb:
12970                     for (j = 0; j < nkverbs; j++)
12971                       if (kverbs[j].kwval == (pnode->def.kverb.id & ~F_KVERB))
12972                         break;
12973                     if (j != nkverbs) {
12974 #ifdef COMMENT
12975                         sprintf(buf, "set terminal key %s \\%d \\K%s\t; %s",
12976                                 ttkeytab[k].kwd,
12977                                 mskkeys ? cktomsk(pnode->key) : pnode->key,
12978                                 kverbs[j].kwd, keyname(pnode->key)
12979                                 );
12980 #else
12981                         ckmakxmsg(buf,
12982                                   1024,
12983                                   "set terminal key ",
12984                                   ttkeytab[k].kwd,
12985                                   " \\",
12986                                   ckitoa(mskkeys ?
12987                                          cktomsk(pnode->key) :
12988                                          pnode->key),
12989                                   " \\K",
12990                                   kverbs[j].kwd,
12991                                   "\t; ",
12992                                   keyname(pnode->key),
12993                                   NULL,NULL,NULL,NULL
12994                                   );
12995 #endif /* COMMENT */
12996                         zsoutl(ZMFILE,buf);
12997                     }
12998                     break;
12999                   case macro: {
13000                       int len = strlen((char *)pnode->def.macro.string);
13001 #ifdef COMMENT
13002                       sprintf(buf,"set terminal key %s \\%d ",
13003                               ttkeytab[k].kwd,
13004                               mskkeys ? cktomsk(pnode->key) : pnode->key);
13005 #else
13006                       ckmakxmsg(buf,
13007                                1024,
13008                                "set terminal key ",
13009                                ttkeytab[k].kwd,
13010                                " \\",
13011                                ckitoa(mskkeys ?
13012                                       cktomsk(pnode->key) :
13013                                       pnode->key),
13014                                " ",
13015                                NULL,NULL,NULL,NULL,NULL,NULL,NULL
13016                               );
13017 #endif /* COMMENT */
13018                       zsout(ZMFILE,buf);
13019
13020                       for (j = 0; j < len; j++) {
13021                           char ch = pnode->def.macro.string[j];
13022                           if (ch <= SP || ch >= DEL ||
13023                                ch == '-' || ch == ',' ||
13024                                ch == '{' || ch == '}' ||
13025                                ch == ';' || ch == '?' ||
13026                                ch == '.' || ch == '\'' ||
13027                                ch == '\\' || ch == '/' ||
13028                                ch == '#') {
13029                               ckmakmsg(buf,1024,
13030                                        "\\{",ckitoa((int)ch),"}",NULL);
13031                               zsout(ZMFILE,buf);
13032                           } else {
13033                               ckmakmsg(buf,1024,
13034                                        ckctoa((char)ch),NULL,NULL,NULL);
13035                               zsout(ZMFILE,buf);
13036                           }
13037                       }
13038                       ckmakmsg(buf,1024,"\t; ",keyname(pnode->key),NULL,NULL);
13039                       zsoutl(ZMFILE,buf);
13040                       break;
13041                   }
13042                   case literal: {
13043                       int len = strlen((char *)pnode->def.literal.string);
13044 #ifdef COMMENT
13045                       sprintf(buf,"set terminal key %s /literal \\%d ",
13046                               ttkeytab[k].kwd,
13047                               mskkeys ? cktomsk(pnode->key) : pnode->key);
13048 #else
13049                       ckmakxmsg(buf,
13050                                1024,
13051                                "set terminal key ",
13052                                ttkeytab[k].kwd,
13053                                " /literal \\",
13054                                ckitoa(mskkeys ?
13055                                       cktomsk(pnode->key) :
13056                                       pnode->key),
13057                                " ",
13058                                NULL,NULL,NULL,NULL,NULL,NULL,NULL);
13059 #endif /* COMMENT */
13060                       zsout(ZMFILE,buf);
13061
13062                       for (j = 0; j < len; j++) {
13063                           char ch = pnode->def.literal.string[j];
13064                           if (ch <= SP || ch >= DEL ||
13065                                ch == '-' || ch == ',' ||
13066                                ch == '{' || ch == '}' ||
13067                                ch == ';' || ch == '?' ||
13068                                ch == '.' || ch == '\'' ||
13069                                ch == '\\' || ch == '/' ||
13070                                ch == '#') {
13071                               ckmakmsg(buf,1024,
13072                                        "\\{",ckitoa((int)ch),"}",NULL);
13073                               zsout(ZMFILE,buf);
13074                           } else {
13075                               ckmakmsg(buf,1024,
13076                                        ckctoa((char)ch),NULL,NULL,NULL);
13077                               zsout(ZMFILE,buf);
13078                           }
13079                       }
13080                       ckmakmsg(buf,1024,"\t; ",keyname(pnode->key),NULL,NULL);
13081                       zsoutl(ZMFILE,buf);
13082                       break;
13083                   }
13084                   case esc:
13085 #ifdef COMMENT
13086                     sprintf(buf,
13087                        "set terminal key %s /literal \\%d \\{%d}\\{%d}\t; %s",
13088                             ttkeytab[k].kwd,
13089                             mskkeys ? cktomsk(pnode->key) : pnode->key,
13090                             ISDG200(ttkeytab[k].kwval) ? 30 : 27,
13091                             pnode->def.esc.key & ~F_ESC,
13092                             keyname(pnode->key)
13093                             );
13094 #else
13095                     ckmakxmsg(buf,
13096                               1024,
13097                               "set terminal key ",
13098                               ttkeytab[k].kwd,
13099                               " /literal \\",
13100                               ckitoa(mskkeys ?
13101                                      cktomsk(pnode->key) :
13102                                      pnode->key),
13103                               " \\{",
13104                               ckitoa(ISDG200(ttkeytab[k].kwval) ? 30 : 27),
13105                               "}\\{",
13106                               ckitoa(pnode->def.esc.key & ~F_ESC),
13107                               "}\t; ",
13108                               keyname(pnode->key),
13109                               NULL,NULL
13110                               );
13111 #endif /* COMMENT */
13112                     zsoutl(ZMFILE,buf);
13113                     break;
13114                   case csi:
13115 #ifdef COMMENT
13116                     sprintf(buf,
13117                        "set terminal key %s /literal \\%d \\{27}[\\{%d}\t; %s",
13118                             ttkeytab[k].kwd,
13119                             mskkeys ? cktomsk(pnode->key) : pnode->key,
13120                             pnode->def.csi.key & ~F_CSI,
13121                             keyname(pnode->key)
13122                             );
13123 #else
13124                     ckmakxmsg(buf,
13125                               1024,
13126                               "set terminal key ",
13127                               ttkeytab[k].kwd,
13128                               " /literal \\",
13129                               ckitoa(mskkeys ?
13130                                      cktomsk(pnode->key) :
13131                                      pnode->key),
13132                               " \\{27}[\\{",
13133                               ckitoa(pnode->def.csi.key & ~F_CSI),
13134                               "}\t; ",
13135                               keyname(pnode->key),
13136                               NULL,NULL,NULL,NULL
13137                               );
13138 #endif /* COMMENT */
13139                     zsoutl(ZMFILE,buf);
13140                     break;
13141                   default:
13142                     continue;
13143                 }
13144             }
13145         }
13146 #endif /* OS2 */
13147
13148         zsoutl(ZMFILE,"");
13149         zsoutl(ZMFILE,"; End");
13150         zclose(ZMFILE);
13151         return(success = 1);
13152     } else {
13153         return(success = 0);
13154     }
13155 }
13156 #endif /* NOSETKEY */
13157
13158 #define SV_SCRL 0
13159 #define SV_HIST 1
13160
13161 #ifdef OS2
13162 #ifndef NOLOCAL
13163 static struct keytab trmtrmopt[] = {
13164     { "scrollback", SV_SCRL, 0 }
13165 };
13166 #endif /* NOLOCAL */
13167 #endif /* OS2 */
13168
13169 static struct keytab cmdtrmopt[] = {
13170 #ifdef CK_RECALL
13171     { "history",    SV_HIST, 0 },
13172 #endif /* CK_RECALL */
13173 #ifdef OS2
13174 #ifndef NOLOCAL
13175     { "scrollback", SV_SCRL, 0 },
13176 #endif /* NOLOCAL */
13177 #endif /* OS2 */
13178     { "", 0, 0 }
13179 };
13180 static int ncmdtrmopt = (sizeof (cmdtrmopt) / sizeof (struct keytab)) - 1;
13181
13182 #ifdef OS2
13183 #ifndef NOLOCAL
13184 _PROTOTYP(int savscrbk, (int, char *, int));
13185 #endif /* NOLOCAL */
13186 #endif /* OS2 */
13187
13188 #ifdef CK_RECALL
13189 _PROTOTYP(int savhistory, (char *, int));
13190 #endif /* CK_RECALL */
13191
13192 int
13193 dosave(xx) int xx; {
13194     int x, y = 0, disp;
13195     char * s = NULL;
13196     extern struct keytab disptb[];
13197 #ifdef ZFNQFP
13198     struct zfnfp * fnp;
13199 #endif /* ZFNQFP */
13200
13201 #ifndef NOSETKEY
13202     if (xx == XSKEY) {                  /* SAVE KEYMAP.. */
13203         z = cmofi("Name of Kermit command file","keymap.ksc",&s,xxstring);
13204     } else {
13205 #endif /* NOSETKEY */
13206         switch (xx) {
13207           case XSCMD:                   /* SAVE COMMAND.. */
13208             if ((y = cmkey(cmdtrmopt, ncmdtrmopt, "What to save",
13209 #ifdef OS2
13210                            "scrollback",
13211 #else
13212                            "history",
13213 #endif /* OS2 */
13214                            xxstring)) < 0)
13215               return(y);
13216             break;
13217 #ifdef OS2
13218 #ifndef NOLOCAL
13219           case XSTERM:                  /* SAVE TERMINAL.. */
13220             if ((y = cmkey(trmtrmopt,1,
13221                            "What to save","scrollback",xxstring)) < 0)
13222               return(y);
13223             break;
13224 #endif /* NOLOCAL */
13225 #endif /* OS2 */
13226         }
13227         z = cmofi("Filename",
13228                   ((y == SV_SCRL) ? "scrollbk.txt" : "history.txt"),
13229                   &s,
13230                   xxstring
13231                   );
13232 #ifndef NOSETKEY
13233     }
13234 #endif /* NOSETKEY */
13235     if (z < 0)                          /* Check output-file parse results */
13236       return(z);
13237     if (z == 2) {
13238         printf("?Sorry, %s is a directory name\n",s);
13239         return(-9);
13240     }
13241 #ifdef ZFNQFP
13242     if ((fnp = zfnqfp(s,TMPBUFSIZ - 1,tmpbuf))) {/* Convert to full pathname */
13243         if (fnp->fpath)
13244           if ((int) strlen(fnp->fpath) > 0)
13245             s = fnp->fpath;
13246     }
13247 #endif /* ZFNQFP */
13248
13249     ckstrncpy(line,s,LINBUFSIZ);        /* Make safe copy of pathname */
13250     s = line;
13251 #ifdef MAC
13252     z = 0;
13253 #else
13254     /* Get NEW/APPEND disposition */
13255     if ((z = cmkey(disptb,2,"Disposition","new",xxstring)) < 0)
13256       return(z);
13257 #endif /* MAC */
13258     disp = z;
13259     if ((x = cmcfm()) < 0)              /* Get confirmation */
13260       return(x);
13261
13262     switch (xx) {                       /* Do action.. */
13263 #ifndef NOSETKEY
13264       case XSKEY:                       /* SAVE KEYMAP */
13265         return (savkeys(s,disp));
13266 #endif /* NOSETKEY */
13267
13268       case XSCMD:                       /* SAVE COMMAND.. */
13269 #ifdef OS2
13270 #ifndef NOLOCAL
13271         if (y == SV_SCRL)               /* .. SCROLLBACK */
13272           return(success = savscrbk(VCMD,s,disp));
13273 #endif /* NOLOCAL */
13274 #endif /* OS2 */
13275 #ifndef NORECALL
13276         if (y == SV_HIST)               /* .. HISTORY */
13277           return(success = savhistory(s,disp));
13278         break;
13279 #endif /* NORECALL */
13280
13281 #ifdef OS2
13282 #ifndef NOLOCAL
13283       case XSTERM:                      /* SAVE TERMINAL SCROLLBACK */
13284         return(success = savscrbk(VTERM,s,disp));
13285 #endif /* NOLOCAL */
13286 #endif /* OS2 */
13287     }
13288     success = 0;
13289     return(-2);
13290 }
13291
13292 /*
13293   R E A D T E X T
13294
13295   Read text with a custom prompt into given buffer using command parser but
13296   with no echoing or entry into recall buffer.
13297 */
13298 int
13299 readtext(prmpt, buffer, bufsiz) char * prmpt; char * buffer; int bufsiz; {
13300 #ifdef CK_RECALL
13301     extern int on_recall;               /* Around Password prompting */
13302 #endif /* CK_RECALL */
13303     int rc;
13304 #ifndef NOLOCAL
13305 #ifdef OS2
13306     extern int vmode;
13307     extern int startflags;
13308     int vmode_sav = vmode;
13309
13310     if (!prmpt) prmpt = "";
13311
13312     if (win95_popup && !(startflags & 96)
13313 #ifdef IKSD
13314          && !inserver
13315 #endif /* IKSD */
13316          )
13317       return(popup_readtext(vmode,NULL,prmpt,buffer,bufsiz,0));
13318
13319     if (vmode == VTERM) {
13320         vmode = VCMD;
13321         VscrnIsDirty(VTERM);
13322         VscrnIsDirty(VCMD);
13323     }
13324 #endif /* OS2 */
13325 #endif /* NOLOCAL */
13326
13327 #ifdef CK_RECALL
13328     on_recall = 0;
13329 #endif /* CK_RECALL */
13330     cmsavp(psave,PROMPTL);              /* Save old prompt */
13331     cmsetp(prmpt);                      /* Make new prompt */
13332     concb((char)escape);                /* Put console in cbreak mode */
13333     cmini(1);                           /* and echo mode */
13334     if (pflag) prompt(xxstring);        /* Issue prompt if at top level */
13335     cmres();                            /* Reset the parser */
13336     for (rc = -1; rc < 0; ) {           /* Prompt till they answer */
13337         rc = cmtxt("","",&s,NULL);      /* Get a literal line of text */
13338         cmres();                        /* Reset the parser again */
13339     }
13340     ckstrncpy(buffer,s,bufsiz);
13341     cmsetp(psave);                      /* Restore original prompt */
13342
13343 #ifndef NOLOCAL
13344 #ifdef OS2
13345     if (vmode != vmode_sav) {
13346         vmode = VTERM;
13347         VscrnIsDirty(VCMD);
13348         VscrnIsDirty(VTERM);
13349     }
13350 #endif /* OS2 */
13351 #endif /* NOLOCAL */
13352     return(0);
13353 }
13354 #endif /* NOICP */
13355
13356 /* A general function to allow a Password or other information  */
13357 /* to be read from the command prompt without it going into     */
13358 /* the recall buffer or being echo'd.                           */
13359
13360 int
13361 readpass(prmpt, buffer, bufsiz) char * prmpt; char * buffer; int bufsiz; {
13362     int x;
13363 #ifdef NOICP
13364     if (!prmpt) prmpt = "";
13365     printf("%s", prmpt);
13366 #ifdef COMMENT
13367     /* Some linkers won't allow this because it's unsafe */
13368     gets(buffer);
13369 #else  /* COMMENT */
13370     {
13371         int c, i; char * p;
13372         p = buffer;
13373         for (i = 0; i < bufsiz-1; i++) {
13374             if ((c = getchar()) == EOF)
13375               break;
13376             if (c < SP)
13377               break;
13378             buffer[i] = c;
13379         }
13380         buffer[i] = NUL;
13381     }
13382 #endif /* COMMENT */
13383     return(1);
13384 #else  /* NOICP */
13385 #ifdef CK_RECALL
13386     extern int on_recall;               /* around Password prompting */
13387 #endif /* CK_RECALL */
13388     int rc;
13389 #ifndef NOLOCAL
13390 #ifdef OS2
13391     extern int vmode;
13392     extern int startflags;
13393     int vmode_sav = vmode;
13394 #endif /* OS2 */
13395 #endif /* NOLOCAL */
13396 #ifdef CKSYSLOG
13397     int savlog;
13398 #endif /* CKSYSLOG */
13399     if (!prmpt) prmpt = "";
13400 #ifndef NOLOCAL
13401     debok = 0;                          /* Don't log */
13402 #ifdef OS2
13403     if (win95_popup && !(startflags & 96)
13404 #ifdef IKSD
13405          && !inserver
13406 #endif /* IKSD */
13407          ) {
13408         x = popup_readpass(vmode,NULL,prmpt,buffer,bufsiz,0);
13409         debok = 1;
13410         return(x);
13411     }
13412 #endif /* OS2 */
13413 #endif /* NOLOCAL */
13414
13415 #ifdef CKSYSLOG
13416     savlog = ckxsyslog;                 /* Save and turn off syslogging */
13417     ckxsyslog = 0;
13418 #endif /* CKSYSLOG */
13419 #ifndef NOLOCAL
13420 #ifdef OS2
13421     if (vmode == VTERM) {
13422         vmode = VCMD;
13423         VscrnIsDirty(VTERM);
13424         VscrnIsDirty(VCMD);
13425     }
13426 #endif /* OS2 */
13427 #endif /* NOLOCAL */
13428 #ifdef CK_RECALL
13429     on_recall = 0;
13430 #endif /* CK_RECALL */
13431     cmsavp(psave,PROMPTL);              /* Save old prompt */
13432     cmsetp(prmpt);                      /* Make new prompt */
13433     concb((char)escape);                /* Put console in cbreak mode */
13434     cmini(0);                           /* and no-echo mode */
13435     if (pflag) prompt(xxstring);        /* Issue prompt if at top level */
13436     cmres();                            /* Reset the parser */
13437     for (rc = -1; rc < 0; ) {           /* Prompt till they answer */
13438         rc = cmtxt("","",&s,NULL);      /* Get a literal line of text */
13439         cmres();                        /* Reset the parser again */
13440     }
13441     ckstrncpy(buffer,s,bufsiz);
13442     printf("\r\n");                     /* Echo a CRLF */
13443     cmsetp(psave);                      /* Restore original prompt */
13444     cmini(1);                           /* Restore echo mode */
13445 #ifndef NOLOCAL
13446 #ifdef OS2
13447     if (vmode != vmode_sav) {
13448         vmode = VTERM;
13449         VscrnIsDirty(VCMD);
13450         VscrnIsDirty(VTERM);
13451     }
13452 #endif /* OS2 */
13453 #endif /* NOLOCAL */
13454 #ifdef CKSYSLOG
13455     ckxsyslog = savlog;                 /* Restore syslogging */
13456 #endif /* CKSYSLOG */
13457     debok = 1;
13458     return(0);
13459 #endif /* NOICP */
13460 }
13461
13462 #ifndef NOICP
13463 struct keytab authtab[] = {             /* Available authentication types */
13464 #ifdef CK_KERBEROS
13465     { "k4",        AUTH_KRB4, CM_INV },
13466     { "k5",        AUTH_KRB5, CM_INV },
13467     { "kerberos4", AUTH_KRB4, 0      },
13468     { "kerberos5", AUTH_KRB5, 0      },
13469     { "krb4",      AUTH_KRB4, CM_INV },
13470     { "krb5",      AUTH_KRB5, CM_INV },
13471 #endif /* CK_KERBEROS */
13472 #ifdef NT
13473     { "ntlm",      AUTH_NTLM, 0 },
13474 #endif /* NT */
13475 #ifdef CK_SRP
13476     { "srp",       AUTH_SRP,  0 },
13477 #endif /* CK_SRP */
13478 #ifdef CK_SSL
13479     { "ssl",       AUTH_SSL,  0 },
13480 #endif /* CK_SSL */
13481     { "",          0,         0 }
13482 };
13483 int authtabn = sizeof(authtab)/sizeof(struct keytab)-1;
13484
13485 #ifdef CK_KERBEROS
13486 struct keytab kerbtab[] = {             /* Kerberos authentication types */
13487     { "k4",        AUTH_KRB4, CM_INV },
13488     { "k5",        AUTH_KRB5, CM_INV },
13489     { "kerberos4", AUTH_KRB4, 0      },
13490     { "kerberos5", AUTH_KRB5, 0      },
13491     { "krb4",      AUTH_KRB4, CM_INV },
13492     { "krb5",      AUTH_KRB5, CM_INV }
13493 };
13494 int kerbtabn = sizeof(kerbtab)/sizeof(struct keytab);
13495
13496 static struct keytab krb_s_tbl[] = {    /* AUTHENTICATE command switches: */
13497     { "/cache",   KRB_S_CA, CM_ARG }
13498 };
13499 static int krb_s_n = sizeof(krb_s_tbl)/sizeof(struct keytab);
13500
13501 static struct keytab krb_v_tbl[] = {    /* KERBEROS version values: */
13502     { "4",    4, 0 },
13503     { "5",    5, 0 },                   /* (add others as needed...) */
13504     { "auto", 0, 0 }                    /* Note: 0 = auto */
13505 };
13506 static int krb_v_n = sizeof(krb_v_tbl)/sizeof(struct keytab);
13507
13508 static struct keytab krb_a_tbl[] = {    /* KERBEROS actions: */
13509     { "destroy",           KRB_A_DE, 0 },
13510     { "initialize",        KRB_A_IN, 0 },
13511     { "list-credentials",  KRB_A_LC, 0 }
13512 };
13513 static int krb_a_n = sizeof(krb_a_tbl)/sizeof(struct keytab);
13514
13515 static struct keytab krb4_i_tbl[] = {   /* KERBEROS 4 INITIALIZE switches: */
13516     { "/brief",            KRB_I_BR, 0 },      /* /BRIEF       */
13517     { "/instance",         KRB_I_IN, CM_ARG }, /* /INSTANCE:   */
13518     { "/lifetime",         KRB_I_LF, CM_ARG }, /* /LIFETIME:   */
13519     { "/not-preauth",      KRB_I_NPA, 0 },     /* /NOT-PREAUTH */
13520     { "/password",         KRB_I_PW, CM_ARG }, /* /PASSWORD:   */
13521 #ifdef OS2
13522     { "/popup",            KRB_I_POP, 0 },     /* /POPUP       */
13523 #endif /* OS2 */
13524     { "/preauth",          KRB_I_PA, 0 },      /* /PREAUTH     */
13525     { "/realm",            KRB_I_RL, CM_ARG }, /* /REALM:      */
13526     { "/verbose",          KRB_I_VB, 0 },      /* /VERBOSE     */
13527     { "", 0, 0 }
13528 };
13529 static int krb4_i_n = sizeof(krb4_i_tbl)/sizeof(struct keytab) - 1;
13530
13531 static struct keytab krb5_i_tbl[] = {   /* KERBEROS 5 INITIALIZE switches: */
13532     { "/addresses",        KRB_I_ADR, CM_ARG },
13533     { "/forwardable",      KRB_I_FW,  0 },         /* /FORWARDABLE */
13534     { "/instance",         KRB_I_IN, CM_ARG }, /* /INSTANCE:   */
13535     { "/k4",               KRB_I_K4,  CM_INV }, /* /KERBEROS4   */
13536     { "/kerberos4",        KRB_I_K4,  0 },      /* /KERBEROS4   */
13537     { "/krb4",             KRB_I_K4,  CM_INV }, /* /KERBEROS4   */
13538     { "/lifetime",         KRB_I_LF,  CM_ARG }, /* /LIFETIME:   */
13539     { "/no-addresses",     KRB_I_NAD, 0 },      /* /NO-ADDRESSES */
13540     { "/no-k4",            KRB_I_NK4, CM_INV },/* /NO-KERBEROS4 */
13541     { "/no-kerberos4",     KRB_I_NK4, 0 },     /* /NO-KERBEROS4 */
13542     { "/no-krb4",          KRB_I_NK4, CM_INV },/* /NO-KERBEROS4 */
13543     { "/not-forwardable",  KRB_I_NFW, 0 },         /* /NOT-FORWARDABLE */
13544     { "/not-proxiable",    KRB_I_NPR, 0 },     /* /NOT-PROXIABLE   */
13545     { "/password",         KRB_I_PW,  CM_ARG }, /* /PASSWORD:   */
13546 #ifdef OS2
13547     { "/popup",            KRB_I_POP, 0 },     /* /POPUP       */
13548 #endif /* OS2 */
13549     { "/postdate",         KRB_I_PD, CM_ARG }, /* /POSTDATE:   */
13550     { "/pr",               KRB_I_PR, CM_INV|CM_ABR }, /* to allow for */
13551     { "/pro",              KRB_I_PR, CM_INV|CM_ABR }, /* different spellings */
13552     { "/prox",             KRB_I_PR, CM_INV|CM_ABR },
13553     { "/proxiable",        KRB_I_PR, 0 },      /* /PROXIABLE   */
13554     { "/proxyable",        KRB_I_PR, CM_INV }, /* /PROXYABLE   */
13555     { "/realm",            KRB_I_RL, CM_ARG }, /* /REALM:      */
13556     { "/renew",            KRB_I_RN, 0 },          /* /RENEW       */
13557     { "/renewable",        KRB_I_RB, CM_ARG }, /* /RENEWABLE:  */
13558     { "/service",          KRB_I_SR, CM_ARG }, /* /SERVICE:    */
13559     { "/validate",         KRB_I_VA, 0 },          /* /VALIDATE    */
13560     { "", 0, 0 }
13561 };
13562 static int krb5_i_n = sizeof(krb5_i_tbl)/sizeof(struct keytab) - 1;
13563
13564 static struct keytab klctab[] = {       /* List Credentials switches*/
13565     { "/addresses",  XYKLCAD, 0 },
13566     { "/encryption", XYKLCEN, 0 },
13567     { "/flags",      XYKLCFL, 0 }
13568 };
13569 static int nklctab = sizeof(klctab)/sizeof(struct keytab);
13570
13571 extern int krb_action;
13572 extern struct krb_op_data krb_op;
13573
13574 extern struct krb5_list_cred_data krb5_lc;
13575 extern struct krb5_init_data krb5_init;
13576 extern char * krb5_d_principal;         /* Default principal */
13577 extern char * krb5_d_instance;
13578 extern char * krb5_d_realm;             /* Default realm */
13579 extern char * krb5_d_cc;                /* Default credentials cache */
13580 extern char * krb5_d_srv;               /* Default service name */
13581 extern int    krb5_d_lifetime;          /* Default lifetime */
13582 extern int    krb5_d_forwardable;
13583 extern int    krb5_d_proxiable;
13584 extern int    krb5_d_renewable;
13585 extern int    krb5_autoget;
13586 extern int    krb5_autodel;
13587 extern int    krb5_d_getk4;
13588 extern int    krb5_d_no_addresses;
13589 extern int    krb5_checkaddrs;
13590 extern char * krb5_d_addrs[];
13591 extern char * k5_keytab;                /* Keytab file */
13592
13593 extern struct krb4_init_data krb4_init;
13594 extern char * krb4_d_principal;         /* Default principal */
13595 extern char * krb4_d_realm;             /* Default realm */
13596 extern char * krb4_d_srv;               /* Default service name */
13597 extern int    krb4_d_lifetime;          /* Default lifetime */
13598 extern int    krb4_d_preauth;
13599 extern char * krb4_d_instance;
13600 extern int    krb4_autoget;
13601 extern int    krb4_autodel;
13602 extern int    krb4_checkaddrs;
13603 extern char * k4_keytab;                /* Keytab file */
13604 #endif /* CK_KERBEROS */
13605
13606 #ifndef NOSHOW
13607 int
13608 sho_iks() {
13609 #ifdef IKSDCONF
13610 #ifdef CK_LOGIN
13611     extern int ckxsyslog, ckxwtmp, ckxanon;
13612 #ifdef UNIX
13613     extern int ckxpriv;
13614 #endif /* UNIX */
13615 #ifdef CK_PERMS
13616     extern int ckxperms;
13617 #endif /* CK_PERMS */
13618     extern char * anonfile, * userfile, * anonroot;
13619 #ifdef OS2
13620     extern char * anonacct;
13621 #endif /* OS2 */
13622 #ifdef NT
13623     extern char * iks_domain;
13624 #endif /* NT */
13625 #endif /* CK_LOGIN */
13626 #ifdef CKWTMP
13627     extern char * wtmpfile;
13628 #endif /* CKWTMP */
13629 #ifdef IKSDB
13630     extern char * dbfile;
13631     extern int dbenabled;
13632 #endif /* IKSDB */
13633 #ifdef CK_LOGIN
13634     extern int logintimo;
13635 #endif /* CK_LOGIN */
13636     extern int srvcdmsg, success, iksdcf, noinit, arg_x;
13637     extern char * cdmsgfile[], * cdmsgstr, *kermrc;
13638     char * bannerfile = NULL;
13639     char * helpfile = NULL;
13640     extern int xferlog;
13641     extern char * xferfile;
13642     int i;
13643
13644     if (isguest) {
13645         printf("?Command disabled\r\n");
13646         return(success = 0);
13647     }
13648
13649     printf("IKS Settings\r\n");
13650 #ifdef CK_LOGIN
13651 #ifdef OS2
13652     printf("  Anonymous Account:   %s\r\n",anonacct?anonacct:"<none>");
13653 #endif /* OS2 */
13654     printf("  Anonymous Initfile:  %s\r\n",anonfile?anonfile:"<none>");
13655     printf("  Anonymous Login:     %d\r\n",ckxanon);
13656     printf("  Anonymous Root:      %s\r\n",anonroot?anonroot:"<none>");
13657 #endif /* CK_LOGIN */
13658     printf("  Bannerfile:          %s\r\n",bannerfile?bannerfile:"<none>");
13659     printf("  CDfile:              %s\r\n",cdmsgfile[0]?cdmsgfile[0]:"<none>");
13660     for ( i=1;i<16 && cdmsgfile[i];i++ )
13661         printf("  CDfile:              %s\r\n",cdmsgfile[i]);
13662     printf("  CDMessage:           %d\r\n",srvcdmsg);
13663 #ifdef IKSDB
13664     printf("  DBfile:              %s\r\n",dbfile?dbfile:"<none>");
13665     printf("  DBenabled:           %d\r\n",dbenabled);
13666 #endif /* IKSDB */
13667 #ifdef CK_LOGIN
13668 #ifdef NT
13669     printf("  Default-domain:      %s\r\n",iks_domain?iks_domain:".");
13670 #endif /* NT */
13671 #endif /* CK_LOGIN */
13672     printf("  Helpfile:            %s\r\n",helpfile?helpfile:"<none>");
13673     printf("  Initfile:            %s\r\n",kermrc?kermrc:"<none>");
13674     printf("  No-Initfile:         %d\r\n",noinit);
13675 #ifdef CK_LOGIN
13676 #ifdef CK_PERM
13677     printf("  Permission code:     %0d\r\n",ckxperms);
13678 #endif /* CK_PERM */
13679 #ifdef UNIX
13680     printf("  Privileged Login:    %d\r\n",ckxpriv);
13681 #endif /* UNIX */
13682 #endif /* CK_LOGIN */
13683     printf("  Server-only:         %d\r\n",arg_x);
13684     printf("  Syslog:              %d\r\n",ckxsyslog);
13685     printf("  Timeout (seconds):   %d\r\n",logintimo);
13686     printf("  Userfile:            %s\r\n",userfile?userfile:"<none>");
13687 #ifdef CK_LOGIN
13688 #ifdef CKWTMP
13689     printf("  Wtmplog:             %d\r\n",ckxwtmp);
13690     printf("  Wtmpfile:            %s\r\n",wtmpfile?wtmpfile:"<none>");
13691 #endif /* CKWTMP */
13692 #endif /* CK_LOGIN */
13693     printf("  Xferfile:            %s\r\n",xferfile?xferfile:"<none>");
13694     printf("  Xferlog:             %d\r\n",xferlog);
13695 #else /* IKSDCONF */
13696     printf("?Nothing to show.\r\n");
13697 #endif /* IKSDCONF */
13698     return(success = 1);
13699 }
13700
13701 #ifdef CK_AUTHENTICATION
13702 int
13703 sho_auth(cx) int cx; {
13704     extern int auth_type_user[], cmd_rows;
13705     int i;
13706     char * p;
13707     int kv = 0, all = 0, n = 0;
13708
13709 #ifdef IKSD
13710     if (inserver && isguest) {
13711         printf("?Sorry, command disabled.\r\n");
13712         return(success = 0);
13713     }
13714 #endif /* IKSD */
13715     if (cx) {
13716         kv = cx;
13717     } else if (auth_type_user[0] != AUTHTYPE_AUTO) {
13718         kv = auth_type_user[0];
13719     } else {
13720         all = 1;
13721         kv = AUTHTYPE_KERBEROS_V4;
13722     }
13723     while (kv) {
13724         switch (kv) {
13725           case AUTHTYPE_KERBEROS_V4:
13726             kv = all ? AUTHTYPE_KERBEROS_V5 : 0;
13727             if (ck_krb4_is_installed()) {
13728                 printf(" Authentication:      Kerberos 4\n");
13729                 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13730             } else {
13731                 printf(" Authentication:      Kerberos 4 (not installed)\n");
13732                 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13733                 continue;
13734             }
13735 #ifdef CK_KERBEROS
13736             printf(" Keytab file:         %s\n",
13737                       k4_keytab ? k4_keytab : "(none)");
13738             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13739             if (krb_action < 0) {
13740                 p = "(none)";
13741             } else {
13742                 for (p = "", i = 0; i < krb_a_n; i++) {
13743                     if (krb_action == krb_a_tbl[i].kwval) {
13744                         p = krb_a_tbl[i].kwd;
13745                         break;
13746                     }
13747                 }
13748             }
13749             printf(" Action:              %s\n", p);
13750             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13751             printf(" Default lifetime     %d\n",krb4_d_lifetime);
13752             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13753             printf(" Lifetime:            %d (minutes)\n",krb4_init.lifetime);
13754             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13755             printf(" Default preauth:     %d\n",krb4_d_preauth);
13756             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13757             printf(" Preauth:             %d\n",krb4_init.preauth);
13758             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13759             printf(" Default principal:   \"%s\"\n",
13760                     krb4_d_principal ? krb4_d_principal : "");
13761             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13762             printf(" Principal:           \"%s\"\n",
13763                     krb4_init.principal ? krb4_init.principal : "");
13764             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13765             printf(" Default realm:       \"%s\"\n",
13766                     krb4_d_realm ? krb4_d_realm : "");
13767             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13768             printf(" Realm:               \"%s\"\n",
13769                     krb4_init.realm ? krb4_init.realm : "");
13770             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13771             printf(" Default instance:    \"%s\"\n",
13772                     krb4_d_instance ? krb4_d_instance : "");
13773             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13774             printf(" Instance:            \"%s\"\n",
13775                     krb4_init.instance ? krb4_init.instance : "");
13776             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13777             printf(" Auto-Get TGTs:       %d\n",krb4_autoget);
13778             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13779             printf(" Auto-Destroy TGTs:   %s\n",
13780                     krb4_autodel==KRB_DEL_NO?"never":
13781                     krb4_autodel==KRB_DEL_CL?"on-close":"on-exit");
13782             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13783             printf(" Check IP Addresses:  %d\n",krb4_checkaddrs);
13784             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13785 #ifdef COMMENT
13786             printf(" Password:    \"%s\"\n",
13787                     krb4_init.password  ? krb4_init.password  : "");
13788             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13789 #endif /* COMMENT */
13790 #endif /* CK_KERBEROS */
13791             printf("\n");
13792             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13793             break;
13794         case AUTHTYPE_KERBEROS_V5:
13795             kv = all ? AUTHTYPE_SSL : 0;
13796             if (ck_krb5_is_installed()) {
13797                 if (ck_gssapi_is_installed())
13798                     printf(" Authentication:      Kerberos 5 plus GSSAPI\n");
13799                 else
13800                     printf(" Authentication:      Kerberos 5\n");
13801                 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13802             } else {
13803                 printf(" Authentication:      Kerberos 5 (not installed)\n");
13804                 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13805                 continue;
13806             }
13807
13808 #ifdef CK_KERBEROS
13809             printf(" Cache file:          %s\n",
13810                     krb_op.cache ? krb_op.cache : "(none)");
13811             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13812             printf(" Default cache:       %s\n",
13813                     krb5_d_cc ? krb5_d_cc : "(none)");
13814             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13815             printf(" Keytab file:         %s\n",
13816                       k5_keytab ? k5_keytab : "(none)");
13817             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13818             if (krb_action < 0) {
13819                 p = "(none)";
13820             } else  {
13821                 for (p = "", i = 0; i < krb_a_n; i++) {
13822                     if (krb_action == krb_a_tbl[i].kwval) {
13823                         p = krb_a_tbl[i].kwd;
13824                         break;
13825                     }
13826                 }
13827             }
13828             printf(" Action:              %s\n", p);
13829             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13830
13831             printf(" Default forwardable  %d\n",krb5_d_forwardable);
13832             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13833             printf(" Forwardable:         %d\n",krb5_init.forwardable);
13834             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13835             printf(" Default lifetime     %d\n",krb5_d_lifetime);
13836             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13837             printf(" Lifetime:            %d (minutes)\n",krb5_init.lifetime);
13838             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13839             printf(" Postdate:            \"%s\"\n",
13840                     krb5_init.postdate ? krb5_init.postdate: "");
13841             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13842             printf(" Default proxiable:   %d\n",krb5_d_proxiable);
13843             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13844             printf(" Proxiable:           %d\n",krb5_init.proxiable);
13845             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13846             printf(" Renew:               %d\n",krb5_init.renew);
13847             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13848             printf(" Default renewable:   %d (minutes)\n",krb5_d_renewable);
13849             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13850             printf(" Renewable:           %d (minutes)\n",krb5_init.renewable);
13851             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13852             printf(" Service:             \"%s\"\n",
13853                     krb5_init.service ? krb5_init.service : "");
13854             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13855             printf(" Validate:            %d\n",krb5_init.validate);
13856             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13857             printf(" Default principal:   \"%s\"\n",
13858                     krb5_d_principal ? krb5_d_principal : "");
13859             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13860             printf(" Principal:           \"%s\"\n",
13861                     krb5_init.principal ? krb5_init.principal : "");
13862             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13863             printf(" Default instance:    \"%s\"\n",
13864                     krb5_d_instance ? krb5_d_instance : "");
13865             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13866             printf(" Default realm:       \"%s\"\n",
13867                     krb5_d_realm ? krb5_d_realm : "");
13868             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13869             printf(" Realm:               \"%s\"\n",
13870                     krb5_init.realm ? krb5_init.realm : "");
13871             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13872             printf(" Auto-Get TGTs:       %d\n",krb5_autoget);
13873             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13874             printf(" Auto-Destroy TGTs:   %s\n",
13875                     krb5_autodel==KRB_DEL_NO?"never":
13876                     krb5_autodel==KRB_DEL_CL?"on-close":"on-exit");
13877             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13878             printf(" Default get K4 TGTs: %d\n",krb5_d_getk4);
13879             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13880             printf(" Get K4 TGTs: %d\n",krb5_init.getk4);
13881             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13882             printf(" Check IP Addresses:  %d\n",krb5_checkaddrs);
13883             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13884             printf(" No IP Addresses:  %d\n",krb5_d_no_addresses);
13885             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13886             printf(" IP-Addresses:        ");
13887             if (krb5_init.addrs && krb5_init.addrs[0]) {
13888                 for (i = 0; krb5_init.addrs[i]; i++) {
13889                     if (i)
13890                       printf(",");
13891                     printf("%s",krb5_init.addrs[i]);
13892                 }
13893             } else if (krb5_d_addrs[0]) {
13894                 for (i = 0;i < KRB5_NUM_OF_ADDRS && krb5_d_addrs[i];i++) {
13895                     if (i)
13896                       printf(",");
13897                     printf("%s",krb5_d_addrs[i]);
13898                 }
13899             } else {
13900                 printf("(use default)");
13901             }
13902             printf("\n");
13903             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13904 #ifdef COMMENT
13905             printf(" Password:            \"%s\"\n",
13906                     krb5_init.password  ? krb5_init.password  : "");
13907             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13908 #endif /* COMMENT */
13909 #endif /* CK_KERBEROS */
13910             printf("\n");
13911             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13912             break;
13913           case AUTHTYPE_SSL:
13914             kv = all ? AUTHTYPE_SRP : 0;
13915             if (ck_ssleay_is_installed()) {
13916                 printf(" Authentication:      SSL/TLS (%s)\n",
13917                         SSLeay_version(SSLEAY_VERSION));
13918                 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13919             } else {
13920                 printf(" Authentication:      SSL/TLS (not installed)\n");
13921                 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13922                 continue;
13923             }
13924
13925 #ifdef CK_SSL
13926             printf(" RSA Certs file: %s\n",ssl_rsa_cert_file?
13927                   ssl_rsa_cert_file:"(none)");
13928             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13929             printf(" RSA Certs Chain file: %s\n",ssl_rsa_cert_chain_file?
13930                   ssl_rsa_cert_chain_file:"(none)");
13931             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13932             printf(" RSA Key file: %s\n",ssl_rsa_key_file?
13933                   ssl_rsa_key_file:"(none)");
13934             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13935             printf(" DSA Certs file: %s\n",ssl_dsa_cert_file?
13936                   ssl_dsa_cert_file:"(none)");
13937             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13938             printf(" DSA Certs Chain file: %s\n",ssl_dsa_cert_chain_file?
13939                   ssl_dsa_cert_chain_file:"(none)");
13940             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13941             printf(" DH Key file: %s\n",ssl_dh_key_file?
13942                   ssl_dh_key_file:"(none)");
13943             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13944             printf(" DH Param file: %s\n",ssl_dh_param_file?
13945                   ssl_dh_param_file:"(none)");
13946             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13947             printf(" CRL file: %s\n",ssl_crl_file?
13948                   ssl_crl_file:"(none)");
13949             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13950             printf(" CRL dir: %s\n",ssl_crl_dir?
13951                     ssl_crl_dir:"(none)");
13952             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13953             printf(" Random file: %s\n",ssl_rnd_file?
13954                   ssl_rnd_file:"(none)");
13955             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13956             printf(" Verify file: %s\n",ssl_verify_file?
13957                   ssl_verify_file:"(none)");
13958             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13959             printf(" Verify dir: %s\n",ssl_verify_dir?
13960                   ssl_verify_dir:"(none)");
13961             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13962             printf(" Cipher list: %s\n",ssl_cipher_list ? ssl_cipher_list : 
13963                     DEFAULT_CIPHER_LIST);
13964             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13965             if (ssl_con == NULL) {
13966                 SSL_library_init();
13967                 ssl_ctx = (SSL_CTX *)
13968                   SSL_CTX_new((SSL_METHOD *)TLSv1_method());
13969                 if (ssl_ctx != NULL)
13970                   ssl_con= (SSL *) SSL_new(ssl_ctx);
13971             }
13972             if (ssl_con != NULL) {
13973                 CHAR * p = NULL;
13974                 int i;
13975
13976                 for (i = 0; ; i++) {
13977                     p = (CHAR *) SSL_get_cipher_list(ssl_con,i);
13978                     if (p == NULL)
13979                       break;
13980                     printf("    %s\n",p);
13981                     if (++n > cmd_rows - 3)
13982                         if (!askmore()) return(0); else n = 0;
13983                 }
13984             }
13985             printf(" Certs OK? %s\n",ssl_certsok_flag? "yes" : "no");
13986             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13987             printf(" Debug mode: %s\n", ssl_debug_flag ? "on" : "off");
13988             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13989             printf(" Verbose mode: %s\n", ssl_verbose_flag ? "on" : "off");
13990             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13991             printf(" Verify mode: %s\n",
13992                     ssl_verify_flag == SSL_VERIFY_NONE ? "none" :
13993                     ssl_verify_flag == SSL_VERIFY_PEER ? "peer-cert" :
13994                     "fail-if-no-peer-cert");
13995             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13996             printf(" SSL only? %s\n", ssl_only_flag ? "yes" : "no");
13997             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
13998             printf(" TLS only? %s\n", tls_only_flag ? "yes" : "no");
13999             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
14000 #endif /* CK_SSL */
14001             break;
14002           case AUTHTYPE_NTLM:
14003             kv = 0;
14004             if (ck_ntlm_is_installed()) {
14005                 printf(" Authentication:      NTLM\n");
14006                 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
14007                 printf(" No options\n");
14008                 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
14009             } else {
14010                 printf(" Authentication:      NTLM (not installed)\n");
14011                 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
14012                 continue;
14013             }
14014             printf("\n");
14015             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
14016             break;
14017           case AUTHTYPE_SRP:
14018             kv = all ? AUTHTYPE_NTLM : 0;
14019             if (ck_srp_is_installed()) {
14020                 if (ck_krypto_is_installed())
14021                     printf(" Authentication:      SRP plus Krypto API\n");
14022                 else
14023                     printf(" Authentication:      SRP\n");
14024                 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
14025                 printf(" No options\n");
14026                 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
14027             } else {
14028                 printf(" Authentication:      SRP (not installed)\n");
14029                 if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
14030                 continue;
14031             }
14032             printf("\n");
14033             if (++n > cmd_rows - 3) if (!askmore()) return(0); else n = 0;
14034             break;
14035         }
14036     }
14037     return(success = 1);
14038 }
14039 #endif /* CK_AUTHENTICATION */
14040 #endif /* NOSHOW */
14041
14042 #ifdef CK_KERBEROS
14043
14044 /*  C P _ A U T H  --  AUTHENTICATE command parsing  */
14045
14046 int
14047 cp_auth() {                             /* Command_Parse AUTHENTICATE */
14048     int c, i, n;                        /* Workers */
14049     int rc = 0;                         /* Return code */
14050     int getval;                         /* Parsing helpers */
14051     int tmpauth = 0;                    /* Temporary authentication type */
14052     int kv = 0;                         /* Temporary Kerberos version */
14053     int tmp_action = -1;                /* Temporary Kerberos action */
14054     int tmp_klc = 0;                    /* Temporary list-credentials */
14055     char tmphlp[256];                   /* For building help message */
14056     char * p;
14057     char * tmppswd  = NULL;             /* Password */
14058     char * tmpprinz = NULL;             /* Principal */
14059     char * tmprealm = NULL;             /* Realm */
14060     char * tmpcache = NULL;             /* Cache file */
14061     char * tmpinst  = NULL;             /* K4 Instance */
14062     char * tmpaddrs[KRB5_NUM_OF_ADDRS];
14063 #ifdef CK_RECALL
14064     extern int on_recall;               /* around Password prompting */
14065 #endif /* CK_RECALL */
14066     struct stringint {                  /* Temporary array for switch values */
14067         char * sval;                    /* String value */
14068         int ival;                       /* Integer value */
14069     } pv[KRB_I_MAX+1];                  /* This many */
14070     struct FDB kw, sw, fl;              /* FDBs for each parse function */
14071
14072     krb_action = -1;                    /* Initialize Kerberos action. */
14073     tmp_action = -1;                    /* And our local copy. */
14074     for (i = 0; i < KRB5_NUM_OF_ADDRS; i++)
14075       tmpaddrs[i] = NULL;
14076
14077     if ((y = cmkey(kerbtab,kerbtabn,"authentication type","",xxstring)) < 0)
14078       {
14079           if (y == -3)
14080             printf("?Authentication type not specified - nothing happens\n");
14081           return(y);
14082       }
14083     tmpauth = y;
14084     debug(F101,"kerberos authentication","",tmpauth);
14085     switch (tmpauth) {
14086       case AUTH_KRB4: kv = 4; break;    /* Don't assume values are the same */
14087       case AUTH_KRB5: kv = 5; break;
14088       default:
14089         printf("?Authentication type not supported: \"%s\"\n",atmbuf);
14090         return(-9);
14091     }
14092
14093     /* From here down is Kerberos */
14094     ini_kerb();                         /* Reset Init data to defaults */
14095
14096     if (kv == 4) {                      /* Set K4 defaults */
14097         if (krb4_d_realm)
14098           makestr(&tmprealm,krb4_d_realm);
14099         if (krb4_d_principal)
14100           makestr(&tmpprinz,krb4_d_principal);
14101         if (krb4_d_instance)
14102           makestr(&tmpinst,krb4_d_instance);
14103     } else if (kv == 5) {               /* Set K5 defaults */
14104         if (krb5_d_cc)
14105           makestr(&tmpcache,krb5_d_cc);
14106         if (krb5_d_realm)
14107           makestr(&tmprealm,krb5_d_realm);
14108         if (krb5_d_principal)
14109           makestr(&tmpprinz,krb5_d_principal);
14110         if (krb5_d_instance)
14111           makestr(&tmpinst,krb5_d_instance);
14112     }
14113
14114     for (i = 0; i <= KRB_I_MAX; i++) {  /* Initialize switch values */
14115         pv[i].sval = NULL;              /* to null pointers */
14116         pv[i].ival = 0;                 /* and 0 int values */
14117     }
14118
14119     if (kv == 4) {                      /* Kerberos 4 */
14120         pv[KRB_I_LF].ival = krb4_d_lifetime;
14121         pv[KRB_I_PA].ival = krb4_d_preauth;
14122
14123         if ((n = cmkey(krb_a_tbl,krb_a_n,"Kerberos 4 action","",xxstring)) < 0)
14124           {
14125               if (n == -3)
14126                 printf("?Action not specified - nothing happens.\n");
14127               return(n);
14128           }
14129     } else if (kv == 5) {               /* Kerberos 5 */
14130         pv[KRB_I_FW].ival = krb5_d_forwardable;
14131         pv[KRB_I_PR].ival = krb5_d_proxiable;
14132         pv[KRB_I_LF].ival = krb5_d_lifetime;
14133         pv[KRB_I_RB].ival = krb5_d_renewable;
14134         pv[KRB_I_K4].ival = krb5_d_getk4;
14135         pv[KRB_I_NAD].ival = krb5_d_no_addresses;
14136
14137         /* Make help message that shows switches and action keywords */
14138         ckstrncpy(tmphlp,"Kerberos 5 action, one of the following:\n ",256);
14139         for (i = 0; i < krb_a_n; i++) {
14140             ckstrncat(tmphlp,krb_a_tbl[i].kwd,sizeof(tmphlp));
14141             if (i == krb_a_n - 1)
14142               ckstrncat(tmphlp,"\nor switch",sizeof(tmphlp));
14143             else
14144               ckstrncat(tmphlp,"   ",sizeof(tmphlp));
14145         }
14146         /* Set up first set of chained FDB's */
14147
14148         cmfdbi(&sw,                     /* First FDB - command switches */
14149                _CMKEY,                  /* fcode */
14150                tmphlp,                  /* hlpmsg */
14151                "",                      /* default (none) */
14152                "",                      /* addtl string data */
14153                krb_s_n,                 /* Switch table size */
14154                4,                       /* addtl numeric data 2: 4 = cmswi */
14155                xxstring,                /* Processing function */
14156                krb_s_tbl,               /* Switch table */
14157                &kw                      /* Pointer to next FDB */
14158                );
14159         cmfdbi(&kw,                     /* Second FDB - action keywords */
14160                _CMKEY,                  /* fcode */
14161                "Kerberos action",       /* hlpmsg */
14162                "",                      /* default (none) */
14163                "",                      /* addtl string data */
14164                krb_a_n,                 /* Switch table size */
14165                0,                       /* addtl num data (0 = NOT switch) */
14166                xxstring,                /* Processing function */
14167                krb_a_tbl,               /* Keyword table */
14168                NULL                     /* Pointer to next FDB (none) */
14169                );
14170
14171         /* Parse */
14172
14173         while (1) {                     /* Parse 0 or more switches */
14174             rc = cmfdb(&sw);            /* Parse something */
14175             debug(F101,"kerberos cmfdb 1 rc","",rc);
14176             if (rc < 0) {                       /* Error */
14177                 if (rc == -3)
14178                   printf("?Action not specified - nothing happens.\n");
14179                 return(rc);             /* or reparse needed */
14180             }
14181             if (cmresult.fdbaddr != &sw) /* Break out if not a switch */
14182               break;
14183             c = cmgbrk();               /* Have switch - get break character */
14184             getval = (c == ':' || c == '='); /* Must parse an agument? */
14185             if (getval && !(cmresult.kflags & CM_ARG)) {
14186                 printf("?This switch does not take arguments\n");
14187                 return(-9);             /* OK because nothing malloc'd yet */
14188             }
14189             if (!getval && (cmgkwflgs() & CM_ARG)) {
14190                 printf("?This switch requires an argument\n");
14191                 return(-9);
14192             }
14193             n = cmresult.nresult;       /* Numeric result = switch value */
14194             debug(F101,"kerberos command switch","",n);
14195
14196             switch (n) {                /* Handle the switch */
14197               case KRB_S_CA:            /* /CACHE:<filename> */
14198                 p = krb5_d_cc ? krb5_d_cc : "";
14199                 if ((y = cmofi("Name of cache file",p,&s,xxstring)) < 0) {
14200                     if (y == -3)
14201                       s = NULL;
14202                     else
14203                       return(y);
14204                 }
14205                 makestr(&tmpcache,s);
14206                 break;
14207               default:
14208                 printf("?Unexpected switch value - internal error\n");
14209                 return(-9);             /* (if) nothing malloc'd yet. */
14210             }
14211         }
14212         if (cmresult.fdbaddr != &kw) {  /* Checking... */
14213             printf("?Unexpected result - internal error\n");
14214             return(-9);                 /* Nothing malloc'd yet. */
14215         }
14216         n = cmresult.nresult;           /* Get keyword value */
14217     } else {
14218         printf("?Unexpected Kerberos version - Internal error\n");
14219         return(-9);
14220     }
14221     debug(F101,"kerberos action","",n);
14222     switch (n) {
14223       case KRB_A_IN:                    /* INITIALIZE */
14224       case KRB_A_DE:                    /* DESTROY */
14225       case KRB_A_LC:                    /* LIST-CREDENTIALS */
14226         tmp_action = n;                 /* OK, set */
14227         break;
14228       default:                          /* Not OK, punt. */
14229         printf("?Unexpected action - internal error\n");
14230         return(-9);
14231     }
14232     if (tmp_action == KRB_A_IN) {       /* Action is INITIALIZE */
14233         int x;
14234         cmfdbi(&sw,                     /* INITIALIZE switches */
14235                _CMKEY,                  /* fcode */
14236                "Principal,\n or optional INITIALIZE switch(es)", /* hlpmsg */
14237                "",                      /* default (none) */
14238                "",                      /* addtl string data */
14239                kv == 4 ?  krb4_i_n : krb5_i_n, /* Switch table size */
14240                4,                       /* addtl numeric data 2: 4 = cmswi */
14241                xxstring,                /* Processing function */
14242                kv == 4 ?  krb4_i_tbl : krb5_i_tbl,      /* Switch table */
14243                &fl                      /* Pointer to next FDB */
14244                );
14245         cmfdbi(&fl,                     /* 3rd FDB - command to send from */
14246                _CMFLD,                  /* fcode */
14247                "Principal",             /* hlpmsg */
14248                kv == 4 ? krb4_d_principal : krb5_d_principal, /* principal */
14249                "",                      /* addtl string data */
14250                0,                       /* addtl numeric data 1 */
14251                0,                       /* addtl numeric data 2 */
14252                xxstring,
14253                NULL,
14254                NULL
14255                );
14256         while (1) {                     /* Parse INIT switches or principal */
14257             rc = cmfdb(&sw);
14258             debug(F101,"kerberos cmfdb 2 rc","",rc);
14259             if (rc < 0) {
14260                 if (rc == -3)
14261                   printf("?Principal name required\n");
14262                 goto kerbx;
14263             }
14264             debug(F101,"kerberos cmfdb 2 fcode","",cmresult.fcode);
14265             if (cmresult.fcode != _CMKEY) /* Not a switch, quit switch loop */
14266               break;
14267             c = cmgbrk();               /* Switch - get break character */
14268             debug(F101,"kerberos cmfdb 2 cmgbrk","",c);
14269             getval = (c == ':' || c == '=');
14270             if (getval && !(cmresult.kflags & CM_ARG)) {
14271                 printf("?This switch does not take arguments\n");
14272                 return(-9);             /* OK because nothing malloc'd yet */
14273             }
14274             if (!getval && (cmgkwflgs() & CM_ARG)) {
14275                 printf("?This switch requires an argument\n");
14276                 return(-9);
14277             }
14278             n = cmresult.nresult;       /* Numeric result = switch value */
14279             switch (n) {
14280               /* These don't take args... */
14281               case KRB_I_PA:            /* /PREAUTH */
14282               case KRB_I_FW:            /* /FORWARDABLE */
14283               case KRB_I_PR:            /* /PROXIABLE */
14284               case KRB_I_RN:            /* /RENEW */
14285               case KRB_I_VA:            /* /VALIDATE */
14286               case KRB_I_NPA:           /* /NOT-PREAUTH */
14287               case KRB_I_NFW:           /* /NOT-FORWARDABLE */
14288               case KRB_I_NPR:           /* /NOT-PROXIABLE */
14289               case KRB_I_VB:            /* /VERBOSE */
14290               case KRB_I_BR:            /* /BRIEF */
14291               case KRB_I_K4:            /* /KERBEROS4 */
14292               case KRB_I_NK4:           /* /NO-KERBEROS4 */
14293               case KRB_I_POP:           /* /POPUP */
14294               case KRB_I_NAD:           /* /NO-ADDRESSES */
14295                 if (getval) {
14296                     printf("?This switch does not take a value\n");
14297                     rc = -9;
14298                     goto kerbx;
14299                 }
14300                 switch (n) {
14301                   case KRB_I_NPA:
14302                     pv[KRB_I_PA].ival = 0;
14303                     break;
14304                   case KRB_I_NFW:
14305                     pv[KRB_I_FW].ival = 0;
14306                     break;
14307                   case KRB_I_NPR:
14308                     pv[KRB_I_PR].ival = 0;
14309                     break;
14310                   case KRB_I_VB:
14311                     pv[KRB_I_BR].ival = 0;
14312                     break;
14313                   case KRB_I_NK4:
14314                     pv[KRB_I_K4].ival = 0;
14315                     break;
14316                   default:
14317                     pv[n].ival = 1;
14318                 }
14319                 break;
14320
14321                 /* These do take arguments */
14322
14323               case KRB_I_RB:            /* /RENEWABLE:<minutes> */
14324                 pv[n].ival = 0;
14325                 if (!getval) break;
14326                 if ((rc = cmnum("Minutes",ckitoa(krb5_init.renewable),
14327                                 10,&y, xxstring)) < 0)
14328                   goto kerbx;
14329                 pv[n].ival = y;
14330                 break;
14331
14332               case KRB_I_LF:            /* /LIFETIME:<minutes> */
14333                 pv[n].ival = 0;
14334                 /* Default is previous value */
14335                 sprintf(tmpbuf,"%d",    /* SAFE */
14336                         kv == 4 ?
14337                         krb4_init.lifetime :
14338                         krb5_init.lifetime
14339                         );
14340                 if (!getval) break;
14341                 if ((rc = cmnum("Minutes",tmpbuf,10,&y, xxstring)) < 0)
14342                   goto kerbx;
14343                 pv[n].ival = y;
14344                 break;
14345
14346               case KRB_I_PD:            /* /POSTDATE:<timestamp> */
14347                 if (pv[n].sval) {
14348                     free(pv[n].sval);
14349                     pv[n].sval = NULL;
14350                 }
14351                 if (!getval) break;
14352                 if ((rc = cmdate("date-time","",&s,0,xxstring)) < 0)
14353                   goto kerbx;
14354                 makestr(&(pv[n].sval),s);
14355                 break;
14356
14357               case KRB_I_SR:            /* /SERVICE:<name> */
14358                 if (pv[n].sval) {
14359                     free(pv[n].sval);
14360                     pv[n].sval = NULL;
14361                 }
14362                 if (!getval) break;
14363                 if ((rc = cmfld("Service-name","",&s,xxstring)) < 0)
14364                   goto kerbx;
14365                 makestr(&(pv[n].sval),s);
14366                 break;
14367
14368               case KRB_I_RL:            /* /REALM:<name> */
14369                 if (pv[n].sval) {
14370                     free(pv[n].sval);
14371                     pv[n].sval = NULL;
14372                 }
14373                 if (!getval) break;
14374                 if (kv == 4)
14375                   p = krb4_d_realm ? krb4_d_realm : "";
14376                 else
14377                   p = krb5_d_realm ? krb5_d_realm : "";
14378                 if ((rc = cmfld("Realm",p,&s,xxstring)) < 0)
14379                   goto kerbx;
14380                 makestr(&(pv[n].sval),s);
14381                 break;
14382
14383               case KRB_I_IN:            /* /INSTANCE:<name> */
14384                 if (pv[n].sval) {
14385                     free(pv[n].sval);
14386                     pv[n].sval = NULL;
14387                 }
14388                 if (!getval) break;
14389                 if (kv == 4)
14390                     p = krb4_d_instance ? krb4_d_instance : "";
14391                 else
14392                     p = krb5_d_instance ? krb5_d_instance : "";
14393                 if ((rc = cmfld("Instance",p,&s,xxstring)) < 0)
14394                   goto kerbx;
14395                 makestr(&(pv[n].sval),s);
14396                 break;
14397
14398               case KRB_I_PW:            /* /PASSWORD:<password> */
14399                 debok = 0;
14400                 if (pv[n].sval) {
14401                     free(pv[n].sval);
14402                     pv[n].sval = NULL;
14403                 }
14404                 if (!getval) break;
14405                 if ((rc = cmfld("Password","",&s,xxstring)) < 0)
14406                   if (rc != -3)
14407                     goto kerbx;
14408                 makestr(&(pv[n].sval),s);
14409                 break;
14410
14411               case KRB_I_ADR:           /* /ADDRESSES:{<address-list>} */
14412                 if (pv[n].sval) {
14413                     free(pv[n].sval);
14414                     pv[n].sval = NULL;
14415                 }
14416                 if (!getval) break;
14417                 if ((rc = cmfld("List of IP addresses","",&s,xxstring)) < 0)
14418                   goto kerbx;
14419                 makelist(s,tmpaddrs,KRB5_NUM_OF_ADDRS);
14420                 for (i = 0; i < KRB5_NUM_OF_ADDRS && tmpaddrs[i]; i++) {
14421                     if (inet_addr(tmpaddrs[i]) == 0xffffffff) {
14422                         printf("invalid ip address: %s\n",tmpaddrs[i]);
14423                         rc = -9;
14424                         goto kerbx;
14425                     }
14426                 }
14427                 pv[KRB_I_NAD].ival = 0;
14428                 break;
14429
14430               default:
14431                 printf("?Unexpected switch value - internal error\n");
14432                 rc = -9;
14433                 goto kerbx;
14434             }
14435         }
14436         if (cmresult.fcode != _CMFLD) {
14437             printf("?Unexected result - internal error\n");
14438             rc = -9;
14439             goto kerbx;
14440         }
14441         /* cmresult.sresult may be of the form PRINCIPAL@REALM */
14442         i = ckindex("@",cmresult.sresult,0,0,0);
14443         if (i != 0) {
14444             makestr(&tmprealm,&cmresult.sresult[i]);
14445             cmresult.sresult[i-1] = '\0';
14446         }
14447         makestr(&tmpprinz,cmresult.sresult); /* Principal (user) */
14448
14449         if ((rc = cmcfm()) < 0) {       /* Now get confirmation */
14450             if (rc == -3) {
14451                 printf("?Principal name required\n");
14452             }
14453             goto kerbx;
14454         }
14455         if (!tmpprinz || !tmpprinz[0]) {
14456             printf("?Principal name required\n");
14457             goto kerbx;
14458         }
14459         if (!pv[KRB_I_RN].ival && !pv[KRB_I_VA].ival) {
14460             /* Don't use a password if Validating or Renewing */
14461             if (pv[KRB_I_PW].sval) {    /* If they gave a /PASSWORD switch */
14462                 makestr(&tmppswd,pv[KRB_I_PW].sval); /* use this value */
14463             }
14464 #ifdef COMMENT
14465             /* Password prompting has been moved to ck_krb[45]_initTGT() */
14466             else {                      /* Otherwise must prompt for it */
14467                 char prmpt[80];
14468                 if (pv[KRB_I_RL].sval)
14469                   sprintf(prmpt,"%s@%s's Password: ",
14470                           tmpprinz,pv[KRB_I_RL].sval);
14471                 else if (tmprealm)
14472                   sprintf(prmpt,"%s@%s's Password: ",
14473                           tmpprinz,tmprealm);
14474                 else
14475                   sprintf(prmpt,"%s's Password: ",tmpprinz);
14476 #ifdef OS2
14477                 if (pv[KRB_I_POP].ival) {
14478                     char passwd[80]="";
14479                     readpass(prmpt,passwd,80);
14480                     makestr(&tmppswd,passwd);
14481                     memset(passwd,0,80);
14482                 } else
14483 #endif /* OS2 */
14484                 {
14485 #ifdef CK_RECALL
14486                     on_recall = 0;
14487 #endif /* CK_RECALL */
14488                     cmsavp(psave,PROMPTL); /* Save old prompt */
14489                     cmsetp(prmpt);      /* Make new prompt */
14490                     concb((char)escape); /* Put console in cbreak mode */
14491                     cmini(0);           /* and no-echo mode */
14492                     /* Issue prompt if at top level */
14493                     if (pflag) prompt(xxstring);
14494                     cmres();            /* Reset the parser */
14495                     for (rc = -1; rc < 0; ) { /* Prompt till they answer */
14496                         /* Get a literal line of text */
14497                         rc = cmtxt("","",&s,NULL);
14498                         cmres();        /* Reset the parser again */
14499                     }
14500                     makestr(&tmppswd,s);
14501                     printf("\n");       /* Echo a CRLF */
14502                     cmsetp(psave);      /* Restore original prompt */
14503                 }
14504             }
14505             x = 0;                      /* Check for password */
14506             if (tmppswd)
14507               if (*tmppswd)
14508                 x = 1;
14509             if (!x) {
14510                 printf("?Password required\n");
14511                 goto kerbx;
14512             }
14513 #endif /* COMMENT */
14514         }
14515     } else if (kv == 5 && tmp_action == KRB_A_LC) { /* LIST-CREDENTIALS */
14516         tmp_klc = 0;
14517         while (1) {
14518             if ((x = cmkey(klctab,nklctab,"Switch","",xxstring)) < 0) {
14519                 if (x == -3) {
14520                     if ((rc = cmcfm()) < 0)
14521                       goto kerbx;
14522                     else
14523                       break;
14524                 } else {
14525                     rc = x;
14526                     goto kerbx;
14527                 }
14528             }
14529             tmp_klc |= x;
14530         }
14531     } else if ((rc = cmcfm()) < 0)      /* DESTROY, just confirm */
14532         goto kerbx;
14533
14534 /* Done - Move confirmed data to final locations */
14535
14536     krb_action = tmp_action;            /* Action requested */
14537     krb_op.version = kv;                /* Kerberos version */
14538     krb_op.cache = tmpcache;            /* Cache file */
14539     tmpcache = NULL;                    /* So we don't free it */
14540
14541     switch (krb_action) {
14542       case KRB_A_IN:                    /* INITIALIZE */
14543         if (kv == 5) {
14544             krb5_init.forwardable = pv[KRB_I_FW].ival;
14545             krb5_init.proxiable   = pv[KRB_I_PR].ival;
14546             krb5_init.lifetime    = pv[KRB_I_LF].ival;
14547             krb5_init.renew       = pv[KRB_I_RN].ival;
14548             krb5_init.renewable   = pv[KRB_I_RB].ival;
14549             krb5_init.validate    = pv[KRB_I_VA].ival;
14550
14551             /* Here we just reassign the pointers and then set them to NULL */
14552             /* so they won't be freed below. */
14553
14554             krb5_init.postdate = pv[KRB_I_PD].sval; pv[KRB_I_PD].sval = NULL;
14555             krb5_init.service  = pv[KRB_I_SR].sval; pv[KRB_I_SR].sval = NULL;
14556             if (pv[KRB_I_RL].sval) {
14557                 krb5_init.realm  = pv[KRB_I_RL].sval; pv[KRB_I_RL].sval = NULL;
14558             } else if (tmprealm) {
14559                 krb5_init.realm = tmprealm; tmprealm = NULL;
14560             }
14561             if (pv[KRB_I_IN].sval) {
14562                 krb5_init.instance = pv[KRB_I_IN].sval;
14563                 pv[KRB_I_IN].sval = NULL;
14564             } else if ( tmpinst ) {
14565                 krb5_init.instance = tmpinst;
14566                 tmpinst = NULL;
14567             }
14568             if (tmpprinz) {
14569                 krb5_init.principal = tmpprinz;
14570                 tmpprinz = NULL;
14571             }
14572             krb5_init.password = tmppswd;
14573             tmppswd = NULL;
14574
14575             krb5_init.getk4 = pv[KRB_I_K4].ival;
14576             if (krb5_init.getk4) {
14577                 krb4_init.lifetime = pv[KRB_I_LF].ival;
14578                 if (krb5_init.realm)
14579                     makestr(&krb4_init.realm,krb5_init.realm);
14580                 krb4_init.preauth  = krb4_d_preauth;
14581                 krb4_init.verbose  = pv[KRB_I_BR].ival ? 0 : 1;
14582                 if (krb5_init.principal)
14583                     makestr(&krb4_init.principal,krb5_init.principal);
14584                 if (krb5_init.principal)
14585                     makestr(&krb4_init.password,krb5_init.password);
14586             }
14587             krb5_init.no_addresses = pv[KRB_I_NAD].ival;
14588             if (tmpaddrs[0]) {
14589                 for (i = 0; i < KRB5_NUM_OF_ADDRS; i++) {
14590                     if (krb5_init.addrs[i]) {
14591                         free(krb5_init.addrs[i]);
14592                         krb5_init.addrs[i] = NULL;
14593                     }
14594                     krb5_init.addrs[i] = tmpaddrs[i];
14595                     tmpaddrs[i] = NULL;
14596                 }
14597             }
14598         } else if (kv == 4) {           /* Same deal for Kerberos 4 */
14599             krb4_init.lifetime = pv[KRB_I_LF].ival;
14600             if (pv[KRB_I_RL].sval) {
14601                 krb4_init.realm  = pv[KRB_I_RL].sval;
14602                 pv[KRB_I_RL].sval = NULL;
14603             } else if ( tmprealm ) {
14604                 krb4_init.realm  = tmprealm;
14605                 tmprealm = NULL;
14606             }
14607             if (pv[KRB_I_IN].sval) {
14608                 krb4_init.instance = pv[KRB_I_IN].sval;
14609                 pv[KRB_I_IN].sval = NULL;
14610             } else if ( tmpinst ) {
14611                 krb4_init.instance = tmpinst;
14612                 tmpinst = NULL;
14613             }
14614             krb4_init.preauth  = pv[KRB_I_PA].ival;
14615             krb4_init.verbose  = pv[KRB_I_BR].ival ? 0 : 1;
14616
14617             if (tmpprinz) {
14618                 krb4_init.principal = tmpprinz;
14619                 tmpprinz = NULL;
14620             }
14621             krb4_init.password = tmppswd;
14622             tmppswd = NULL;
14623         }
14624         break;
14625       case KRB_A_LC:                    /* List Credentials */
14626         krb5_lc.encryption = tmp_klc & XYKLCEN;
14627         krb5_lc.flags = tmp_klc & XYKLCFL;
14628         krb5_lc.addr  = tmp_klc & XYKLCAD;
14629         break;
14630     }
14631
14632 /* Common exit - Free temporary storage */
14633
14634   kerbx:
14635     for (i = 0; i <= KRB_I_MAX; i++) {  /* Free malloc'd switch data */
14636         if (pv[i].sval)
14637           free(pv[i].sval);
14638     }
14639     for (i = 0; i < KRB5_NUM_OF_ADDRS; i++) {
14640         if (tmpaddrs[i])
14641           free(tmpaddrs[i]);
14642     }
14643     if (tmpprinz) free(tmpprinz);       /* And these too. */
14644     if (tmppswd)  free(tmppswd);
14645     if (tmpcache) free(tmpcache);
14646     if (tmprealm) free(tmprealm);
14647     if (tmpinst)  free(tmpinst);
14648
14649     return(rc);                         /* Return the return code */
14650 }
14651 #endif /* CK_KERBEROS */
14652
14653 #ifdef CK_LOGIN
14654 int
14655 #ifdef CK_ANSIC
14656 ckxlogin(CHAR * userid, CHAR * passwd, CHAR * acct, int promptok)
14657 #else /* CK_ANSIC */
14658 ckxlogin(userid, passwd, acct, promptok)
14659   CHAR * userid; CHAR * passwd; CHAR * acct; int promptok;
14660 #endif /* CK_ANSIC */
14661 /* ckxlogin */ {
14662 #ifdef CK_RECALL
14663     extern int on_recall;               /* around Password prompting */
14664 #endif /* CK_RECALL */
14665 #ifdef COMMENT
14666     extern int guest;
14667 #endif /* COMMENT */
14668     int rprompt = 0;                    /* Restore prompt */
14669 #ifdef CKSYSLOG
14670     int savlog;
14671 #endif /* CKSYSLOG */
14672
14673     extern int what, srvcdmsg;
14674
14675     int x = 0, ok = 0, rc = 0;
14676     CHAR * _u = NULL, * _p = NULL, * _a = NULL;
14677
14678     debug(F111,"ckxlogin userid",userid,promptok);
14679     debug(F110,"ckxlogin passwd",passwd,0);
14680
14681     isguest = 0;                        /* Global "anonymous" flag */
14682
14683     if (!userid) userid = (CHAR *)"";
14684     if (!passwd) passwd = (CHAR *)"";
14685
14686     debug(F111,"ckxlogin userid",userid,what);
14687
14688 #ifdef CK_RECALL
14689     on_recall = 0;
14690 #endif /* CK_RECALL */
14691
14692 #ifdef CKSYSLOG
14693     savlog = ckxsyslog;                 /* Save and turn off syslogging */
14694 #endif /* CKSYSLOG */
14695
14696     if ((!*userid || !*passwd) &&       /* Need to prompt for missing info */
14697         promptok) {
14698         cmsavp(psave,PROMPTL);          /* Save old prompt */
14699         debug(F110,"ckxlogin saved",psave,0);
14700         rprompt = 1;
14701     }
14702     if (!*userid) {
14703         if (!promptok)
14704           return(0);
14705         cmsetp("Username: ");           /* Make new prompt */
14706         concb((char)escape);            /* Put console in cbreak mode */
14707         cmini(1);
14708
14709 /* Flush typeahead */
14710
14711 #ifdef IKS_OPTION
14712         debug(F101,
14713               "ckxlogin TELOPT_SB(TELOPT_KERMIT).kermit.me_start",
14714               "",
14715               TELOPT_SB(TELOPT_KERMIT).kermit.me_start
14716               );
14717 #endif /* IKS_OPTION */
14718
14719         while (ttchk() > 0) {
14720             x = ttinc(0);
14721             debug(F101,"ckxlogin flush user x","",x);
14722             if (x < 0)
14723               doexit(GOOD_EXIT,0);      /* Connection lost */
14724 #ifdef TNCODE
14725             if (sstelnet) {
14726                 if (x == IAC) {
14727                     x = tn_doop((CHAR)(x & 0xff),ckxech,ttinc);
14728                     debug(F101,"ckxlogin user tn_doop","",x);
14729 #ifdef IKS_OPTION
14730                     debug(F101,
14731                       "ckxlogin user TELOPT_SB(TELOPT_KERMIT).kermit.me_start",
14732                       "",
14733                       TELOPT_SB(TELOPT_KERMIT).kermit.me_start
14734                       );
14735 #endif /* IKS_OPTION */
14736
14737                     if (x < 0)
14738                       goto XCKXLOG;
14739                     switch (x) {
14740                       case 1: ckxech = 1; break; /* Turn on echoing */
14741                       case 2: ckxech = 0; break; /* Turn off echoing */
14742 #ifdef IKS_OPTION
14743                       case 4:                    /* IKS event */
14744                         if (!TELOPT_SB(TELOPT_KERMIT).kermit.me_start)
14745                           break;                 /* else fall thru... */
14746 #endif /* IKS_OPTION */
14747                       case 6:                    /* Logout */
14748                         goto XCKXLOG;
14749                     }
14750                 }
14751             }
14752 #endif /* TNCODE */
14753         }
14754         if (pflag) prompt(xxstring);    /* Issue prompt if at top level */
14755         cmres();                        /* Reset the parser */
14756         for (x = -1; x < 0;) {          /* Prompt till they answer */
14757             /* Get a literal line of text */
14758             x=cmtxt("Your username, or \"ftp\", or \"anonymous\"","",&s,NULL);
14759             if (x == -4 || x == -10) {
14760                 printf("\r\n%sLogin cancelled\n",
14761                        x == -10 ? "Timed out: " : "");
14762 #ifdef CKSYSLOG
14763                 ckxsyslog = savlog;
14764 #endif /* CKSYSLOG */
14765                 doexit(GOOD_EXIT,0);
14766             }
14767             if (sstate)                 /* Did a packet come instead? */
14768               goto XCKXLOG;
14769             cmres();                    /* Reset the parser again */
14770         }
14771         if ((_u = (CHAR *)malloc((int)strlen(s) + 1)) == NULL) {
14772             printf("?Internal error: malloc\n");
14773             goto XCKXLOG;
14774         } else {
14775             strcpy((char *)_u,s);       /* safe */
14776             userid = _u;
14777         }
14778     }
14779     ok = zvuser((char *)userid);        /* Verify username */
14780     debug(F111,"ckxlogin zvuser",userid,ok);
14781
14782     if (!*passwd && promptok
14783 #ifdef COMMENT
14784         && guest
14785 #endif /* COMMENT */
14786         ) {
14787         char prmpt[80];
14788
14789 #ifdef CKSYSLOG
14790         savlog = ckxsyslog;             /* Save and turn off syslogging */
14791         ckxsyslog = 0;
14792 #endif /* CKSYSLOG */
14793
14794 /* Flush typeahead again */
14795
14796         while (ttchk() > 0) {
14797             x = ttinc(0);
14798             debug(F101,"ckxlogin flush user x","",x);
14799 #ifdef TNCODE
14800             if (sstelnet) {
14801                 if (x == IAC) {
14802                     x = tn_doop((CHAR)(x & 0xff),ckxech,ttinc);
14803                     debug(F101,"ckxlogin pass tn_doop","",x);
14804 #ifdef IKS_OPTION
14805                     debug(F101,
14806                       "ckxlogin pass TELOPT_SB(TELOPT_KERMIT).kermit.me_start",
14807                       "",
14808                       TELOPT_SB(TELOPT_KERMIT).kermit.me_start
14809                       );
14810 #endif /* IKS_OPTION */
14811                     if (x < 0)
14812                       goto XCKXLOG;
14813                     switch (x) {
14814                       case 1: ckxech = 1; break; /* Turn on echoing */
14815                       case 2: ckxech = 0; break; /* Turn off echoing */
14816                       case 4:                    /* IKS event */
14817                         if (!TELOPT_SB(TELOPT_KERMIT).kermit.me_start)
14818                           break;                 /* else fall thru... */
14819                       case 6:                    /* Logout */
14820                         goto XCKXLOG;
14821                     }
14822                 }
14823             }
14824 #endif /* TNCODE */
14825         }
14826         if (!strcmp((char *)userid,"anonymous") ||
14827             !strcmp((char *)userid,"ftp")) {
14828             if (!ok)
14829               goto XCKXLOG;
14830             ckstrncpy(prmpt,"Enter e-mail address as Password: ",80);
14831         } else if (*userid && strlen((char *)userid) < 60) {
14832 #ifdef NT
14833             extern CHAR * pReferenceDomainName;
14834             if (pReferenceDomainName)
14835               ckmakxmsg(prmpt,
14836                        80,
14837                        "Enter ",
14838                        pReferenceDomainName,
14839                        "\\\\",
14840                        userid,
14841                        "'s Password: ",
14842                        NULL,NULL,NULL,NULL,NULL,NULL,NULL
14843                        );
14844             else
14845 #endif /* NT */
14846               ckmakmsg(prmpt,80,"Enter ",(char *)userid,"'s Password: ",NULL);
14847         } else
14848           ckstrncpy(prmpt,"Enter Password: ",80);
14849         cmsetp(prmpt);                  /* Make new prompt */
14850         concb((char)escape);            /* Put console in cbreak mode */
14851         if (strcmp((char *)userid,"anonymous") &&
14852             strcmp((char *)userid,"ftp")) { /* and if not anonymous */
14853             debok = 0;
14854             cmini(0);                   /* and no-echo mode */
14855         } else {
14856             cmini(1);
14857         }
14858         if (pflag) prompt(xxstring);    /* Issue prompt if at top level */
14859         cmres();                        /* Reset the parser */
14860         for (x = -1; x < 0;) {          /* Prompt till they answer */
14861 #ifdef CK_PAM
14862             gotemptypasswd=0;
14863 #endif /* CK_PAM */
14864             x = cmtxt("","",&s,NULL);   /* Get a literal line of text */
14865             if (x == -4 || x == -10) {
14866                 printf("\r\n%sLogin cancelled\n",
14867                        x == -10 ? "Timed out: " : "");
14868 #ifdef CKSYSLOG
14869                 ckxsyslog = savlog;
14870 #endif /* CKSYSLOG */
14871                 doexit(GOOD_EXIT,0);
14872             }
14873 #ifdef CK_PAM
14874             if(!*s)
14875                 gotemptypasswd=1;
14876 #endif /* CK_PAM */
14877             if (sstate)                 /* In case of a Kermit packet */
14878               goto XCKXLOG;
14879             cmres();                    /* Reset the parser again */
14880         }
14881         printf("\r\n");                 /* Echo a CRLF */
14882         if ((_p = (CHAR *)malloc((int)strlen(s) + 1)) == NULL) {
14883             printf("?Internal error: malloc\n");
14884             goto XCKXLOG;
14885         } else {
14886             strcpy((char *)_p,s);       /* safe */
14887             passwd = _p;
14888         }
14889     }
14890 #ifdef CK_PAM
14891     else {
14892         cmres();                        /* Reset the parser */
14893
14894         /* We restore the prompt now because the PAM engine will call  */
14895         /* readpass() which will overwrite psave. */
14896         if (rprompt) {
14897             cmsetp(psave);              /* Restore original prompt */
14898             debug(F110,"ckxlogin restored",psave,0);
14899             rprompt = 0;
14900         }
14901     }
14902 #endif /* CK_PAM */
14903
14904 #ifdef CKSYSLOG
14905     ckxsyslog = savlog;
14906 #endif /* CKSYSLOG */
14907
14908     if (ok) {
14909         ok = zvpass((char *)passwd);    /* Check password */
14910         debug(F101,"ckxlogin zvpass","",ok);
14911 #ifdef CK_PAM
14912     } else {
14913         /* Fake pam password failure for nonexistent users */
14914         sleep(1);
14915         printf("Authentication failure\n");
14916 #endif
14917     }
14918
14919     if (ok > 0 && isguest) {
14920 #ifndef NOPUSH
14921         nopush = 1;
14922 #endif /* NOPUSH */
14923         srvcdmsg = 1;
14924     }
14925     rc = ok;                            /* Set the return code */
14926     if ((char *)uidbuf != (char *)userid)
14927       ckstrncpy(uidbuf,(char *)userid,UIDBUFLEN); /* Remember username */
14928
14929   XCKXLOG:                              /* Common exit */
14930 #ifdef CKSYSLOG
14931     ckxsyslog = savlog;                 /* In case of GOTO above */
14932 #endif /* CKSYSLOG */
14933     if (rprompt) {
14934         cmsetp(psave);                  /* Restore original prompt */
14935         debug(F110,"ckxlogin restored",psave,0);
14936     }
14937     if (_u || _p || _a) {
14938         if (_u) free(_u);
14939         if (_p) free(_p);
14940         if (_a) free(_a);
14941     }
14942     return(rc);
14943 }
14944
14945 int
14946 ckxlogout() {
14947     doexit(GOOD_EXIT,0);                /* doexit calls zvlogout */
14948     return(0);                          /* not reached */
14949 }
14950 #endif /* CK_LOGIN */
14951
14952 #endif /* NOICP */