update changelog
[ckermit.git] / ckuusx.c
1 #include "ckcsym.h"
2
3 /*  C K U U S X --  "User Interface" common functions. */
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 module contains user interface functions needed by both the interactive
20   user interface and the command-line-only user interface.
21 */
22
23 /* Includes */
24
25 #include "ckcdeb.h"
26 #include "ckcasc.h"
27 #include "ckcker.h"
28 #include "ckuusr.h"
29 #include "ckcxla.h"
30
31 #ifndef NOHTERMCAP
32 #ifdef NOTERMCAP
33 #define NOHTERMCAP
34 #else
35 #ifndef BSD44
36 #define NOHTERMCAP
37 #else
38 #ifdef __bsdi__
39 #define NOHTERMCAP
40 #else
41 #ifdef OPENBSD
42 #define NOHTERMCAP
43 #else
44 #ifdef MACOSX
45 #define NOHTERMCAP
46 #endif /* MACOSX */
47 #endif /* OPENBSD */
48 #endif /* __bsdi__ */
49 #endif /* BSD44 */
50 #endif /* NOTERMCAP */
51 #endif /* NOHTERMCAP */
52
53 #ifndef NOTERMCAP
54 #ifdef BSD44
55 #ifndef NOHTERMCAP
56 #include <termcap.h>
57 #endif /* NOHTERMCAP */
58 #endif /* BSD44 */
59 #else  /* !BSD44 */
60 #ifdef linux
61 #include <term.h>
62 #endif /* linux */
63 #endif /* NOTERMCAP */
64
65 #ifdef OS2
66 #include <string.h>
67 _PROTOTYP(char * os2_gethostname, (void));
68 #define getpid _getpid
69 #endif /* OS2 */
70 #ifdef BSD44
71 #include <errno.h>
72 #endif /* BSD44 */
73
74 extern xx_strp xxstring;
75
76 #ifdef OS2
77 #include "ckcnet.h"
78 #else /* OS2 */
79 _PROTOTYP(int getlocalipaddr, (void));
80 _PROTOTYP(int istncomport, (void));
81 #ifndef NOCKGETFQHOST
82 _PROTOTYP( char * ckgetfqhostname,(char *));
83 #endif  /* NOCKGETFQHOST */
84 #ifndef NETCONN
85 /*
86   We should just pull in ckcnet.h here, but it causes a conflict with curses.h.
87 */
88 #ifdef TCPSOCKET
89 #define NETCONN
90 #else
91 #ifdef SUNX25
92 #define NETCONN
93 #else
94 #ifdef STRATUSX25
95 #define NETCONN
96 #else
97 #ifdef IBMX25
98 #define NETCONN
99 #else
100 #ifdef HPX25
101 #define NETCONN
102 #else
103 #ifdef DECNET
104 #define NETCONN
105 #else
106 #ifdef NPIPE
107 #define NETCONN
108 #else
109 #ifdef CK_NETBIOS
110 #define NETCONN
111 #ifdef SUPERLAT
112 #define NETCONN
113 #else
114 #endif /* SUPERLAT */
115 #endif /* TCPSOCKET */
116 #endif /* SUNX25 */
117 #endif /* STRATUSX25 */
118 #endif /* IBMX25 */
119 #endif /* HPX25 */
120 #endif /* DECNET */
121 #endif /* NPIPE */
122 #endif /* CK_NETBIOS */
123 #endif /* NETCONN */
124 #endif /* OS2 */
125
126 #ifndef TCPSOCKET
127 #ifdef MULTINET
128 #define TCPSOCKET
129 #endif /* MULTINET */
130 #ifdef DEC_TCPIP
131 #define TCPSOCKET
132 #endif /* DEC_TCPIP */
133 #ifdef WINTCP
134 #define TCPSOCKET
135 #endif /* WINTCP */
136 #ifdef TCPWARE
137 #define TCPSOCKET
138 #endif /* TCPWARE */
139 #endif /* TCPSOCKET */
140
141 #ifdef OS2
142 #ifdef NT
143 #include <windows.h>
144 #include <tapi.h>
145 #include "ckntap.h"
146 #else /* NT */
147 #define INCL_VIO
148 #include <os2.h>
149 #endif /* NT */
150 #ifdef COMMENT                          /* Would you believe */
151 #undef COMMENT                          /* <os2.h> defines this ? */
152 #endif /* COMMENT */
153 #ifdef CK_NETBIOS
154 #include "ckonbi.h"
155 #endif /* CK_NETBIOS */
156
157 #include "ckocon.h"
158 extern ascreen commandscreen;
159 #ifdef KUI
160 #include "ikui.h"
161 #endif /* KUI */
162 #endif /* OS2 */
163
164 #ifdef NT
165 #include "cknwin.h"
166 #endif /* NT */
167 #ifdef OS2
168 #include "ckowin.h"
169 #include "ckosyn.h"
170 #endif /* OS2 */
171
172 #ifdef CK_TAPI
173 extern int tttapi;
174 extern int tapipass;
175 #endif /* CK_TAPI */
176
177 #ifdef CK_KERBEROS
178 #include "ckuath.h"
179 #endif /* CK_KERBEROS */
180
181 #ifndef WINTCP
182 #include <signal.h>
183 #endif /* WINTCP */
184
185 #ifdef VMS
186 #include <descrip.h>
187 #include <ssdef.h>
188 #include <stsdef.h>
189 #ifndef OLD_VMS
190 #include <lib$routines.h>  /* Not for VAX C 2.3 */
191 #else
192 #include <libdef.h>
193 #endif /* OLD_VMS */
194 #ifdef WINTCP
195 #include <signal.h>
196 #endif /* WINTCP */
197 #endif /* VMS */
198
199 #ifdef DCLFDOPEN
200 /* fdopen() needs declaring because it's not declared in <stdio.h> */
201 _PROTOTYP( FILE * fdopen, (int, char *) );
202 #endif /* DCLFDOPEN */
203
204 #ifdef DCLPOPEN
205 /* popen() needs declaring because it's not declared in <stdio.h> */
206 _PROTOTYP( FILE * popen, (char *, char *) );
207 #endif /* DCLPOPEN */
208
209 int tt_crd = 0;                         /* Carriage return display */
210 int interrupted = 0;                    /* Interrupted from keyboard flag */
211 static int fxd_inited = 0;              /* Fullscreen stuff initialized */
212
213 #ifdef DEBUG
214 char debfil[CKMAXPATH+1];               /* Debugging log file name */
215 #endif /* DEBUG */
216
217 #ifdef TLOG
218 char trafil[CKMAXPATH+1];               /* Transaction log file name */
219 #endif /* TLOG */
220
221 char sesfil[CKMAXPATH+1];               /* Session log file name */
222
223 #ifdef CKLOGDIAL
224 char diafil[CKMAXPATH+1];               /* Connection log file name */
225 char cxlogbuf[CXLOGBUFL+1];             /* Connection log record buffer */
226 int cx_active = 0;                      /* Connection is active */
227 extern int dialog;
228 #endif /* CKLOGDIAL */
229
230 #ifdef DYNAMIC
231 static char *cmdstr = NULL;             /* Place to build generic command */
232 #else
233 #ifdef pdp11
234 static char cmdstr[256];
235 #else
236 static char cmdstr[4096];
237 #endif /* pdp11 */
238 #endif /* DYNAMIC */
239
240 #ifndef NOMSEND
241 char fspec[CMDBL+4];                    /* Filename string for \v(filespec) */
242 int fspeclen = CMDBL;
243 #else
244 char fspec[CKMAXPATH+4];
245 int fspeclen = CKMAXPATH;
246 #endif /* NOMSEND */
247
248 char * rfspec = NULL;                   /* Received filespec: local */
249 char * prfspec = NULL;                  /* Preliminary rfspec */
250 char * sfspec = NULL;                   /* Sent filespec: local */
251 char * psfspec = NULL;                  /* Preliminary sfspec */
252 char * srfspec = NULL;                  /* Received filespec: remote */
253 char * psrfspec = NULL;                 /* Preliminary srfspec */
254 char * rrfspec = NULL;                  /* Sent filespec: remote */
255 char * prrfspec = NULL;                 /* Preliminary rrfspec */
256
257 int success = 1,                        /* Command success/failure flag */
258     cmdlvl = 0,                         /* Command level */
259     action = 0,                         /* Action selected on command line */
260     slogts = 0,                         /* Session-log timestamps on/off */
261 #ifdef UNIX
262     sessft = XYFT_T,                    /* Session log file type */
263 #else
264     sessft = XYFT_B,                    /* (text for UNIX binary for others) */
265 #endif /* UNIX */
266     pflag = 1,                          /* Print prompt */
267     msgflg = 1;                         /* Print informational messages */
268
269 extern int xaskmore, saveask;           /* More-prompting */
270
271 #ifdef CK_APC
272 extern int apcactive;
273 #endif /* CK_APC */
274 /* External variables */
275
276 extern int local, quiet, binary, network, what, parity, xitsta, escape,
277   tlevel, bgset, backgrd, xsuspend, cmdint, nettype, seslog, dfloc;
278
279 extern int cmd_rows, cmd_cols, xcmdsrc;
280
281 extern char cmdfil[];
282
283 #ifdef VMS
284 extern int batch;
285 #endif /* VMS */
286
287 #ifdef datageneral                      /* 2/12/92 ENH */
288 #include <sysid.h>
289 extern int con_reads_mt, conint_ch, conint_avl;
290 #endif /* datageneral */
291
292 extern long speed;
293
294 extern char ttname[], *dftty, *cmarg, **cmlist, *versio, myhost[];
295
296 #ifndef NOCSETS
297 extern int fcharset, tcharset, xfrxla;
298 extern struct csinfo fcsinfo[], tcsinfo[];
299 #endif /* NOCSETS */
300
301 #ifdef OS2
302 extern unsigned char colorcmd;
303 #endif /* OS2 */
304
305 #ifdef NOXFER
306
307 int fdispla = XYFD_N;
308
309 #else  /* NOXFER is not defined */
310
311 #ifdef OS2                              /* File transfer display type */
312 int fdispla = XYFD_C;                   /* Curses (fullscreen) if we have it */
313 #else
314 #ifdef CK_CURSES
315 int fdispla = XYFD_C;
316 #else
317 int fdispla = XYFD_S;                   /* Otherwise CRT */
318 #endif /* CK_CURSES */
319 #endif /* OS2 */
320
321 extern struct ck_p ptab[];
322 extern int protocol, xfrbel, xfrint;
323
324 #ifdef STREAMING
325 extern int streaming, streamok;
326 #endif /* STREAMING */
327
328 /* Used internally */
329
330 _PROTOTYP( VOID screenc, (int, char, long, char *) );
331 _PROTOTYP( VOID screeng, (int, char, long, char *) );
332
333 #ifdef CK_CURSES
334 #ifndef DYNAMIC
335 static char xtrmbuf[TRMBUFL];           /* tgetent() buffer */
336 char * trmbuf = xtrmbuf;
337 #else
338 char * trmbuf = NULL;
339 #endif /* DYNAMIC */
340 _PROTOTYP( static VOID dpyinit, (void) );
341 _PROTOTYP( static long shocps, (int, long, long) );
342 _PROTOTYP( static long shoetl, (long, long, long, long) );
343 #endif /* CK_CURSES */
344
345 static int ft_win = 0;  /* Fullscreen file transfer display window is active */
346
347 /* Variables declared here */
348
349 static char * skreason[] = {
350     "",                                 /* 0 */
351     "Remote file not older",            /* SKP_DAT */
352     "Identical modification times",     /* SKP_EQU */
353     "Type",                             /* SKP_TYP */
354     "Size",                             /* SKP_SIZ */
355     "Name collision",                   /* SKP_NAM */
356     "Exception List",                   /* SKP_EXL */
357     "Dot file",                         /* SKP_DOT */
358     "Backup file",                      /* SKP_BKU */
359     "Recovery not needed",              /* SKP_RES */
360     "Access denied",                    /* SKP_ACC */
361     "Not a regular file",               /* SKP_NRF */
362     "Simulated",                        /* SKP_SIM */
363     "Simulated - Remote file older",    /* SKP_XUP */
364     "Simulated - No remote file",       /* SKP_XNX */
365 };
366 static int nskreason = (sizeof(skreason) / sizeof(char *));
367
368 char *
369 gskreason(n) int n; {
370     return((n > 0 && n < nskreason) ? skreason[n] : "");
371 }
372
373 char pktfil[CKMAXPATH+1];               /* Packet log file name */
374
375 #ifndef NOMSEND                         /* Multiple SEND */
376 char *msfiles[MSENDMAX];
377 #endif /* NOMSEND */
378
379 #ifdef CK_TIMERS
380 extern long rttdelay;
381 extern int  rttflg;
382 #endif /* CK_TIMERS */
383 extern int rcvtimo;
384
385 #ifdef CK_RESEND
386 extern int sendmode;
387 extern long sendstart, rs_len;
388 #endif /* CK_RESEND */
389
390 #ifdef CK_PCT_BAR                       /* File transfer thermometer */
391 int thermometer = 1;                    /* ON by default */
392 #endif /* CK_PCT_BAR */
393
394 #ifdef GFTIMER
395 CKFLOAT gtv = -1.0, oldgtv = -1.0;
396 #else
397 #ifndef OS2
398 static
399 #endif /* OS2 */
400   long gtv = -1L, oldgtv = -1L;
401 #endif /* GFTIMER */
402
403 extern int server, bctu, rptflg, ebqflg, spsiz, urpsiz, wmax, czseen, cxseen,
404   winlo, displa, timint, npad, ebq, bctr, rptq, atcapu, lpcapu,
405   swcapu, wslotn, wslotr, rtimo, mypadn, sq, capas, rpsiz, tsecs,
406   pktlog, lscapu, dest, srvdis, wslots, spackets, spktl, rpktl,
407   retrans, wcur, numerrs, fsecs, whatru, crunched, timeouts,
408   rpackets, fncnv, bye_active, discard, inserver, diractive, cdactive;
409
410 extern long filcnt, filrej, ffc, tfc, rptn, fsize, filcps, tfcps, cps, peakcps;
411
412 long oldcps = 0L;
413
414 extern CHAR *rdatap, padch, seol, ctlq, mypadc, eol, *epktmsg;
415 extern char *xfrmsg;
416
417 #ifdef IKSDB
418 FILE * dbfp = NULL;                     /* File pointer to database file */
419
420 int dbenabled = 1;                      /* Flag for database is enabled */
421 extern int ikdbopen;                    /* Flag for database is open */
422
423 unsigned long mydbseek = 0L;            /* Seek pointer to my record */
424 int mydbslot = 0;                       /* My slot number */
425 unsigned long myflags = 0L;             /* My flags */
426 unsigned long myatype = 0L;             /* My authorization type */
427 unsigned long myamode = 0L;             /* My authorization mode */
428 unsigned long mystate = 0L;             /* My state (SEND, RECEIVE, etc) */
429 unsigned long mypid = 0L;               /* My PID */
430 unsigned long myip = 0L;                /* My IP address */
431 unsigned long peerip = 0L;              /* My peer's IP address */
432
433 unsigned long dbip = 0L;                /* IP address in db record */
434 unsigned long dbpid = 0L;               /* PID in db record */
435 unsigned long dbflags = 0L;             /* Flags field in db record */
436 unsigned long dblastused = 0L;          /* Last in-use record in db */
437 char dbrec[DB_RECL];                    /* Database record buffer */
438
439 char * dbdir   = NULL;                  /* Database directory */
440 char * dbfile  = NULL;                  /* Database file full pathname */
441 char myhexip[33] = { NUL, NUL };        /* My IP address in hex */
442 char peerhexip[33] = { NUL, NUL };      /* Client's IP address in hex */
443 #endif /* IKSDB */
444
445 #ifdef GFTIMER
446 extern CKFLOAT fpfsecs, fptsecs, fpxfsecs;
447 #else
448 extern long xfsecs;
449 #endif /* GFTIMER */
450 #endif /* NOXFER */
451
452 #ifdef TCPSOCKET
453 #ifdef NEWFTP
454 extern char * ftp_host, ftp_srvtyp[];
455 extern int ftp_csx, ftp_csl, ftp_deb;
456 #endif /* NEWFTP */
457 extern char myipaddr[];
458 #endif /* TCPSOCKET */
459
460 #ifndef NOICP
461 #ifndef NOSPL
462     extern struct mtab *mactab;         /* For ON_EXIT macro. */
463     extern int nmac;
464 #endif /* NOSPL */
465 #ifdef DCMDBUF
466 extern char *cmdbuf;                    /* Command buffer */
467 #else
468 extern char cmdbuf[];                   /* Command buffer */
469 #endif /* DCMDBUF */
470 extern int cmd_quoting;
471 #endif /* NOICP */
472
473 #ifndef NOCCTRAP
474 #ifdef NT
475 #include <setjmpex.h>
476 #else /* NT */
477 #include <setjmp.h>
478 #endif /* NT */
479 #include "ckcsig.h"
480 extern ckjmpbuf cmjbuf;
481 #endif /* NOCCTRAP */
482
483 extern int xfiletype, nscanfile;
484
485 int
486 shoesc(escape) int escape; {
487     extern char * ccntab[];             /* C0 control character name table */
488     extern int tt_escape;
489     if ((escape > 0 && escape < 32) || (escape == 127)) {
490         printf(" Escape character: Ctrl-%c (ASCII %d, %s): %s\r\n",
491                ctl(escape),
492                escape,
493                (escape == 127 ? "DEL" : ccntab[escape]),
494                tt_escape ? "enabled" : "disabled"
495                );
496     } else {
497         printf(" Escape character: Code %d",escape);
498         if (escape > 160 && escape < 256)
499           printf(" (%c)",escape);
500         printf(": %s\r\n", tt_escape ? "enabled" : "disabled"); 
501     }
502     return(0);
503 }
504
505 #ifndef NOXFER
506 /*  P R E S E T  --  Reset global protocol variables  */
507
508 extern int recursive;
509
510 #ifdef PATTERNS
511 int patterns = SET_AUTO;                /* Whether to use filename patterns */
512 extern int g_patterns;                  /* For saving and restoring */
513 #else
514 int patterns = SET_OFF;
515 #endif /* PATTERNS */
516
517 #ifndef NOICP
518 #ifdef CK_LABELED
519 extern int g_lf_opts, lf_opts;
520 #endif /* CK_LABELED */
521 extern int g_matchdot, g_usepipes, usepipes;
522 extern int g_binary, g_proto, g_displa, g_spath, g_rpath, g_fncnv;
523 extern int g_recursive;
524 extern int g_xfermode, xfermode;
525 extern int g_urpsiz, g_spsizf, g_spsiz;
526 extern int g_spsizr, g_spmax, g_wslotr, g_prefixing, g_fncact;
527 extern int g_fnspath, g_fnrpath, g_skipbup;
528 extern int nolinks;
529 #ifdef CKSYMLINK
530 extern int zgfs_link;
531 #endif /* CKSYMLINK */
532 #ifndef NOSPL
533 extern int g_pflg, pwflg, g_pcpt, pwcrypt;
534 extern char * g_pswd, pwbuf[];
535 #endif /* NOSPL */
536 #endif /* NOICP */
537
538 extern int spsizf, spsizr, spmax, prefixing, fncact, fnspath, fnrpath;
539 extern int moving;                      /* SEND criteria */
540 extern char sndafter[], sndbefore[], *sndexcept[], *rcvexcept[];
541 extern long sndlarger, sndsmaller, calibrate, skipbup;
542 extern int rmailf, rprintf;
543 extern char optbuf[];
544
545 #ifdef PIPESEND
546 extern char * g_sfilter, * g_rfilter;
547 extern char * sndfilter, * rcvfilter;
548 #endif /* PIPESEND */
549 extern char ** sndarray;
550
551 VOID
552 ftreset() {
553 #ifndef NOICP
554     int i;
555     extern char * filefile;
556     extern int reliable, xreliable, c_save, ss_save, slostart, urclear;
557     extern int oopts, omode, oname, opath, kactive, autopath;
558     extern char * snd_move;             /* Directory to move sent files to */
559     extern char * snd_rename;           /* What to rename sent files to */
560     extern char * rcv_move;
561     extern char * rcv_rename;
562     extern char * g_snd_move;
563     extern char * g_snd_rename;
564     extern char * g_rcv_move;
565     extern char * g_rcv_rename;
566
567 #ifdef CK_TMPDIR
568     extern int f_tmpdir;
569     extern char savdir[];
570 #endif /* CK_TMPDIR */
571
572 #ifdef CK_SPEED
573 #ifdef COMMENT
574     extern int f_ctlp;
575     extern short s_ctlp[], ctlp[];
576 #endif /* COMMENT */
577 #endif /* CK_SPEED */
578
579 #ifndef NOCSETS
580     extern int fcs_save, tcs_save;
581     extern int g_xfrxla, xfrxla;
582 #endif /* NOCSETS */
583
584 /* Restore / reset per-command file-transfer switches */
585
586     makestr(&snd_move,g_snd_move);
587     makestr(&rcv_move,g_rcv_move);
588     makestr(&snd_rename,g_snd_rename);
589     makestr(&rcv_rename,g_rcv_rename);
590
591     kactive = 0;                        /* Kermit protocol no longer active */
592     oopts = -1;                         /* O-Packet Options */
593     omode = -1;                         /* O-Packet Transfer Mode */
594     oname = -1;                         /* O-Packet Filename Options */
595     opath = -1;                         /* O-Packet Pathname Options */
596
597 #ifdef CK_RESEND
598     rs_len = 0L;                        /* REGET position */
599 #endif /* CK_RESEND */
600
601 #ifdef COMMENT
602 #ifdef CK_SPEED
603     if (f_ctlp) {
604         for (i = 0; i < 256; i++)
605           ctlp[i] = s_ctlp[i];
606         f_ctlp = 0;
607     }
608 #endif /* CK_SPEED */
609 #endif /* COMMENT */
610
611 #ifdef CK_TMPDIR
612     if (f_tmpdir) {                     /* If we changed to download dir */
613         zchdir((char *) savdir);        /* Go back where we came from */
614         f_tmpdir = 0;
615     }
616 #endif /* CK_TMPDIR */
617
618     calibrate = 0L;                     /* Calibration run */
619     if (xreliable > -1) {
620         reliable = xreliable;
621         debug(F101,"ftreset reliable","",reliable);
622     }
623     urclear = 0;
624
625     if (autopath) {                     /* SET RECEIVE PATHNAMES AUTO */
626         fnrpath = PATH_AUTO;
627         autopath = 0;
628     }
629     if (filefile) {                     /* File list */
630         zclose(ZMFILE);
631         makestr(&filefile,NULL);
632     }
633     if (c_save > -1) {                  /* Block Check Type */
634         bctr = c_save;
635         c_save = -1;
636     }
637     if (ss_save > -1) {                 /* Slow Start */
638         slostart = ss_save;
639         ss_save = -1;
640     }
641 #ifdef CK_LABELED
642     if (g_lf_opts > -1) {
643         lf_opts = g_lf_opts;            /* Restore labeled transfer options */
644         g_lf_opts = -1;
645     }
646 #endif /* CK_LABELED */
647
648 #ifndef NOCSETS
649     if (tcs_save > -1) {                /* Character sets */
650         tcharset = tcs_save;
651         tcs_save = -1;
652     }
653     if (fcs_save > -1) {
654         fcharset = fcs_save;
655         fcs_save = -1;
656     }
657     if (g_xfrxla > -1) {
658         xfrxla = g_xfrxla;
659         g_xfrxla = -1;
660     }
661     setxlatype(tcharset,fcharset);      /* Translation type */
662 #endif /* NOCSETS */
663
664 #ifdef NETCONN
665 #ifndef NOSPL
666     if (g_pswd) {
667         ckstrncpy(pwbuf,g_pswd,PWBUFL);
668         makestr(&g_pswd,NULL);
669     }
670     if (g_pflg > -1) {
671         pwflg = g_pflg;
672         g_pflg = -1;
673     }
674     if (g_pcpt > -1) {
675         pwcrypt = g_pcpt;
676         g_pcpt = -1;
677     }
678 #endif /* NOSPL */
679 #endif /* NETCONN */
680
681     if (g_binary > -1) {                /* File type */
682         binary = g_binary;
683         g_binary = -1;
684     }
685     if (g_xfermode > -1) {              /* Transfer mode */
686         xfermode = g_xfermode;
687         g_xfermode = -1;
688     }
689 #ifdef PATTERNS
690     if (g_patterns > -1) {              /* Filename patterns */
691         patterns = g_patterns;
692         g_patterns = -1;
693     }
694 #endif /* PATTERNS */
695
696     if (g_usepipes > -1) {
697         usepipes = g_usepipes;
698         g_usepipes = -1;
699     }
700     if (g_matchdot > -1) {
701         matchdot = g_matchdot;
702         g_matchdot = -1;
703     }
704     if (g_proto > -1) {                 /* Protocol */
705         protocol = g_proto;
706         g_proto = -1;
707     }
708     if (g_urpsiz > -1) {
709         urpsiz = g_urpsiz;
710         debug(F101,"ftreset restoring urpsiz","",urpsiz);
711         g_urpsiz = -1;
712     }
713     if (g_spsizf > -1) {
714         spsizf = g_spsizf;
715         debug(F101,"ftreset restoring spsizf","",spsizf);
716         g_spsizf = -1;
717     }
718     if (g_spsiz > -1) {
719         spsiz = g_spsiz;
720         debug(F101,"ftreset restoring spsiz","",spsiz);
721         g_spsiz = -1;
722     }
723     if (g_spsizr > -1) {
724         spsizr = g_spsizr;
725         debug(F101,"ftreset restoring spsizr","",spsizr);
726         g_spsizr = -1;
727     }
728     if (g_spmax > -1) {
729         spmax = g_spmax;
730         g_spmax = -1;
731     }
732     if (g_wslotr > -1) {
733         wslotr = g_wslotr;
734         g_wslotr = -1;
735     }
736     if (g_prefixing > -1) {
737         prefixing = g_prefixing;
738         g_prefixing = -1;
739     }
740     if (g_fncact > -1) {
741         fncact = g_fncact;
742         g_fncact = -1;
743     }
744     if (g_fncnv > -1) {
745         fncnv = g_fncnv;
746         g_fncnv = -1;
747     }
748     if (g_fnspath > -1) {
749         fnspath = g_fnspath;
750         g_fnspath = -1;
751     }
752     if (g_fnrpath > -1) {
753         fnrpath = g_fnrpath;
754         g_fnrpath = -1;
755     }
756     if (g_skipbup > -1) {
757         skipbup = g_skipbup;
758         g_skipbup = -1;
759     }
760     nolinks = 2;                        /* /FOLLOWLINKS is never global */
761     recursive = 0;                      /* /RECURSIVE can never be global */
762     xfiletype = -1;
763
764     if (g_displa > -1) {                /* File transfer display */
765         fdispla = g_displa;
766         g_displa = -1;
767     }
768     if (g_spath > -1) {                 /* Send pathnames */
769         fnspath = g_spath;
770         g_spath = -1;
771     }
772     if (g_rpath > -1) {                 /* Receive pathnames */
773         fnrpath = g_rpath;
774         g_rpath = -1;
775     }
776     if (g_fncnv > -1) {                 /* Filename conversion */
777         fncnv = g_fncnv;
778         g_fncnv = -1;
779     }
780 #ifdef PIPESEND
781     makestr(&sndfilter,g_sfilter);      /* Send filter */
782     makestr(&rcvfilter,g_rfilter);      /* Receive filter */
783 #endif /* PIPESEND */
784
785 #ifndef NOFRILLS
786     rmailf = rprintf = 0;               /* MAIL and PRINT modifiers for SEND */
787     optbuf[0] = NUL;                    /* MAIL and PRINT options */
788 #endif /* NOFRILLS */
789
790     moving = 0;                         /* Reset delete-after-send indicator */
791     sndafter[0]  = NUL;                 /* Reset SEND selection switches */
792     sndbefore[0] = NUL;
793
794     for (i = 0; i < NSNDEXCEPT; i++) {
795         if (sndexcept[i])
796           free(sndexcept[i]);
797         sndexcept[i] = NULL;
798         if (rcvexcept[i])
799           free(rcvexcept[i]);
800         rcvexcept[i] = NULL;
801     }
802     sndlarger =  -1L;
803     sndsmaller = -1L;
804 #ifdef GFTIMER
805     gtv = -1.0;
806     oldgtv = -1.0;
807 #else
808     gtv = -1L;
809     oldgtv = -1L;
810 #endif /* GFTIMER */
811 #endif /* NOICP */
812 }
813 #endif /* NOXFER */
814
815 char *
816 ttgtpn() {                              /* Get typical port name */
817 /*
818   Ideally this routine would be implemented in each of the cku?io.* modules,
819   but that requires changing the API definition.
820 */
821     return(
822 #ifdef OS2
823 #ifdef OS2ONLY
824 "COM1"
825 #else  /* OS2ONLY */
826 "TAPI [ name ] or COM1"
827 #endif /* OS2ONLY */
828 #else  /* OS2 */
829 #ifdef VMS
830 "TXA0:, TTA0:, or LTA0:"
831 #else  /* VMS */
832 #ifdef SOLARIS
833 "/dev/cua/a"
834 #else  /* SOLARIS */
835 #ifdef HPUX10
836 "/dev/cua0p0"
837 #else  /* HPUX10 */
838 #ifdef HPUX
839 "/dev/cua00"
840 #else  /* HPUX */
841 #ifdef __FreeBSD__
842 "/dev/cuaa0"
843 #else  /* __FreeBSD__ */
844 #ifdef __linux__
845 "/dev/ttyS0"
846 #else  /* __linux__ */
847 #ifdef BSD44
848 "/dev/tty00"
849 #else  /* BSD44 */
850 #ifdef OSK
851 "/t1"
852 #else  /* OSK */
853 #ifdef QNX
854 "/dev/ser1"
855 #else  /* QNX */
856 #ifdef QNX6
857 "/dev/ser1"
858 #else  /* QNX6 */
859 #ifdef UNIXWARE
860 "/dev/term/00 or /dev/tty00"
861 #else  /* UNIXWARE */
862 #ifdef CK_SCOV5
863 "/dev/tty1A"
864 #else  /* CK_SCOV5 */
865 #ifdef CK_SCO32V4
866 "/dev/tty1A"
867 #else  /* CK_SCO32V4 */
868 #ifdef M_XENIX
869 "/dev/tty1A"
870 #else  /* M_XENIX */
871 #ifdef AIXRS
872 "/dev/tty0"
873 #else  /* AIXRS */
874 #ifdef DGUX
875 "/dev/tty00"
876 #else  /* DGUX */
877 #ifdef datageneral
878 "@con1"
879 #else  /* datageneral */
880 #ifdef IRIX
881 "/dev/ttym0"
882 #else  /* IRIX */
883 #ifdef SUNOS4
884 "/dev/ttyh0"
885 #else  /* SUNOS4 */
886 #ifdef SV68R3V6
887 "/dev/scc0"
888 #else  /* SV68R3V6 */
889 #ifdef MOTSV88R4
890 "/dev/contty00"
891 #else  /* MOTSV88R4 */
892 #ifdef NEXT
893 "/dev/cufa"
894 #else
895 #ifdef OSF
896 "/dev/ttyd1"
897 #else
898 #ifdef SINIX
899 "/dev/ttyc1"
900 #else
901 #ifdef UNIX
902 "/dev/cua, /dev/acu, /dev/tty0, etc"
903 #else  /* UNIX */
904 "(sorry no example available)"
905 #endif /* UNIX */
906 #endif /* SINIX */
907 #endif /* OSF */
908 #endif /* NEXT */
909 #endif /* MOTSV88R4 */
910 #endif /* SV68R3V6 */
911 #endif /* SUNOS4 */
912 #endif /* IRIX */
913 #endif /* datageneral */
914 #endif /* DGUX */
915 #endif /* AIX */
916 #endif /* M_XENIX */
917 #endif /* CK_SCO32V4 */
918 #endif /* CK_SCOV5 */
919 #endif /* UNIXWARE */
920 #endif /* QNX6 */
921 #endif /* QNX */
922 #endif /* OSK */
923 #endif /* BSD44 */
924 #endif /* __linux__ */
925 #endif /* __FreeBSD__ */
926 #endif /* HPUX */
927 #endif /* HPUX10 */
928 #endif /* SOLARIS */
929 #endif /* VMS */
930 #endif /* OS2 */
931            );
932 }
933
934 /*  C K _ E R R S T R  --  Return message from most recent system error */
935
936 #ifdef CKROOT
937 extern int ckrooterr;
938 #endif /* CKROOT */
939
940 char *
941 ck_errstr() {
942 #ifdef USE_STRERROR
943 #ifndef CK_ANSILIBS
944     /* Should have been declared in <string.h> */
945 _PROTOTYP( char * strerror, (int) );
946 #endif /* CK_ANSILIBS */
947 #ifdef CKROOT
948     if (ckrooterr)
949       return("Off limits");
950 #endif /* CKROOT */
951     return(strerror(errno));
952 #else  /* !USE_STRERROR */
953 #ifdef VMS
954     extern char * ckvmserrstr(unsigned long);
955 #ifdef CKROOT
956     if (ckrooterr)
957       return("Off limits");
958 #endif /* CKROOT */
959     return(ckvmserrstr(0L));
960 #else  /* !VMS */
961 #ifdef BSD44
962 #ifdef __386BSD__
963 #ifndef NDSYSERRLIST
964     extern int sys_nerr;
965     extern char *sys_errlist[];
966 #endif /* NDSYSERRLIST */
967 #else  /* !__386BSD__ */
968 #ifndef __bsdi__
969 #ifndef NDSYSERRLIST
970     extern int sys_nerr;
971     extern const char *const sys_errlist[];
972 #endif /* NDSYSERRLIST */
973 #endif /* __bsdi__ */
974 #endif /* __386BSD__ */
975 #ifdef CKROOT
976     if (ckrooterr)
977       return("Off limits");
978     else
979 #endif /* CKROOT */
980     if (errno >= sys_nerr)
981       return("Error number out of range");
982     else
983       return((char *) sys_errlist[errno]);
984 #else /* !BSD44 */
985 #ifdef ATTSV
986 #ifndef NDSYSERRLIST
987     extern int sys_nerr;
988     extern char *sys_errlist[];
989 #endif /* NDSYSERRLIST */
990 #ifdef CKROOT
991     if (ckrooterr)
992       return("Off limits");
993     else
994 #endif /* CKROOT */
995     if (errno >= sys_nerr)
996       return("Error number out of range");
997     else
998       return((char *) sys_errlist[errno]);
999 #else /* !ATTSV */
1000 #ifdef BSD4
1001 #ifndef NDSYSERRLIST
1002     extern int sys_nerr;
1003     extern char *sys_errlist[];
1004 #endif /* NDSYSERRLIST */
1005 #ifdef CKROOT
1006     if (ckrooterr)
1007       return("Off limits");
1008     else
1009 #endif /* CKROOT */
1010     if (errno >= sys_nerr)
1011       return("Error number out of range");
1012     else
1013       return((char *) sys_errlist[errno]);
1014 #else
1015 #ifdef OS2
1016 #ifndef NDSYSERRLIST
1017     extern char *sys_errlist[];
1018 #endif /* NDSYSERRLIST */
1019 #ifdef NT
1020     extern int_sys_nerr;
1021 #endif /* NT */
1022     char *e;
1023 #ifdef CKROOT
1024     if (ckrooterr)
1025       return("Off limits");
1026 #endif /* CKROOT */
1027     e = (errno > -1
1028 #ifdef NT
1029          && errno <= _sys_nerr
1030 #endif /* NT */
1031          ) ?
1032 #ifdef NT
1033          (char *) sys_errlist[errno]
1034 #else /* NT */
1035          /* I don't know how to get a CLIB error string in OS/2 */
1036          strerror(errno)
1037 #endif /* NT */
1038              : "";
1039     return(e ? e : "");
1040 #else /* OS2 */
1041     return("");
1042 #endif /* OS2 */
1043 #endif /* BSD4 */
1044 #endif /* ATTSV */
1045 #endif /* BSD44 */
1046 #endif /* VMS */
1047 #endif /* USE_STRERROR */
1048 }
1049
1050 #ifdef PATTERNS
1051 /*
1052   Filename pattern recognition lists for automatic text/binary switching.
1053   These are somewhat passe after the addition of scanfile()  (7.0).
1054   But with the addition of FTP [M]GET, they're back in style (8.0).
1055
1056   Although, with FTP the lists need to be used in the reverse.  With
1057   Kermit the list is used to imply the types of the local system.  Whereas
1058   with FTP, the list must be used to imply the type of the remote system.
1059   Therefore, all platforms must now support all of the lists.
1060 */
1061 char *txtpatterns[FTPATTERNS+1] = { NULL, NULL };
1062 char *binpatterns[FTPATTERNS+1] = { NULL, NULL };
1063 /*
1064   Default pattern lists for each platform...
1065
1066   NOTE: In most cases we leave ".hlp", ".ini", and ".scr" alone; although they
1067   are traditionally text types, they are binary in Windows.  So they are
1068   handled by the prevailing SET FILE TYPE, rather than automatically.
1069   Similarly for ".dat", ".inf", and so on.  Also ".ps" since PostScript files
1070   are not always text.  ".log" is omitted since logs can be text or binary,
1071   except in VMS they are usually text, etc etc.
1072
1073   Later (Sep 2003): Add PostScript to binary patterns.
1074 */
1075 static char *txtp[SYS_MAX][FTPATTERNS] = {
1076     /* UNKNOWN */ {
1077         NULL, NULL
1078     },
1079     {                                   /* UNIX */
1080     "*.txt","*.c","*.h","*.r","*.w","*.cpp","*.cc","*.ksc","*.bwr","*.upd",
1081     "*.html","*.htm","*.mss","*.tex","*.nr","[Mm]akefile", "*.hex", "*.hqx",
1082     "*.for","*.f77","*.f","*.F","*.s","*.pas","*.java","*.el","*.lisp","*.sh",
1083     "*.m4","*.perl","*.pl","*.pod","*.pm","*.awk","*.sno","*.spt","*.sed",
1084     "*.ksc","*.TXT", "*read.me", "*READ.ME", ".*", "*/.*", "*.mem","*.mac",
1085     NULL
1086     },
1087     {                                   /* WIN32 */
1088     "*.txt","*.ksc","*.htm","*.html","*.bat","*.cmd","*.jav","*.asm", "*.hex",
1089     "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w",
1090     "*.java", "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile",
1091     "*.mem","*.mac","*.cc","*.pl","*.pod","*.pm","*.m4",NULL
1092     },
1093     {                                   /* VMS */
1094     "*.com","*.txt","*.c",  "*.for","*.pas","*.rno","*.rnh","*.mar","*.bli",
1095     "*.hlp","*.mss","*.doc","*.bwr","*.cld","*.hex","*.bas","*.ini","*.log",
1096     "*.mms","*.opt","*.ksc","*.perl","*.pl","*.pod","*.pm","*.sno","*.spt",
1097     "*.mem",NULL
1098     },
1099     {                                   /* OS2 */
1100     "*.txt","*.ksc","*.htm","*.html","*.bat","*.cmd","*.jav","*.asm", "*.hex",
1101     "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w",
1102     "*.java", "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile",
1103     NULL
1104     },
1105     {                                   /* DOS */
1106     "*.txt","*.ksc","*.htm","*.bat","*.cmd","*.jav","*.asm", "*.hex",
1107     "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w",
1108     "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile", NULL
1109     },
1110     {                                   /* TOPS-10 */
1111     "*.cmd","*.hlp","*.doc","*.ini","*.txt","*.mac","*.for","*.sai","*.bli",
1112     "*.pas","*.sno","*.spt","*.pcl","*.mss","*.rno","*.b36","*.tex","*.pub",
1113     "*.req","*.r36","*.mem","*.bwr","*.ccl","*.ctl","*.rnh","*.ksc",NULL
1114     },
1115     {                                   /* TOPS-20 */
1116     "*.cmd","*.hlp","*.doc","*.ini","*.txt","*.mac","*.for","*.sai","*.bli",
1117     "*.pas","*.sno","*.spt","*.pcl","*.mss","*.rno","*.b36","*.tex","*.pub",
1118     "*.req","*.r36","*.mem","*.bwr","*.ccl","*.ctl","*.rnh","*.ksc",NULL
1119     },
1120     {                                   /* STRATUS VOS */
1121     "*.txt","*.ksc","*.htm","*.html","*.bat", "*.cmd","*.jav","*.asm","*.hex",
1122     "*.hqx","*.c",  "*.h",  "*.w",   "*.java","*.bwr","*.upd","*.ttp","*.cm",
1123     "*.pl1","*.emacs", "read.me", "*.pl", "makefile", NULL
1124     },
1125     {                                   /* DG AOS/VS */
1126     "*.txt", "*.c", "*.h", "*.w", "*.er", "*.bwr", "*.upd", "read.me",
1127     "*.cli", "*.ksc", NULL
1128     },
1129     {                                   /* OSK */
1130     "*.c","*.cpp","*.h","*.a","*akefile", /* program sources */
1131     "*.for","*.f77","*.f","*.F","*.s","*.pas","*.java","*.el","*.lisp",
1132     "*.sh","*.perl","*.awk","*.sno","*.spt","*.sed",
1133     "*.txt","*.w",                      /* general text */
1134     "*.ksc","*.bwr","*.upd",
1135     "*.html","*.htm","*.mss","*.tex","*.nr","*.hex", "*.hqx",
1136     "*.TXT", "*read.me", "*READ.ME", ".*", "*/.*",
1137     NULL
1138     }
1139 };
1140
1141 /* Note: .DOC added to (some) binary patterns June 1998... Microsoft wins. */
1142
1143 static char *binp[SYS_MAX][FTPATTERNS] = {
1144     {                                   /* UNKNOWN */
1145     NULL, NULL
1146     },
1147     {                                   /* UNIX */
1148     "*.gz","*.Z","*.tgz","*.gif", "*.tar","*.zip","*.o","*.so","*.a","*.out",
1149     "*.exe", "*.jpg", "*.jpeg", "*.tif","*.tiff", "*.pdf", "*.so.*", "*.class",
1150     "*.rpm", "*.bmp", "*.bz2", "*.BMP", "*.dll", "*.doc", "*.vxd", "*.dcx",
1151     "*.xl*", "*.lzh", "*.lhz", "*.au", "*.voc", "*.mpg", "*.mpeg","[wk]ermit",
1152     "*.ps", NULL
1153     },
1154     {                                   /* WIN32 */
1155     "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
1156     "*.class","*.cla","*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
1157     "*.bmp", "*.tif", "*.tar", "*.gz",  "*.tgz", "*.xl*", "*.doc", "*.vxd",
1158     "*.pdf", "*.lzh", "*.vxd", "*.snd", "*.au", "* .voc", "*.mpg", "*.mpeg",
1159     "*.ps", NULL
1160     },
1161     {                                   /* VMS */
1162     "*.exe","*.obj","*.bak","*.bin","*.adf","*.stb","*.mai","*.sys","*.dmp",
1163     "*.ps", "*.dat","*.par", NULL
1164     },
1165     {                                   /* OS2 */
1166     "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
1167     "*.class", "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
1168     "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
1169     "*.pdf", "*.ps", "*.lzh", NULL
1170     },
1171     {                                   /* DOS */
1172     "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
1173     "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
1174     "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
1175     "*.pdf", "*.ps", "*.lzh", NULL
1176     },
1177     {                                   /* TOPS10 */
1178     "*.exe","*.sav","*.bin","*.rim","*.rel","*.unv","*.lib","*.tap","*.dvi",
1179     "*.ps", NULL
1180     },
1181     {                                   /* TOPS20 */
1182     "*.exe","*.sav","*.bin","*.rim","*.rel","*.unv","*.lib","*.tap","*.dvi",
1183     "*.ps", NULL
1184     },
1185     {                                   /* STRATUS VOS */
1186     "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
1187     "*.class", "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
1188     "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
1189     "*.pdf", "*.ps", "*.lzh", "*.pm", NULL
1190     },
1191     {                                   /* DG */
1192     "*.ob", "*.pr", "*.dmp", "*.ps", NULL
1193     },
1194     { /* OSK */
1195     "*.gz","*.Z","*.z","*.tgz","*.lhz","*.tar", /* archivers */
1196     "*.zip","*.ar","*.zoo","*.rpm","*.lzh",
1197     /* object files, libraries, executables */
1198     "*.r","*.l","*.exe", "*.dll", "*.so.*", "*.class",
1199     /* images */
1200     "*.gif", "*.jpg", "*.jpeg", "*.tif","*.tiff", "*.pdf", "*.ps",
1201     "*.bmp", "*.bz2", "*.BMP","*.pcx",
1202     NULL
1203     }
1204 };
1205
1206 /*
1207   Set up default pattern lists so they can be freed and re-malloc'd.
1208   Each pattern list must terminated by a null element.
1209 */
1210 VOID
1211 initpat() {
1212     int i;
1213     for (i = 0; i < FTPATTERNS; i++) {
1214         txtpatterns[i] = NULL;
1215         binpatterns[i] = NULL;
1216     }
1217     for (i = 0; i < FTPATTERNS; i++) {
1218 #ifdef UNIX
1219         makestr(&(txtpatterns[i]),txtp[SYS_UNIX][i]);
1220 #else /* UNIX */
1221 #ifdef OS2
1222 #ifdef NT
1223         makestr(&(txtpatterns[i]),txtp[SYS_WIN32][i]);
1224 #else /* NT */
1225         makestr(&(txtpatterns[i]),txtp[SYS_OS2][i]);
1226 #endif /* NT */
1227 #else /* OS2 */
1228 #ifdef VMS
1229         makestr(&(txtpatterns[i]),txtp[SYS_VMS][i]);
1230 #else /* VMS */
1231 #ifdef STRATUS
1232         makestr(&(txtpatterns[i]),txtp[SYS_VOS][i]);
1233 #else /* STRATUS */
1234 #ifdef datageneral
1235         makestr(&(txtpatterns[i]),txtp[SYS_DG][i]);
1236 #else /* datageneral */
1237 #ifdef OSK
1238         makestr(&(txtpatterns[i]),txtp[SYS_OSK][i]);
1239 #else /* OSK */
1240         makestr(&(txtpatterns[i]),txtp[SYS_UNK][i]);
1241 #endif /* OSK */
1242 #endif /* datageneral */
1243 #endif /* STRATUS */
1244 #endif /* VMS */
1245 #endif /* OS2 */
1246 #endif /* UNIX */
1247         if (!txtp[i])
1248           break;
1249     }
1250     for (i = 0; i < FTPATTERNS; i++) {
1251 #ifdef UNIX
1252         makestr(&(binpatterns[i]),binp[SYS_UNIX][i]);
1253 #else /* UNIX */
1254 #ifdef OS2
1255 #ifdef NT
1256         makestr(&(binpatterns[i]),binp[SYS_WIN32][i]);
1257 #else /* NT */
1258         makestr(&(binpatterns[i]),binp[SYS_OS2][i]);
1259 #endif /* NT */
1260 #else /* OS2 */
1261 #ifdef VMS
1262         makestr(&(binpatterns[i]),binp[SYS_VMS][i]);
1263 #else /* VMS */
1264 #ifdef STRATUS
1265         makestr(&(binpatterns[i]),binp[SYS_VOS][i]);
1266 #else /* STRATUS */
1267 #ifdef datageneral
1268         makestr(&(binpatterns[i]),binp[SYS_DG][i]);
1269 #else /* datageneral */
1270 #ifdef OSK
1271         makestr(&(binpatterns[i]),binp[SYS_OSK][i]);
1272 #else /* OSK */
1273         makestr(&(binpatterns[i]),binp[SYS_UNK][i]);
1274 #endif /* OSK */
1275 #endif /* datageneral */
1276 #endif /* STRATUS */
1277 #endif /* VMS */
1278 #endif /* OS2 */
1279 #endif /* UNIX */
1280         if (!binp[i])
1281           break;
1282     }
1283 }
1284
1285 /*
1286   m a t c h n a m e  --  Compare filename with text & binary name patterns.
1287
1288   Returns:
1289     0 if name matches a text pattern but not a binary pattern.
1290     1 if name matches a binary pattern but not a text pattern.
1291    -1 if name matches no patterns.
1292    -2 if name matches a binary pattern and a text pattern.
1293 */
1294 int
1295 matchname(filename, local, os) char * filename; int local; int os; {
1296     int rc = -1;                        /* Return code */
1297     char * name, * p;
1298 #ifdef OS2ORUNIX
1299     char tmpbuf[CKMAXPATH+1];
1300 #endif /* OS2ORUNIX */
1301
1302     name = filename ? filename : "";    /* Copy of original arg */
1303     if (patterns && *name) {            /* If PATTERNS ON... */
1304         int i;
1305
1306 #ifdef OS2ORUNIX
1307         if (ckmatch("*.~[1-9]*~",name,1,1)) { /* Name has backup suffix? */
1308             int k;
1309             k = ckstrncpy(tmpbuf,name,CKMAXPATH+1); /* Yes, copy and strip */
1310             for (i = k - 3; i > 4; i--) {
1311                 if (tmpbuf[i] == '~' && tmpbuf[i-1] == '.') {
1312                     tmpbuf[i-1] = NUL;
1313                     break;
1314                 }
1315             }
1316             name = tmpbuf;              /* And point to stripped copy */
1317         }
1318 #endif /* OS2ORUNIX */
1319         zstrip(name,&p);                /* Strip pathname too */
1320         name = p;
1321
1322         if (local) {
1323             if (txtpatterns[0]) {       /* Search text patterns */
1324                 for (i = 0; i < FTPATTERNS && txtpatterns[i]; i++) {
1325                     if (ckmatch(txtpatterns[i],name,filecase,1)) {
1326                         rc = 0;
1327                         break;
1328                     }
1329                 }
1330             }
1331             if (binpatterns[0]) {       /* And search binary patterns */
1332                 for (i = 0; i < FTPATTERNS && binpatterns[i]; i++) {
1333                     if (ckmatch(binpatterns[i],name,filecase,1)) {
1334                         rc = (rc > -1) ? -2 : 1;
1335                         break;
1336                     }
1337                 }
1338             }
1339         } else {
1340             if (os >= 0 && os < SYS_MAX) {
1341                 if (txtp[os][0]) {
1342                     for (i = 0; i < FTPATTERNS && txtp[os][i]; i++) {
1343                         if (ckmatch(txtp[os][i],name,filecase,1)) {
1344                             rc = 0;
1345                             break;
1346                         }
1347                     }
1348                 }
1349                 if (binp[os][0]) {
1350                     for (i = 0; i < FTPATTERNS && binp[os][i]; i++) {
1351                         if (ckmatch(binp[os][i],name,filecase,1)) {
1352                             rc = (rc > -1) ? -2 : 1;
1353                             break;
1354                         }
1355                     }
1356                 }
1357             }
1358         }
1359     }
1360     debug(F111,"matchname",name,rc);
1361     return(rc);
1362 }
1363 #endif /* PATTERNS */
1364
1365 #ifdef UNICODE
1366 #ifndef NOEVENMAX
1367 #define EVENMAX
1368 #endif /* NOEVENMAX */
1369 #endif /* UNICODE */
1370
1371 /*  S C A N F I L E  --  Analyze a file's contents  */
1372
1373 /*
1374   Call with:
1375     name:    Pointer to name of existing file.
1376     flag:    Pointer to int in which to return additional numeric data.
1377
1378   Returns:
1379     -1 on failure (to open file or to read from it).
1380     Integer, 0..4, on success indicating file type:
1381      0 = 7-bit text (flag = -1)
1382      1 = UTF-8 text (flag = -1)
1383      2 = UCS-2 text (flag =  0: big-endian; flag = 1: little-endian)
1384      3 = 8-bit text (flag =  0: no C1 bytes; flag = 1: includes C1 bytes)
1385      4 = binary     (flag = -1)
1386
1387   If UNICODE is defined:
1388
1389    1. If file begins with a valid BOM, it is believed.  Otherwise we
1390       read the first 4K of the file (since it might be email with verbose
1391       headers) and analyze it:
1392
1393    2. If file contains only valid UTF-8 sequences, we call it UTF-8;
1394       otherwise:
1395
1396    3. If the file contains lots of alternate 0 bytes, we call it UCS-2, and
1397       set the polarity according to whether the preponderance of them are in
1398       even or odd positions; otherwise:
1399
1400    4. If EVENMAX is defined and the file contains lots of alternate bytes that
1401       are identical, even if they aren't zero, and the number of such bytes
1402       is at least four times the length of the maximum run of alternating
1403       identical bytes of the opposite polarity, we call it UCS-2; otherwise:
1404
1405    5. If the file contained no bytes with their 8th bits on and no controls
1406       other than CR, LF, HT, and FF, we call it ASCII; otherwise:
1407
1408    6. If it contains C0 control characters other than CR, LF, HT, and FF, we
1409       call it binary; otherwise:
1410
1411    7. We call it 8-bit text, character set unknown (could be Latin-1 or
1412       anything else).
1413
1414    Note that malformed UTF-8 is not diagnosed as UTF-8.
1415
1416    If UNICODE is not defined:
1417
1418    1. If the file contains C0 control characters other than CR, LF, HT, and
1419       FF, we call it binary; otherwise:
1420
1421    2. If the file contains any 8-bit bytes, we call it 8-bit text; otherwise:
1422
1423    3. We call it 7-bit text.
1424
1425    In the non-Unicode case, UCS-2 is diagnosed as binary, but UTF-8 as
1426    8-bit text.
1427
1428    There is no significant speed difference between the Unicode and
1429    non-Unicode cases.
1430 */
1431 int
1432 scanfile(name,flag,nscanfile) char * name; int * flag, nscanfile; {
1433     FILE * fp;                          /* File pointer */
1434     unsigned char buf[SCANFILEBUF];     /* File data buffer for analysis */
1435     int x, val = -1, count = 0;         /* Workers */
1436     int rc = -1;                        /* Return code */
1437     int pv = -1;                        /* Pattern-match value */
1438     int eof = 0;                        /* Flag for file EOF encountered */
1439     int bytes = 0;                      /* Total byte count */
1440 #ifdef UNICODE
1441     unsigned int c0, c1;                /* First 2 file bytes (for BOM) */
1442 #endif /* UNICODE */
1443     extern int pipesend, filepeek;
1444
1445     register int i;                     /* Loop control */
1446     int readsize = 0;                   /* How much to read */
1447     int eightbit = 0;                   /* Number of bytes with 8th bit on */
1448     int c0controls = 0;                 /* C0 non-text control-char counter */
1449     int c0noniso = 0;                   /* C0 non-ISO control-char counter */
1450     int c1controls = 0;                 /* C1 control-character counter */
1451     unsigned int c;                     /* Current character */
1452     int runmax = 0;                     /* Longest run of 0 bytes */
1453     int runzero = 0;                    /* Run of 0 bytes */
1454     int pctzero = 0;                    /* Percentage of 0 bytes */
1455     int txtcz = 0;
1456 #ifdef CK_CTRLZ
1457     extern int eofmethod;
1458 #endif /* CK_CTRLZ */
1459
1460 #ifdef UNICODE
1461     int notutf8 = 0;                    /* Nonzero if definitely not UTF-8 */
1462     int utf8state = 0;                  /* UTF-8 recognizer state */
1463     int oddzero = 0;                    /* Number of 0 bytes in odd postions */
1464     int evenzero = 0;                   /* and in even positions */
1465     int lfnul = 0;                      /* Number of <LF><NUL> sequences */
1466     int crlf = 0;                       /* Number of <CRLF> sequences */
1467 #else
1468     int notutf8 = 1;
1469 #endif /* UNICODE */
1470
1471 #ifdef COMMENT
1472 #ifdef EVENMAX
1473     int oddrun = 0, oddmax = 0, oddbyte = 0, oddmaxbyte = 0;
1474     int evenrun = 0, evenmax = 0, evenbyte = 0, evenmaxbyte = 0;
1475 #endif /* EVENMAX */
1476 #endif /* COMMENT */
1477
1478 #ifndef NOXFER
1479     if (pipesend || calibrate || sndarray) /* Only for real files */
1480       return(-1);
1481 #endif /* NOXFER */
1482     debug(F111,"scanfile",name,nscanfile);
1483 #ifdef PATTERNS
1484     if (!filepeek) {
1485         pv = matchname(name,1,-1);
1486         if (pv < 0)
1487           rc = -1;
1488         else
1489           rc = (pv == 1) ? FT_BIN : FT_TEXT;
1490         debug(F111,"scanfile !filepeek result",name,rc);
1491         return(rc);
1492     }
1493 #endif /* PATTERNS */
1494
1495 #ifdef VMS
1496 /* We don't scan in VMS where text files have various record formats in  */
1497 /* which record headers contain seemingly non-text bytes.  So the best   */
1498 /* we can do in VMS is tell whether the file is text or binary, period.  */
1499     {
1500         int b, x;
1501         b = binary;                     /* Save current binary setting */
1502         if (zopeni(ZIFILE,name) > 0) {  /* In VMS this sets binary */
1503             x = binary;                 /* Get result */
1504             zclose(ZIFILE);             /* Close the file */
1505             binary = b;                 /* Restore previous binary setting */
1506             rc = x ? FT_BIN : FT_TEXT;
1507             val = 0;
1508             goto xscanfile;
1509         }
1510     }
1511 #endif /* VMS */
1512
1513     eof = 0;                            /* End-of-file reached indicator */
1514 #ifdef OS2
1515     fp = fopen(name, "rb");             /* Open the file in binary mode */
1516 #else
1517     fp = fopen(name, "r");
1518 #endif /* OS2 */
1519
1520     if (!fp)                            /* Failed? */
1521       return(-1);
1522
1523     while (1) {                         /* One or more gulps from file */
1524         if (eof) {                      /* EOF from last time? */
1525             debug(F111,"scanfile at EOF",name,bytes);
1526             if (runzero > runmax)
1527               runmax = runzero;
1528             break;
1529         }
1530         if (nscanfile < 0) {            /* Reading whole file */
1531             readsize = SCANFILEBUF;
1532         } else {                        /* Reading first nscanfilee bytes */
1533             readsize = nscanfile - bytes;
1534             if (readsize < 1)
1535               break;
1536             if (readsize > SCANFILEBUF)
1537               readsize = SCANFILEBUF;
1538         }
1539         debug(F101,"scanfile readsize","",readsize);
1540         count = fread(buf,1,readsize,fp); /* Read a buffer */
1541         if (count == EOF || count == 0) {
1542             debug(F111,"scanfile EOF",name,count);
1543             break;
1544         }
1545         debug(F111,"scanfile buffer ok",name,count);
1546
1547         if (bytes == 0 && count > 8) {
1548             /* PDF files can look like text in the beginning. */
1549             if (!ckstrcmp((char *)buf,"%PDF-1.",7,1)) {
1550                 if (isdigit(buf[7])) {
1551                     if (buf[8] == '\015' ||
1552                         count > 9 && buf[8] == SP && buf[9] == '\015') {
1553 #ifdef DEBUG
1554                         buf[8] = NUL;
1555                         debug(F110,"scanfile PDF",buf,0);
1556 #endif /* DEBUG */
1557                         binary = 1;     /* But they are binary. */
1558                         break;
1559                     }
1560                 }
1561             } else if (!ckstrcmp((char *)buf,"%!PS-Ado",8,1)) {
1562                 /* Ditto for PostScript */
1563 #ifdef DEBUG
1564                 int i;
1565                 for (i = 8; i < count; i++) {
1566                     if (buf[i] < '!') {
1567                         buf[i] = NUL;
1568                         break;
1569                     }
1570                 }
1571                 debug(F110,"scanfile PostScript",buf,0);
1572 #endif /* DEBUG */
1573                 binary = 1;
1574                 break;
1575 #ifndef NOPCLSCAN
1576             } else if (!ckstrcmp((char *)buf,") HP-PCL",8,1)) {
1577                 /* HP PCL printer language */
1578 #ifdef DEBUG
1579                 int i;
1580                 for (i = 8; i < count; i++) {
1581                     if (buf[i] < '!') {
1582                         buf[i] = NUL;
1583                         break;
1584                     }
1585                 }
1586                 debug(F110,"scanfile PCL",buf,0);
1587 #endif /* DEBUG */
1588                 binary = 1;
1589                 break;
1590             } 
1591 #endif /* NOPCLSCAN */
1592 #ifndef NOPJLSCAN
1593               else if (buf[0] == '\033' && (buf[1] == 'E' || buf[1] == '%')) {
1594                 /* Ditto for PJL Job printer header */
1595 #ifdef DEBUG
1596                 int i;
1597                 for (i = 2; i < count; i++) {
1598                     if (buf[i] < '!') {
1599                         buf[i] = NUL;
1600                         break;
1601                     }
1602                 }
1603                 debug(F110,"scanfile PJL Job printer header",buf,0);
1604 #endif /* DEBUG */
1605                 binary = 1;
1606                 break;
1607 #endif /* NOPJLSCAN */
1608             }
1609         }
1610
1611 #ifdef UNICODE
1612         if (bytes == 0 && count > 1) {
1613             int incl_cnt = 0;
1614
1615             /* First look for BOM */
1616
1617             c0 = (unsigned)((unsigned)buf[0]&0xFF); /* First file byte */
1618             c1 = (unsigned)((unsigned)buf[1]&0xFF); /* Second byte */
1619
1620             if (c0 == 0xFE && c1 == 0xFF) {     /* UCS-2 BE */
1621                 rc = FT_UCS2;
1622                 val = 0;
1623                 debug(F111,"scanfile UCS2 BOM BE",ckitoa(val),rc);
1624                 incl_cnt++;
1625             } else if (c0 == 0xFF && c1 == 0xFE) { /* UCS-2 LE */
1626                 rc = FT_UCS2;
1627                 val = 1;
1628                 debug(F111,"scanfile UCS2 BOM LE",ckitoa(val),rc);
1629                 incl_cnt++;
1630             } else if (count > 2) if (c0 == 0xEF && c1 == 0xBB &&
1631                        (unsigned)((unsigned)buf[2]&0xFF) == 0xBF) {
1632                 rc = FT_UTF8;
1633                 debug(F111,"scanfile UTF8 BOM",ckitoa(val),rc);
1634                 incl_cnt++;
1635             }
1636             if (incl_cnt) {             /* Have BOM */
1637                 bytes += count;
1638                 goto xscanfile;
1639             }
1640         }
1641 #endif /* UNICODE */
1642
1643         bytes += count;                 /* Count bytes read */
1644         eof = feof(fp);                 /* Flag for at EOF  */
1645
1646         for (i = 0; i < count; i++) {   /* For each byte... */
1647             c = (unsigned)buf[i];       /* For ease of reference */
1648             if (!c) {                   /* Zero byte? */
1649 #ifdef EVENMAX
1650                 if (i&1)                /* In odd position */
1651                   oddzero++;
1652                 else
1653                   evenzero++;           /* In even position */
1654 #endif /* EVENMAX */
1655                 runzero++;
1656             } else {                    /* Not a zero byte */
1657                 if (runzero > runmax)
1658                   runmax = runzero;
1659                 if (runmax > 2)         /* That's all we need to be certain */
1660                   break;                /* it's a binary file. */
1661                 runzero = 0;
1662             }
1663
1664 #ifdef COMMENT
1665 #ifdef EVENMAX
1666
1667 /* This is to catch UCS-2 with a non-ASCII, non-Latin-1 repertoire  */
1668
1669             if (i > 1) {              /* Look for runs of alternating chars */
1670                 if (i&1) {
1671                     if (c == buf[i-2]) { /* In odd positions */
1672                         oddrun++;
1673                         oddbyte = c;
1674                     } else {
1675                         oddmax = oddrun;
1676                         oddmaxbyte = oddbyte;
1677                     }
1678                 } else {                /* and even positions */
1679                     if (c == buf[i-2]) {
1680                         evenrun++;
1681                         evenbyte = c;
1682                     } else {
1683                         evenmax = evenrun;
1684                         evenmaxbyte = evenbyte;
1685                     }
1686                 }
1687             }
1688 #endif /* EVENMAX */
1689 #endif /* COMMENT */
1690
1691             if ((c & 0x80) == 0) {      /* We have a 7-bit byte */
1692 #ifdef UNICODE
1693                 if (i > 0 && c == 10) { /* Linefeed */
1694                     if (buf[i-1] == 0) lfnul++; /* Preceded by NUL */
1695                     else if (buf[i-1] == 13) crlf++; /* or by CR... */
1696                 }
1697 #endif /* UNICODE */
1698                 if (c < ' ') {          /* Check for CO controls */
1699                     if (c != LF && c != CR && c != HT && c != FF) {
1700                         c0controls++;
1701                         if (c != ESC && c != SO && c != SI)
1702                           c0noniso++;
1703                     }
1704                     if ((c == '\032')   /* Ctrl-Z */
1705 #ifdef COMMENT
1706                         && eof && (i >= count - 2)
1707 #endif /* COMMENT */
1708                         ) {
1709                         c0controls--;
1710                         c0noniso--;
1711 #ifdef CK_CTRLZ
1712                         if (eofmethod == XYEOF_Z && txtcz == 0) {
1713                             if (c0controls == 0) /* All text prior to Ctrl-Z */
1714                               txtcz = 1;
1715                         }
1716 #endif /* CK_CTRLZ */
1717                     }
1718                 }
1719 #ifdef UNICODE
1720                 if (!notutf8 && utf8state) { /* In UTF-8 sequence? */
1721                     utf8state = 0;
1722                     debug(F000,"scanfile","7-bit byte in UTF8 sequence",c);
1723                     notutf8++;          /* Then it's not UTF-8 */
1724                     continue;
1725                 }
1726 #endif /* UNICODE */
1727             } else {                    /* We have an 8-bit byte */
1728                 eightbit++;             /* Count it */
1729                 if (c >= 0x80 && c < 0xA0) /* Check for C1 controls */
1730                   c1controls++;
1731 #ifdef UNICODE
1732                 if (!notutf8) {         /* If it might still be UTF8... */
1733                     switch (utf8state) { /* Enter the UTF-8 state machine */
1734                       case 0:            /* First byte... */
1735                         if ((c & 0xE0) == 0xC0) { /* Tells number of */
1736                             utf8state = 1;        /* subsequent bytes */
1737                         } else if ((c & 0xF0) == 0xE0) {
1738                             utf8state = 2;
1739                         } else if ((c & 0xF8) == 0xF0) {
1740                             utf8state = 3;
1741                         } else {
1742                             notutf8++;
1743                         }
1744                         break;
1745                       case 1:           /* Subsequent byte */
1746                       case 2:
1747                       case 3:
1748                         if ((c & 0xC0) != 0x80) { /* Must start with 10 */
1749                             debug(F000,"scanfile",
1750                                   "bad byte in UTF8 sequence",c);
1751                             notutf8++;
1752                             break;
1753                         }
1754                         utf8state--;    /* Good, one less in this sequence */
1755                         break;
1756                       default:          /* Shouldn't happen */
1757                         debug(F111,"scanfile","bad UTF8 state",utf8state);
1758                         notutf8++;
1759                     }
1760                 }
1761 #endif /* UNICODE */
1762             }
1763         }
1764     }
1765     fclose(fp);                         /* Close the file */
1766     debug(F101,"scanfile bytes","",bytes);
1767
1768     if (bytes == 0)                     /* If nothing was read */
1769       return(-1);                       /* we're done. */
1770
1771 #ifdef EVENMAX
1772     /* In case we had a run that never broke... */
1773 #ifdef COMMENT
1774     if (oddmax == 0) {
1775         oddmax = oddrun;
1776         oddmaxbyte = oddbyte;
1777     }
1778     if (evenmax == 0) {
1779         evenmax = evenrun;
1780         evenmaxbyte = evenbyte;
1781     }
1782 #endif /* COMMENT */
1783     if (runmax == 0) {
1784         runmax = runzero;
1785     }
1786 #endif /* EVENMAX */
1787
1788 #ifdef UNICODE
1789     if (bytes > 100)                    /* Bytes is not 0 */
1790       pctzero = (evenzero + oddzero) / (bytes / 100);
1791     else
1792       pctzero = ((evenzero + oddzero) * 100) / bytes;
1793 #endif /* UNICODE */
1794
1795 #ifdef DEBUG
1796     if (deblog) {                       /* If debugging, dump statistics */
1797         debug(F101,"scanfile c0controls ","",c0controls);
1798         debug(F101,"scanfile c0noniso   ","",c0noniso);
1799         debug(F101,"scanfile c1controls ","",c1controls);
1800         debug(F101,"scanfile eightbit   ","",eightbit);
1801 #ifdef UNICODE
1802         debug(F101,"scanfile crlf       ","",crlf);
1803         debug(F101,"scanfile lfnul      ","",lfnul);
1804         debug(F101,"scanfile notutf8    ","",notutf8);
1805         debug(F101,"scanfile evenzero   ","",evenzero);
1806         debug(F101,"scanfile oddzero    ","",oddzero);
1807         debug(F101,"scanfile even/odd   ","",(evenzero / (oddzero + 1)));
1808         debug(F101,"scanfile odd/even   ","",(oddzero / (evenzero + 1)));
1809         debug(F101,"scanfile pctzero    ","",pctzero);
1810 #endif /* UNICODE */
1811 #ifdef COMMENT
1812 #ifdef EVENMAX
1813         debug(F101,"scanfile oddmax     ","",oddmax);
1814         debug(F101,"scanfile oddmaxbyte ","",oddmaxbyte);
1815         debug(F101,"scanfile evenmax    ","",evenmax);
1816         debug(F101,"scanfile evenmaxbyte","",evenmaxbyte);
1817 #endif /* EVENMAX */
1818 #endif /* COMMENT */
1819         debug(F101,"scanfile runmax     ","",runmax);
1820     }
1821 #endif /* DEBUG */
1822
1823 #ifdef UNICODE
1824     x = eightbit ? bytes / 20 : bytes / 4; /* For UCS-2... */
1825
1826     if (runmax > 2) {                   /* File has run of more than 2 NULs */
1827         debug(F100,"scanfile BIN runmax","",0);
1828         rc = FT_BIN;                    /* so it can't be any kind of text. */
1829         goto xscanfile;
1830
1831     } else if (rc == FT_UCS2 || (rc == FT_UTF8 && runmax == 0)) {
1832         goto xscanfile;                 /* File starts with a BOM */
1833
1834     } else if (eightbit > 0 && !notutf8) { /* File has 8-bit data */
1835         if (runmax > 0) {                  /* and runs of NULs */
1836             debug(F100,"scanfile BIN (nnUTF8) runmax","",0);
1837             rc = FT_BIN;                   /* UTF-8 doesn't have NULs */
1838         } else {                           /* No NULs */
1839             debug(F100,"scanfile UTF8 (nnUTF8 + runmax == 0)","",0);
1840             rc = FT_UTF8;                  /* and not not UTF-8, so is UTF-8 */
1841         }
1842         goto xscanfile;
1843     }
1844 /*
1845   For UCS-2 detection, see if the text contains lines delimited by
1846   ASCII controls and containing spaces, ASCII digits, or other ASCII
1847   characters, thus forcing the presence of a certain percentage of zero bytes.
1848   For this purpose require 20% zero bytes, with at least six times as many
1849   in even (odd) positions as in odd (even) positions.
1850 */
1851     if ((evenzero >= x && oddzero == 0) ||
1852         ((((evenzero / (oddzero + 1)) > 6) && (pctzero > 20)) &&
1853         (crlf == 0) &&
1854         (lfnul > 1))
1855         ) {
1856             debug(F100,"scanfile UCS2 noBOM BE (even/oddzero)","",0);
1857         rc = FT_UCS2;
1858         val = 0;
1859     } else if ((evenzero == 0 && oddzero >= x) ||
1860                ((((oddzero / (evenzero + 1)) > 6) && (pctzero > 20)) &&
1861                (crlf == 0) &&
1862                (lfnul > 1))
1863                ) {
1864         debug(F100,"scanfile UCS2 noBOM LE (even/oddzero)","",0);
1865         rc = FT_UCS2;
1866         val = 1;
1867
1868 #ifdef COMMENT
1869 #ifdef EVENMAX
1870 /*
1871   If the tests above fail, we still might have UCS-2 if there are significant
1872   runs of identical bytes in alternating positions, but only if it also has
1873   unusual C0 controls (otherwise we'd pick up hex files here).  NOTE: We
1874   don't actually do this -- EVENMAX is not defined (see comments above at
1875   first occurrence of EVENMAX).
1876 */
1877     } else if (c0noniso && evenmax > bytes / 4) {
1878         debug(F100,"scanfile UCS2 BE (evenmax)","",0);
1879         rc = FT_UCS2;
1880         val = 0;
1881     } else if (c0noniso && oddmax > bytes / 4) {
1882         debug(F100,"scanfile UCS2 LE (evenmax)","",0);
1883         rc = FT_UCS2;
1884         val = 1;
1885 #endif /* EVENMAX */
1886 #endif /* COMMENT */
1887
1888     }
1889 /*
1890   It seems to be UCS-2 but let's be more certain since there is no BOM...
1891   If the number of 7- and 8-bit characters is approximately equal, it might
1892   be a compressed file.  In this case we decide based on the name.
1893 */
1894     if (rc == FT_UCS2) {
1895         if (eightbit > 0) {
1896             int j, k;
1897             j = (c1controls * 100) / (c0controls + 1);
1898             debug(F101,"scanfile c1/c0      ","",j);
1899             k = (bytes * 100) / eightbit;
1900             debug(F101,"scanfile pct 8bit   ","",k);
1901             if (k > 40 && k < 60 && j > 60) {
1902                 if (ckmatch("{*.Z,*.gz,*.zip,*.ZIP}",name,1,1)) {
1903                     debug(F110,"scanfile 8-bit BIN compressed",name,0);
1904                     rc = FT_BIN;
1905                     goto xscanfile;
1906                 }
1907             }
1908         }
1909         /* Small file - not enough evidence unless ... */
1910
1911         if (bytes < 100) {
1912             if (oddzero != 0 && evenzero != 0) {
1913                 debug(F100,"scanfile small UCS2 doubtful","",0);
1914                 rc = FT_BIN;
1915                 goto xscanfile;
1916             } else if (oddzero == 0 && evenzero == 0) {
1917                 rc = eightbit ? FT_8BIT : FT_7BIT;
1918             }
1919         }
1920         goto xscanfile;                 /* Seems to be UCS-2 */
1921     }
1922
1923 /* If none of the above, it's probably not Unicode.  */
1924
1925     if (!eightbit) {                    /* It's 7-bit */
1926         if (c0controls) {               /* This would be strange */
1927             if ((c0noniso > 0) && (txtcz == 0)) {
1928                 debug(F100,"scanfile 7-bit BIN (c0coniso)","",0);
1929                 rc = FT_BIN;
1930             } else {
1931                 debug(F100,"scanfile 7-bit ISO2022 TEXT (no c0noniso)","",0);
1932                 rc = FT_7BIT;
1933             }
1934         } else {                        /* 7-bit text */
1935             debug(F100,"scanfile 7-bit TEXT (no c0controls)","",0);
1936             rc = FT_7BIT;
1937         }
1938     } else if (!c0noniso || txtcz) {    /* 8-bit text */
1939         debug(F100,"scanfile 8-bit TEXT (no c0noniso)","",0);
1940         rc = FT_8BIT;
1941         val = c1controls ? 1 : 0;
1942     } else {                            /* 8-bit binary */
1943         debug(F100,"scanfile 8-bit BIN (c0noniso)","",0);
1944         rc = FT_BIN;
1945     }
1946
1947 #else  /* !UNICODE */
1948
1949     if (c0noniso) {
1950         debug(F100,"scanfile 8-bit BIN (c0noniso)","",0);
1951         rc = FT_BIN;
1952     } else if (eightbit) {
1953         debug(F100,"scanfile 8-bit TEXT (no c0noniso)","",0);
1954         rc = FT_8BIT;
1955         val = c1controls ? 1 : 0;
1956     } else {
1957         debug(F100,"scanfile 7-bit TEXT (no c0noniso)","",0);
1958         rc = FT_7BIT;
1959     }
1960
1961 #endif /* UNICODE */
1962
1963   xscanfile:
1964     if (flag) *flag = val;
1965     debug(F101,"scanfile result     ","",rc);
1966     return(rc);
1967 }
1968
1969 /*  F I L E S E L E C T  --  Select this file for sending  */
1970
1971 int
1972 #ifdef CK_ANSIC
1973 fileselect(
1974     char *f, char *sa, char *sb, char *sna, char *snb,
1975     long minsiz, long maxsiz,
1976     int nbu, int nxlist,
1977     char ** xlist
1978 )
1979 #else
1980 fileselect(f,sa,sb,sna,snb,minsiz,maxsiz,nbu,nxlist,xlist)
1981  char *f,*sa,*sb,*sna,*snb; long minsiz,maxsiz; int nbu,nxlist; char ** xlist;
1982 #endif /* CK_ANSIC */
1983 /* fileselect */ {
1984     char *fdate;
1985     int n;
1986     long z;
1987
1988     if (!sa) sa = "";
1989     if (!sb) sb = "";
1990     if (!sna) sna = "";
1991     if (!snb) snb = "";
1992
1993 #ifdef CKSYMLINK
1994 #ifndef NOICP
1995 #ifndef NOXFER
1996     if (nolinks) {
1997         long zz;
1998         zz = zgetfs(f);
1999         debug(F111,"fileselect NOLINKS zgetfs",f,zz);
2000         if (zz < 0L)
2001           return(0);
2002         debug(F111,"fileselect NOLINKS zgfs_link",f,zgfs_link);
2003         if (zgfs_link)
2004           return(0);
2005     }
2006 #endif /* NOXFER */
2007 #endif /* NOICP */
2008 #endif /* CKSYMLINK */
2009
2010     debug(F110,"fileselect",f,0);
2011     if (*sa || *sb || *sna || *snb) {
2012         fdate = zfcdat(f);              /* Date/time of this file */
2013         if (!fdate) fdate = "";
2014         n = strlen(fdate);
2015         debug(F111,"fileselect fdate",fdate,n);
2016         if (n != 17)                    /* Failed to get it */
2017           return(1);
2018         /* /AFTER: */
2019         if (sa[0] && (strcmp(fdate,(char *)sa) <= 0)) {
2020             debug(F110,"fileselect sa",sa,0);
2021             /* tlog(F110,"Skipping (too old)",f,0); */
2022             return(0);
2023         }
2024         /* /BEFORE: */
2025         if (sb[0] && (strcmp(fdate,(char *)sb) >= 0)) {
2026             debug(F110,"fileselect sb",sb,0);
2027             /* tlog(F110,"Skipping (too new)",f,0); */
2028             return(0);
2029         }
2030         /* /NOT-AFTER: */
2031         if (sna[0] && (strcmp(fdate,(char *)sna) > 0)) {
2032             debug(F110,"fileselect sna",sna,0);
2033             /* tlog(F110,"Skipping (too new)",f,0); */
2034             return(0);
2035         }
2036         /* /NOT-BEFORE: */
2037         if (snb[0] && (strcmp(fdate,(char *)snb) < 0)) {
2038             debug(F110,"fileselect snb",snb,0);
2039             /* tlog(F110,"Skipping (too old)",f,0); */
2040             return(0);
2041         }
2042     }
2043     if (minsiz > -1L || maxsiz > -1L) { /* Smaller or larger */
2044         z = zchki(f);                   /* Get size */
2045         debug(F101,"fileselect filesize","",z);
2046         if (z < 0)
2047           return(1);
2048         if ((minsiz > -1L) && (z >= minsiz)) {
2049             debug(F111,"fileselect minsiz skipping",f,minsiz);
2050             /* tlog(F111,"Skipping (too big)",f,z); */
2051             return(0);
2052         }
2053         if ((maxsiz > -1L) && (z <= maxsiz)) {
2054             debug(F111,"fileselect maxsiz skipping",f,maxsiz);
2055             /* tlog(F110,"Skipping (too small)",f,0); */
2056             return(0);
2057         }
2058     }
2059     if (nbu) {                          /* Skipping backup files? */
2060         if (ckmatch(
2061 #ifdef CKREGEX
2062                     "*.~[0-9]*~"        /* Not perfect but close enough. */
2063 #else
2064                     "*.~*~"             /* Less close. */
2065 #endif /* CKREGEX */
2066                     ,f,filecase,1)) {
2067             debug(F110,"fileselect skipping backup",f,0);
2068             return(0);
2069         }
2070     }
2071     for (n = 0; xlist && n < nxlist; n++) {
2072         if (!xlist[n]) {
2073             debug(F101,"fileselect xlist empty",0,n);
2074             break;
2075         }
2076         if (ckmatch(xlist[n],f,filecase,1)) {
2077             debug(F111,"fileselect xlist",xlist[n],n);
2078             debug(F110,"fileselect skipping",f,0);
2079             return(0);
2080         }
2081     }
2082     if (xfiletype > -1) {
2083         n = scanfile(f,NULL,nscanfile);
2084         if (n < 0) {
2085             n = binary ? 1 : 0;
2086         } else {
2087             n = (n == FT_BIN) ? 1 : 0;
2088         }
2089         if (n != xfiletype)
2090           return(0);
2091     }
2092     debug(F110,"fileselect selecting",f,0);
2093     return(1);
2094 }
2095
2096
2097 #ifdef TCPSOCKET
2098 #ifdef NT
2099 extern int WSASafeToCancel;
2100 #endif /* NT */
2101 #endif /* TCPSOCKET */
2102
2103 VOID
2104 setflow() {
2105     extern int flow, autoflow, mdmtyp, cxtype, cxflow[];
2106 #ifndef NODIAL
2107     extern int dialcapas, dialfc;
2108     extern MDMINF * modemp[];
2109     MDMINF * p = NULL;
2110     long bits = 0;
2111 #endif /* NODIAL */
2112
2113     debug(F101,"setflow autoflow","",autoflow);
2114
2115 /* #ifdef COMMENT */
2116 /* WHY WAS THIS COMMENTED OUT? */
2117     if (!autoflow)                      /* Only if FLOW is AUTO */
2118       return;
2119 /* #endif */ /* COMMENT */
2120
2121     debug(F101,"setflow local","",local);
2122     debug(F101,"setflow network","",network);
2123     debug(F101,"setflow cxtype","",cxtype);
2124
2125 #ifdef TN_COMPORT
2126     if (network && istncomport()) {
2127         flow = cxflow[CXT_MODEM];
2128         debug(F101,"setflow TN_COMPORT flow","",flow);
2129         return;
2130     }
2131 #endif /* TN_COMPORT */
2132
2133     if (network || !local || cxtype == CXT_DIRECT) {
2134         flow = cxflow[cxtype];          /* Set appropriate flow control */
2135         debug(F101,"setflow flow","",flow);
2136         return;
2137     }
2138     if (cxtype != CXT_MODEM)            /* Connection type should be modem */
2139       return;
2140
2141 #ifndef NODIAL
2142     bits = dialcapas;                   /* Capability bits */
2143     if (!bits) {                        /* No bits? */
2144         p = modemp[mdmtyp];             /* Look in modem info structure */
2145         if (p)
2146           bits = p->capas;
2147     }
2148     if (dialfc == FLO_AUTO) {           /* If DIAL flow is AUTO */
2149 #ifdef CK_RTSCTS                        /* If we can do RTS/CTS flow control */
2150         if (bits & CKD_HW)              /* and modem can do it too */
2151           flow = FLO_RTSC;              /* then switch to RTS/CTS */
2152         else                            /* otherwise */
2153           flow = FLO_XONX;              /* use Xon/Xoff. */
2154 #else
2155 #ifndef NEXT
2156 #ifndef IRIX
2157         flow = FLO_XONX;                /* Use Xon/Xoff. */
2158 #endif /* IRIX */
2159 #endif /* NEXT */
2160 #endif /* CK_RTSCTS */
2161     }
2162 #endif /* NODIAL */
2163     debug(F101,"setflow modem flow","",flow);
2164     return;
2165 }
2166
2167 #ifndef NOLOCAL
2168 #ifdef CK_TRIGGER
2169
2170 /*  A U T O E X I T C H K  --  Check for CONNECT-mode trigger string  */
2171 /*
2172   Returns -1 if trigger not found, or else the trigger index, 0 or greater.
2173   (Replace with fancier and more efficient matcher later...)
2174   NOTE: to prevent unnecessary function call overhead, call this way:
2175
2176     x = tt_trigger[0] ? autoexitchk(c) : -1;
2177
2178 */
2179 int
2180 #ifdef CK_ANSIC
2181 autoexitchk(CHAR c)
2182 #else
2183 autoexitchk(c) CHAR c;
2184 #endif /* CK_ANSIC */
2185 /* autoexitchk */ {
2186     extern CHAR * tt_trmatch[];
2187     extern char * tt_trigger[];
2188     int i;
2189     for (i = 0; i < TRIGGERS; i++) {
2190         if (!tt_trigger[i]) {           /* No more triggers in list */
2191             break;
2192         } else if (*tt_trigger[i]) {
2193             if (!tt_trmatch[i])         /* Just starting? */
2194               tt_trmatch[i] = (CHAR *)tt_trigger[i]; /* Set match pointer */
2195             if (c == *tt_trmatch[i]) {  /* Compare this character */
2196                 tt_trmatch[i]++;        /* It matches */
2197                 if (!*tt_trmatch[i]) {  /* End of match string? */
2198                     tt_trmatch[i] = (CHAR *) tt_trigger[i]; /* Yes, rewind, */
2199                     debug(F101,"autoexitchk",tt_trigger[i],i); /* log, */
2200                     return(i);          /* and return success */
2201                 }
2202             } else                      /* No match */
2203               tt_trmatch[i] = (CHAR *) tt_trigger[i]; /* Rewind match string */
2204         } /* and go on the next match string */
2205     }
2206     return(-1);                         /* No match found */
2207 }
2208 #endif /* CK_TRIGGER */
2209
2210 #ifndef NOSHOW
2211 /*  S H O M D M  --  Show modem signals  */
2212
2213 VOID
2214 shomdm() {
2215 /*
2216   Note use of "\r\n" to make sure this report prints right, even when
2217   called during CONNECT mode.
2218 */
2219     int y;
2220     y = ttgmdm();
2221     switch (y) {
2222       case -3: printf(
2223                  "Modem signals unavailable in this version of Kermit\r\n");
2224                break;
2225       case -2: printf("No modem control for this device\r\n"); break;
2226       case -1: printf("Modem signals unavailable\r\n"); break;
2227       default:
2228 #ifndef MAC
2229         printf(
2230           " Carrier Detect      (CD):  %s\r\n",(y & BM_DCD) ? "On": "Off");
2231         printf(
2232           " Dataset Ready       (DSR): %s\r\n",(y & BM_DSR) ? "On": "Off");
2233 #endif /* MAC */
2234         printf(
2235           " Clear To Send       (CTS): %s\r\n",(y & BM_CTS) ? "On": "Off");
2236 #ifndef STRATUS
2237 #ifndef MAC
2238         printf(
2239           " Ring Indicator      (RI):  %s\r\n",(y & BM_RNG) ? "On": "Off");
2240 #endif /* MAC */
2241         printf(
2242           " Data Terminal Ready (DTR): %s\r\n",
2243 #ifdef NT
2244           "(unknown)"
2245 #else /* NT */
2246           (y & BM_DTR) ? "On": "Off"
2247 #endif /* NT */
2248           );
2249 #ifndef MAC
2250         printf(
2251           " Request To Send     (RTS): %s\r\n",
2252 #ifdef NT
2253           "(unknown)"
2254 #else /* NT */
2255           (y & BM_RTS) ? "On": "Off"
2256 #endif /* NT */
2257           );
2258 #endif /* MAC */
2259 #endif /* STRATUS */
2260     }
2261 #ifdef BETADEBUG
2262 #ifdef CK_TAPI
2263     if (tttapi && !tapipass) {
2264         LPDEVCFG        lpDevCfg = NULL;
2265         LPCOMMCONFIG    lpCommConfig = NULL;
2266         LPMODEMSETTINGS lpModemSettings = NULL;
2267         DCB *           lpDCB = NULL;
2268
2269         if (cktapiGetModemSettings(&lpDevCfg,&lpModemSettings,
2270                                     &lpCommConfig,&lpDCB)) {
2271             printf("\n");
2272             cktapiDisplayModemSettings(lpDevCfg,lpModemSettings,
2273                                        lpCommConfig,lpDCB);
2274         }
2275     }
2276 #endif /* CK_TAPI */
2277 #endif /* BETADEBUG */
2278 }
2279 #endif /* NOSHOW */
2280 #endif /* NOLOCAL */
2281
2282 #ifndef NOXFER
2283 /*  S D E B U  -- Record spar results in debugging log  */
2284
2285 VOID
2286 sdebu(len) int len; {
2287     debug(F111,"spar: data",(char *) rdatap,len);
2288     debug(F101," spsiz ","", spsiz);
2289     debug(F101," timint","",timint);
2290     debug(F101," npad  ","",  npad);
2291     debug(F101," padch ","", padch);
2292     debug(F101," seol  ","",  seol);
2293     debug(F101," ctlq  ","",  ctlq);
2294     debug(F101," ebq   ","",   ebq);
2295     debug(F101," ebqflg","",ebqflg);
2296     debug(F101," bctr  ","",  bctr);
2297     debug(F101," rptq  ","",  rptq);
2298     debug(F101," rptflg","",rptflg);
2299     debug(F101," lscapu","",lscapu);
2300     debug(F101," atcapu","",atcapu);
2301     debug(F101," lpcapu","",lpcapu);
2302     debug(F101," swcapu","",swcapu);
2303     debug(F101," wslotn","", wslotn);
2304     debug(F101," whatru","", whatru);
2305 }
2306 /*  R D E B U -- Debugging display of rpar() values  */
2307
2308 VOID
2309 rdebu(d,len) CHAR *d; int len; {
2310     debug(F111,"rpar: data",d,len);
2311     debug(F101," rpsiz ","", xunchar(d[0]));
2312     debug(F101," rtimo ","", rtimo);
2313     debug(F101," mypadn","",mypadn);
2314     debug(F101," mypadc","",mypadc);
2315     debug(F101," eol   ","",   eol);
2316     debug(F101," ctlq  ","",  ctlq);
2317     debug(F101," sq    ","",    sq);
2318     debug(F101," ebq   ","",   ebq);
2319     debug(F101," ebqflg","",ebqflg);
2320     debug(F101," bctr  ","",  bctr);
2321     debug(F101," rptq  ","",  d[8]);
2322     debug(F101," rptflg","",rptflg);
2323     debug(F101," capas ","", capas);
2324     debug(F101," bits  ","",d[capas]);
2325     debug(F101," lscapu","",lscapu);
2326     debug(F101," atcapu","",atcapu);
2327     debug(F101," lpcapu","",lpcapu);
2328     debug(F101," swcapu","",swcapu);
2329     debug(F101," wslotr","", wslotr);
2330     debug(F101," rpsiz(extended)","",rpsiz);
2331 }
2332
2333 #ifdef COMMENT
2334 /*  C H K E R R  --  Decide whether to exit upon a protocol error  */
2335
2336 VOID
2337 chkerr() {
2338     if (backgrd && !server) fatal("Protocol error");
2339 }
2340 #endif /* COMMENT */
2341 #endif /* NOXFER */
2342
2343 /*  F A T A L  --  Fatal error message */
2344
2345 VOID
2346 fatal(msg) char *msg; {
2347     extern int initflg;
2348     static int initing = 0;
2349     if (!msg) msg = "";
2350     debug(F111,"fatal",msg,initflg);
2351
2352     if (!initflg) {                     /* If called from prescan */
2353         if (initing)                    /* or called from sysinit() */
2354           exit(253);
2355         initing = 1;
2356         sysinit();
2357     }
2358
2359     debug(F111,"fatal",msg,xitsta);
2360     tlog(F110,"Fatal:",msg,0L);
2361 #ifdef VMS
2362     if (strncmp(msg,"%CKERMIT",8))
2363       conol("%CKERMIT-E-FATAL, ");
2364     conoll(msg);
2365 #else /* !VMS */
2366     conoll(msg);
2367 #endif /* VMS */
2368 #ifdef OS2
2369 #ifndef NOXFER
2370     if (xfrbel) {
2371         bleep(BP_FAIL);
2372         sleep(1);
2373         bleep(BP_FAIL);
2374     }
2375 #endif /* NOXFER */
2376
2377 #endif /* OS2 */
2378     doexit(BAD_EXIT,xitsta | 1);        /* Exit indicating failure */
2379 }
2380
2381 #ifndef NOXFER
2382 /*  B L D L E N  --  Make length-encoded copy of string  */
2383
2384 char *
2385 bldlen(str,dest) char *str, *dest; {
2386     int len;
2387     len = (int)strlen(str);
2388     if (len > 94)
2389       *dest = SP;
2390     else
2391       *dest = (char) tochar(len);
2392     strcpy(dest+1,str);                 /* Checked below in setgen() */
2393     return(dest+len+1);
2394 }
2395
2396
2397 /*  S E T G E N  --  Construct a generic command  */
2398 /*
2399   Call with Generic command character followed by three string arguments.
2400   Trailing strings are allowed to be empty ("").  Each string except the last
2401   non-empty string must be less than 95 characters long.  The final nonempty
2402   string is allowed to be longer.
2403 */
2404 CHAR
2405 #ifdef CK_ANSIC
2406 setgen(char type, char * arg1, char * arg2, char * arg3)
2407 #else
2408 setgen(type,arg1,arg2,arg3) char type, *arg1, *arg2, *arg3;
2409 #endif /* CK_ANSIC */
2410 /* setgen */ {
2411     char *upstr, *cp;
2412 #ifdef DYNAMIC
2413     if (!cmdstr)
2414       if (!(cmdstr = malloc(MAXSP + 1)))
2415         fatal("setgen: can't allocate memory");
2416 #endif /* DYNAMIC */
2417
2418     cp = cmdstr;
2419     *cp++ = type;
2420     *cp = NUL;
2421     if (!arg1) arg1 = "";
2422     if (!arg2) arg2 = "";
2423     if (!arg3) arg3 = "";
2424     if (((int)strlen(arg1)+(int)strlen(arg2)+(int)strlen(arg3)+4) < MAXSP) {
2425         if (*arg1 != NUL) {
2426             upstr = bldlen(arg1,cp);
2427             if (*arg2 != NUL) {
2428                 upstr = bldlen(arg2,upstr);
2429                 if (*arg3 != NUL) bldlen(arg3,upstr);
2430             }
2431         }
2432         cmarg = cmdstr;
2433         debug(F110,"setgen",cmarg,0);
2434         return('g');
2435     }
2436     return('E');
2437 }
2438 #endif /* NOXFER */
2439
2440 #ifndef NOMSEND
2441 static char *mgbufp = NULL;
2442
2443 /*  F N P A R S E  --  */
2444
2445 /*
2446   Argument is a character string containing one or more filespecs.
2447   This function breaks the string apart into an array of pointers, one
2448   to each filespec, and returns the number of filespecs.  Used by server
2449   when it receives a GET command to allow it to process multiple file
2450   specifications in one transaction.  Sets cmlist to point to a list of
2451   file pointers, exactly as if they were command line arguments.
2452
2453   This version of fnparse treats spaces as filename separators.  If your
2454   operating system allows spaces in filenames, you'll need a different
2455   separator.
2456
2457   This version of fnparse mallocs a string buffer to contain the names.  It
2458   cannot assume that the string that is pointed to by the argument is safe.
2459 */
2460 int
2461 fnparse(string) char *string; {
2462     char *p, *s, *q;
2463     int r = 0, x;                       /* Return code */
2464 #ifdef RECURSIVE
2465     debug(F111,"fnparse",string,recursive);
2466 #endif /* RECURSIVE */
2467
2468     if (mgbufp) free(mgbufp);           /* Free this from last time. */
2469     mgbufp = malloc((int)strlen(string)+2);
2470     if (!mgbufp) {
2471         debug(F100,"fnparse malloc error","",0);
2472         return(0);
2473     }
2474 #ifndef NOICP
2475 #ifndef NOSPL
2476     ckstrncpy(fspec,string,fspeclen);   /* Make copy for \v(filespec) */
2477 #endif /* NOSPL */
2478 #endif /* NOICP */
2479     s = string;                         /* Input string */
2480     p = q = mgbufp;                     /* Point to the copy */
2481     r = 0;                              /* Initialize our return code */
2482     while (*s == SP || *s == HT)        /* Skip leading spaces and tabs */
2483       s++;
2484     for (x = strlen(s);                 /* Strip trailing spaces */
2485          (x > 1) && (s[x-1] == SP || s[x-1] == HT);
2486          x--)
2487       s[x-1] = NUL;
2488     while (1) {                         /* Loop through rest of string */
2489         if (*s == CMDQ) {               /* Backslash (quote character)? */
2490             if ((x = xxesc(&s)) > -1) { /* Go interpret it. */
2491                 *q++ = (char) x;        /* Numeric backslash code, ok */
2492             } else {                    /* Just let it quote next char */
2493                 s++;                    /* get past the backslash */
2494                 *q++ = *s++;            /* deposit next char */
2495             }
2496             continue;
2497         } else if (*s == SP || *s == NUL) { /* Unquoted space or NUL? */
2498             *q++ = NUL;                 /* End of output filename. */
2499             msfiles[r] = p;             /* Add this filename to the list */
2500             debug(F111,"fnparse",msfiles[r],r);
2501             r++;                        /* Count it */
2502             if (*s == NUL) break;       /* End of string? */
2503             while (*s == SP) s++;       /* Skip repeated spaces */
2504             p = q;                      /* Start of next name */
2505             continue;
2506         } else *q++ = *s;               /* Otherwise copy the character */
2507         s++;                            /* Next input character */
2508     }
2509     debug(F101,"fnparse r","",r);
2510     msfiles[r] = "";                    /* Put empty string at end of list */
2511     cmlist = msfiles;
2512     return(r);
2513 }
2514 #endif /* NOMSEND */
2515
2516 char *                                  /* dbchr() for DEBUG SESSION */
2517 dbchr(c) int c; {
2518     static char s[8];
2519     char *cp = s;
2520
2521     c &= 0xff;
2522     if (c & 0x80) {                     /* 8th bit on */
2523         *cp++ = '~';
2524         c &= 0x7f;
2525     }
2526     if (c < SP) {                       /* Control character */
2527         *cp++ = '^';
2528         *cp++ = (char) ctl(c);
2529     } else if (c == DEL) {
2530         *cp++ = '^';
2531         *cp++ = '?';
2532     } else {                            /* Printing character */
2533         *cp++ = (char) c;
2534     }
2535     *cp = '\0';                         /* Terminate string */
2536     cp = s;                             /* Return pointer to it */
2537     return(cp);
2538 }
2539
2540 /*  C K H O S T  --  Get name of local host (where C-Kermit is running)  */
2541
2542 /*
2543   Call with pointer to buffer to put hostname in, and length of buffer.
2544   Copies hostname into buffer on success, puts null string in buffer on
2545   failure.
2546 */
2547 #ifdef BSD44
2548 #define BSD4
2549 #undef ATTSV
2550 #endif /* BSD44 */
2551
2552 #ifdef SVORPOSIX
2553 #ifndef BSD44
2554 #ifndef apollo
2555 #include <sys/utsname.h>
2556 #endif /* apollo */
2557 #endif /* BSD44 */
2558 #else
2559 #ifdef BELLV10
2560 #include <utsname.h>
2561 #endif /* BELLV10 */
2562 #endif /* SVORPOSIX*/
2563
2564 #ifdef CKSYSLOG
2565 extern char uidbuf[], * clienthost;
2566 #endif /* CKSYSLOG */
2567
2568 VOID
2569 ckhost(vvbuf,vvlen) char * vvbuf; int vvlen; {
2570
2571 #ifndef NOPUSH
2572     extern int nopush;
2573 #ifndef NOSERVER
2574     extern int en_hos;
2575 #endif /* NOSERVER */
2576 #endif /* NOPUSH */
2577
2578 #ifdef pdp11
2579     *vvbuf = NUL;
2580 #else  /* Everything else - rest of this routine */
2581
2582     char *g;
2583     int havefull = 0;
2584 #ifdef VMS
2585     int x;
2586 #endif /* VMS */
2587
2588 #ifdef SVORPOSIX
2589 #ifndef BSD44
2590 #ifndef _386BSD
2591 #ifndef APOLLOSR10
2592     struct utsname hname;
2593 #endif /* APOLLOSR10 */
2594 #endif /* _386BSD */
2595 #endif /* BSD44 */
2596 #endif /* SVORPOSIX */
2597 #ifdef datageneral
2598     int ac0 = (char *) vvbuf, ac1 = -1, ac2 = 0;
2599 #endif /* datageneral */
2600
2601 #ifndef NOPUSH
2602     if (getenv("CK_NOPUSH")) {          /* No shell access allowed */
2603         nopush = 1;                     /* on this host... */
2604 #ifndef NOSERVER
2605         en_hos = 0;
2606 #endif /* NOSERVER */
2607     }
2608 #endif /* NOPUSH */
2609
2610     *vvbuf = NUL;                       /* How let's get our host name ... */
2611
2612 #ifndef BELLV10                         /* Does not have gethostname() */
2613 #ifndef OXOS
2614 #ifdef SVORPOSIX
2615 #ifdef APOLLOSR10
2616     ckstrncpy(vvbuf,"Apollo",vvlen);
2617 #else
2618 #ifdef BSD44
2619     if (gethostname(vvbuf,vvlen) < 0)
2620       *vvbuf = NUL;
2621 #else
2622 #ifdef _386BSD
2623     if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
2624 #else
2625 #ifdef QNX
2626 #ifdef TCPSOCKET
2627     if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
2628 #else
2629     if (uname(&hname) > -1) ckstrncpy(vvbuf,hname.nodename,vvlen);
2630 #endif /* TCPSOCKET */
2631 #else /* SVORPOSIX but not _386BSD or BSD44 */
2632 #ifdef __ia64__
2633     if (uname(&hname) > -1) ckstrncpy(vvbuf,hname.nodename,vvlen);
2634 #else
2635     if (uname(&hname) > -1) {
2636         char * p;
2637         p = hname.nodename;
2638 #ifdef TCPSOCKET
2639 #ifndef NOCKGETFQHOST
2640         if (!ckstrchr(p,'.'))
2641           p = (char *)ckgetfqhostname(p);
2642 #endif /* NOCKGETFQHOST */
2643 #endif /* TCPSOCKET */
2644         if (!p) p = "";
2645         if (!*p) p = "(unknown)";
2646         ckstrncpy(vvbuf,p,vvlen);
2647     }
2648 #endif /* __ia64__ */
2649 #endif /* QNX */
2650 #endif /* _386BSD */
2651 #endif /* BSD44 */
2652 #endif /* APOLLOSR10 */
2653 #else /* !SVORPOSIX */
2654 #ifdef BSD4
2655     if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
2656 #else /* !BSD4 */
2657 #ifdef VMS
2658     g = getenv("SYS$NODE");
2659     if (g) ckstrncpy(vvbuf,g,vvlen);
2660     x = (int)strlen(vvbuf);
2661     if (x > 1 && vvbuf[x-1] == ':' && vvbuf[x-2] == ':') vvbuf[x-2] = NUL;
2662 #else
2663 #ifdef datageneral
2664     if (sys($HNAME,&ac0,&ac1,&ac2) == 0) /* successful */
2665         vvlen = ac2 + 1;                /* enh - have to add one */
2666 #else
2667 #ifdef OS2                              /* OS/2 */
2668     g = os2_gethostname();
2669     if (g) ckstrncpy(vvbuf,g,vvlen);
2670 #else /* OS2 */
2671 #ifdef OSK
2672 #ifdef TCPSOCKET
2673         if (gethostname(vvbuf, vvlen) < 0) *vvbuf = NUL;
2674 #endif /* TCPSOCKET */
2675 #endif /* OSK */
2676 #endif /* OS2 */
2677 #endif /* datageneral */
2678 #endif /* VMS */
2679 #endif /* BSD4 */
2680 #endif /* SVORPOSIX */
2681 #else /* OXOS */
2682     /* If TCP/IP is not installed, gethostname() fails, use uname() */
2683     if (gethostname(vvbuf,vvlen) < 0) {
2684         if (uname(&hname) > -1)
2685             ckstrncpy(vvbuf,hname.nodename,vvlen);
2686         else
2687             *vvbuf = NUL;
2688     }
2689 #endif /* OXOS */
2690 #endif /* BELLV10 */
2691     if (*vvbuf == NUL) {                /* If it's still empty */
2692         g = getenv("HOST");             /* try this */
2693         if (g) ckstrncpy(vvbuf,g,vvlen);
2694     }
2695     vvbuf[vvlen-1] = NUL;               /* Make sure result is terminated. */
2696 #endif /* pdp11 */
2697 }
2698 #ifdef BSD44
2699 #undef BSD4
2700 #define ATTSV
2701 #endif /* BSD44 */
2702
2703 /*
2704   A S K M O R E  --  Poor person's "more".
2705   Returns 0 if no more, 1 if more wanted.
2706 */
2707 int
2708 askmore() {
2709     char c;
2710     int rv, cx;
2711 #ifdef IKSD
2712     extern int timelimit;
2713 #endif /* IKSD */
2714 #ifdef IKSDCONF
2715     extern int iksdcf;
2716 #endif /* IKSDCONF */
2717 #ifdef CK_APC
2718     extern int apcstatus, apcactive;
2719 #endif /* CK_APC */
2720
2721 #ifdef NOICP
2722     return(1);
2723 #else
2724     if (!xaskmore)
2725       return(1);
2726 #ifdef IKSDCONF
2727     if (inserver && !iksdcf)
2728       return(1);
2729 #endif /* IKSDCONF */
2730 #ifdef CK_APC
2731     if (apcactive == APC_LOCAL ||
2732         (apcactive == APC_REMOTE && (apcstatus & APC_NOINP)))
2733         return(1);
2734 #endif /* CK_APC */
2735 #ifdef VMS
2736     if (batch)
2737       return(1);
2738 #else
2739 #ifdef UNIX
2740     if (backgrd)
2741       return(1);
2742 #endif /* UNIX */
2743 #endif /* VMS */
2744
2745 #ifndef VMS
2746     concb((char)escape);                /* Force CBREAK mode. */
2747 #endif /* VMS */
2748
2749     rv = -1;
2750     while (rv < 0) {
2751 #ifndef OS2
2752         printf("more? ");
2753 #ifdef UNIX
2754 #ifdef NOSETBUF
2755         fflush(stdout);
2756 #endif /* NOSETBUF */
2757 #endif /* UNIX */
2758 #else
2759         printf("more? ");
2760         fflush(stdout);
2761 #endif /* OS2 */
2762
2763 #ifdef IKSD
2764         if (inserver) {
2765             cx = cmdgetc(timelimit);
2766             if (cx < -1 && timelimit) {
2767                 printf("\n?IKS idle timeout - Goodbye.\n");
2768                 doexit(GOOD_EXIT,0);
2769             } else if (cx == -1) {      /* Connection lost */
2770                 doexit(BAD_EXIT,0);
2771             }
2772             c = (char) cx;
2773         } else {
2774 #endif /* IKSD */
2775 #ifdef VMS
2776             conbin((char)escape);       /* Protect against Ctrl-Z */
2777             cx = coninc(0);
2778             concb((char)escape);
2779 #else
2780             cx = cmdgetc(0);
2781 #endif /* VMS */
2782             debug(F101,"askmore cmdgetc","",cx);
2783             if (cx == EOF) {
2784                 debug(F100,"askmore EOF","",0);
2785 #ifdef VMS
2786                 c = '\032';
2787 #else
2788                 c = 'n';
2789 #endif /* VMS */
2790             } else {
2791                 c = (char)cx;
2792             }
2793             debug(F101,"askmore c","",c);
2794
2795 #ifdef IKSD
2796         }
2797 #endif /* IKSD */
2798         switch (c) {
2799           /* Yes */
2800           case 'p': case 'P': case 'g': case 'G': /* Proceed or Go */
2801             xaskmore = 0;
2802             /* fall thru on purpose */
2803
2804           case SP: case 'y': case 'Y': case 012:  case 015:
2805 #ifdef OSK
2806             write(1, "\015      \015", sizeof "\015      \015" - 1);
2807 #else
2808             printf("\015      \015");
2809 #endif /* OSK */
2810             rv = 1;
2811             break;
2812           /* No */
2813           case 'n': case 'N': case 'q': case 'Q':
2814 #ifdef OSK
2815             printf("\n");
2816 #else
2817             printf("\015\012");
2818 #endif /* OSK */
2819             rv = 0;
2820             break;
2821           case '\003':
2822           case '\004':
2823           case '\032':
2824 #ifdef OSK
2825             printf("^%c...\n", (c + 0100));
2826 #else
2827             printf("^%c...\015\012", (c + 0100));
2828 #endif /* OSK */
2829             rv = 0;
2830             break;
2831           /* Invalid answer */
2832           default:
2833             debug(F111,"askmore","invalid answer",c);
2834             printf("Y or space-bar for yes, N for no, G to show the rest\n");
2835             continue;
2836         }
2837 #ifdef OS2
2838         printf("\r                                                   \r");
2839         fflush(stdout);
2840 #endif /* OS2 */
2841     }
2842     return(rv);
2843 #endif /* NOICP */
2844 }
2845
2846 /*  T R A P  --  Terminal interrupt handler */
2847
2848 SIGTYP
2849 #ifdef CK_ANSIC
2850 trap(int sig)
2851 #else
2852 trap(sig) int sig;
2853 #endif /* CK_ANSIC */
2854 /* trap */ {
2855     extern int b_save, f_save;
2856 #ifndef NOICP
2857     extern int timelimit;
2858 #endif /* NOICP */
2859 #ifdef OS2
2860     extern unsigned long startflags;
2861 #ifndef NOSETKEY
2862     extern int os2gks;
2863 #endif /* NOSETKEY */
2864     int i;
2865 #endif /* OS2 */
2866 #ifndef NOSPL
2867     extern int i_active, instatus;
2868 #endif /* NOSPL */
2869 #ifdef VMS
2870     int i; FILE *f;
2871 #endif /* VMS */
2872     extern int zchkod, zchkid;
2873 #ifndef NOSPL
2874     extern int unkmacro;
2875 #endif /* NOSPL */
2876
2877     debok = 1;
2878 #ifdef NTSIG
2879     connoi();
2880 #endif /* NTSIG */
2881 #ifdef __EMX__
2882     signal(SIGINT, SIG_ACK);
2883 #endif
2884 #ifdef GEMDOS
2885 /* GEM is not reentrant, no i/o from interrupt level */
2886     cklongjmp(cmjbuf,1);                /* Jump back to parser now! */
2887 #endif /* GEMDOS */
2888
2889 #ifdef DEBUG
2890     if (deblog) {
2891         if (sig == SIGINT)
2892           debug(F101,"trap caught SIGINT","",sig);
2893         else
2894           debug(F101,"trap caught signal","",sig);
2895     }
2896 #endif /* DEBUG */
2897
2898 #ifdef OS2
2899     if ( sig == SIGBREAK && (startflags & 128) ) {
2900         debug(F101,"trap ignoring SIGBREAK","",sig);
2901         return;
2902     }
2903 #endif /* OS2 */
2904
2905 #ifndef NOICP
2906     timelimit = 0;                      /* In case timed ASK interrupted */
2907 #ifndef NOSPL
2908     unkmacro = 0;                       /* Or ON_UNKNOWN_MACRO interrupted.. */
2909 #endif /* NOSPL */
2910 #endif /* NOICP */
2911     zchkod = 0;                         /* Or file expansion interrupted... */
2912     zchkid = 0;
2913     interrupted = 1;
2914
2915     if (what & W_CONNECT) {             /* Are we in CONNECT mode? */
2916 /*
2917   The HP workstation Reset key sends some kind of ueber-SIGINT that can not
2918   be SIG_IGNored, so we wind up here somehow (even though this is *not* the
2919   current SIGINT handler).  Just return.
2920 */
2921         debug(F101,"trap: SIGINT caught during CONNECT","",sig);
2922         SIGRETURN;
2923     }
2924 #ifndef NOSPL
2925     if (i_active) {                     /* INPUT command was active? */
2926         i_active = 0;                   /* Not any more... */
2927         instatus = INP_UI;              /* INPUT status = User Interrupted */
2928     }
2929 #endif /* NOSPL */
2930
2931 #ifndef NOXFER
2932     ftreset();                          /* Restore global protocol settings */
2933     binary = b_save;                    /* Then restore these */
2934     fncnv  = f_save;
2935     bye_active = 0;
2936     diractive = 0;
2937     cdactive = 0;
2938 #endif /* NOXFER */
2939     zclose(ZIFILE);                     /* If we were transferring a file, */
2940     zclose(ZOFILE);                     /* close it. */
2941 #ifndef NOICP
2942     cmdsquo(cmd_quoting);               /* If command quoting was turned off */
2943 #ifdef CKLEARN
2944     {
2945         extern FILE * learnfp;
2946         extern int learning;
2947         if (learnfp) {
2948             fclose(learnfp);
2949             learnfp = NULL;
2950             learning = 0;
2951         }
2952     }
2953 #endif /* CKLEARN */
2954 #endif /* NOICP */
2955 #ifdef CK_APC
2956     delmac("_apc_commands",1);
2957     apcactive = APC_INACTIVE;
2958 #endif /* CK_APC */
2959
2960 #ifdef VMS
2961 /*
2962   Fix terminal.
2963 */
2964     if (ft_win) {                       /* If curses window open */
2965         debug(F100,"^C trap() curses","",0);
2966         xxscreen(SCR_CW,0,0L,"");       /* Close it */
2967         conres();                       /* Restore terminal */
2968         i = printf("^C...");            /* Echo ^C to standard output */
2969     } else {
2970         conres();
2971         i = printf("^C...\n");          /* Echo ^C to standard output */
2972     }
2973     if (i < 1 && ferror(stdout)) {      /* If there was an error */
2974         debug(F100,"^C trap() error","",0);
2975         fclose(stdout);                 /* close standard output */
2976         f = fopen(dftty, "w");          /* open the controlling terminal */
2977         if (f) stdout = f;              /* and make it standard output */
2978         printf("^C...\n");              /* and echo the ^C again. */
2979     }
2980 #else                                   /* Not VMS */
2981 #ifdef STRATUS
2982     conres();                           /* Set console back to normal mode */
2983 #endif /* STRATUS */
2984 #ifndef NOXFER
2985     if (ft_win) {                       /* If curses window open, */
2986         debug(F100,"^C trap() curses","",0);
2987         xxscreen(SCR_CW,0,0L,"");       /* close it. */
2988         printf("^C...");                /* Echo ^C to standard output */
2989     } else {
2990 #endif /* NOXFER */
2991         printf("^C...\n");
2992 #ifndef NOXFER
2993     }
2994 #endif /* NOXFER */
2995 #endif /* VMS */
2996 #ifdef datageneral
2997     connoi_mt();                        /* Kill asynch task that listens to */
2998     ttimoff();
2999     conres();                           /* the keyboard */
3000 #endif /* datageneral */
3001
3002 #ifndef NOCCTRAP
3003 /*  This is stupid -- every version should have ttimoff()...  */
3004 #ifdef UNIX
3005     ttimoff();                          /* Turn off any timer interrupts */
3006 #else
3007 #ifdef OSK
3008     ttimoff();                          /* Turn off any timer interrupts */
3009 #else
3010 #ifdef STRATUS
3011     ttimoff();                          /* Turn off any timer interrupts */
3012 #else
3013 #ifdef OS2
3014 #ifndef NOSETKEY
3015     os2gks = 1;                         /* Turn back on keycode mapping  */
3016 #endif /* NOSETKEY */
3017 #ifndef NOLOCAL
3018     for (i = 0; i < VNUM; i++)
3019       VscrnResetPopup(i);
3020 #endif /* NOLOCAL */
3021 #ifdef TCPSOCKET
3022 #ifdef NT
3023     /* WSAIsBlocking() returns FALSE in Win95 during a blocking accept call */
3024     if ( WSASafeToCancel /* && WSAIsBlocking() */ ) {
3025         WSACancelBlockingCall();
3026     }
3027 #endif /* NT */
3028 #endif /* TCPSOCKET */
3029 #ifdef CK_NETBIOS
3030     NCBCancelOutstanding();
3031 #endif /* CK_NETBIOS */
3032     ttimoff();                          /* Turn off any timer interrupts */
3033 #else
3034 #ifdef VMS
3035     ttimoff();                          /* Turn off any timer interrupts */
3036 #endif /* VMS */
3037 #endif /* OS2 */
3038 #endif /* STRATUS */
3039 #endif /* OSK */
3040 #endif /* UNIX */
3041
3042 #ifdef OSK
3043     sigmask(-1);
3044 /*
3045   We are in an intercept routine but do not perform a F$RTE (done implicitly
3046   by rts).  We have to decrement the sigmask as F$RTE does.  Warning: longjump
3047   only restores the cpu registers, NOT the fpu registers.  So don't use fpu at
3048   all or at least don't use common fpu (double or float) register variables.
3049 */
3050 #endif /* OSK */
3051
3052 #ifdef NTSIG
3053     PostCtrlCSem();
3054 #else /* NTSIG */
3055     debug(F100,"trap about to longjmp","",0);
3056 #ifdef NT
3057     cklongjmp(ckjaddr(cmjbuf),1);
3058 #else /* NT */
3059     cklongjmp(cmjbuf,1);
3060 #endif /* NT */
3061 #endif /* NTSIG */
3062 #else /* NOCCTRAP */
3063 /* No Ctrl-C trap, just exit. */
3064 #ifdef CK_CURSES                        /* Curses support? */
3065     xxscreen(SCR_CW,0,0L,"");           /* Close curses window */
3066 #endif /* CK_CURSES */
3067     doexit(BAD_EXIT,what);              /* Exit poorly */
3068 #endif /* NOCCTRAP */
3069     SIGRETURN;
3070 }
3071
3072
3073 /*  C K _ T I M E  -- Returns pointer to current time. */
3074
3075 char *
3076 ck_time() {
3077     static char tbuf[10];
3078     char *p;
3079     int x;
3080
3081     ztime(&p);                          /* "Thu Feb  8 12:00:00 1990" */
3082     if (!p)                             /* like asctime()! */
3083       return("");
3084     if (*p) {
3085         for (x = 11; x < 19; x++)       /* copy hh:mm:ss */
3086           tbuf[x - 11] = p[x];          /* to tbuf */
3087         tbuf[8] = NUL;                  /* terminate */
3088     }
3089     return(tbuf);                       /* and return it */
3090 }
3091
3092 /*  C C _ C L E A N  --  Cleanup after terminal interrupt handler */
3093
3094 #ifdef GEMDOS
3095 int
3096 cc_clean() {
3097     zclose(ZIFILE);                     /* If we were transferring a file, */
3098     zclose(ZOFILE);                     /* close it. */
3099     printf("^C...\n");                  /* Not VMS, no problem... */
3100 }
3101 #endif /* GEMDOS */
3102
3103
3104 /*  S T P T R A P -- Handle SIGTSTP (suspend) signals */
3105
3106 SIGTYP
3107 #ifdef CK_ANSIC
3108 stptrap(int sig)
3109 #else
3110 stptrap(sig) int sig;
3111 #endif /* CK_ANSIC */
3112 /* stptrap */ {
3113
3114 #ifndef NOJC
3115     int x; extern int cmflgs;
3116     debug(F101,"stptrap() caught signal","",sig);
3117     if (!xsuspend) {
3118         printf("\r\nsuspend disabled\r\n");
3119 #ifndef NOICP
3120         if (what & W_COMMAND) {         /* If we were parsing commands */
3121             prompt(xxstring);           /* reissue the prompt and partial */
3122             if (!cmflgs)                /* command (if any) */
3123               printf("%s",cmdbuf);
3124         }
3125 #endif /* NOICP */
3126     } else {
3127         conres();                       /* Reset the console */
3128 #ifndef OS2
3129         /* Flush pending output first, in case we are continued */
3130         /* in the background, which could make us block */
3131         fflush(stdout);
3132
3133         x = psuspend(xsuspend);         /* Try to suspend. */
3134         if (x < 0)
3135 #endif /* OS2 */
3136           printf("Job control not supported\r\n");
3137         conint(trap,stptrap);           /* Rearm the trap. */
3138         debug(F100,"stptrap back from suspend","",0);
3139         switch (what) {
3140           case W_CONNECT:               /* If suspended during CONNECT? */
3141             conbin((char)escape);       /* put console back in binary mode */
3142             debug(F100,"stptrap W_CONNECT","",0);
3143             break;
3144 #ifndef NOICP
3145           case W_COMMAND:               /* Suspended in command mode */
3146             debug(F101,"stptrap W_COMMAND pflag","",pflag);
3147             concb((char)escape);        /* Put back CBREAK tty mode */
3148             if (pflag) {                /* If command parsing was */
3149                 prompt(xxstring);       /* reissue the prompt and partial */
3150                 if (!cmflgs)            /* command (if any) */
3151                   printf("%s",cmdbuf);
3152             }
3153             break;
3154 #endif /* NOICP */
3155           default:                      /* All other cases... */
3156             debug(F100,"stptrap default","",0);
3157             concb((char)escape);        /* Put it back in CBREAK mode */
3158             break;
3159         }
3160     }
3161 #endif /* NOJC */
3162     SIGRETURN;
3163 }
3164
3165 #ifdef TLOG
3166 #define TBUFL 300
3167
3168 /*  T L O G  --  Log a record in the transaction file  */
3169 /*
3170  Call with a format and 3 arguments: two strings and a number:
3171    f     - Format, a bit string in range 0-7, bit x is on, arg #x is printed.
3172    s1,s2 - String arguments 0 and 1.
3173    n     - Long, argument 2.
3174 */
3175 VOID
3176 #ifdef CK_ANSIC
3177 dotlog(int f, char *s1, char *s2, long n)
3178 #else
3179 dotlog(f,s1,s2,n) int f; long n; char *s1, *s2;
3180 #endif /* CK_ANSIC */
3181 /* dotlog */ {
3182     static char s[TBUFL];
3183     extern int tlogfmt;
3184     char *sp = s; int x;
3185     if (!s1) s1 = "";
3186     if (!s2) s2 = "";
3187
3188     if (!tralog) return;                /* If no transaction log, don't */
3189     if (tlogfmt != 1) return;
3190     switch (f) {
3191       case F000:                        /* 0 (special) "s1 n s2"  */
3192         if ((int)strlen(s1) + (int)strlen(s2) + 15 > TBUFL)
3193           sprintf(sp,"?T-Log string too long");
3194         else
3195           sprintf(sp,"%s %ld %s",s1,n,s2);
3196         if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3197         break;
3198       case F001:                        /* 1, " n" */
3199         sprintf(sp," %ld",n);
3200         if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3201         break;
3202       case F010:                        /* 2, "[s2]" */
3203         x = (int)strlen(s2);
3204         if (s2[x] == '\n') s2[x] = '\0';
3205         if (x + 6 > TBUFL)
3206           sprintf(sp,"?String too long");
3207         else sprintf(sp,"[%s]",s2);
3208         if (zsoutl(ZTFILE,"") < 0) tralog = 0;
3209         break;
3210       case F011:                        /* 3, "[s2] n" */
3211         x = (int)strlen(s2);
3212         if (s2[x] == '\n') s2[x] = '\0';
3213         if (x + 6 > TBUFL)
3214           sprintf(sp,"?String too long");
3215         else sprintf(sp,"[%s] %ld",s2,n);
3216         if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3217         break;
3218       case F100:                        /* 4, "s1" */
3219         if (zsoutl(ZTFILE,s1) < 0) tralog = 0;
3220         break;
3221       case F101:                        /* 5, "s1: n" */
3222         if ((int)strlen(s1) + 15 > TBUFL)
3223           sprintf(sp,"?String too long");
3224         else sprintf(sp,"%s: %ld",s1,n);
3225         if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3226         break;
3227       case F110:                        /* 6, "s1 s2" */
3228         x = (int)strlen(s2);
3229         if (s2[x] == '\n') s2[x] = '\0';
3230         if ((int)strlen(s1) + x + 4 > TBUFL)
3231           sprintf(sp,"?String too long");
3232         else
3233           sprintf(sp,"%s%s%s",s1,((*s2 == ':') ? "" : " "),s2);
3234         if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3235         break;
3236       case F111:                        /* 7, "s1 s2: n" */
3237         x = (int)strlen(s2);
3238         if (s2[x] == '\n') s2[x] = '\0';
3239         if ((int)strlen(s1) + x + 15 > TBUFL)
3240           sprintf(sp,"?String too long");
3241         else
3242           sprintf(sp,"%s%s%s: %ld",s1,((*s2 == ':') ? "" : " "),s2,n);
3243         if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3244         break;
3245       default:
3246         sprintf(sp,"?Invalid format for tlog() - %ld",n);
3247         if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3248     }
3249 }
3250
3251 /*
3252   D O X L O G
3253
3254   This is the transaction-log writer for BRIEF format.
3255   The idea is produce one record (line) per file.  Each record
3256   has the following delimited fields:
3257     Date (yyyymmdd)
3258     Time (hh:mm:ss)
3259     Action: SEND or RECV
3260     File name
3261     File size
3262     Transfer mode (text, binary, image, labeled, etc).
3263     Status: OK or FAILED
3264     Free-form comments in doublequotes
3265   The default separator is comma.
3266   If a field contains the separator, it is enclosed in doublequotes.
3267 */
3268 VOID
3269 #ifdef CK_ANSIC
3270 doxlog(int x, char * fn, long fs, int fm, int status, char * msg)
3271 #else
3272 doxlog(x, fn, fs, fm, status, msg)
3273     int x; char * fn; long fs; int fm; int status; char * msg;
3274 #endif /* CK_ANSIC */
3275 /* doxlog */ {
3276     extern int tlogsep;
3277     char sep[2];
3278     char buf[CKMAXPATH+256], * bufp;
3279     char tmpbuf[32];
3280     char * s, * p;
3281     int len, left, ftp = 0, k;
3282
3283     if (!tralog) return;                /* If no transaction log, don't */
3284
3285     if (!fn) fn = "";                   /* Protect against null pointers */
3286     if (!msg) msg = "";
3287     if (x & W_FTP)
3288       ftp++;
3289
3290     sep[0] = (char) tlogsep;
3291     sep[1] = NUL;
3292     if (!sep[0]) sep[0] = ',';
3293
3294     bufp = buf;
3295     left = sizeof(buf);
3296     debug(F101,"XXX doxlog left 1","",left);
3297
3298     p = zzndate();                      /* Date */
3299     ckmakmsg(buf, left, p ? p : "00000000", sep, NULL, NULL);
3300     bufp += 9;
3301     left -= 9;
3302     debug(F111,"XXX doxlog left 2",buf,left);
3303
3304     ztime(&p);
3305     ckstrncpy(bufp,p+11,left);
3306     bufp += 8;
3307     left -= 8;
3308     debug(F111,"XXX doxlog left 3",buf,left);
3309
3310     if (ftp) {
3311         if (!(x & (W_SEND|W_RECV)))
3312           return;
3313         s =  (x & W_SEND) ? "PUT" : "GET";
3314         k = 3;
3315     } else {
3316         s =  (x & W_SEND) ? "SEND" : "RECV";
3317         k = 4;
3318     }
3319     ckmakmsg(bufp,left,sep,s,sep,NULL);
3320     bufp += k + 2;
3321     left -= (k + 2);
3322     debug(F111,"XXX doxlog left 4",buf,left);
3323
3324     s = "";
3325     if (ckstrchr(fn,sep[0]))            /* Filename */
3326       s = "\"";
3327     ckmakmsg(bufp,left,s,fn,s,sep);
3328     sprintf(tmpbuf,"%ld",fs);           /* Size */
3329     ckstrncat(buf,tmpbuf,CKMAXPATH);
3330     ckstrncat(buf,sep,CKMAXPATH);
3331     debug(F110,"doxlog 4",buf,0);
3332
3333 #ifdef NOICP
3334     /* Transfer mode */
3335     ckstrncpy(tmpbuf, (binary ? "binary" : "text"), TMPBUFSIZ);
3336 #else
3337     ckstrncpy(tmpbuf,gfmode(fm,0),TMPBUFSIZ);
3338 #endif /* NOICP */
3339     if (ckstrchr(tmpbuf,sep[0])) {      /* Might contain spaces */
3340         ckstrncat(buf,"\"",CKMAXPATH);
3341         ckstrncat(buf,tmpbuf,CKMAXPATH);
3342         ckstrncat(buf,"\"",CKMAXPATH);
3343     } else
3344       ckstrncat(buf,tmpbuf,CKMAXPATH);
3345     ckstrncat(buf,sep,CKMAXPATH);
3346     debug(F110,"doxlog 5",buf,0);
3347
3348     ckstrncat(buf, status ? "FAILED" : "OK",CKMAXPATH);
3349     len = strlen(buf);
3350     left = CKMAXPATH+256 - len;
3351     if (left < 2) fatal("doxlog buffer overlow");
3352
3353     debug(F111,"XXX doxlog left 5",buf,left);
3354
3355     debug(F110,"doxlog buf 1", buf, len);
3356     s = buf + len;
3357     if (status == 0 && left > 32) {
3358         long cps;
3359
3360 #ifdef GFTIMER
3361         debug(F101,"DOXLOG fpxfsecs","",(long)(fpxfsecs * 1000));
3362
3363         cps = (long)((CKFLOAT) fs / fpxfsecs);
3364         sprintf(s,"%s\"%0.3fsec %ldcps\"",sep,fpxfsecs,cps);
3365 #else
3366         cps = fs / xfsecs;
3367         sprintf(s,"%s\"%ldsec %ldcps\"",sep,xfsecs,cps);
3368 #endif /* GFTIMER */
3369     } else if ((int)strlen(msg) + 4 < left) {
3370         sprintf(s,"%s\"%s\"",sep,msg);
3371     }
3372     debug(F111,"XXX doxlog left 5",buf,left);
3373
3374     debug(F110,"doxlog 5",buf,0);
3375     x = zsoutl(ZTFILE,buf);
3376     debug(F101,"doxlog zsoutl","",x);
3377     if (x < 0) tralog = 0;
3378 }
3379 #endif /* TLOG */
3380
3381 #ifndef MAC
3382 /*
3383   The rest of this file is for all implementations but the Macintosh.
3384 */
3385
3386 #ifdef CK_CURSES
3387 static int repaint = 0;                 /* Transfer display needs repainting */
3388 #endif /* CK_CURSES */
3389
3390 #ifndef NOXFER
3391 /*  C H K I N T  --  Check for console interrupts  */
3392
3393 /*
3394   Used during file transfer in local mode only:
3395   . If user has not touched the keyboard, returns 0 with no side effects.
3396   . If user typed S or A (etc, see below) prints status message and returns 0.
3397   . If user typed X or F (etc, see below) returns 0 with cxseen set to 1.
3398   . If user typed Z or B (etc, see below) returns 0 with czseen set to 1.
3399   . If user typed E or C (etc, see below) returns -1.
3400 */
3401 int
3402 chkint() {
3403     int ch, cn, ofd; long zz;
3404     if (!xfrint)
3405       return(0);
3406     if ((!local) || (quiet)) return(0); /* Only do this if local & not quiet */
3407 #ifdef datageneral
3408     if (con_reads_mt)                   /* if conint_mt task is active */
3409       if (conint_avl) {                 /* and there's an interrupt pending */
3410           cn = 1;                       /* process it */
3411           ch = conint_ch;
3412           conint_avl = 0;               /* turn off flag so conint_mt can */
3413       } else                            /* proceed */
3414         return(0);
3415     else                                /* if conint_mt not active */
3416       if ((ch = coninc(2)) < 0)         /* try to get char manually */
3417         return(0);                      /* I/O error, or no data */
3418       else                              /* if successful, set cn so we */
3419         cn = 1;                         /* know we got one */
3420     debug(F101,"chkint got keyboard character",ch,cn);
3421 #else /* !datageneral */
3422 #ifdef NTSIG
3423     {
3424         extern int TlsIndex;
3425         struct _threadinfo * threadinfo;
3426         threadinfo = (struct _threadinfo *) TlsGetValue(TlsIndex);
3427         if (threadinfo) {
3428             if (!WaitSem(threadinfo->DieSem,0))
3429               return -1;                /* Cancel Immediately */
3430         }
3431     }
3432 #endif /* NTSIG */
3433     cn = conchk();                      /* Any input waiting? */
3434     debug(F101,"conchk","",cn);
3435     if (cn < 1) return(0);
3436     ch = coninc(5) ;
3437     debug(F101,"coninc","",ch);
3438     if (ch < 0) return(0);
3439 #endif /* datageneral */
3440
3441     ch &= 0177;
3442     switch (ch) {
3443       case 'A': case 'a': case 0001:    /* Status report */
3444       case 'S': case 's':
3445         if (fdispla != XYFD_R && fdispla != XYFD_S && fdispla != XYFD_N)
3446           return(0);                    /* Only for serial, simple or none */
3447         ofd = fdispla;                  /* [MF] Save file display type */
3448         if (fdispla == XYFD_N)
3449           fdispla = XYFD_R;             /* [MF] Pretend serial if no display */
3450         xxscreen(SCR_TN,0,0l,"Status report:");
3451         xxscreen(SCR_TN,0,0l," file type: ");
3452         if (binary) {
3453             switch(binary) {
3454               case XYFT_L: xxscreen(SCR_TZ,0,0l,"labeled"); break;
3455               case XYFT_I: xxscreen(SCR_TZ,0,0l,"image"); break;
3456               case XYFT_U: xxscreen(SCR_TZ,0,0l,"binary undefined"); break;
3457               default:
3458               case XYFT_B: xxscreen(SCR_TZ,0,0l,"binary"); break;
3459             }
3460         } else {
3461 #ifdef NOCSETS
3462             xxscreen(SCR_TZ,0,0l,"text");
3463 #else
3464             xxscreen(SCR_TU,0,0l,"text, ");
3465             if (tcharset == TC_TRANSP || xfrxla == 0) {
3466                 xxscreen(SCR_TZ,0,0l,"transparent");
3467             } else {
3468                 if (what & W_SEND) {
3469                     xxscreen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword);
3470                     xxscreen(SCR_TU,0,0l," => ");
3471                     xxscreen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword);
3472                 } else {
3473                     xxscreen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword);
3474                     xxscreen(SCR_TU,0,0l," => ");
3475                     xxscreen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword);
3476                 }
3477             }
3478 #endif /* NOCSETS */
3479         }
3480         xxscreen(SCR_QE,0,filcnt," file number");
3481         if (fsize) xxscreen(SCR_QE,0,fsize," size");
3482         xxscreen(SCR_QE,0,ffc," characters so far");
3483         if (fsize > 0L) {
3484 #ifdef CK_RESEND
3485             zz = what & W_SEND ? sendstart : what & W_RECV ? rs_len : 0;
3486             zz = ( (ffc + zz) * 100L ) / fsize;
3487 #else
3488             zz = ( ffc * 100L ) / fsize;
3489 #endif /* CK_RESEND */
3490             xxscreen(SCR_QE,0,zz,      " percent done");
3491         }
3492         if (bctu == 4) {                /* Block check */
3493             xxscreen(SCR_TU,0,0L," block check: ");
3494             xxscreen(SCR_TZ,0,0L,"blank-free-2");
3495         } else xxscreen(SCR_QE,0,(long)bctu,  " block check");
3496         xxscreen(SCR_QE,0,(long)rptflg," compression");
3497         xxscreen(SCR_QE,0,(long)ebqflg," 8th-bit prefixing");
3498         xxscreen(SCR_QE,0,(long)lscapu," locking shifts");
3499         if (!network)
3500           xxscreen(SCR_QE,0, speed, " speed");
3501         if (what & W_SEND)
3502
3503           xxscreen(SCR_QE,0,(long)spsiz, " packet length");
3504         else if (what & W_RECV || what & W_REMO)
3505           xxscreen(SCR_QE,0,(long)urpsiz," packet length");
3506         xxscreen(SCR_QE,0,(long)wslots,  " window slots");
3507         fdispla = ofd; /* [MF] Restore file display type */
3508         return(0);
3509
3510       case 'B': case 'b': case 0002:    /* Cancel batch */
3511       case 'Z': case 'z': case 0032:
3512         czseen = 1;
3513         interrupted = 1;
3514         xxscreen(SCR_ST,ST_MSG,0l,
3515                  (((what & W_RECV) && (wslots > 1)) ?
3516                   "Canceling batch, wait... " :
3517                   "Canceling batch... ")
3518                  );
3519         return(0);
3520
3521       case 'F': case 'f': case 0006:    /* Cancel file */
3522       case 'X': case 'x': case 0030:
3523         cxseen = 1;
3524         interrupted = 1;
3525         xxscreen(SCR_ST,ST_MSG,0l,
3526                  (((what & W_RECV) && (wslots > 1)) ?
3527                   "Canceling file, wait... " :
3528                   "Canceling file... ")
3529                  );
3530         return(0);
3531
3532       case 'R': case 'r': case 0022:    /* Resend packet */
3533       case 0015: case 0012:
3534 #ifdef STREAMING
3535         if (streaming)
3536           return(0);
3537 #endif /* STREAMING */
3538         xxscreen(SCR_ST,ST_MSG,0l,"Resending packet... ");
3539         numerrs++;
3540         resend(winlo);
3541         return(0);
3542
3543 #ifdef datageneral
3544       case '\03':                       /* We're not trapping ^C's with */
3545         trap(0);                        /* signals, so we check here    */
3546 #endif /* datageneral */
3547
3548       case 'C': case 'c':               /* Ctrl-C */
3549 #ifndef datageneral
3550       case '\03':
3551 #endif /* datageneral */
3552
3553       case 'E': case 'e':               /* Send error packet */
3554       case 0005:
3555         interrupted = 1;
3556         return(-1);
3557
3558 #ifdef CK_CURSES
3559       case 0014:                        /* Ctrl-L to refresh screen */
3560       case 'L': case 'l':               /* Also accept L (upper, lower) */
3561       case 0027:                        /* Ctrl-W synonym for VMS & Ingres */
3562         repaint = 1;
3563         return(0);
3564 #endif /* CK_CURSES */
3565
3566       case 'T':
3567       case 't':                         /* Turn on debug-log timestamps */
3568 #ifdef DEBUG
3569         {
3570             extern int debtim;
3571             if (ch == 'T') {
3572                 debtim = 1;
3573                 xxscreen(SCR_ST,ST_MSG,0l,
3574                          "Debug timestamps On... ");
3575             } else {
3576                 debtim = 1;
3577                 xxscreen(SCR_ST,ST_MSG,0l,
3578                          "Debug timestamps Off... ");
3579             }
3580         }
3581 #endif /* DEBUG */
3582         return(0);
3583
3584       case 'D':
3585 #ifdef DEBUG
3586         if (!deblog) {
3587             debopn("debug.log",0);
3588             if (deblog) {
3589                 xxscreen(SCR_ST,ST_MSG,0l,"debug.log open... ");
3590             } else {
3591                 xxscreen(SCR_ST,ST_MSG,0l,"debug.log open FAILED... ");
3592             }
3593         } else {
3594             xxscreen(SCR_ST,ST_MSG,0l,"Debug log On... ");
3595         }
3596         if (deblog)
3597           debok = 1;
3598 #endif /* DEBUG */
3599         return(0);
3600
3601       case 'd':                         /* Turn off debugging */
3602 #ifdef DEBUG
3603         if (deblog)
3604           xxscreen(SCR_ST,ST_MSG,0l,"Debug log Off... ");
3605         debok = 0;
3606 #endif /* DEBUG */
3607         return(0);
3608
3609       default:                          /* Anything else, print message */
3610         intmsg(1L);
3611         return(0);
3612     }
3613 }
3614
3615 /*  I N T M S G  --  Issue message about terminal interrupts  */
3616
3617 VOID
3618 #ifdef CK_ANSIC
3619 intmsg(long n)
3620 #else
3621 intmsg(n) long n;
3622 #endif /* CK_ANSIC */
3623 /* intmsg */ {
3624 #ifdef CK_NEED_SIG
3625     char buf[80];
3626 #endif /* CK_NEED_SIG */
3627
3628     if (!displa || quiet)               /* Not if we're being quiet */
3629       return;
3630     if (server && (!srvdis || n > -1L)) /* Special for server */
3631       return;
3632 #ifdef CK_NEED_SIG
3633     buf[0] = NUL;                       /* Keep compilers happy */
3634 #endif /* CK_NEED_SIG */
3635 #ifndef OXOS
3636 #ifdef SVORPOSIX
3637     conchk();                           /* Clear out pending escape-signals */
3638 #endif /* SVORPOSIX */
3639 #endif /* ! OXOS */
3640 #ifdef VMS
3641     conres();                           /* So Ctrl-C will work */
3642 #endif /* VMS */
3643     if ((!server && n == 1L) || (server && n < 0L)) {
3644
3645 #ifdef CK_NEED_SIG
3646         if (xfrint) {
3647             ckmakmsg(buf,
3648                      80,
3649                      "Type escape character (",
3650                      dbchr(escape),
3651                      ") followed by:",
3652                      NULL
3653                      );
3654             xxscreen(SCR_TN,0,0l,buf);
3655         }
3656 #endif /* CK_NEED_SIG */
3657
3658         if (xfrint) {
3659             if (protocol == PROTO_K) {
3660  xxscreen(SCR_TN,0,0l,"X to cancel file,  CR to resend current packet");
3661  xxscreen(SCR_TN,0,0l,"Z to cancel group, A for status report");
3662  xxscreen(SCR_TN,0,0l,"E to send Error packet, Ctrl-C to quit immediately: ");
3663             } else {
3664                 xxscreen(SCR_TN,0,0l,"Ctrl-C to cancel file transfer: ");
3665             }
3666         } else {
3667             xxscreen(SCR_TN,0,0l,"Transfer interruption disabled. ");
3668         }
3669     }
3670     else xxscreen(SCR_TU,0,0l," ");
3671 }
3672
3673 #ifndef NODISPLAY
3674 static int newdpy = 0;                  /* New display flag */
3675 static char fbuf[80];                   /* Filename buffer */
3676 static char abuf[80];                   /* As-name buffer */
3677 static char a2buf[80];                  /* Second As-name buffer */
3678 static long oldffc = 0L;
3679 static long dots = 0L;
3680 static int hpos = 0;
3681
3682 static VOID                             /* Initialize Serial or CRT display */
3683 dpyinit() {
3684     int m = 0, n = 0;
3685     char * s = "";
3686
3687     newdpy = 0;                         /*  Don't do this again */
3688     oldffc = 0L;                        /*  Reset this */
3689     dots = 0L;                          /*  and this.. */
3690     oldcps = cps = 0L;
3691
3692     conoll("");                         /* New line */
3693     if (what & W_SEND) s = "Sending: "; /* Action */
3694     else if (what & W_RECV) s = "Receiving: ";
3695     n = (int)strlen(s) + (int)strlen(fbuf);
3696     conol(fbuf);
3697     m = (int)strlen(abuf) + 4;
3698     if (n + m > cmd_cols) {
3699         conoll("");
3700         n = 0;
3701     } else
3702       n += m;
3703     if (*abuf) {
3704         conol(" => ");
3705         conol(abuf);
3706     }
3707     m = (int)strlen(a2buf) + 4;
3708     if (n + m > cmd_cols) {
3709         conoll("");
3710         n = 0;
3711     } else
3712       n += m;
3713     if (*a2buf) {
3714         conol(" => ");
3715         conol(a2buf);
3716     }
3717     *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
3718     conoll("");
3719     if (fsize > -1L) {                  /* Size */
3720         sprintf(fbuf,"Size: %ld, Type: ",fsize); /* SAFE (80) */
3721         conol(fbuf); *fbuf = NUL;
3722     } else conol("Size: unknown, Type: ");
3723     if (binary) {                       /* Type */
3724         switch(binary) {
3725               case XYFT_L: conol("labeled"); break;
3726               case XYFT_I: conol("image"); break;
3727               case XYFT_U: conol("binary undefined"); break;
3728               default:
3729               case XYFT_B: conol("binary"); break;
3730         }
3731     } else {
3732 #ifdef NOCSETS
3733         conol("text");
3734 #else
3735         conol("text, ");
3736         if (tcharset == TC_TRANSP || xfrxla == 0) {
3737             conol("transparent");
3738         } else {
3739             if (what & W_SEND) {
3740                 conol(fcsinfo[fcharset].keyword);
3741                 conol(" => ");
3742                 conol(tcsinfo[tcharset].keyword);
3743             } else {
3744                 conol(tcsinfo[tcharset].keyword);
3745                 conol(" => ");
3746                 conol(fcsinfo[fcharset].keyword);
3747             }
3748         }
3749 #endif /* NOCSETS */
3750     }
3751 #ifdef STREAMING
3752     if (streaming)
3753       conol(", STREAMING");
3754 #endif /* STREAMING */
3755     conoll("");
3756
3757     if (fdispla == XYFD_S) {            /* CRT field headings */
3758 /*
3759   Define CK_CPS to show current transfer rate.
3760   Leave it undefined to show estimated time remaining.
3761   Estimated-time-remaining code from Andy Fyfe, not tested on
3762   pathological cases.
3763 */
3764 #define CK_CPS
3765
3766 #ifdef CK_CPS
3767         conoll("    File   Percent       Packet");
3768         conoll("    Bytes  Done     CPS  Length");
3769 #else
3770         conoll("    File   Percent  Secs Packet");
3771         conoll("    Bytes  Done     Left Length");
3772 #endif /* CK_CPS */
3773         newdpy = 0;
3774     }
3775     hpos = 0;
3776 }
3777
3778 /*
3779   showpkt(c)
3780   c = completion code: 0 means transfer in progress, nonzero means it's done.
3781   Show the file transfer progress counter and perhaps verbose packet type.
3782 */
3783 VOID
3784 #ifdef CK_ANSIC
3785 showpkt(char c)
3786 #else
3787 showpkt(c) char c;
3788 #endif /* CK_ANSIC */
3789 /* showpkt */ {
3790
3791 #ifndef GFTIMER
3792     long et;                            /* Elapsed time, entire batch  */
3793 #endif /* GFTIMER */
3794     long howfar;                        /* How far into file */
3795     long pd;                            /* Percent done, this file     */
3796     long tp;                            /* Transfer rate, entire batch */
3797     long ps;                            /* Packet size, current packet */
3798     long mytfc;                         /* Local copy of byte counter  */
3799
3800 #ifdef GFTIMER
3801     CKFLOAT tnow;
3802 #endif /* GFTIMER */
3803
3804     if (newdpy)                         /* Put up filenames, etc, */
3805       dpyinit();                        /* if they're not there already. */
3806
3807     howfar = ffc;                       /* How far */
3808 /*
3809   Calculate CPS rate even if not displaying on screen for use in file
3810   transfer statistics.
3811 */
3812 #ifdef GFTIMER
3813     tnow = gftimer();                   /* Time since we started */
3814     ps = (what & W_RECV) ? rpktl : spktl; /* Packet size */
3815 #ifdef CK_RESEND
3816     if (what & W_SEND)                  /* In case we didn't start at */
3817       howfar += sendstart;              /*  the beginning... */
3818     else if (what & W_RECV)
3819       howfar += rs_len;
3820 #endif /* CK_RESEND */
3821     pd = -1;                            /* Percent done. */
3822     if (c == NUL) {                     /* Still going, figure % done */
3823         if (fsize == 0L) return;        /* Empty file, don't bother */
3824         pd = (fsize > 99L) ? (howfar / (fsize / 100L)) : 0L;
3825         if (pd > 100) pd = 100;         /* Expansion */
3826     }
3827     if (c != NUL)
3828       if (!cxseen && !discard && !czseen)
3829         pd = 100;                       /* File complete, so 100%. */
3830
3831     mytfc = (pd < 100) ? tfc + ffc : tfc;    /* CPS */
3832     tp = (long)((tnow > 0.0) ? (CKFLOAT) mytfc / tnow : 0);
3833     if (c && (tp == 0))
3834       tp = ffc;
3835
3836     cps = tp;                           /* Set global variable */
3837     if (cps > peakcps &&                /* Peak transfer rate */
3838          ((what & W_SEND && spackets > wslots + 4) ||
3839           (!(what & W_SEND) && spackets > 10))) {
3840         peakcps = cps;
3841     }
3842
3843 #else  /* Not GFTIMER */
3844
3845     et = gtimer();                      /* Elapsed time  */
3846     ps = (what & W_RECV) ? rpktl : spktl; /* Packet length */
3847 #ifdef CK_RESEND
3848     if (what & W_SEND)                  /* And if we didn't start at */
3849       howfar += sendstart;              /*  the beginning... */
3850     else if (what & W_RECV)
3851       howfar += rs_len;
3852 #endif /* CK_RESEND */
3853     pd = -1;                            /* Percent done. */
3854     if (c == NUL) {                     /* Still going, figure % done */
3855         if (fsize == 0L) return;        /* Empty file, don't bother */
3856         pd = (fsize > 99L) ? (howfar / (fsize / 100L)) : 0L;
3857         if (pd > 100) pd = 100;         /* Expansion */
3858     }
3859     if (c != NUL)
3860       if (!cxseen && !discard && !czseen)
3861         pd = 100;                       /* File complete, so 100%. */
3862
3863
3864 #ifndef CK_CPS
3865 /*
3866   fsecs = time (from gtimer) that this file started (set in sfile()).
3867   Rate so far is ffc / (et - fsecs),  estimated time for remaining bytes
3868   is (fsize - ffc) / (ffc / (et - fsecs)).
3869 */
3870     tp = (howfar > 0L) ? (fsize - howfar) * (et - fsecs) / howfar : 0L;
3871 #endif /* CK_CPS */
3872
3873 #ifdef CK_CPS
3874     mytfc = (pd < 100) ? tfc + ffc : tfc;
3875     tp = (et > 0) ? mytfc / et : 0;     /* Transfer rate */
3876     if (c && (tp == 0))                 /* Watch out for subsecond times */
3877         tp = ffc;
3878
3879     cps = tp;                           /* Set global variable */
3880     if (cps > peakcps &&                /* Peak transfer rate */
3881          ((what & W_SEND && spackets > wslots + 4) ||
3882           (!(what & W_SEND) && spackets > 10))) {
3883         peakcps = cps;
3884     }
3885 #endif /* CK_CPS */
3886
3887 #endif /* GFTIMER */
3888
3889     if (fdispla == XYFD_S) {            /* CRT display */
3890         char buffer[128];
3891         /* These sprintfs should be safe until we have 32-digit numbers */
3892
3893         if (pd > -1L)
3894           sprintf(buffer, "%c%9ld%5ld%%%8ld%8ld ", CR, howfar, pd, tp, ps);
3895         else
3896           sprintf(buffer, "%c%9ld      %8ld%8ld ", CR, howfar, tp, ps);
3897         conol(buffer);
3898         hpos = 31;
3899     } else if (fdispla == XYFD_R) {     /* SERIAL */
3900         long i, k;
3901         if (howfar - oldffc < 1024)     /* Update display every 1K */
3902           return;
3903         oldffc = howfar;                /* Time for new display */
3904         k = (howfar / 1024L) - dots;    /* How many K so far */
3905         for (i = 0L; i < k; i++) {
3906             if (hpos++ > (cmd_cols - 3)) { /* Time to wrap? */
3907                 conoll("");
3908                 hpos = 0;
3909             }
3910             conoc('.');                 /* Print a dot for this K */
3911             dots++;                     /* Count it */
3912         }
3913     }
3914 }
3915
3916
3917 /*  C K S C R E E N  --  Screen display function  */
3918
3919 /*
3920   ckscreen(f,c,n,s)
3921     f - argument descriptor
3922     c - a character or small integer
3923     n - a long integer
3924     s - a string.
3925
3926   and global fdispla = SET FILE DISPLAY value:
3927
3928     XYFD_N = NONE
3929     XYFD_R = SERIAL:     Dots, etc, works on any terminal, even hardcopy.
3930     XYFD_S = CRT:        Works on any CRT, writes over current line.
3931     XYFD_C = FULLSCREEN: Requires terminal-dependent screen control.
3932     XYFD_B = BRIEF:      Like SERIAL but only filename & completion status.
3933     XYFD_G = GUI;        Windows GUI, same behavior as FULLSCREEN
3934 */
3935 VOID
3936 #ifdef CK_ANSIC
3937 ckscreen(int f, char c,long n,char *s)
3938 #else
3939 ckscreen(f,c,n,s) int f; char c; long n; char *s;
3940 #endif /* CK_ANSIC */
3941 /* screen */ {
3942     char buf[80];
3943     int len;                            /* Length of string */
3944 #ifdef UNIX
3945 #ifndef NOJC
3946     int obg;
3947 _PROTOTYP( VOID conbgt, (int) );
3948 #endif /* NOJC */
3949 #endif /* UNIX */
3950     int ftp = 0;
3951
3952     ftp = (what & W_FTP) ? 1 : 0;       /* FTP or Kermit? */
3953
3954     if (!local && !ftp)                 /* In remote mode - don't do this */
3955       return;
3956
3957     if (!s) s = "";
3958
3959     if (!fxd_inited)                    /* Initialize if necessary */
3960       fxdinit(fdispla);
3961
3962 #ifdef UNIX
3963 #ifndef NOJC
3964     obg = backgrd;                      /* Previous background status */
3965     conbgt(1);                          /* See if running in background */
3966     if (!backgrd && obg) {              /* Just came into foreground? */
3967         concb((char)escape);            /* Put console back in CBREAK mode */
3968         setint();                       /* Restore interrupts */
3969     }
3970 #endif /* NOJC */
3971 #endif /* UNIX */
3972
3973     if ((f != SCR_WM) && (f != SCR_EM)) /* Always update warnings & errors */
3974       if (!displa ||
3975           (backgrd && bgset) ||
3976           fdispla == XYFD_N ||
3977           (server && !srvdis)
3978           )
3979         return;
3980
3981 #ifdef VMS
3982     if (f == SCR_FN)                    /* VMS - shorten the name */
3983       s = zrelname(s,zgtdir());
3984 #endif /* VMS */
3985
3986     if (dest == DEST_S)                 /* SET DESTINATION SCREEN */
3987       return;                           /*  would interfere... */
3988
3989 #ifdef KUI
3990     if (fdispla == XYFD_G) {            /* If gui display selected */
3991         screeng(f,c,n,s);               /* call the gui version */
3992         return;
3993     }
3994 #endif /* KUI */
3995 #ifdef CK_CURSES
3996     if (fdispla == XYFD_C) {            /* If fullscreen display selected */
3997         screenc(f,c,n,s);               /* call the fullscreen version */
3998         return;
3999     }
4000 #endif /* CK_CURSES */
4001
4002     len = (int)strlen(s);               /* Length of string */
4003
4004     switch (f) {                        /* Handle our function code */
4005       case SCR_FN:                      /* Filename */
4006         if (fdispla == XYFD_B) {
4007 #ifdef NEWFTP
4008             if (ftp)
4009               printf(" %s %s", what & W_SEND ? "PUT" : "GET", s);
4010             else
4011 #endif /* NEWFTP */
4012               printf(" %s %s", what & W_SEND ? "SEND" : "RECV", s);
4013 #ifdef UNIX
4014             fflush(stdout);
4015 #endif /* UNIX */
4016             return;
4017         }
4018 #ifdef MAC
4019         conoll(""); conol(s); conoc(SP); hpos = len + 1;
4020 #else
4021         ckstrncpy(fbuf,s,80);
4022         abuf[0] = a2buf[0] = NUL;
4023         newdpy = 1;                     /* New file so refresh display */
4024 #endif /* MAC */
4025         return;
4026
4027       case SCR_AN:                      /* As-name */
4028         if (fdispla == XYFD_B) {
4029 #ifdef COMMENT
4030             printf("(as %s) ",s);
4031 #endif /* COMMENT */
4032             return;
4033         }
4034 #ifdef MAC
4035         if (hpos + len > 75) { conoll(""); hpos = 0; }
4036         conol("=> "); conol(s);
4037         if ((hpos += (len + 3)) > 78) { conoll(""); hpos = 0; }
4038 #else
4039         if (abuf[0]) {
4040             ckstrncpy(a2buf,s,80);
4041         } else {
4042             ckstrncpy(abuf,s,80);
4043         }
4044 #endif /* MAC */
4045         return;
4046
4047       case SCR_FS:                      /* File-size */
4048         if (fdispla == XYFD_B) {
4049             printf(" (%s) (%ld byte%s)",
4050 #ifdef NOICP
4051                    (binary ? "binary" : "text")
4052 #else
4053                    gfmode(binary,0)
4054 #endif /* NOICP */
4055                    , n, n == 1L ? "" : "s");
4056 #ifdef UNIX
4057             fflush(stdout);
4058 #endif /* UNIX */
4059             return;
4060         }
4061 #ifdef MAC
4062         sprintf(buf,", Size: %ld",n);  conoll(buf);  hpos = 0;
4063 #endif /* MAC */
4064         return;
4065
4066       case SCR_XD:                      /* X-packet data */
4067         if (fdispla == XYFD_B)
4068           return;
4069 #ifdef MAC
4070         conoll(""); conoll(s); hpos = 0;
4071 #else
4072         ckstrncpy(fbuf,s,80);
4073         abuf[0] = a2buf[0] = NUL;
4074 #endif /* MAC */
4075         return;
4076
4077       case SCR_ST:                      /* File status */
4078         switch (c) {
4079           case ST_OK:                   /* Transferred OK */
4080             showpkt('Z');               /* Update numbers one last time */
4081             if (fdispla == XYFD_B) {
4082 #ifdef GFTIMER
4083                 printf(": OK (%0.3f sec, %ld cps)\n",fpxfsecs,
4084                        (long)((CKFLOAT)ffc / fpxfsecs));
4085 #else
4086                 printf(": OK (%d sec, %ld cps)\n",xfsecs,ffc/xfsecs);
4087 #endif /* GFTIMER */
4088                 return;
4089             }
4090             if ((hpos += 5) > 78) conoll(""); /* Wrap screen line. */
4091             conoll(" [OK]"); hpos = 0;  /* Print OK message. */
4092             if (fdispla == XYFD_S) {    /* We didn't show Z packet when */
4093                 conoc('Z');             /* it came, so show it now. */
4094                 hpos = 1;
4095             }
4096             return;
4097
4098           case ST_DISC:                 /*  Discarded */
4099             if (fdispla == XYFD_B) {
4100                 printf(": DISCARDED\n");
4101                 return;
4102             }
4103             if ((hpos += 12) > 78) conoll("");
4104             conoll(" [discarded]"); hpos = 0;
4105             return;
4106
4107           case ST_INT:                  /*  Interrupted */
4108             if (fdispla == XYFD_B) {
4109                 printf(": INTERRUPTED\n");
4110                 return;
4111             }
4112             if ((hpos += 14) > 78) conoll("");
4113             conoll(" [interrupted]"); hpos = 0;
4114             return;
4115
4116           case ST_SIM:
4117             if (fdispla == XYFD_B) {
4118                 if (n == SKP_XNX)
4119                   printf(": WOULD BE TRANSFERRED (New file)\n");
4120                 else if (n == SKP_XUP)
4121                   printf(": WOULD BE TRANSFERRED (Remote file older)\n");
4122                 else if (n == SKP_SIM)
4123                   printf(": WOULD BE TRANSFERRED\n");
4124                 else if (n > 0 && n < nskreason)
4125                   printf(": SKIPPED (%s)\n",skreason[n]);
4126                 else
4127                   printf(": SKIPPED\n");
4128                 return;
4129             } else if (fdispla == XYFD_S) {
4130                 if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
4131                     conoll("");         /* New line */
4132                     if (what & W_SEND) conol("Would Send: "); /* Action */
4133                     else if (what & W_RECV) conol("Would Receive: ");
4134                     conol(fbuf);
4135                     if (*abuf) conol(" => "); conol(abuf); /* Names */
4136                     if (*a2buf) conol(" => "); conol(a2buf); /* Names */
4137                     *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
4138                 }
4139                 conoll(" [simulated]");
4140                 return;
4141             }
4142             if ((hpos += 10) > 78) conoll("");
4143             conol(" [simulated]"); hpos = 0;
4144             return;
4145
4146           case ST_SKIP:                 /*  Skipped */
4147             if (fdispla == XYFD_B) {
4148                 if (n == SKP_XNX)
4149                   printf(": WOULD BE TRANSFERRED (New file)\n");
4150                 else if (n == SKP_XUP)
4151                   printf(": WOULD BE TRANSFERRED (Remote file older)\n");
4152                 else if (n == SKP_SIM)
4153                   printf(": WOULD BE TRANSFERRED\n");
4154                 else if (n > 0 && n < nskreason)
4155                   printf(": SKIPPED (%s)\n",skreason[n]);
4156                 else
4157                   printf(": SKIPPED\n");
4158                 return;
4159             } else if (fdispla == XYFD_S) {
4160                 if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
4161                     conoll("");         /* New line */
4162                     if (what & W_SEND) conol("Sending: "); /* Action */
4163                     else if (what & W_RECV) conol("Receiving: ");
4164                     conol(fbuf);
4165                     if (*abuf) conol(" => "); conol(abuf); /* Names */
4166                     if (*a2buf) conol(" => "); conol(a2buf); /* Names */
4167                     *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
4168                 }
4169                 conoll(" [skipped]");
4170                 return;
4171             }
4172             if ((hpos += 10) > 78) conoll("");
4173             conol(" "); conol(fbuf);
4174             conoll(" [skipped]"); hpos = 0;
4175             return;
4176
4177           case ST_ERR:                  /* Error */
4178             if (fdispla == XYFD_B) {
4179                 printf(": ERROR: %s\n",s);
4180                 return;
4181             }
4182             conoll("");
4183             conol("Error: "); conoll(s); hpos = 0;
4184             return;
4185
4186           case ST_MSG:                  /* Message */
4187 #ifdef NEWFTP
4188             if (fdispla == XYFD_B) {
4189                 if (ftp && ftp_deb)
4190                   printf(": MESSAGE: %s\n",s);
4191                 return;
4192             }
4193 #endif /* NEWFTP */
4194             conoll("");
4195             conol("Message: ");
4196             conoll(s);
4197             hpos = 0;
4198             return;
4199
4200           case ST_REFU:                 /* Refused */
4201             if (fdispla == XYFD_B) {
4202                 printf(": REFUSED\n");
4203                 return;
4204             } else if (fdispla == XYFD_S) {
4205                 if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
4206                     conoll("");         /* New line */
4207                     if (what & W_SEND) conol("Sending: "); /* Action */
4208                     else if (what & W_RECV) conol("Receiving: ");
4209                     conol(fbuf);
4210                     if (*abuf) conol(" => "); conol(abuf);      /* Names */
4211                     if (*a2buf) conol(" => "); conol(a2buf);    /* Names */
4212                     *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
4213                     conoll("");
4214                 }
4215                 conol("Refused: "); conoll(s);
4216                 return;
4217             }
4218             conoll("");
4219             conol("Refused: "); conoll(s); hpos = 0;
4220             return;
4221
4222           case ST_INC:                  /* Incomplete */
4223             if (fdispla == XYFD_B) {
4224                 printf(": INCOMPLETE\n");
4225                 return;
4226             }
4227             if ((hpos += 12) > 78) conoll("");
4228             conoll(" [incomplete]"); hpos = 0;
4229             return;
4230
4231           default:
4232             conoll("*** screen() called with bad status ***");
4233             hpos = 0;
4234             return;
4235         }
4236
4237 #ifdef MAC
4238       case SCR_PN:                      /* Packet number */
4239         if (fdispla == XYFD_B) {
4240             return;
4241         }
4242         ckmakmsg(buf,80,s,": ",ckltoa(n),NULL);
4243         conol(buf); hpos += (int)strlen(buf); return;
4244 #endif /* MAC */
4245
4246       case SCR_PT:                      /* Packet type or pseudotype */
4247         if (fdispla == XYFD_B)
4248           return;
4249         if (c == 'Y') return;           /* Don't bother with ACKs */
4250         if (c == 'D') {                 /* In data transfer phase, */
4251             showpkt(NUL);               /* show progress. */
4252             return;
4253         }
4254 #ifndef AMIGA
4255         if (hpos++ > 77) {              /* If near right margin, */
4256             conoll("");                 /* Start new line */
4257             hpos = 0;                   /* and reset counter. */
4258         }
4259 #endif /* AMIGA */
4260         if (c == 'Z' && fdispla == XYFD_S)
4261           return;
4262         else
4263           conoc(c);                     /* Display the packet type. */
4264 #ifdef AMIGA
4265         if (c == 'G') conoll("");       /* New line after G packets */
4266 #endif /* AMIGA */
4267         return;
4268
4269       case SCR_TC:                      /* Transaction complete */
4270         if (xfrbel) bleep(BP_NOTE);
4271         if (fdispla == XYFD_B) {        /* Brief display... */
4272             if (filcnt > 1) {
4273                 long fx;
4274                 fx = filcnt - filrej;
4275                 printf(" SUMMARY: %ld file%s", fx, ((fx == 1L) ? "" : "s"));
4276                 printf(", %ld byte%s", tfc, ((tfc == 1L) ? "" : "s"));
4277 #ifdef GFTIMER
4278                 printf(", %0.3f sec, %ld cps", fptsecs, tfcps);
4279 #else
4280                 printf(", %ld sec, %ld cps", tsecs, tfcps);
4281 #endif /* GFTIMER */
4282                 printf(".\n");
4283             }
4284         } else {
4285             conoll("");
4286         }
4287 #ifdef UNIX
4288         fflush(stdout);
4289 #endif /* UNIX */
4290         return;
4291
4292       case SCR_EM:                      /* Error message */
4293         if (fdispla == XYFD_B) {
4294             printf(" ERROR: %s\n",s);
4295             return;
4296         }
4297         conoll(""); conoc('?'); conoll(s); hpos = 0; return;
4298
4299       case SCR_WM:                      /* Warning message */
4300         if (fdispla == XYFD_B) {
4301             printf(" WARNING: %s\n",s);
4302             return;
4303         }
4304         conoll(""); conoll(s); hpos = 0; return;
4305
4306       case SCR_TU:                      /* Undelimited text */
4307         if (fdispla == XYFD_B)
4308           return;
4309         if ((hpos += len) > 77) { conoll(""); hpos = len; }
4310         conol(s); return;
4311
4312       case SCR_TN:                      /* Text delimited at beginning */
4313         if (fdispla == XYFD_B)
4314           return;
4315         conoll(""); conol(s); hpos = len; return;
4316
4317       case SCR_TZ:                      /* Text delimited at end */
4318         if (fdispla == XYFD_B)
4319           return;
4320         if ((hpos += len) > 77) { conoll(""); hpos = len; }
4321         conoll(s); return;
4322
4323       case SCR_QE:                      /* Quantity equals */
4324         if (fdispla == XYFD_B)
4325           return;
4326         ckmakmsg(buf,80,s,": ",ckltoa(n),NULL);
4327         conoll(buf); hpos = 0; return;
4328
4329       case SCR_CW:                      /* Close fullscreen window */
4330         return;                         /* No window to close */
4331
4332       case SCR_CD:
4333         return;
4334
4335       default:
4336         conoll("*** screen() called with bad object ***");
4337         hpos = 0;
4338         return;
4339     }
4340 }
4341 #endif /* NODISPLAY */
4342
4343 /*  E R M S G  --  Nonfatal error message  */
4344
4345 /* Should be used only for printing the message text from an Error packet. */
4346
4347 VOID
4348 ermsg(msg) char *msg; {                 /* Print error message */
4349     debug(F110,"ermsg",msg,0);
4350     if (local)
4351       xxscreen(SCR_EM,0,0L,msg);
4352     tlog(F110,"Protocol Error:",msg,0L);
4353 }
4354 #endif /* NOXFER */
4355
4356 VOID
4357 setseslog(x) int x; {
4358     seslog = x;
4359 #ifdef KUI
4360     KuiSetProperty(KUI_TERM_CAPTURE,x,0);
4361 #endif /* KUI */
4362 }
4363
4364 VOID
4365 doclean(fc) int fc; {                   /* General cleanup */
4366 #ifdef OS2ORUNIX
4367     extern int ttyfd;
4368 #endif /* OS2ORUNIX */
4369     extern int  keep;
4370     extern int exithangup;
4371 #ifndef NOXFER
4372     extern char filnam[];
4373 #endif /* NOXFER */
4374 #ifndef NOICP
4375     int x;
4376
4377     if (fc > 0)
4378       dostop();                 /* Stop all command files and end macros */
4379 #endif /* NOICP */
4380
4381 #ifndef NOXFER
4382     if (pktlog) {
4383         *pktfil = '\0';
4384         pktlog = 0;
4385         zclose(ZPFILE);
4386     }
4387 #endif /* NOXFER */
4388     if (seslog) {
4389         *sesfil = '\0';
4390         setseslog(0);
4391         zclose(ZSFILE);
4392     }
4393 #ifdef TLOG
4394     if (tralog) {
4395         tlog(F100,"Transaction Log Closed","",0L);
4396         *trafil = '\0';
4397         tralog = 0;
4398         zclose(ZTFILE);
4399     }
4400 #endif /* TLOG */
4401
4402     debug(F100,"doclean calling dologend","",0);
4403     dologend();                         /* End current log record if any */
4404 #ifdef COMMENT
4405     if (dialog) {                       /* If connection log open */
4406         dialog = 0;
4407         *diafil = '\0';                 /* close it. */
4408         zclose(ZDIFIL);
4409     }
4410 #endif /* COMMENT */
4411
4412 #ifndef NOICP
4413 #ifndef NOSPL
4414     zclose(ZRFILE);                     /* READ and WRITE files, if any. */
4415     zclose(ZWFILE);
4416 #ifndef NOXFER
4417     zclose(ZIFILE);                     /* And other files too */
4418     x = chkfn(ZOFILE);                  /* Download in progress? */
4419     debug(F111,"doclean chkfn ZOFILE",filnam,x);
4420     debug(F111,"doclean keep","",keep);
4421     zclose(ZOFILE);                     /* Close output file */
4422     if (x > 0 && !keep) {               /* If it was being downloaded */
4423         if (filnam[0])
4424           x = zdelet(filnam);           /* Delete if INCOMPLETE = DISCARD */
4425         debug(F111,"doclean download filename",filnam,x);
4426     }
4427 #endif /* NOXFER */
4428     zclose(ZSYSFN);
4429     zclose(ZMFILE);
4430
4431     if (fc < 1) {                       /* RESETing, not EXITing */
4432 #ifdef DEBUG
4433         if (deblog) {                   /* Close the debug log. */
4434             *debfil = '\0';
4435             deblog = 0;
4436             zclose(ZDFILE);
4437         }
4438 #endif /* DEBUG */
4439         return;
4440     }
4441 #endif /* NOSPL */
4442 #endif /* NOICP */
4443
4444 #ifndef NOLOCAL
4445     debug(F101,"doclean exithangup","",exithangup);
4446     if (local && exithangup) {          /* Close communication connection */
4447         extern int haslock;
4448         int x;
4449         
4450         x = ttchk();
4451         debug(F101,"doclean ttchk()","",x);
4452 #ifdef OS2ORUNIX
4453         debug(F101,"doclean ttyfd","",ttyfd);
4454 #endif /* OS2ORUNIX */
4455         if (x >= 0
4456 #ifdef OS2
4457             || ttyfd != -1
4458 #else
4459 #ifdef UNIX
4460             || haslock                  /* Make sure we get lockfile! */
4461             || (!network && ttyfd > -1)
4462 #endif /* UNIX */
4463 #endif /* OS2 */
4464             ) {
4465             extern int wasclosed, whyclosed;
4466             debug(F100,"doclean hanging up and closing","",0);
4467             if (msgflg) {
4468 #ifdef UNIX
4469                 fflush(stdout);
4470 #endif /* UNIX */
4471                 printf("Closing %s...",ttname);
4472             }
4473 #ifndef NODIAL
4474             mdmhup();                   /* Hangup the modem??? */
4475 #endif /* NODIAL */
4476             ttclos(0);                  /* Close external line, if any */
4477             if (msgflg) {
4478                 printf("OK\n");
4479 #ifdef UNIX
4480                 fflush(stdout);
4481 #endif /* UNIX */
4482             }
4483             if (wasclosed) {
4484                 whyclosed = WC_CLOS;
4485 #ifndef NOSPL
4486                 if (nmac) {             /* Any macros defined? */
4487                     int k;              /* Yes */
4488                     k = mlook(mactab,"on_close",nmac);  /* Look this up */
4489                     if (k >= 0) {                       /* If found, */
4490                         wasclosed = 0;
4491                         /* printf("ON_CLOSE DOCLEAN\n"); */
4492                         *(mactab[k].kwd) = NUL;         /* See comment below */
4493                         if (dodo(k,ckitoa(whyclosed),0) > -1) /* set it up, */
4494                           parser(1);                    /* and execute it */
4495                     }
4496                 }
4497 #endif /* NOSPL */
4498                 wasclosed = 0;
4499             }
4500         }
4501         ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default tty */
4502         local = dfloc;                  /* And default remote/local status */
4503     }
4504 #ifdef DEBUG
4505     else if (local) debug(F100,"doclean hangup/close skipped","",0);
4506 #endif /* DEBUG */
4507 #endif /* NOLOCAL */
4508
4509 #ifdef NEWFTP
4510     ftpbye();                           /* If FTP connection open, close it */
4511 #endif /* NEWFTP */
4512
4513 #ifdef IKSD
4514     if (inserver)
4515       ttclos(0);                        /* If IKSD, close socket */
4516 #endif /* IKSD */
4517
4518 #ifndef NOSPL
4519 /*
4520   If a macro named "on_exit" is defined, execute it.  Also remove it from the
4521   macro table, in case its definition includes an EXIT or QUIT command, which
4522   would cause much recursion and would prevent the program from ever actually
4523   EXITing.
4524 */
4525     if (nmac) {                         /* Any macros defined? */
4526         int k;                          /* Yes */
4527         char * cmd = "on_exit";         /* MSVC 2.x compiler error */
4528         k = mlook(mactab,cmd,nmac);     /* Look up "on_exit" */
4529         if (k >= 0) {                   /* If found, */
4530 #ifdef COMMENT
4531             /* This makes a mess if ON_EXIT itself executes macros */
4532             *(mactab[k].kwd) = NUL;     /* poke its name from the table, */
4533 #else
4534             /* Replace the keyword with something that doesn't wreck the */
4535             /* order of the keyword table */
4536             ckstrncpy(mactab[k].kwd,"on_exxx",8);
4537 #endif /* COMMENT */
4538             if (dodo(k,"",0) > -1)      /* set it up, */
4539               parser(1);                /* and execute it */
4540         }
4541     }
4542 #endif /* NOSPL */
4543 /*
4544   Put console terminal back to normal.  This is done here because the
4545   ON_EXIT macro calls the parser, which meddles with console terminal modes.
4546 */
4547     conres();                           /* Restore console terminal. */
4548
4549 #ifdef COMMENT
4550 /* Should be no need for this, and maybe it's screwing things up? */
4551     connoi();                           /* Turn off console interrupt traps */
4552 #endif /* COMMENT */
4553
4554     /* Delete the Startup File if we are supposed to. */
4555 #ifndef NOICP
4556     {
4557         extern int DeleteStartupFile;
4558         debug(F111,"doclean DeleteStartupFile",cmdfil,DeleteStartupFile);
4559         if (DeleteStartupFile) {
4560             int rc = zdelet(cmdfil);
4561             debug(F111,"doclean zdelet",cmdfil,rc);
4562         }
4563     }
4564 #endif /* NOICP */
4565     syscleanup();                       /* System-dependent cleanup, last */
4566 }
4567
4568 /*  D O E X I T  --  Exit from the program.  */
4569
4570 /*
4571   First arg is general, system-independent symbol: GOOD_EXIT or BAD_EXIT.
4572   If second arg is -1, take 1st arg literally.
4573   If second arg is not -1, work it into the exit code.
4574 */
4575 VOID
4576 doexit(exitstat,code) int exitstat, code; {
4577     extern int x_logged, quitting;
4578 #ifdef OS2
4579     extern int display_demo;
4580     extern int SysInited;
4581 #endif /* OS2 */
4582 #ifdef CK_KERBEROS
4583 #ifdef KRB4
4584     extern int krb4_autodel;
4585 #endif /* KRB4 */
4586 #ifdef KRB5
4587     extern int krb5_autodel;
4588 #endif /* KRB5 */
4589 #endif /* CK_KERBEROS */
4590
4591 #ifdef VMS
4592     char envstr[64];
4593     static $DESCRIPTOR(symnam,"CKERMIT_STATUS");
4594     static struct dsc$descriptor_s symval;
4595 #endif /* VMS */
4596     int i;
4597
4598 #ifdef DEBUG
4599 #ifdef USE_LUCACHE
4600     extern long lucalls, luhits, xxhits, luloop;
4601     extern int lusize;
4602 #endif /* USE_LUCACHE */
4603 #ifndef NOSPL
4604     extern int cmdstats[];
4605 #endif /* NOSPL */
4606
4607     quitting++;
4608
4609 #ifdef OS2
4610     if ( !SysInited ) {
4611         static int initing = 0;
4612         if ( initing )
4613           exit(253);
4614         initing = 1;
4615         sysinit();
4616     }
4617 #endif /* OS2 */
4618
4619     if (deblog) {
4620 #ifdef USE_LUCACHE
4621         debug(F101,"lookup cache size","",lusize);
4622         debug(F101,"lookup calls ....","",lucalls);
4623         debug(F101,"lookup cache hits","",luhits);
4624         debug(F101,"lookup start hits","",xxhits);
4625         debug(F101,"lookup loop iterations","",luloop);
4626 #endif /* USE_LUCACHE */
4627 #ifndef NOSPL
4628         for (i = 0; i < 256; i++) {
4629             if (cmdstats[i])
4630               debug(F111,"CMSTATS",ckitoa(i),cmdstats[i]);
4631         }
4632 #endif /* NOSPL */
4633         debug(F101,"doexit exitstat","",exitstat);
4634         debug(F101,"doexit code","",code);
4635         debug(F101,"doexit xitsta","",xitsta);
4636     }
4637 #endif /* DEBUG */
4638
4639 #ifdef CK_KERBEROS
4640     /* If we are automatically destroying Kerberos credentials on Exit */
4641     /* do it now. */
4642 #ifdef KRB4
4643     if (krb4_autodel == KRB_DEL_EX) {
4644         extern struct krb_op_data krb_op;
4645         krb_op.version = 4;
4646         krb_op.cache = NULL;
4647         ck_krb4_destroy(&krb_op);
4648     }
4649 #endif /* KRB4 */
4650 #ifdef KRB5
4651     if (krb5_autodel == KRB_DEL_EX) {
4652         extern struct krb_op_data krb_op;
4653         extern char * krb5_d_cc;
4654         krb_op.version = 5;
4655         krb_op.cache = krb5_d_cc;
4656         ck_krb5_destroy(&krb_op);
4657     }
4658 #endif /* KRB5 */
4659 #endif /* CK_KERBEROS */
4660
4661 #ifndef NOLOCAL
4662 #ifdef OS2
4663     if (SysInited)
4664     {
4665 #ifdef DCMDBUF
4666         extern struct cmdptr *cmdstk;
4667 #else
4668         extern struct cmdptr cmdstk[];
4669 #endif /* DCMDBUF */
4670         extern int tt_status[];
4671         extern int vmode;
4672
4673         /* If there is a demo screen to be displayed, display it */
4674         if (display_demo) {
4675             demoscrn(VCMD);
4676             display_demo = 0;
4677         }
4678 #ifndef KUI
4679         /* This is going to be hideous.  If we have a status line */
4680         /* in the command window turn it off before we exit.      */
4681
4682         if ( tt_status[VCMD] && vmode == VCMD ) {
4683             domac("_clear_statusline","set command statusline off",
4684                    cmdstk[cmdlvl].ccflgs);
4685             delmac("_clear_statusline",1);
4686             RequestScreenMutex(-1);
4687             VscrnIsDirty(vmode);
4688             ReleaseScreenMutex();
4689             while ( IsVscrnDirty(vmode) )
4690                 msleep(200);
4691             RequestScreenMutex(-1);
4692             ReleaseScreenMutex();
4693         }
4694 #endif /* KUI */
4695         DialerSend(OPT_KERMIT_EXIT,exitstat);
4696 #ifndef KUI
4697         debug(F100,"doexit about to msleep","",0);
4698
4699         if ( isWin95() )
4700             msleep(250);
4701 #endif /* KUI */
4702     }
4703 #endif /* OS2 */
4704 #endif /* NOLOCAL */
4705
4706 #ifdef IKSD
4707 #ifdef CK_LOGIN
4708     if (inserver && x_logged) {
4709 #ifndef NOSPL
4710 /*
4711   If a macro named "on_logout" is defined, execute it.  Also remove it from the
4712   macro table, in case its definition includes an EXIT or QUIT command, which
4713   would cause much recursion and would prevent the program from ever actually
4714   EXITing.
4715 */
4716         if (nmac) {                     /* Any macros defined? */
4717             int k;                      /* Yes */
4718             char * cmd = "on_logout";   /* MSVC 2.x compiler error */
4719             k = mlook(mactab,cmd,nmac); /* Look up "on_logout" */
4720             if (k >= 0) {               /* If found, */
4721                 *(mactab[k].kwd) = NUL; /* poke its name from the table, */
4722                 if (dodo(k,"",0) > -1)  /* set it up, */
4723                   parser(1);            /* and execute it */
4724             }
4725         }
4726 #endif /* NOSPL */
4727         zvlogout();
4728     }
4729 #endif /* CK_LOGIN */
4730 #endif /* IKSD */
4731
4732     debug(F100,"doexit about to doclean","",0);
4733     doclean(1);                         /* Clean up most things */
4734
4735 #ifdef VMS
4736     if (code == -1)
4737       code = 0;                         /* Since we set two different items */
4738     sprintf(envstr,"%d", exitstat | code); /* SAFE */
4739     symval.dsc$w_length = (int)strlen(envstr);
4740     symval.dsc$a_pointer = envstr;
4741     symval.dsc$b_class = DSC$K_CLASS_S;
4742     symval.dsc$b_dtype = DSC$K_DTYPE_T;
4743     i = 2;                              /* Store in global table */
4744 #ifdef COMMENT                          /* Martin Zinser */
4745     LIB$SET_SYMBOL(&symnam, &symval, &i);
4746 #else
4747     lib$set_symbol(&symnam, &symval, &i);
4748 #endif /* COMMENT */
4749     if (exitstat == BAD_EXIT)
4750       exitstat = SS$_ABORT | STS$M_INHIB_MSG;
4751     if (exitstat == GOOD_EXIT)
4752       exitstat = SS$_NORMAL | STS$M_INHIB_MSG;
4753 #else /* Not VMS */
4754     if (code != -1)                     /* Take 1st arg literally */
4755       exitstat |= code;
4756 #endif /* VMS */
4757
4758 #ifdef IKSD
4759 #ifdef IKSDB
4760     debug(F101,"doexit ikdbopen","",ikdbopen);
4761     if (ikdbopen && dbfp) {             /* If IKSD database open */
4762         int x;
4763         x = freeslot(mydbslot);         /* Free our slot... */
4764         debug(F101,"doexit freeslot","",x);
4765         fclose(dbfp);                   /* and close it. */
4766     }
4767 #endif /* IKSDB */
4768 #endif /* IKSD */
4769
4770 /* We have put this off till the very last moment... */
4771
4772 #ifdef DEBUG
4773     if (deblog) {                       /* Close the debug log. */
4774         debug(F101,"C-Kermit EXIT status","",exitstat);
4775         *debfil = '\0';
4776         deblog = 0;
4777         zclose(ZDFILE);
4778     }
4779 #endif /* DEBUG */
4780
4781 #ifdef OS2
4782     _exit(exitstat);            /* Exit from C-Kermit (no matter what) */
4783 #else /* OS2 */
4784     exit(exitstat);                     /* Exit from C-Kermit */
4785 #endif /* OS2 */
4786 }
4787
4788 VOID
4789 bgchk() {                               /* Check background status */
4790     if (bgset < 0) {                    /* They didn't type SET BACKGROUND */
4791 #ifdef VMS                              /* Set prompt flag based on */
4792         pflag = !batch;                 /* what we detected at startup. */
4793 #else
4794         pflag = !backgrd;
4795 #endif /* VMS */
4796     } else {                            /* Otherwise SET BACKGROUND value */
4797         pflag = (bgset == 0 ? 1 : 0);
4798     }
4799
4800 #ifndef NOICP
4801     /* Message flag on only if at top level, pflag is on, and QUIET is OFF */
4802     if (!xcmdsrc)
4803       msgflg = (pflag == 0) ? 0 : !quiet;
4804     else msgflg = 0;
4805 #else
4806     msgflg = 0;
4807 #endif /* NOICP */
4808 }
4809
4810 /* Set console interrupts */
4811
4812 VOID
4813 setint() {                              /* According to SET COMMAND INTERRUP */
4814     int x = 0;
4815     if (cmdint)  x |= 1;
4816     if (xsuspend) x |= 2;
4817     debug(F101,"setint","",x);
4818
4819     switch (x) {                        /* Set the desired combination */
4820       case 0: connoi(); break;          /* No interrupts */
4821       case 1: conint(trap,SIG_IGN); break;
4822       case 2: conint(SIG_IGN,stptrap); break;
4823       case 3: conint(trap,stptrap); break;
4824     }
4825     bgchk();                            /* Check background status */
4826 }
4827
4828 #ifdef DEBUG
4829 /*  D E B U G  --  Enter a record in the debugging log  */
4830
4831 /*
4832  Call with a format, two strings, and a number:
4833    f  - Format, a bit string in range 0-7.
4834         If bit x is on, then argument number x is printed.
4835    s1 - String, argument number 1.  If selected, printed as is.
4836    s2 - String, argument number 2.  If selected, printed in brackets.
4837    n  - Long int, argument 3.  If selected, printed preceded by equals sign.
4838
4839    f=0 is special: print s1,s2, and interpret n as a char.
4840
4841    f=F011 (3) is also special; in this case s2 is interpeted as a counted
4842    string that might contain NULs.  n is the length.  If n is negative, this
4843    means the string has been truncated and ".." should be printed after the
4844    first n bytes.  NUL and LF bytes are printed as "<NUL>" and "<LF>".
4845
4846    Globals:
4847      deblog: nonzero if debug log open.
4848      debok:  nonzero if ok to write entries.
4849 */
4850 /*
4851   WARNING: Don't change DEBUFL without changing sprintf() formats below,
4852   accordingly.
4853 */
4854 #define DBUFL 4000
4855 /*
4856   WARNING: This routine is not thread-safe, especially when Kermit is
4857   executing on multiple CPUs -- as different threads write to the same
4858   static buffer, the debug statements are all interleaved.  To be fixed
4859   later...
4860 */
4861 static char *dbptr = (char *)0;
4862
4863 int
4864 #ifdef CK_ANSIC
4865 dodebug(int f, char *s1, char *s2, long n)
4866 #else
4867 dodebug(f,s1,s2,n) int f; char *s1, *s2; long n;
4868 #endif /* CK_ANSIC */
4869 /* dodebug */ {
4870     char *sp;
4871     int len1, len2;
4872     extern int debtim;
4873 #ifdef OS2
4874     extern int SysInited;
4875 #endif /* OS2 */
4876
4877     if (!deblog || !debok)
4878       return(0);
4879
4880 #ifdef COMMENT
4881     /* expensive... */
4882     if (!chkfn(ZDFILE))                 /* Debug log not open, don't. */
4883       return(0);
4884 #endif /* COMMENT */
4885     if (!dbptr) {                       /* Allocate memory buffer */
4886         dbptr = malloc(DBUFL+4);        /* This only happens once */
4887         if (!dbptr) {
4888             zclose(ZDFILE);
4889             return(0);
4890         }
4891     }
4892 /*
4893   This prevents infinite recursion in case we accidentally put a debug()
4894   call in this routine, or call another routine that contains debug() calls.
4895   From this point on, all returns from this return must be via goto xdebug,
4896   which sets deblog back to 1.
4897 */
4898 #ifdef OS2
4899     if (SysInited) {
4900         if (RequestDebugMutex(30000))
4901             goto xdebug;
4902     }
4903 #else /* OS2 */
4904     deblog = 0;                         /* Prevent infinite recursion */
4905 #endif /* OS2 */
4906
4907     if (debtim) {                       /* Timestamp */
4908         char *tb, tsbuf[48];
4909         ztime(&tb);
4910         ckstrncpy(tsbuf,tb,32);
4911         if (ztmsec > -1L) {
4912             sprintf(tsbuf+19,".%03ld ",ztmsec); /* SAFE */
4913         } else {
4914             tsbuf[19] = ':';
4915             tsbuf[20] = SP;
4916             tsbuf[21] = NUL;
4917         }
4918         zsout(ZDFILE,tsbuf+11);
4919     }
4920     if (!s1) s1="(NULL)";
4921     if (!s2) s2="(NULL)";
4922
4923     len1 = strlen(s1);
4924     len2 = strlen(s2);
4925
4926 #ifdef COMMENT
4927 /*
4928   This should work, but it doesn't.
4929   So instead we'll cope with overflow via sprintf formats.
4930   N.B.: UNFORTUNATELY, this means we have to put constants in the
4931   sprintf formats.
4932 */
4933     if (f != F011 && (!f || (f & 6))) { /* String argument(s) included? */
4934         x = (int) strlen(s1) + (int) strlen(s2) + 18;
4935         if (x > dbufl) {                /* Longer than buffer? */
4936             if (dbptr)                  /* Yes, free previous buffer */
4937               free(dbptr);
4938             dbptr = (char *) malloc(x + 2); /* Allocate a new one */
4939             if (!dbptr) {
4940                 zsoutl(ZDFILE,"DEBUG: Memory allocation failure");
4941                 deblog = 0;
4942                 zclose(ZDFILE);
4943                 goto xdebug;
4944             } else {
4945                 dbufl = x;
4946                 sprintf(dbptr,"DEBUG: Buffer expanded to %d\n", x + 18);
4947                 zsoutl(ZDFILE,dbptr);
4948             }
4949         }
4950     }
4951 #endif /* COMMENT */
4952
4953 #ifdef COMMENT
4954 /* The aforementioned sprintf() formats were like this: */
4955         if (n > 31 && n < 127)
4956           sprintf(sp,"%.100s%.2000s:%c\n",s1,s2,(CHAR) n);
4957         else if (n < 32 || n == 127)
4958           sprintf(sp,"%.100s%.2000s:^%c\n",s1,s2,(CHAR) ((n+64) & 0x7F));
4959         else if (n > 127 && n < 160)
4960           sprintf(sp,"%.100s%.2000s:~^%c\n",s1,s2,(CHAR)((n-64) & 0x7F));
4961         else if (n > 159 && n < 256)
4962           sprintf(sp,"%.100s%.2000s:~%c\n",s1,s2,(CHAR) (n & 0x7F));
4963         else sprintf(sp,"%.100s%.2000s:%ld\n",s1,s2,n);
4964 /*
4965   But, naturally, it turns out these are not portable either, so now
4966   we do the stupidest possible thing.
4967 */
4968 #endif /* COMMENT */
4969
4970 #ifdef BIGBUFOK
4971 /* Need to accept longer strings when debugging authenticated connections */
4972     if (f == F010) {
4973         if (len2 + 2 >= DBUFL) s2 = "(string too long)";
4974     } else if (f != F011 && f != F100) {
4975         if (len1 > 100) s1 = "(string too long)";
4976         if (len2 + 101 >= DBUFL) s2 = "(string too long)";
4977     }
4978 #else
4979     if (f != F011) {
4980         if (len1 > 100) s1 = "(string too long)";
4981         if (len2 + 101 >= DBUFL) s2 = "(string too long)";
4982     }
4983 #endif /* BIGBUFOK */
4984
4985     sp = dbptr;
4986
4987     switch (f) {                /* Write log record according to format. */
4988       case F000:                /* 0 = print both strings, and n as a char. */
4989         if (len2 > 0) {
4990             if ((n > 31 && n < 127) || (n > 159 && n < 256))
4991               sprintf(sp,"%s[%s]=%c\n",s1,s2,(CHAR) n);
4992             else if (n < 32 || n == 127)
4993               sprintf(sp,"%s[%s]=^%c\n",s1,s2,(CHAR) ((n+64) & 0x7F));
4994             else if (n > 127 && n < 160)
4995               sprintf(sp,"%s[%s]=~^%c\n",s1,s2,(CHAR)((n-64) & 0x7F));
4996             else sprintf(sp,"%s[%s]=0x%lX\n",s1,s2,n);
4997         } else {
4998             if ((n > 31 && n < 127) || (n > 159 && n < 256))
4999               sprintf(sp,"%s=%c\n",s1,(CHAR) n);
5000             else if (n < 32 || n == 127)
5001               sprintf(sp,"%s=^%c\n",s1,(CHAR) ((n+64) & 0x7F));
5002             else if (n > 127 && n < 160)
5003               sprintf(sp,"%s=~^%c\n",s1,(CHAR)((n-64) & 0x7F));
5004             else sprintf(sp,"%s=0x%lX\n",s1,n);
5005         }
5006         if (zsout(ZDFILE,dbptr) < 0) {
5007             deblog = 0;
5008             zclose(ZDFILE);
5009         }
5010 #ifdef CKSYSLOG
5011         if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5012             cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5013         }
5014 #endif /* CKSYSLOG */
5015         break;
5016
5017       case F001:                        /* 1, "=n" */
5018 #ifdef COMMENT
5019         /* This was never used */
5020         sprintf(sp,"=%ld\n",n);
5021 #else
5022         /* Like F111, but shows number n in hex */
5023         ckmakxmsg(sp,DBUFL,
5024                   s1,
5025                   (*s1 ? ":" : ""),
5026                   s2,
5027                   (*s2 ? ":" : ""),
5028                   ckltox(n),
5029                   "\n",
5030                   NULL,NULL,NULL,NULL,NULL,NULL
5031                   );
5032 #endif /* COMMENT */
5033         if (zsout(ZDFILE,dbptr) < 0) {
5034             deblog = 0;
5035             zclose(ZDFILE);
5036         }
5037 #ifdef CKSYSLOG
5038         if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5039             cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5040         }
5041 #endif /* CKSYSLOG */
5042         break;
5043
5044 /*
5045   This one was never used so (October 2000) we now use it like F011,
5046   except in this case we treat s2 as NUL terminated.
5047 */
5048       case F010:
5049         n = -debxlen;
5050 /*
5051   This one treats n as the length of the string s2, which may contain NULs.
5052   It's good for logging NUL-bearing data in the debug log.
5053 */
5054       case F011: {
5055           int i, j, contd = 0;
5056           char * p = s2, *pbuf = NULL;  /* p = source pointer */
5057           int m;                        /* pbuf = destination pointer */
5058
5059           if (f == F011) {
5060               if (n < 0) {              /* n = size of source */
5061                   n = 0 - n;            /* Negative means to add "..." */
5062                   contd = 1;
5063               }
5064           } else {
5065               int x, flag = 0;
5066               x = strlen(s2);
5067               if (n < 0) {
5068                   flag = 1;
5069                   n = 0 - n;
5070               }
5071               if (x < n)
5072                 n = x;
5073           }
5074           if (n == 0)                   /* 0 means do nothing */
5075             goto xdebug;
5076           m = DBUFL - 8;                /* Get size for interpreted part */
5077           if (n > m)                    /* Ensure requested size not too big */
5078             n = m;
5079           pbuf = dbptr;                 /* Construction pointer */
5080           i = 0;
5081           pbuf[i++] = '[';              /* Interpret the string into it */
5082           for (j = 0; j < n && i < m-4; p++,j++) { /* char by char... */
5083               if (*p == LF) {
5084                   if (i >= m-4)
5085                     break;
5086                   pbuf[i++] = '<';
5087                   pbuf[i++] = 'L';
5088                   pbuf[i++] = 'F';
5089                   pbuf[i++] = '>';
5090                   continue;
5091               } else if (*p == CR) {
5092                   if (i >= m-4)
5093                     break;
5094                   pbuf[i++] = '<';
5095                   pbuf[i++] = 'C';
5096                   pbuf[i++] = 'R';
5097                   pbuf[i++] = '>';
5098                   continue;
5099               } else if (*p == HT) {
5100                   if (i >= m-5)
5101                     break;
5102                   pbuf[i++] = '<';
5103                   pbuf[i++] = 'T';
5104                   pbuf[i++] = 'A';
5105                   pbuf[i++] = 'B';
5106                   pbuf[i++] = '>';
5107                   continue;
5108               } else if (*p) {
5109                   pbuf[i++] = *p;
5110                   continue;
5111               } else {
5112                   if (i >= m-5)
5113                     break;
5114                   pbuf[i++] = '<';
5115                   pbuf[i++] = 'N';
5116                   pbuf[i++] = 'U';
5117                   pbuf[i++] = 'L';
5118                   pbuf[i++] = '>';
5119                   continue;
5120               }
5121           }
5122           if (i < m-2 && (*p || contd)) {
5123               pbuf[i++] = '.';
5124               pbuf[i++] = '.';
5125           }
5126           pbuf[i++] = ']';
5127           pbuf[i] = NUL;
5128           if (zsout(ZDFILE,s1) < 0) {
5129               deblog = 0;
5130               zclose(ZDFILE);
5131           }
5132           if (zsoutl(ZDFILE,pbuf) < 0) {
5133               deblog = 0;
5134               zclose(ZDFILE);
5135           }
5136 #ifdef CKSYSLOG
5137           if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5138               cksyslog(SYSLG_DB,1,"debug",s1,pbuf);
5139           }
5140 #endif /* CKSYSLOG */
5141         }
5142         break;
5143
5144       case F100:                        /* 4, "s1" */
5145         if (zsoutl(ZDFILE,s1) < 0) {
5146             deblog = 0;
5147             zclose(ZDFILE);
5148         }
5149 #ifdef CKSYSLOG
5150         if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5151             cksyslog(SYSLG_DB,1,"debug",s1,NULL);
5152         }
5153 #endif /* CKSYSLOG */
5154         break;
5155       case F101:                        /* 5, "s1=n" */
5156         sprintf(sp,"%s=%ld\n",s1,n);
5157         if (zsout(ZDFILE,dbptr) < 0) {
5158             deblog = 0;
5159             zclose(ZDFILE);
5160         }
5161 #ifdef CKSYSLOG
5162         if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5163             cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5164         }
5165 #endif /* CKSYSLOG */
5166         break;
5167       case F110:                        /* 6, "s1[s2]" */
5168         sprintf(sp,"%s[%s]\n",s1,s2);
5169         if (zsout(ZDFILE,dbptr) < 0) {
5170             deblog = 0;
5171             zclose(ZDFILE);
5172         }
5173 #ifdef CKSYSLOG
5174         if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5175             cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5176         }
5177 #endif /* CKSYSLOG */
5178         break;
5179       case F111:                        /* 7, "s1[s2]=n" */
5180         sprintf(sp,"%s[%s]=%ld\n",s1,s2,n);
5181         if (zsout(ZDFILE,dbptr) < 0) {
5182             deblog = 0;
5183             zclose(ZDFILE);
5184         }
5185 #ifdef CKSYSLOG
5186         if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5187             cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5188         }
5189 #endif /* CKSYSLOG */
5190         break;
5191       default:
5192         sprintf(sp,"\n?Invalid format for debug() - %d\n",f);
5193         if (zsout(ZDFILE,dbptr) < 0) {
5194             deblog = 0;
5195             zclose(ZDFILE);
5196         }
5197 #ifdef CKSYSLOG
5198         if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5199             cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5200         }
5201 #endif /* CKSYSLOG */
5202         break;
5203     }
5204   xdebug:                               /* Common exit point */
5205 #ifdef OS2
5206     if (SysInited)
5207         ReleaseDebugMutex();
5208 #else /* OS2 */
5209     deblog = 1;                         /* Restore this */
5210 #endif /* OS2 */
5211     return(0);
5212 }
5213
5214 int
5215 #ifdef CK_ANSIC
5216 dohexdump(CHAR *msg, CHAR *st, int cnt)
5217 #else
5218 dohexdump(msg,st,cnt) CHAR *msg; CHAR *st; int cnt;
5219 #endif /* CK_ANSIC */
5220 /* dohexdump */ {
5221     int i = 0, j = 0, k = 0;
5222     char tmp[8];
5223 #ifdef OS2
5224     extern int SysInited;
5225 #endif /* OS2 */
5226
5227     if (!deblog) return(0);             /* If no debug log, don't. */
5228     if (!dbptr) {                       /* Allocate memory buffer */
5229         dbptr = malloc(DBUFL+1);        /* This only happens once */
5230         if (!dbptr) {
5231             deblog = 0;
5232             zclose(ZDFILE);
5233             return(0);
5234         }
5235     }
5236
5237 #ifdef OS2
5238     if (SysInited) {
5239         if (RequestDebugMutex(30000))
5240             goto xdebug;
5241     }
5242 #else /* OS2 */
5243     deblog = 0;                         /* Prevent infinite recursion */
5244 #endif /* OS2 */
5245
5246     if (msg != NULL) {
5247         ckmakxmsg(dbptr,
5248                   DBUFL,
5249                   "HEXDUMP: ",
5250                   (char *)msg,
5251                   " (",
5252                   ckitoa(cnt),
5253                   " bytes)\n",
5254                   NULL,NULL,NULL,NULL,NULL,NULL,NULL
5255                  );
5256         if (zsout(ZDFILE,dbptr) < 0) {
5257             deblog = 0;
5258             zclose(ZDFILE);
5259             goto xdebug;
5260         }
5261     } else {
5262         ckmakmsg(dbptr,
5263                  DBUFL,
5264                  "HEXDUMP: (",
5265                  ckitoa(cnt),
5266                  " bytes)\n",
5267                  NULL
5268                  );
5269         zsout(ZDFILE,dbptr);
5270         if (zsout(ZDFILE,dbptr) < 0) {
5271             deblog = 0;
5272             zclose(ZDFILE);
5273             goto xdebug;
5274         }
5275     }
5276     for (i = 0; i < cnt; i++) {
5277         dbptr[0] = '\0';
5278         for (j = 0 ; (j < 16); j++) {
5279             if ((i + j) < cnt)
5280               sprintf(tmp,
5281                       "%s%02x ",
5282                       (j == 8 ? "| " : ""),
5283                       (CHAR) st[i + j]
5284                       );
5285             else
5286               sprintf(tmp,
5287                       "%s   ",
5288                       (j == 8 ? "| " : "")
5289                       );
5290             ckstrncat(dbptr,tmp,DBUFL+1);
5291         }
5292         ckstrncat(dbptr," ",DBUFL+1);
5293         for (k = 0; (k < 16) && ((i + k) < cnt); k++) {
5294             sprintf(tmp,
5295                     "%s%c",
5296                     (k == 8 ? " " : ""),
5297                     isprint(st[i + k]) ? st[i + k] : '.'
5298                     );
5299             ckstrncat(dbptr,tmp,DBUFL+1);
5300         }
5301         ckstrncat(dbptr,"\n",DBUFL+1);
5302         i += j - 1;
5303         if (zsout(ZDFILE,dbptr) < 0) {
5304             deblog = 0;
5305             zclose(ZDFILE);
5306             goto xdebug;
5307         }
5308     } /* end for */
5309
5310
5311   xdebug:
5312 #ifdef OS2
5313     if (SysInited)
5314       ReleaseDebugMutex();
5315 #else /* OS2 */
5316     deblog = 1;
5317 #endif /* OS2 */
5318     return(0);
5319 }
5320 #endif /* DEBUG */
5321
5322 /*  Session Log... */
5323
5324 extern int slogts;                      /* Session Log timestamps */
5325 int tsstate = 0;
5326
5327 VOID
5328 #ifdef OS2
5329 logchar(unsigned short c)
5330 #else /* OS2 */
5331 #ifdef CK_ANSIC
5332 logchar(char c)
5333 #else
5334 logchar(c) char c;
5335 #endif /* CK_ANSIC */
5336 #endif /* OS2 */
5337 /* logchar */ {                         /* Log character c to session log */
5338     int oktolog = 0;
5339 #ifndef NOLOCAL
5340     if (!seslog)
5341       return;
5342
5343     if ((sessft != XYFT_T) ||
5344         (c != '\0' &&
5345 #ifdef UNIX
5346          c != '\r' &&
5347 #else
5348 #ifdef datageneral
5349          c != '\r' &&
5350 #else
5351 #ifdef STRATUS
5352          c != '\r' &&
5353 #else
5354 #ifdef AMIGA
5355          c != '\r' &&
5356 #else
5357 #ifdef GEMDOS
5358          c != '\r' &&
5359 #endif /* GEMDOS */
5360 #endif /* AMIGA */
5361 #endif /* STRATUS */
5362 #endif /* datageneral */
5363 #endif /* UNIX */
5364 #ifdef OSK
5365          c != '\n' &&
5366 #else
5367 #ifdef MAC
5368          c != '\n' &&
5369 #endif /* MAC */
5370 #endif /* OSK */
5371          c != XON &&
5372          c != XOFF))
5373       oktolog = 1;
5374     if (!oktolog)
5375       return;
5376     if (slogts) {                       /* Log is timestamped */
5377         if (tsstate == 0) {             /* State = between-lines */
5378             char * p;                   /* zstime() pointer */
5379             char ts[48];                /* timestamp buffer */
5380             ztime(&p);                  /* Get asctime() string */
5381             ckstrncpy(ts,p,32);         /* Make safe copy */
5382             if (ztmsec > -1L) {         /* Add msecs if we have them */
5383                 sprintf(&ts[19],".%03ld: ",ztmsec); /* SAFE */
5384             } else {
5385                 ts[19] = ':';
5386                 ts[20] = SP;
5387                 ts[21] = NUL;
5388             }
5389             if (zsout(ZSFILE,&ts[11]) < 0)
5390               goto xlogchar;
5391             if (c != '\n')              /* If this is not eol */
5392               tsstate = 1;              /* go to in-a-line state. */
5393         } else if (c == '\n') {         /* In a line */
5394             tsstate = 0;                /* If eol go to between-lines state. */
5395         }
5396     }
5397     if (zchout(ZSFILE,(CHAR)(c & 0xFF)) < 0) /* Log the character */
5398       goto xlogchar;
5399     return;
5400
5401   xlogchar:
5402     conoll("");
5403     conoll("ERROR WRITING SESSION LOG, LOG CLOSED!");
5404     setseslog(0);
5405     zclose(ZSFILE);
5406 #endif /* NOLOCAL */
5407 }
5408
5409 VOID
5410 logstr(s, len) char * s; int len; {     /* Log string to session log */
5411 #ifndef NOLOCAL
5412     int n = 0;
5413     if (!s)
5414       return;
5415     while (seslog && (n < len))
5416       logchar(s[n++]);
5417 #endif /* NOLOCAL */
5418 }
5419
5420 #ifdef CK_CURSES
5421 int
5422 ck_repaint() {
5423     repaint = 1;
5424     return(0);
5425 }
5426
5427 #ifdef STRATUS
5428 /* VOS has curses but no tgetent() */
5429 int
5430 tgetent(s1, s2) char * s1, * s2; {
5431     return(1);
5432 }
5433 #endif /* STRATUS */
5434
5435 #ifdef VMS
5436 #ifdef __DECC
5437 _PROTOTYP(int tgetent,(char *, char *));
5438 #endif /* __DECC */
5439 #endif /* VMS */
5440
5441 /*
5442   There are three different ways to do fullscreen on VMS.
5443   1. Use the real curses library, VAXCCURSE.
5444   2. Use do-it-yourself code.
5445   3. Use the Screen Manager, SMG$.
5446
5447   Method 1 doesn't work quite right; you can't call endwin(), so once you've
5448   started curses mode, you can never leave.
5449
5450   Method 2 doesn't optimize the screen, and so much more time is spent in
5451   screen writes.  This actually causes file transfers to fail because the
5452   tty device input buffer can be overrun while the screen is being updated,
5453   especially on a slow MicroVAX that has small typeahead buffers.
5454
5455   In the following #ifdef block, #define one of them and #undef the other 2.
5456
5457   So now let's try method 3...
5458 */
5459 #ifdef VMS
5460 #define CK_SMG                          /* Screen Manager */
5461 #undef MYCURSES                         /* Do-it-yourself */
5462 #undef VMSCURSE                         /* VAXCCURSE library */
5463 #endif /* VMS */
5464 /*
5465   But just before New Years, 2000, the SMG library seemed to break on
5466   both VMS systems we have here (an Alpha with VMS 7.1 and a VAX with 5.5).
5467   So back to MYCURSES, which works fine.
5468 */
5469 #ifdef VMS
5470 #undef CK_SMG
5471 #define MYCURSES
5472 #endif /* VMS */
5473
5474 #ifdef MYCURSES
5475 #define stdscr 0
5476 #ifdef CK_WREFRESH
5477 #undef CK_WREFRESH
5478 #endif /* CK_WREFRESH */
5479 #endif /* MYCURSES */
5480
5481 /*  S C R E E N C  --  Screen display function, uses curses  */
5482
5483 /* Idea for curses display contributed by Chris Pratt of APV Baker, UK */
5484
5485 /* Avoid conficts with curses.h */
5486
5487 #ifdef QNX
5488 /* Same as ckcasc.h, but in a different radix... */
5489 #ifdef ESC
5490 #undef ESC
5491 #endif /* ESC */
5492 #endif /* QNX */
5493
5494 #ifndef MYCURSES
5495 #undef VOID                             /* This was defined in ckcdeb.h */
5496 #endif /* MYCURSES */
5497
5498 #undef BS                               /* These were defined in ckcasc.h */
5499 #undef CR
5500 #undef NL
5501 #undef SO
5502 #undef US
5503 #undef SP                               /* Used in ncurses */
5504 #define CHR_SP 32                       /* Use this instead */
5505
5506 #ifdef VMS                              /* VMS fullscreen display */
5507 #ifdef MYCURSES                         /* Do-it-yourself method */
5508 extern int isvt52;                      /* From CKVTIO.C */
5509 #define printw printf
5510 #else
5511 #ifdef VMSCURSE                         /* VMS curses library VAXCCURSE */
5512 #include <curses.h>
5513 /* Note: Screen manager doesn't need a header file */
5514 #endif /* VMSCURSE */
5515 #endif /* MYCURSES */
5516 #else                                   /* Not VMS */
5517 #ifdef MYCURSES                         /* Do-it-yourself method */
5518 #define isvt52 0                        /* Used by OS/2, VT-100/ANSI always */
5519 #ifdef CKXPRINTF
5520 #define printw ckxprintf
5521 #else /* CKXPRINTF */
5522 #ifdef KUI
5523 #define printw Vscrnprintw
5524 #else /* KUI */
5525 #define printw printf
5526 #endif /* KUI */
5527 #endif /* CKXPRINTF */
5528 #else                                   /* Use real curses */
5529 #ifdef CK_NCURSES                       /* or ncurses... */
5530 #ifdef CKXPRINTF                        /* Our printf macro conflicts with */
5531 #undef printf                           /* use of "printf" in ncurses.h */
5532 #endif /* CKXPRINTF */
5533 #include <ncurses.h>
5534 #ifdef CKXPRINTF
5535 #define printf ckxprintf
5536 #endif /* CKXPRINTF */
5537 #else  /* Not ncurses */
5538 #ifdef CKXPRINTF                        /* Our printf macro conflicts with */
5539 #undef printf                           /* use of "printf" in curses.h */
5540 #endif /* CKXPRINTF */
5541 #ifdef M_XENIX                          /* SCO XENIX... */
5542 #ifdef M_TERMCAP
5543 #undef M_TERMCAP
5544 #endif /* M_TERMCAP */
5545 #ifndef M_TERMINFO
5546 #define M_TERMINFO
5547 #endif /* M_TERMINFO */
5548 #endif /* M_XENIX */
5549 #ifdef RTAIX
5550 #undef NLS                              /* Avoid 'redeclaration of free'. */
5551 #endif /* RTAIX */
5552 #include <curses.h>
5553 #ifdef CKXPRINTF
5554 #define printf ckxprintf
5555 #endif /* CKXPRINTF */
5556 #endif /* CK_NCURSES */
5557 #endif /* MYCURSES */
5558 #endif /* VMS */
5559
5560 #endif /* CK_CURSES */
5561
5562 /*  F X D I N I T  --  File Xfer Display Initialization  */
5563
5564 #ifdef CK_CURSES
5565 #ifndef MYCURSES
5566 #ifndef CK_SMG
5567 static
5568 #ifdef CK_ANSIC
5569 /* Can't use VOID because of curses.h */
5570 void
5571 ck_termset(int);
5572 #else
5573 ck_termset();
5574 #endif /* CK_ANSIC */
5575 #endif /* CK_SMG */
5576 #endif /* MYCURSES */
5577 #endif /* CK_CURSES */
5578
5579 #ifdef NOTERMCAP
5580 static int notermcap = 1;
5581 #else
5582 static int notermcap = 0;
5583 #endif /* NOTERMCAP */
5584
5585 #ifndef NODISPLAY
5586 #ifdef OSK
5587 VOID
5588 #else
5589 #ifdef CK_ANSIC
5590 void
5591 #endif /* CKANSIC */
5592 #endif /* OSK */
5593 fxdinit(xdispla) int xdispla; {
5594 #ifndef COHERENT
5595 #ifndef OS2
5596 #ifndef STRATUS
5597     char *s;
5598     int x, dummy;
5599
5600     debug(F101,"fxdinit xdispla","",xdispla);
5601     debug(F101,"fxdinit fxd_inited","",fxd_inited);
5602
5603 #ifdef IKSD
5604 #ifndef NOXFER
5605     /* No curses for IKSD */
5606     if (inserver) {
5607         fdispla = XYFD_N;
5608         return;
5609     }
5610     if (fxd_inited)                     /* Only do this once */
5611       return;
5612 #endif /* NOXFER */
5613 #endif /* IKSD */
5614
5615     if (xdispla == XYFD_R || xdispla == XYFD_S || xdispla == XYFD_B) {
5616         if (xfrmsg) {
5617             printf("%s\n",xfrmsg);
5618             makestr(&xfrmsg,NULL);
5619         }
5620     }
5621
5622 #ifdef CK_CURSES
5623 #ifdef VMS
5624     /* Force BRIEF in Batch logs */
5625     if (batch && (xdispla == XYFD_C || xdispla == XYFD_S))
5626       xdispla = XYFD_B;
5627 #else
5628     if (xdispla == XYFD_C || xdispla == 9999) {
5629
5630 #ifdef DYNAMIC
5631         if (!trmbuf) {
5632 /*
5633   Allocate tgetent() buffer.  Make it big -- some termcaps can be huge;
5634   tgetent() merrily writes past the end of the buffer, causing core dumps
5635   or worse.
5636 */
5637             trmbuf = (char *)malloc(TRMBUFL);
5638             if (!trmbuf) {
5639                 notermcap = 1;
5640                 debug(F101,"fxdinit malloc trmbuf","FAILED",TRMBUFL);
5641                 fdispla = XYFD_S;
5642                 return;
5643             }
5644             debug(F111,"fxdinit malloc trmbuf","OK",TRMBUFL);
5645             debug(F001,"fxdinit trmbuf","",trmbuf);
5646 #ifdef COMMENT
5647             memset(trmbuf,'\0',(size_t)TRMBUFL);
5648             debug(F100,"fxdinit memset OK","",0);
5649 #endif /* COMMENT */
5650         }
5651 #endif /* DYNAMIC */
5652
5653         debug(F100,"fxdinit before getenv(TERM)","",0);
5654         s = getenv("TERM");
5655         debug(F110,"fxdinit after getenv(TERM)",s,0);
5656         if (!s) s = "";
5657         if (*s) {
5658             debug(F110,"fxdinit before tgetent()",s,0);
5659             x = tgetent(trmbuf,s);
5660             debug(F111,"fxdinit tgetent",s,x);
5661         } else {
5662             x = 0;
5663             notermcap = 1;
5664             debug(F110,"fxdinit TERM null - no tgetent",s,0);
5665         }
5666         if (x < 1 && !quiet && !backgrd
5667 #ifdef VMS
5668             && !batch
5669 #endif /* VMS */
5670             ) {
5671             printf("Warning: terminal type unknown: \"%s\"\n",s);
5672 #ifdef COMMENT
5673             /* Confusing - nobody knows what this means */
5674             printf("SCREEN command will use ANSI sequences.\n");
5675 #endif /* COMMENT */
5676             if (local)
5677               printf("Fullscreen file transfer display disabled.\n");
5678             fdispla = XYFD_S;
5679         }
5680 #ifndef MYCURSES
5681 #ifndef CK_SMG
5682         ck_termset(x);
5683 #endif /* CK_SMG */
5684 #endif /* MYCURSES */
5685         fxd_inited = 1;
5686     }
5687 #endif /* CK_CURSES */
5688 #endif /* VMS */
5689 #endif /* STRATUS */
5690 #endif /* OS2 */
5691 #endif /* COHERENT */
5692 }
5693 #endif /* NODISPLAY */
5694
5695 #ifdef CK_CURSES
5696 #ifdef CK_SMG
5697 /*
5698   Long section for Screen Manager starts here...
5699   By William Bader.
5700 */
5701 #include "ckvvms.h"
5702 #ifdef OLD_VMS
5703 #include <smgdef.h>                     /* use this on VAX C 2.4 */
5704 /* #include <smgmsg.h> */
5705 #else
5706 #include <smg$routines.h>               /* Martin Zinser */
5707 #endif /* OLD_VMS */
5708
5709 extern unsigned int vms_status;     /* Used for system service return status */
5710
5711 static long smg_pasteboard_id = -1;     /* pasteboard identifier */
5712 static long smg_display_id = -1;        /* display identifier */
5713 static int smg_open = 0;                /* flag if smg current open */
5714 static int smg_inited = 0;              /* flag if smg initialized */
5715
5716 #ifdef COMMENT
5717 #define clrtoeol()      SMG$ERASE_LINE(&smg_display_id, 0, 0)
5718
5719 #define clear()         SMG$ERASE_DISPLAY(&smg_display_id, 0, 0, 0, 0)
5720
5721 #define touchwin(scr)   SMG$REPAINT_SCREEN(&smg_pasteboard_id)
5722
5723 #else  /* Not COMMENT */
5724
5725 #define clrtoeol()      smg$erase_line(&smg_display_id, 0, 0)
5726
5727 #define clear()         smg$erase_display(&smg_display_id, 0, 0, 0, 0)
5728
5729 #define touchwin(scr)   smg$repaint_screen(&smg_pasteboard_id)
5730 #endif /* COMMENT */
5731
5732 #define clearok(curscr,ok)              /* Let wrefresh() do the work */
5733
5734 #define wrefresh(cursrc) touchwin(scr)
5735
5736 static void
5737 move(row, col) int row, col; {
5738     /* Change from 0-based for curses to 1-based for SMG */
5739     if (!smg_open)
5740       return;
5741     ++row; ++col;
5742     debug(F111,"VMS smg move",ckitoa(row),col);
5743 #ifdef COMMENT                          /* Martin Zinser */
5744     CHECK_ERR("move: smg$set_cursor_abs",
5745               SMG$SET_CURSOR_ABS(&smg_display_id, &row, &col));
5746 #else
5747     CHECK_ERR("move: smg$set_cursor_abs",
5748               smg$set_cursor_abs(&smg_display_id, &row, &col));
5749 #endif /* COMMENT */
5750     debug(F101,"VMS smg move vms_status","",vms_status);
5751 }
5752
5753 #ifdef VMS_V40
5754 #define OLD_VMS
5755 #endif /* VMS_V40 */
5756 #ifdef VMS_V42
5757 #define OLD_VMS
5758 #endif /* VMS_V42 */
5759 #ifdef VMS_V44
5760 #define OLD_VMS
5761 #endif /* VMS_V44 */
5762
5763 static int
5764 initscr() {
5765     int rows = 24, cols = 80;
5766     int row = 1, col = 1;
5767
5768     debug(F101,"VMS initscr smg_pasteboard_id A","",smg_pasteboard_id);
5769
5770     if (smg_pasteboard_id == -1) { /* Open the screen */
5771 #ifdef OLD_VMS                     /* Note: Routine calls lowercased 9/96 */
5772         CHECK_ERR("initscr: smg$create_pasteboard",
5773                   smg$create_pasteboard(&smg_pasteboard_id, 0, 0, 0, 0));
5774 #else
5775         /* For VMS V5, not tested */
5776         CHECK_ERR("initscr: smg$create_pasteboard",
5777                   smg$create_pasteboard(&smg_pasteboard_id, 0, 0, 0, 0, 0));
5778 #endif /* OLD_VMS */
5779     }
5780     debug(F101,"VMS initscr smg_pasteboard_id B","",smg_pasteboard_id);
5781     if (smg_pasteboard_id == -1) {
5782         printf("?Error initializing fullscreen display\n");
5783         fdispla = XYFD_S;
5784         dpyinit();
5785         return(0);
5786     }
5787     debug(F101,"VMS initscr smg_display_id","",smg_display_id);
5788     if (smg_display_id == -1) {         /* Create a display window */
5789
5790 #ifdef COMMENT                          /* Martin Zinser */
5791         CHECK_ERR("initscr: smg$create_virtual_display",
5792                   SMG$CREATE_VIRTUAL_DISPLAY(&rows, &cols, &smg_display_id,
5793                                              0, 0, 0));
5794
5795         /* Connect the display window to the screen */
5796         CHECK_ERR("initscr: smg$paste_virtual_display",
5797                   SMG$PASTE_VIRTUAL_DISPLAY(&smg_display_id,&smg_pasteboard_id,
5798                                             &row,&col));
5799 #else
5800         CHECK_ERR("initscr: smg$create_virtual_display",
5801                   smg$create_virtual_display(&rows, &cols, &smg_display_id,
5802                                              0, 0, 0));
5803
5804         /* Connect the display window to the screen */
5805         CHECK_ERR("initscr: smg$paste_virtual_display",
5806                   smg$paste_virtual_display(&smg_display_id,&smg_pasteboard_id,
5807                                             &row,&col));
5808 #endif /* COMMENT */
5809     }
5810     debug(F101,"VMS initscr smg_open A","",smg_open);
5811     if (!smg_open) {                    /* Start a batch update */
5812         smg_open = 1;
5813 #ifdef COMMENT
5814         CHECK_ERR("initscr: smg$begin_pasteboard_update",
5815                   SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id));
5816 #else
5817         CHECK_ERR("initscr: smg$begin_pasteboard_update",
5818                   smg$begin_pasteboard_update(&smg_pasteboard_id));
5819 #endif /* COMMENT */
5820         debug(F101,"VMS initscr smg$begin_pasteboard_update","",vms_status);
5821     }
5822     debug(F101,"VMS initscr smg_open B","",smg_open);
5823     smg_inited = 1;
5824     return(1);
5825 }
5826
5827 static void
5828 refresh() {
5829     debug(F101,"refresh smg_pasteboard_id","",smg_pasteboard_id);
5830
5831     if (smg_open == 0 || smg_pasteboard_id == -1)
5832       return;
5833
5834 #ifdef COMMENT                          /* Martin Zinser */
5835     CHECK_ERR("refresh: smg$end_pasteboard_update",
5836               SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id));
5837     CHECK_ERR("refresh: smg$begin_pasteboard_update",
5838               SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id));
5839 #else
5840     CHECK_ERR("refresh: smg$end_pasteboard_update",
5841               smg$end_pasteboard_update(&smg_pasteboard_id));
5842     CHECK_ERR("refresh: smg$begin_pasteboard_update",
5843               smg$begin_pasteboard_update(&smg_pasteboard_id));
5844 #endif /* COMMENT */
5845 }
5846
5847 static void
5848 endwin() {
5849     if (!smg_open)
5850       return;
5851
5852     smg_open = 0;
5853
5854 #ifdef COMMENT
5855     CHECK_ERR("endwin: smg$end_pasteboard_update",
5856               SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id));
5857 #else
5858     CHECK_ERR("endwin: smg$end_pasteboard_update",
5859               smg$end_pasteboard_update(&smg_pasteboard_id));
5860 #endif /* COMMENT */
5861
5862     move(22, 0);
5863
5864 #ifdef COMMENT
5865 /*
5866   These calls clear the screen.
5867   (convert routine calls to lowercase - Martin Zinser)
5868 */
5869     CHECK_ERR("endwin: smg$delete_virtual_display",
5870               SMG$DELETE_VIRTUAL_DISPLAY(&smg_display_id));
5871     smg_display_id = -1;
5872
5873     CHECK_ERR("endwin: smg$delete_pasteboard",
5874               SMG$DELETE_PASTEBOARD(&smg_pasteboard_id, 0));
5875     smg_pasteboard_id = -1;
5876 #endif /* COMMENT */
5877 }
5878
5879 #ifdef COMMENT
5880 /* DECC 6.2 screams bloody murder about printw ("not enough args") */
5881 /* but adding the following prototype only makes it holler louder. */
5882 #ifdef __DECC
5883 /* "varargs" prototype for printw */
5884 _PROTOTYP(static int printw,(char *, ...));
5885 #endif /* __DECC */
5886 #endif /* COMMENT */
5887
5888 #ifdef __DECC
5889 #include <stdarg.h>
5890 _PROTOTYP(static void printw,(char *, ...));
5891 static void
5892 printw(char *str,...) {
5893     char buf[255];
5894     va_list ap;
5895     $DESCRIPTOR(text_dsc, 0);
5896     text_dsc.dsc$a_pointer=buf;
5897     if (!smg_open)
5898       return;
5899     va_start(ap,str);
5900     text_dsc.dsc$w_length = vsprintf(buf, str, ap);
5901     va_end(ap);
5902     CHECK_ERR("printw: smg$put_chars",
5903               smg$put_chars(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0));
5904 }
5905 #else
5906 static void
5907 printw(str, a1, a2, a3, a4, a5, a6, a7, a8)
5908     char *str;
5909     long a1, a2, a3, a4, a5, a6, a7, a8;
5910 /* printw */ {
5911     char buf[255];
5912     $DESCRIPTOR(text_dsc, 0);
5913     if (!smg_open)
5914       return;
5915     text_dsc.dsc$a_pointer=buf;
5916     text_dsc.dsc$w_length = sprintf(buf, str, a1, a2, a3, a4, a5, a6, a7, a8);
5917     CHECK_ERR("printw: smg$put_chars",
5918               smg$put_chars(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0));
5919 }
5920 #endif /* __DECC */
5921
5922 #define CK_CURPOS
5923 int
5924 ck_curpos(row, col) {
5925     debug(F111,"VMS smg ck_curpos",ckitoa(row),col);
5926     if (!smg_inited || !smg_open) {
5927         initscr();
5928     }
5929     debug(F101,"VMS smg curpos smg_open","",smg_open);
5930     if (!smg_open)
5931       return(0);
5932     debug(F111,"VMS smg ck_curpos",ckitoa(row-1),col-1);
5933     move(row - 1, col - 1);             /* SMG is 0-based */
5934     refresh();
5935     /* endwin(); */
5936     return(0);
5937 }
5938
5939 int
5940 ck_cls() {
5941     debug(F101,"VMS smg ck_cls smg_inited","",smg_inited);
5942     if (!smg_inited || !smg_open) {
5943         initscr();
5944     }
5945     debug(F101,"VMS smg ck_cls smg_open","",smg_open);
5946     if (!smg_open)
5947       return(0);
5948     clear();
5949     refresh();
5950     /* endwin(); */
5951     return(0);
5952 }
5953
5954 int
5955 ck_cleol() {
5956     debug(F101,"VMS smg ck_cleol smg_inited","",smg_inited);
5957     if (!smg_inited || !smg_open) {
5958         initscr();
5959     }
5960     debug(F101,"VMS smg ck_cleol smg_open","",smg_open);
5961     if (!smg_open)
5962       return(0);
5963     clrtoeol();
5964     refresh();
5965     /* endwin(); */
5966     return(0);
5967 }
5968 #endif /* CK_SMG */
5969
5970 #ifdef MYCURSES
5971 /*
5972   Do-it-yourself curses implementation for VMS, OS/2 and other ANSI/VT-100's.
5973   Supports only the VT52 and VT1xx (and later VT2xx/3xx/4xx) terminals.
5974   By Terry Kennedy, St Peters College.
5975
5976   First, some stuff we can just ignore:
5977 */
5978
5979 static int
5980 touchwin(x) int x; {
5981     return(0);
5982 }
5983 static int
5984 initscr() {
5985     return(0);
5986 }
5987 static int
5988 refresh() {
5989     return(0);
5990 }
5991 static int
5992 endwin() {
5993     return(0);
5994 }
5995
5996 /*
5997  * Now, some stuff we need to do:
5998  */
5999
6000 _PROTOTYP( int move, (int, int) );
6001 #ifndef OS2
6002 int
6003 move(row, col) int row, col; {
6004     if (isvt52)
6005       printf("\033Y%c%c", row + 037, col + 037);
6006     else
6007       printf("\033[%d;%dH", row + 1, col + 1);
6008     return(0);
6009 }
6010
6011 int
6012 clear() {
6013     move(0,0);
6014     if (isvt52)
6015       printf("\033J");
6016     else
6017       printf("\033[J");
6018     return(0);
6019 }
6020
6021 int
6022 clrtoeol() {
6023     if (isvt52)
6024       printf("\033K");
6025     else
6026       printf("\033[K");
6027     return(0);
6028 }
6029
6030 #define CK_CURPOS
6031 int
6032 ck_cls() {
6033     return(clear());
6034 }
6035
6036 int
6037 ck_cleol() {
6038     return(clrtoeol());
6039 }
6040
6041 int
6042 ck_curpos(row, col) int row, col; {
6043     move(row, col);
6044     return(0);
6045 }
6046
6047 #else /* OS2 */
6048 /* Windows NT and Windows 95 do not provide ANSI emulation */
6049 /* Therefore we might as well not use it for OS/2 either   */
6050
6051 int
6052 move(row, col) int row, col; {
6053 #ifndef ONETERMUPD
6054     SetCurPos(row, col);
6055 #endif /* ONETERMUPD */
6056     lgotoxy( VCMD, col+1, row+1);
6057     VscrnIsDirty(VCMD);
6058     return(0);
6059 }
6060
6061 int
6062 clear() {
6063     viocell cell;
6064     move(0,0);
6065 #ifdef ONETERMUPD
6066     if (VscrnGetBufferSize(VCMD) > 0) {
6067         VscrnScroll(VCMD, UPWARD, 0,
6068                     VscrnGetHeight(VCMD)-(1),
6069                     VscrnGetHeight(VCMD)-(0), TRUE, CHR_SP);
6070         cleartermscreen(VCMD);
6071     }
6072 #else
6073     cell.c = ' ';
6074     cell.a = colorcmd;
6075     WrtNCell(cell, cmd_rows * cmd_cols, 0, 0);
6076 #endif /* ONETERMUPD */
6077     return(0);
6078 }
6079
6080 int
6081 clrtoeol() {
6082     USHORT row, col;
6083     viocell cell;
6084
6085     cell.c = ' ';
6086     cell.a = colorcmd;
6087 #ifndef ONETERMUPD
6088     GetCurPos(&row, &col );
6089     WrtNCell(cell, cmd_cols - col -1, row, col);
6090 #endif /* ONETERMUPD */
6091     clrtoeoln(VCMD,CHR_SP);
6092     return(0);
6093 }
6094
6095 #define CK_CURPOS
6096 int
6097 ck_curpos(row, col) int row, col; {
6098     move(row, col);
6099     return(0);
6100 }
6101
6102 int
6103 ck_cls() {
6104     return(clear());
6105 }
6106
6107 int
6108 ck_cleol() {
6109     return(clrtoeol());
6110 }
6111
6112 #endif /* OS2 */
6113 #endif /* MYCURSES */
6114
6115 #ifndef NOTERMCAP
6116 #ifndef CK_CURPOS
6117 #define CK_CURPOS
6118
6119 /* Termcap/Terminfo section */
6120
6121 static char cur_cls[32] = { NUL, NUL };
6122 static char cur_cleol[32] = { NUL, NUL };
6123 static char cur_cm[64] = { NUL, NUL };
6124 static char tgsbuf[128] = { NUL, NUL };
6125
6126 static
6127 #ifdef CK_ANSIC
6128 void
6129 #endif /* CK_ANSIC */
6130 ck_termset(x) int x; {
6131     cur_cls[0] = NUL;
6132     cur_cleol[0] = NUL;
6133     cur_cm[0] = NUL;
6134 #ifdef tgetent
6135     debug(F100,"tgetent is a macro","",0);
6136 #endif /* tgetent */
6137 #ifdef tgetstr
6138     debug(F100,"tgetstr is a macro","",0);
6139 #endif /* tgetstr */
6140 #ifdef tputs
6141     debug(F100,"tputs is a macro","",0);
6142 #endif /* tputs */
6143 #ifdef tgoto
6144     debug(F100,"tgoto is a macro","",0);
6145 #endif /* tgoto */
6146 #ifdef NOTERMCAP
6147     /* tgetstr() gets a segmentation fault on OSF/1 */
6148     debug(F100,"ck_termset NOTERMCAP","",0);
6149 #else
6150     if (notermcap) {
6151         debug(F100,"ck_termset notermcap","",0);
6152         return;
6153     }
6154     debug(F101,"ck_termset x","",x);
6155     if (x > 0) {
6156         char * bp;
6157         bp = tgsbuf;
6158         *bp = NUL;
6159         debug(F110,"ck_termset calling tgetstr","cl",0);
6160         if (tgetstr("cl", &bp)) {       /* Get clear-screen code */
6161             debug(F110,"ck_termset tgetstr cl",tgsbuf,"");
6162             if ((int)strlen(tgsbuf) < 32)
6163               ckstrncpy(cur_cls,tgsbuf,32);
6164         } else
6165           return;
6166         bp = tgsbuf;
6167         if (tgetstr("ce", &bp)) {       /* Get clear-to-end-of-line code */
6168             debug(F110,"ck_termset tgetstr ce",tgsbuf,"");
6169             if ((int)strlen(tgsbuf) < 32)
6170               ckstrncpy(cur_cleol,tgsbuf,32);
6171         } else
6172           return;
6173         bp = tgsbuf;
6174         if (tgetstr("cm", &bp)) {       /* Get cursor-movement code */
6175             debug(F110,"ck_termset tgetstr cm",tgsbuf,"");
6176             if ((int)strlen(tgsbuf) < 64)
6177               ckstrncpy(cur_cm,tgsbuf,64);
6178         } else
6179           return;
6180     }
6181 #endif /* NOTERMCAP */
6182 }
6183
6184 #ifndef TPUTSFNTYPE
6185 #ifdef TPUTSISVOID
6186 #define TPUTSFNTYPE void
6187 #else
6188 #define TPUTSFNTYPE int
6189 #endif /* TPUTSISVOID */
6190 #endif /* TPUTSFNTYPE */
6191
6192 #ifndef TPUTSARGTYPE
6193 #ifdef HPUX9
6194 #define TPUTSARGTYPE char
6195 #else
6196 #ifdef HPUX10
6197 #define TPUTSARGTYPE char
6198 #else
6199 #define TPUTSARGTYPE int
6200 #endif /* HPUX10 */
6201 #endif /* HPUX9 */
6202 #endif /* TPUTSARGTYPE */
6203
6204 static TPUTSFNTYPE
6205 #ifdef CK_ANSIC
6206 ck_outc(TPUTSARGTYPE x)
6207 #else
6208 ck_outc(x) TPUTSARGTYPE x;
6209 #endif /* CK_ANSIC */
6210 {                                       /* To satisfy tputs() arg3 prototype */
6211     int rc;
6212     char c;
6213     c = (char) x;
6214     rc = (inserver) ? ttoc(c) : conoc(c);
6215 #ifndef TPUTSISVOID
6216     return(rc);
6217 #endif /* TPUTSISVOID */
6218 }
6219
6220 int
6221 ck_curpos(row, col) int row, col; {
6222 #ifdef CK_ANSIC
6223     TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
6224 #else
6225     TPUTSFNTYPE (*fn)();
6226 #endif /* CK_ANSIC */
6227     if (!fxd_inited)
6228       fxdinit(9999);
6229     if (!cur_cm[0]) {                   /* We don't have escape sequences */
6230 #ifdef COMMENT
6231         return(-1);                     /* Do nothing */
6232 #else
6233         /* Both C-Kermit's SCREEN command and ANSI/VT100 are 1-based */
6234         printf("\033[%d;%dH", row, col); /* Or default to ANSI */
6235 #endif /* COMMENT */
6236     } else {
6237         fn = ck_outc;
6238         /* termcap/terminfo is 0-based */
6239         tputs(
6240 #ifdef TPUTSARG1CONST
6241               (const char *)
6242 #endif /* TPUTSARG1CONST */
6243               tgoto(cur_cm,col-1,row-1),1,fn);
6244     }
6245     return(0);
6246 }
6247
6248 int
6249 ck_cls() {
6250 #ifdef CK_ANSIC
6251     TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
6252 #else
6253     TPUTSFNTYPE (*fn)();
6254 #endif /* CK_ANSIC */
6255     if (!fxd_inited)
6256       fxdinit(9999);
6257     if (!cur_cls[0]) {                  /* If we don't have escape sequences */
6258 #ifdef COMMENT
6259         return(-1);                     /* Do nothing */
6260 #else
6261         printf("\033[;H\033[2J");       /* Or default to ANSI */
6262 #endif /* COMMENT */
6263     } else {
6264         fn = ck_outc;
6265         debug(F111,"ck_cls 2",cur_cls,fxd_inited);
6266         tputs(cur_cls,cmd_rows,fn);
6267     }
6268     return(0);
6269 }
6270
6271 int
6272 ck_cleol() {
6273 #ifdef CK_ANSIC
6274     TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
6275 #else
6276     TPUTSFNTYPE (*fn)();
6277 #endif /* CK_ANSIC */
6278     if (!fxd_inited)
6279       fxdinit(9999);
6280     if (!cur_cleol[0]) {                /* If we don't have escape sequences */
6281 #ifdef COMMENT
6282         return(-1);                     /* Do nothing */
6283 #else
6284         printf("\033[K");               /* Or use ANSI */
6285 #endif /* COMMENT */
6286     } else {
6287         fn = ck_outc;
6288         tputs(cur_cleol,1,fn);
6289     }
6290     return(0);
6291 }
6292 #endif /* CK_CURPOS */
6293 #else
6294 static void
6295 ck_termset(x) int x; {
6296     if (x) return;
6297 }
6298 #endif /* NOTERMCAP */
6299
6300 #ifndef CK_CURPOS
6301 #define CK_CURPOS
6302 int
6303 ck_cls() {
6304     printf("\033[;H\033[2J");
6305     return(0);
6306 }
6307
6308 int
6309 ck_cleol() {
6310     printf("\033[K");
6311     return(0);
6312 }
6313
6314 int
6315 ck_curpos(row, col) int row, col; {
6316     printf("\033[%d;%dH", row, col);
6317     return(0);
6318 }
6319 #endif /* CK_CURPOS */
6320
6321
6322 #ifndef NOXFER
6323 static int cinit = 0;                   /* Flag for curses init'd */
6324 static int cendw = 0;                   /* endwin() was called */
6325
6326 static
6327 #ifdef CK_ANSIC                         /* Because VOID used by curses.h */
6328 void
6329 #else
6330 #ifdef MYCURSES
6331 VOID
6332 #else
6333 int
6334 #endif /* MYCURSES */
6335 #endif /* CK_ANSIC */
6336 #ifdef CK_ANSIC                         /* Update % transfered and % bar */
6337 updpct(long old, long new)
6338 #else /* CK_ANSIC */
6339 updpct(old, new) long old, new;
6340 #endif /* CK_ANSIC */
6341 /* updpct */ {
6342 #ifdef COMMENT
6343     int m, n;
6344     move(CW_PCD,22);
6345     printw("%ld", new);
6346 #ifdef KUI
6347 #ifndef K95G
6348     KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_PCD, (long) new);
6349 #endif /* K95G */
6350 #endif /* KUI */
6351 #ifdef CK_PCT_BAR
6352     if (thermometer) {
6353         if (old > new) {
6354             old = 0;
6355             move(CW_PCD, 26);
6356             clrtoeol();
6357         }
6358         m = old/2;
6359         move(CW_PCD, 26 + m);
6360         n = new / 2 - m;
6361 #ifndef OS2
6362         while (n > 0) {
6363             if ((m + 1) % 5 == 0)
6364               printw("*");
6365             else
6366               printw("=");
6367             m++;
6368             n--;
6369         }
6370         if (new % 2 != 0) printw("-");
6371         /* move(CW_PCD, 22+53); */
6372 #else /* OS2 */
6373         while (n > 0) {
6374             printw("%c", '\333');
6375             m++; n--;
6376         }
6377         if (new % 2 != 0)
6378           printw("%c", '\261');
6379 #endif /* OS2 */
6380     }
6381 #endif /* CK_PCT_BAR */
6382     /* clrtoeol(); */
6383 #else  /* !COMMENT */
6384 #ifdef OS2
6385 #define CHAR1   '\333'          /* OS2 - CP437 */
6386 #define CHAR2   '\261'
6387 #else
6388 #define CHAR1   '/'             /* Default */
6389 #define CHAR2   '-'
6390 #endif /* OS2 */
6391     debug(F101,"updpct old","",old);
6392     debug(F101,"updpct new","",new);
6393     move(CW_PCD,22);
6394     printw("%-3ld", new); /*  (was)   printw("%ld", new);  */
6395 #ifdef KUI
6396 #ifndef K95G
6397     KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) new );
6398 #endif /* K95G */
6399 #endif /* KUI */
6400 #ifdef CK_PCT_BAR
6401     if (thermometer) {
6402         int m, n;
6403
6404         if (old > new) {
6405             old = 0 ;
6406             move(CW_PCD, 26);
6407             clrtoeol();
6408         }
6409         if (new <= 100L) {
6410             m = old / 2;
6411             n = new / 2 - m;
6412             move(CW_PCD, 26+m);
6413             while (n-- > 0)
6414               printw("%c", CHAR1);
6415             if (new % 2 != 0)
6416               printw("%c", CHAR2);
6417         }
6418     }
6419 #endif /* CK_PCT_BAR */
6420 #endif /* COMMENT */
6421 }
6422
6423 static long old_tr = -1L;               /* Time remaining previously */
6424
6425 static long
6426 #ifdef CK_ANSIC
6427 shoetl(long old_tr, long cps, long fsiz, long howfar)
6428 #else
6429 shoetl(old_tr, cps, fsiz, howfar) long old_tr, cps, fsiz, howfar;
6430 #endif /* CK_ANSIC */
6431 /* shoetl */ {                          /* Estimated time left in transfer */
6432     long tr;                            /* Time remaining, seconds */
6433
6434 #ifdef GFTIMER
6435     if (fsiz > 0L && cps > 0L)
6436       tr = (long)((CKFLOAT)(fsiz - howfar) / (CKFLOAT)cps);
6437     else
6438       tr = -1L;
6439 #else
6440     tr = (fsiz > 0L && cps > 0L) ?
6441       ((fsiz - howfar) / cps) :
6442         -1L;
6443 #endif /* GFTIMER */
6444     move(CW_TR,22);
6445     if (tr > -1L) {
6446         if (tr != old_tr) {
6447             printw("%s",hhmmss(tr));
6448 #ifdef KUI
6449 #ifndef K95G
6450             KuiSetProperty(KUI_FILE_TRANSFER, (long)CW_TR, (long)hhmmss(tr));
6451 #endif /* K95G */
6452 #endif /* KUI */
6453             clrtoeol();
6454         }
6455     } else {
6456         printw("(unknown)");
6457 #ifdef KUI
6458 #ifndef K95G
6459         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "(unknown)" );
6460 #endif /* K95G */
6461 #endif /* KUI */
6462         clrtoeol();
6463     }
6464     return(tr);
6465 }
6466
6467 static long
6468 #ifdef CK_ANSIC
6469 shocps(int pct, long fsiz, long howfar)
6470 #else
6471 shocps(pct, fsiz, howfar) int pct; long fsiz, howfar;
6472 #endif /* CK_ANSIC */
6473 /* shocps */ {
6474 #ifdef CPS_WEIGHTED
6475     static long oldffc = 0L;
6476 #endif /* CPS_WEIGHTED */
6477 #ifdef GFTIMER
6478     CKFLOAT secs, xx;
6479 #else
6480     long secs, xx;
6481 #endif /* GFTIMER */
6482
6483 #ifdef GFTIMER
6484     xx = (gtv >= 0.0) ? gtv : 0.0;      /* Floating-point version */
6485     gtv = gftimer();
6486     if ((gtv - oldgtv) < (CKFLOAT) 1.0) /* Only do this once per second */
6487       return(oldcps);
6488     oldgtv = xx;
6489 #else
6490     xx = (gtv >= 0) ? gtv : 0;          /* Whole-number version */
6491     gtv = gtimer();
6492     if ((gtv - oldgtv) < 1)
6493       return(oldcps);
6494     oldgtv = xx;
6495 #endif /* GFTIMER */
6496
6497 #ifdef CPS_WEIGHTED
6498     /* debug(F100,"SHOCPS: WEIGHTED","",0); */
6499     if (gtv != oldgtv) {                /* The first packet is ignored */
6500         if (ffc < oldffc)
6501           oldffc = ffc;
6502         oldcps = cps;
6503         if (oldcps && oldgtv >
6504 #ifdef GFTIMER
6505             1.0
6506 #else
6507             1
6508 #endif /* GFTIMER */
6509             ) {                         /* The first second is ignored */
6510 /*
6511   This version of shocps() produces a weighted average that some
6512   people like, but most people find it disconcerting and bombard us
6513   with questions and complaints about why the CPS figure fluctuates so
6514   wildly.  So now you only get the weighted average if you build the
6515   program yourself with CPS_WEIGHTED defined.
6516 */
6517 #ifndef CPS_VINCE
6518 #ifdef GFTIMER
6519             cps = (long)((((CKFLOAT)oldcps * 3.0) +
6520                    (CKFLOAT)(ffc - oldffc) / (gtv-oldgtv) ) / 4.0);
6521 #else
6522             cps = ( (oldcps * 3) + (ffc - oldffc) / (gtv-oldgtv) ) / 4;
6523 #endif /* GFTIMER */
6524 #else
6525 /* And an alternate weighting scheme from Vincent Fatica... */
6526             cps = (3 *
6527              ((1+pct/300)*oldffc/oldgtv+(1-pct/100)*(ffc-oldffc)/(gtv-oldgtv)))
6528               / 4;
6529 #endif /* CPS_VINCE */
6530         } else {
6531             /* No weighted average since there is nothing to weigh */
6532 #ifdef GFTIMER
6533             cps = (long)(gtv != 0.0 ?
6534               (CKFLOAT)(ffc - oldffc) / (gtv - oldgtv) :
6535                 (ffc - oldffc)) ;
6536 #else
6537             cps = gtv ? (ffc - oldffc) / (gtv - oldgtv) : (ffc - oldffc) ;
6538 #endif /* GFTIMER */
6539         }
6540 #ifdef COMMENT
6541 #ifdef DEBUG
6542         if (deblog) {
6543             debug(F101,"SHOCPS: pct   ","",pct);
6544             debug(F101,"SHOCPS: gtv   ","",gtv);
6545             debug(F101,"SHOCPS: oldgtv","",oldgtv);
6546             debug(F101,"SHOCPS: dgtv  ","",(long)(gtv-oldgtv));
6547             debug(F101,"SHOCPS: ffc   ","",ffc);
6548             debug(F101,"SHOCPS: oldffc","",oldffc);
6549             debug(F101,"SHOCPS: dffc  ","",ffc-oldffc);
6550             debug(F101,"SHOCPS: cps   ","",cps);
6551         }
6552 #endif /* DEBUG */
6553 #endif /* COMMENT */
6554         move(CW_CP,22);
6555         printw("%ld", cps);
6556 #ifdef KUI
6557 #ifndef K95G
6558         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
6559 #endif /* K95G */
6560 #endif /* KUI */
6561         clrtoeol();
6562         oldffc = ffc;
6563     }
6564 #else /* !CPS_WEIGHTED */
6565 #ifdef COMMENT
6566 #ifdef DEBUG
6567     if (deblog) {
6568         debug(F100,"SHOCPS: NOT WEIGHTED","",0);
6569         debug(F101,"SHOCPS: pct    ","",pct);
6570         debug(F101,"SHOCPS: gtv    ","",gtv);
6571         debug(F101,"SHOCPS: oldgtv ","",oldgtv);
6572         debug(F101,"SHOCPS: dgtv   ","",(long)gtv - (long)oldgtv);
6573         debug(F101,"SHOCPS: ffc    ","",ffc);
6574         debug(F101,"SHOCPS: oldffc ","",oldffc);
6575         debug(F101,"SHOCPS: dffc   ","",ffc-oldffc);
6576         debug(F101,"SHOCPS: cps    ","",cps);
6577         debug(F101,"SHOCPS: filcnt ","",filcnt);
6578 #ifdef GFTIMER
6579         debug(F101,"SHOCPS: fpfsecs","",fpfsecs);
6580 #endif /* GFTIMER */
6581     }
6582     debug(F101,"shocps gtv","",gtv);
6583 #endif /* DEBUG */
6584 #ifdef GFTIMER
6585 #endif /* COMMENT */
6586     /* debug(F101,"shocps fpfsecs","",fpfsecs); */
6587     secs = gtv - fpfsecs;
6588     /* debug(F101,"shocps secs","",(long)secs); */
6589     if (secs > 0.0) {
6590         cps = (long)((CKFLOAT) ffc / secs);
6591         /* debug(F101,"shocps cps","",cps); */
6592         move(CW_CP,22);
6593 #ifdef KUI
6594 #ifndef K95G
6595         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
6596 #endif /* K95G */
6597 #endif /* KUI */
6598         printw("%ld", cps);
6599         clrtoeol();
6600     }
6601 #else  /* Not GFTIMER */
6602     if ((secs = gtv - fsecs) > 0) {
6603         cps = (secs < 1L) ? ffc : ffc / secs;
6604         move(CW_CP,22);
6605 #ifdef KUI
6606 #ifndef K95G
6607         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
6608 #endif /* K95G */
6609 #endif /* KUI */
6610         printw("%ld", cps);
6611         clrtoeol();
6612     }
6613 #endif /* GFTIMER */
6614 #endif /* CPS_WEIGHTED */
6615
6616     if (cps > peakcps &&                /* Peak transfer rate */
6617         ((what & W_SEND && spackets > wslots + 4) ||
6618          (!(what & W_SEND) && spackets > 10))) {
6619         peakcps = cps;
6620     }
6621     old_tr = shoetl(old_tr, cps, fsiz, howfar);
6622     return(cps);
6623 }
6624
6625 static
6626 #ifdef CK_ANSIC                         /* Because VOID used by curses.h */
6627 void
6628 #else
6629 #ifdef MYCURSES
6630 VOID
6631 #else
6632 int
6633 #endif /* MYCURSES */
6634 #endif /* CK_ANSIC */
6635 scrft() {                               /* Display file type */
6636     char xferstr[256];
6637     xferstr[0] = NUL;
6638     if (binary) {
6639         switch(binary) {
6640           case XYFT_L:
6641             ckstrncpy(xferstr,"LABELED",256);
6642             break;
6643           case XYFT_I:
6644             ckstrncpy(xferstr,"IMAGE",256);
6645             break;
6646           case XYFT_U:
6647             ckstrncpy(xferstr,"BINARY UNDEFINED",256);
6648             break;
6649           case XYFT_M:
6650             ckstrncpy(xferstr,"MACBINARY",256);
6651             break;
6652           case XYFT_X:
6653             ckstrncpy(xferstr,"TENEX",256);
6654             break;
6655           default:
6656           case XYFT_B:
6657             ckstrncpy(xferstr,"BINARY",256);
6658             break;
6659         }
6660 #ifdef CK_RESEND
6661         if (what & W_SEND && sendstart > 0L) {
6662             if (sendmode == SM_PSEND) {
6663                 ckstrncat(xferstr, " / partial", 256);
6664             } else if (sendmode == SM_RESEND) {
6665                 ckstrncat(xferstr, " / resend", 256);
6666             }
6667         } else if (what & W_RECV && rs_len > 0L) {
6668             ckstrncat(xferstr, " / resend", 256);
6669         }
6670 #endif /* CK_RESEND */
6671     } else {
6672
6673 #ifndef NOCSETS
6674         ckstrncpy(xferstr,"TEXT",256);
6675 #ifdef NEWFTP
6676 #ifndef NOUNICODE
6677         if (what & W_FTP) {
6678             if (ftp_csx < 0)
6679               ckstrncat(xferstr," (no translation)", 256);
6680             else
6681               ckmakxmsg(&xferstr[4],252,
6682                        " (",
6683                        fcsinfo[(what & W_SEND) ? ftp_csl : ftp_csx].keyword,
6684                        " => ",
6685                        fcsinfo[(what & W_SEND) ? ftp_csx : ftp_csl].keyword,
6686                        ")",
6687                        NULL,NULL,NULL,NULL,NULL,NULL,NULL
6688                        );
6689         } else
6690 #endif /* NOUNICODE */
6691 #endif /* NEWFTP */
6692           if (tcharset == TC_TRANSP) {
6693             ckstrncat(xferstr, " (no translation)", 256);
6694         } else {
6695             if (what & W_SEND) {
6696                 sprintf( &xferstr[strlen(xferstr)], /* safe */
6697                         " (%s => %s)",
6698                         fcsinfo[fcharset].keyword, /* built-in keywords */
6699                         tcsinfo[tcharset].keyword  /* lengths are controlled */
6700                         );
6701             } else {
6702                 sprintf( &xferstr[strlen(xferstr)], /* safe */
6703                         " (%s => %s)",
6704                         tcsinfo[tcharset].keyword, /* built-in keywords */
6705                         fcsinfo[fcharset].keyword); /* lengths controlled */
6706             }
6707         }
6708 #endif /* NOCSETS */
6709     }
6710     move(CW_TYP,22);
6711     printw("%s", xferstr);
6712     clrtoeol();
6713 #ifdef KUI
6714 #ifndef K95G
6715     KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TYP, (long) xferstr );
6716 #endif /* K95G */
6717 #endif /* KUI */
6718     return;
6719 }
6720
6721 #ifdef CK_NEWTERM
6722 static FILE *ck_stdout = NULL;
6723 static int ck_fd = -1;
6724 #endif /* CK_NEWTERM */
6725
6726 static long pct = 0L, oldpct = 0L, oldrtt = -1L;
6727 static int oldtyp = 0, oldwin = -1, oldtry = -1, oldlen = -1, oldtim = -1;
6728
6729 #ifdef NETCONN
6730 static char *netname[] = {
6731     "none",                             /* 00 */
6732     "TCP/IP",                           /* 01 TCP (Sockets) */
6733     "TCP/IP",                           /* 02 TCP (Streams) */
6734     "X.25",                             /* 03 SunLink X.24  */
6735     "DECnet",                           /* 04 DECnet  */
6736     "VAX PSI",                          /* 05 VAX PSI */
6737     "Named Pipes",                      /* 06 LAN Manager Named Pipe */
6738     "X.25",                             /* 07 Stratus VOS X.25 */
6739     "NetBIOS",                          /* 08 IBM NETBIOS */
6740     "SuperLAT",                         /* 07 Meridian SuperLAT */
6741     "File",                             /* 10 File */
6742     "Command",                          /* 11 Subprocess (pipe) */
6743     "DLL",                              /* 12 DLL does i/o */
6744     "X.25",                             /* 13 IBM AIXLink X.25 */
6745     "X.25",                             /* 14 HP-UX X.25 */
6746     "PTY",                              /* 15 Pseudoterminal */
6747     "SSH",                              /* 16 SSH */
6748     "<ERROR>",                          /* 17 In case new types are added */
6749     "<ERROR>",                          /* 18 but nobody remembers to update */
6750     "<ERROR>",                          /* 19 this table ... */
6751     NULL                                /* 20 */
6752 };
6753 static int nnetname = (sizeof(netname) / sizeof(char *));
6754
6755 #endif /* NETCONN */
6756
6757 #ifdef CK_ANSIC
6758 void
6759 screenc(int f, char c,long n,char *s)
6760 #else
6761 #ifdef MYCURSES
6762 VOID
6763 #else
6764 int
6765 #endif /* MYCURSES */
6766 screenc(f,c,n,s)
6767 int f;          /* argument descriptor */
6768 char c;         /* a character or small integer */
6769 long n;         /* a long integer */
6770 char *s;        /* a string */
6771 #endif /* CK_ANSIC */
6772 /* screenc() */ {
6773 #ifdef CK_SSL
6774     extern int tls_active_flag, ssl_active_flag;
6775 #endif /* CK_SSL */
6776 #ifdef RLOGCODE
6777     extern int ttnproto;
6778 #endif /* RLOGCODE */
6779     static int q = 0;
6780     static long fsiz = -1L;   /* Copy of file size */
6781     static long fcnt = 0L;    /* Number of files transferred */
6782     static long fbyt = 0L;    /* Total file bytes of all files transferred */
6783     static long howfar = 0L;  /* How much of current file has been xfer'd. */
6784     static int  pctlbl = 0L;  /* Percent done vs Bytes so far */
6785     long cps = 0L;
6786
6787     int net = 0;
6788     int xnet = 0;
6789     int ftp = 0;
6790     int len;                            /* Length of string */
6791     int errors = 0;                     /* Error counter */
6792     int x;                              /* Worker */
6793
6794     debug(F101,"screenc cinit","",cinit);
6795     debug(F101,"screenc cendw","",cendw);
6796
6797     if (!s) s = "";                     /* Always do this. */
6798
6799     ftp = (what & W_FTP) ? 1 : 0;       /* FTP or Kermit */
6800     net = network || ftp;
6801     xnet = ftp ? 1 : nettype;           /* NET_TCPB == 1 */
6802
6803     if (cinit == 0 || cendw > 0) {      /* Handle borderline cases... */
6804         if (f == SCR_CW) {              /* Close window, but it's not open */
6805             ft_win = 0;
6806             return;
6807         }
6808         debug(F111,"screenc A",s,f);
6809         if (f == SCR_EM ||
6810            (f == SCR_PT && c == 'E')) { /* Fatal error before window open */
6811             conoll(""); conoc('?'); conoll(s); return; /* Regular display */
6812         }
6813     }
6814     if (cinit == 0) {                   /* Only call initscr() once */
6815         char * s;
6816         /* Check these now -- if they are defined but not numeric */
6817         /* they can crash curses */
6818         s = getenv("LINES");
6819         if (s) if (!rdigits(s)) {
6820             printf("?LINES variable not numeric: \"%s\".\n",s);
6821             printf("(Fullscreen display disabled)\n");
6822             fdispla = XYFD_S;
6823             return;
6824         }
6825         s = getenv("COLUMNS");
6826         if (s) if (!rdigits(s)) {
6827             printf("?COLUMNS variable not numeric: \"%s\".\n",s);
6828             printf("(Fullscreen display disabled)\n");
6829             fdispla = XYFD_S;
6830             return;
6831         }
6832         cendw = 1;                      /* New window needs repainting */
6833 #ifdef COMMENT
6834         if (!initscr()) {               /* Oops, can't initialize window? */
6835 /*
6836   In fact, this doesn't happen.  "man curses" says initscr() halts the
6837   entire program if it fails, which is true on the systems where I've
6838   tested it.  It will fail if your terminal type is not known to it.
6839   That's why SET FILE DISPLAY FULLSCREEN calls tgetent() to make sure the
6840   terminal type is known before allowing a curses display.
6841 */
6842             fprintf(stderr,"CURSES INITSCR ERROR\r\n");
6843             fdispla = XYFD_S;           /* Fall back to CRT display */
6844             return;
6845         } else {
6846             cinit++;                    /* Window initialized ok */
6847             debug(F100,"CURSES INITSCR OK","",0);
6848         }
6849 #else                                   /* Save some memory. */
6850 #ifdef CK_NEWTERM
6851         /* (From Andy Fyfe <andy@vlsi.cs.caltech.edu>)
6852            System V curses seems to reserve the right to alter the buffering
6853            on the output FILE* without restoring it.  Fortunately System V
6854            curses provides newterm(), an alternative to initscr(), that
6855            allows us to specify explicitly the terminal type and input and
6856            output FILE pointers.  Thus we duplicate stdout, and let curses
6857            have the copy.  The original remains unaltered.  Unfortunately,
6858            newterm() seems to be particular to System V.
6859         */
6860         s = getenv("TERM");
6861         if (ck_fd < 0) {
6862             ck_fd = dup(fileno(stdout));
6863             ck_stdout = (ck_fd >= 0) ? (FILE *)fdopen(ck_fd, "w") : NULL;
6864         }
6865         debug(F100,"screenc newterm...","",0);
6866
6867 /* NOTE: It might be necessary to do this with stdin too! */
6868 /* This would have been the case in FreeBSD 4.1 but they fixed the */
6869 /* problem by restoring the buffering of stdin before the final release. */
6870 /* (But T.E. Dickey says stdin is not buffered?) */
6871
6872         if (ck_stdout == NULL || newterm(s, ck_stdout, stdin) == 0) {
6873             fprintf(stderr,
6874               "Fullscreen display not supported for terminal type: %s\r\n",s);
6875             fdispla = XYFD_S;           /* Use CRT instead */
6876             return;
6877         }
6878         debug(F100,"screenc newterm ok","",0);
6879 #else
6880         debug(F100,"screen calling initscr","",0);
6881         initscr();                      /* Initialize curses. */
6882         debug(F100,"screen initscr ok","",0);
6883 #endif /* CK_NEWTERM */
6884         cinit++;                        /* Remember curses was initialized. */
6885 #endif /* COMMENT */
6886     }
6887     ft_win = 1;                         /* Window is open */
6888     if (repaint) {
6889 #ifdef CK_WREFRESH
6890 /*
6891   This totally repaints the screen, just what we want, but we can only
6892   do this with real curses, and then only if clearok() and wrefresh() are
6893   provided in the curses library.
6894 */
6895 #ifdef OS2
6896         RestoreCmdMode();
6897 #else
6898 #ifdef QNX
6899 #ifndef QNX16
6900         clearok(stdscr, 1);             /* QNX doesn't have curscr */
6901 #endif /* QNX16 */
6902         wrefresh(stdscr);
6903 #else
6904         wrefresh(curscr);
6905 #endif /* QNX */
6906 #endif /* OS2 */
6907 #else  /* No CK_WREFRESH */
6908 /*
6909   Kermit's do-it-yourself method, works with all types of fullscreen
6910   support, but does not repaint all the fields.  For example, the filename
6911   is lost, because it arrives at a certain time and never comes again, and
6912   Kermit presently does not save it anywhere.  Making this method work for
6913   all fields would be a rather major recoding task, duplicating what curses
6914   already does, and would add a lot of complexity and storage space.
6915 */
6916         cendw = 1;
6917 #endif /* CK_WREFRESH */
6918         repaint = 0;
6919     }
6920     if (cendw) {                        /* endwin() was called previously */
6921 #ifdef VMS
6922         initscr();                      /* (or should have been!) */
6923         clear();
6924         touchwin(stdscr);
6925         refresh();
6926 #else
6927 #ifdef QNX
6928 /*
6929   In QNX, if we don't call initscr() here we core dump.
6930   I don't have any QNX curses documentation, but other curses manuals
6931   say that initscr() should be called only once per application, and
6932   experience shows that on other systems, calling initscr() here generally
6933   results in a core dump.
6934 */
6935         debug(F100,"screenc re-calling initscr QNX","",0);
6936         initscr();
6937         clear();
6938         refresh();
6939 #ifdef COMMENT
6940 /*
6941   But even so, second and subsequent curses displays are messed up.
6942   Calling touchwin, refresh, etc, doesn't make any difference.
6943 */
6944         debug(F100,"screenc calling touchwin QNX","",0);
6945         touchwin(stdscr);
6946         debug(F100,"screenc calling refresh QNX","",0);
6947         refresh();
6948 #endif /* COMMENT */
6949
6950 #else /* All others... */
6951         debug(F100,"screenc calling clear","",0);
6952         clear();
6953         debug(F100,"screenc clear ok","",0);
6954 #endif /* QNX */
6955 #endif /* VMS */
6956         debug(F100,"screenc setup ok","",0);
6957         debug(F100,"screenc doing first move","",0);
6958         move(CW_BAN,0);                 /* Display the banner */
6959         debug(F110,"screenc myhost",myhost,0);
6960 #ifdef TCPSOCKET
6961         debug(F110,"screenc myipaddr",myipaddr,0);
6962 #endif /* TCPSOCKET */
6963 #ifdef HPUX1010
6964         debug(F100,"screenc calling first printw...","",0);
6965 /* Right here is where HP-UX 10.10 libxcurse.1 Rev 76.20 hangs... */
6966 #endif /* HPUX1010 */
6967         if (myhost[0]) {
6968 #ifdef TCPSOCKET
6969             if (!myipaddr[0]
6970 #ifdef OS2
6971                  /* We need to perform this test because on non-TCP/IP */
6972                  /* systems the call to getlocalipaddr() results in a  */
6973                  /* DNS Lookup which takes several minutes to time out */
6974                  && net &&
6975                  (xnet == NET_TCPA || xnet == NET_TCPB
6976 #ifdef SSHBUILTIN
6977                   || xnet == NET_SSH
6978 #endif /* SSHBUILTIN */
6979                   )
6980 #endif /* OS2 */
6981                  )
6982               getlocalipaddr();
6983             if (myipaddr[0] && strcmp((char *)myhost,(char *)myipaddr))
6984               printw("%s, %s [%s]",versio,(char *)myhost,(char *)myipaddr);
6985             else
6986 #endif /* TCPSOCKET */
6987               printw("%s, %s",versio,(char *)myhost);
6988         } else {
6989             printw("%s",versio);
6990         }
6991 #ifdef HPUX1010
6992         debug(F100,"screenc first printw returns","",0);
6993 #endif /* HPUX1010 */
6994         move(CW_DIR,3);
6995         printw("Current Directory: %s",zgtdir());
6996 #ifdef KUI
6997 #ifndef K95G
6998         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) zgtdir() );
6999 #endif /* K95G */
7000 #endif /* KUI */
7001         if (net) {
7002             move(CW_LIN,8);
7003             printw("Network Host: %s",
7004 #ifdef NEWFTP
7005                    ftp ? (ftp_host ? ftp_host : "(unknown)") :
7006 #endif /* NEWFTP */
7007                    ttname
7008                    );
7009         } else {
7010             move(CW_LIN,0);
7011             printw("Communication Device: %s",ttname);
7012         }
7013 #ifdef KUI
7014 #ifndef K95G
7015         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_LIN, (long) ttname );
7016 #endif /* K95G */
7017 #endif /* KUI */
7018
7019         if (net) {
7020             move(CW_SPD,8);
7021             printw("Network Type: ");
7022         } else {
7023             move(CW_SPD,1);
7024             printw("Communication Speed: ");
7025         }
7026         move(CW_SPD,22);                /* Serial speed or network type */
7027         if (net) {
7028 #ifdef NETCONN
7029             int secure = 0;
7030             char * xname;
7031             if (xnet > nnetname)
7032               xname = "[ERROR]";
7033             else
7034               xname = netname[xnet];
7035 #ifdef NEWFTP
7036             if (ftp) {
7037                 if (ftpissecure())
7038                   secure = 1;
7039             } else
7040 #endif /* NEWFTP */
7041               if (0
7042 #ifdef SSHBUILTIN
7043                 || IS_SSH()
7044 #endif /* SSHBUILTIN */
7045 #ifdef CK_ENCRYPTION
7046                 || ck_tn_encrypting() && ck_tn_decrypting()
7047 #endif /* CK_ENCRYPTION */
7048 #ifdef CK_SSL
7049                 || tls_active_flag || ssl_active_flag
7050 #endif /* CK_SSL */
7051 #ifdef RLOGCODE
7052 #ifdef CK_KERBEROS
7053 #ifdef CK_ENCRYPTION
7054                 || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
7055 #endif /* CK_ENCRYPTION */
7056 #endif /* CK_KERBEROS */
7057 #endif /* RLOGCODE */
7058                  ) {
7059                 secure = 1;
7060             }
7061             if (secure) {
7062 #ifdef KUI
7063 #ifndef K95G
7064                 char buf[30];
7065                 sprintf(buf,"%s (SECURE)",xname);
7066                 KuiSetProperty(KUI_FILE_TRANSFER,
7067                                (long) CW_SPD,
7068                                (long) buf
7069                                );
7070 #endif /* K95G */
7071 #endif /* KUI */
7072                 printw("%s (SECURE)",xname);
7073             } else {
7074                 printw("%s",xname);
7075 #ifdef KUI
7076 #ifndef K95G
7077                 KuiSetProperty(KUI_FILE_TRANSFER,
7078                                (long) CW_SPD,
7079                                (long) xname
7080                                );
7081 #endif /* K95G */
7082 #endif /* KUI */
7083             }
7084 #else
7085             printw("(network)");
7086 #ifdef KUI
7087 #ifndef K95G
7088             KuiSetProperty(KUI_FILE_TRANSFER,
7089                            (long) CW_SPD,
7090                            (long) "(network)"
7091                            );
7092 #endif /* K95G */
7093 #endif /* KUI */
7094 #endif /* NETCONN */
7095         } else {
7096             if (speed < 0L)
7097               speed = ttgspd();
7098             if (speed > 0L) {
7099                 if (speed == 8880) {
7100                     printw("75/1200");
7101 #ifdef KUI
7102 #ifndef K95G
7103                     KuiSetProperty(KUI_FILE_TRANSFER,
7104                                    (long) CW_SPD,
7105                                    (long) "75/1200"
7106                                    );
7107 #endif /* K95G */
7108 #endif /* KUI */
7109                 } else {
7110                     char speedbuf[64] ;
7111                     sprintf(speedbuf, "%ld", speed);
7112                     printw("%s",speedbuf);
7113 #ifdef KUI
7114 #ifndef K95G
7115                     KuiSetProperty(KUI_FILE_TRANSFER,
7116                                    (long) CW_SPD,
7117                                    (long) speedbuf
7118                                    );
7119 #endif /* K95G */
7120 #endif /* KUI */
7121                 }
7122             } else {
7123                 printw("unknown");
7124 #ifdef KUI
7125 #ifndef K95G
7126                 KuiSetProperty(KUI_FILE_TRANSFER,
7127                                (long) CW_SPD,
7128                                (long) "(unknown)"
7129                                );
7130 #endif /* K95G */
7131 #endif /* KUI */
7132             }
7133         }
7134         move(CW_PAR,14);
7135         printw("Parity: %s",ftp ? "none" : parnam((char)parity));
7136 #ifdef KUI
7137 #ifndef K95G
7138         KuiSetProperty(KUI_FILE_TRANSFER,
7139                        (long) CW_PAR,
7140                        (long) parnam((char)parity)
7141                        );
7142 #endif /* K95G */
7143 #endif /* KUI */
7144 #ifdef CK_TIMERS
7145         if (/* rttflg && */ protocol == PROTO_K) {
7146             move(CW_TMO, 9); printw("RTT/Timeout:"); }
7147 #endif /* CK_TIMERS */
7148         move(CW_TYP,11); printw("File Type:");
7149         move(CW_SIZ,11); printw("File Size:");
7150         move(CW_PCD, 8);
7151         clrtoeol();
7152         pctlbl = (what & W_SEND);
7153         printw("%s:", pctlbl ? "Percent Done" : "Bytes So Far");
7154
7155 #ifdef XYZ_INTERNAL
7156         move(CW_BAR, 1);
7157         printw("%10s Protocol:", ftp ? "FTP" : ptab[protocol].p_name);
7158 #endif /* XYZ_INTERNAL */
7159 #ifdef CK_PCT_BAR
7160         if (thermometer) {
7161             oldpct = pct = 0;
7162             move(CW_BAR,22);
7163             printw("    ...10...20...30...40...50...60...70...80...90..100");
7164             move(CW_BAR,22+56);
7165         }
7166 #endif /* CK_PCT_BAR */
7167         move(CW_TR,  1); printw("Estimated Time Left:");
7168         move(CW_CP,  2); printw("Transfer Rate, CPS:");
7169         move(CW_WS,  8); printw("Window Slots:%s",
7170                                 ((protocol == PROTO_K) && !ftp) ?
7171                                 "" : " N/A"
7172                                 );
7173         move(CW_PT,  9); printw("Packet Type:");
7174         if (ftp || protocol != PROTO_K) {
7175             move(CW_PT,22);
7176             printw("%s", "N/A");
7177             move(CW_PC,  11); printw("I/O Count:");
7178             move(CW_PL,  10); printw("I/O Length:");
7179         } else {
7180             move(CW_PC,  8); printw("Packet Count:");
7181             move(CW_PL,  7); printw("Packet Length:");
7182         }
7183 #ifndef COMMENT
7184         move(CW_PR,  9); printw("Error Count:");
7185 #else
7186         move(CW_PR,  2); printw("Packet Retry Count:");
7187 #endif
7188 #ifdef COMMENT
7189         move(CW_PB,  2); printw("Packet Block Check:");
7190 #endif /* COMMENT */
7191         move(CW_ERR,10); printw("Last Error:");
7192         move(CW_MSG, 8); printw("Last Message:");
7193         if (xfrmsg) {
7194             move(CW_MSG, 22); printw("%s",xfrmsg);
7195             makestr(&xfrmsg,NULL);
7196         }
7197         move(CW_INT, 0);
7198         if (!xfrint) {
7199             printw("(Transfer interruption is disabled)");
7200         } else {
7201 #ifdef CK_NEED_SIG
7202             printw(
7203 "<%s>X to cancel file, <%s>Z to cancel group, <%s><CR> to resend last packet",
7204                    dbchr(escape), dbchr(escape), dbchr(escape)
7205                    );
7206             move(CW_INT + 1, 0);
7207             printw(
7208 "<%s>E to send Error packet, ^C to quit immediately, <%s>L to refresh screen.",
7209                    dbchr(escape), dbchr(escape)
7210                    );
7211 #else /* !CK_NEED_SIG */
7212             move(CW_INT, 0);
7213 #ifdef OS2
7214             if (protocol == PROTO_K) {
7215                 printw(
7216 "X to cancel file, Z to cancel group, <Enter> to resend last packet,"
7217                        );
7218             }
7219 #else /* !OS2 */
7220 #ifdef VMS                              /* In VMS avoid bottom line */
7221             printw(
7222 "X: Cancel this file; E: Cancel transfer; ^C: Quit now; ^W: Refresh screen."
7223                    );
7224 #else
7225             printw(
7226 "X to cancel file, Z to cancel group, <CR> to resend last packet,"
7227                    );
7228 #endif /* VMS */
7229 #endif /* OS2 */
7230
7231 #ifndef VMS
7232             move(CW_INT + 1, 0);
7233             if (protocol == PROTO_K) {
7234                 printw(
7235 "E to send Error packet, ^C to quit immediately, ^L to refresh screen."
7236                        );
7237             } else {
7238                 printw("^C to cancel file transfer.");
7239             }
7240 #endif /* VMS */
7241 #endif /* CK_NEED_SIG */
7242         }
7243         refresh();
7244         cendw = 0;
7245     }
7246     debug(F101,"SCREENC switch","",f);
7247     debug(F000,"SCREENC c","",c);
7248     debug(F101,"SCREENC n","",n);
7249
7250     len = strlen(s);                    /* Length of argument string */
7251     switch (f) {                        /* Handle our function code */
7252       case SCR_FN:                      /* Filename */
7253         oldpct = pct = 0L;              /* Reset percents */
7254 #ifdef GFTIMER
7255         gtv = (CKFLOAT) -1.0;
7256         /* oldgtv = (CKFLOAT) -1.0; */
7257 #else
7258         gtv = -1L;
7259         /* oldgtv = -1L; */
7260 #endif /* GFTIMER */
7261         oldwin = -1;
7262         fsiz = -1L;                     /* Invalidate previous file size */
7263         move(CW_PCD,22);                /* Erase percent done from last time */
7264 #ifdef KUI
7265 #ifndef K95G
7266         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) 0 );
7267         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_FFC, (long) 0 );
7268 #endif /* K95G */
7269 #endif /* KUI */
7270         clrtoeol();
7271         move(CW_SIZ,22);                /* Erase file size from last time */
7272 #ifdef KUI
7273 #ifndef K95G
7274         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) 0 );
7275 #endif /* K95G */
7276 #endif /* KUI */
7277         clrtoeol();
7278         move(CW_ERR,22);                /* And last error message */
7279 #ifdef KUI
7280 #ifndef K95G
7281         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) "" );
7282 #endif /* K95G */
7283 #endif /* KUI */
7284         clrtoeol();
7285 #ifdef COMMENT
7286 #ifdef STREAMING
7287         if (protocol == PROTO_K && streamok) {
7288             move(CW_BAR, 1);
7289 #ifdef XYZ_INTERNAL
7290             printw("   Kermit STREAMING:");
7291 #else
7292             printw("          STREAMING:");
7293 #endif /* XYZ_INTERNAL */
7294         }
7295 #endif /* STREAMING */
7296 #endif /* COMMENT */
7297
7298         if (what & W_SEND) {            /* If we're sending... */
7299 #ifdef NEWFTP
7300             if (what & W_FTP) {         /* FTP */
7301                 move(CW_NAM,13);
7302                 printw("FTP PUT:");
7303             } else
7304 #endif /* NEWFTP */
7305 #ifdef CK_RESEND
7306             switch (sendmode) {         /* Kermit */
7307               case SM_RESEND:
7308                 move(CW_NAM,11);
7309                 printw("RESENDING:");
7310                 break;
7311               default:
7312                 move(CW_NAM,13);
7313                 printw("SENDING:");
7314                 break;
7315             }
7316 #else
7317             move(CW_NAM,13);
7318             printw("SENDING:");
7319 #endif /* CK_RESEND */
7320
7321         } else if (what & W_RECV) {     /* If we're receiving... */
7322 #ifdef NEWFTP
7323             if (what & W_FTP) {         /* FTP */
7324                 move(CW_NAM,13);
7325                 printw("FTP GET:");
7326             } else {
7327 #endif /* NEWFTP */
7328                 move(CW_NAM,11);
7329                 printw("RECEIVING:");
7330 #ifdef NEWFTP
7331             }
7332         } else if (what == (W_FTP|W_FT_DELE)) {
7333                 move(CW_NAM,10);
7334                 printw("FTP DELETE:");
7335 #endif /* NEWFTP */
7336         } else {                        /* If we don't know... */
7337             move(CW_NAM,11);            /* (should never see this) */
7338             printw("File Name:");
7339         }
7340         move(CW_NAM,22);                /* Display the filename */
7341         if (len > 57) {
7342             printw("%.55s..",s);
7343             len = 57;
7344         } else printw("%s",s);
7345 #ifdef KUI
7346 #ifndef K95G
7347         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
7348 #endif /* K95G */
7349 #endif /* KUI */
7350         q = len;                        /* Remember name length for later */
7351         clrtoeol();
7352         scrft();                        /* Display file type (can change) */
7353         refresh();
7354 #ifdef OS2
7355         SaveCmdMode(0, 0);
7356 #endif /* OS2 */
7357         return;
7358
7359       case SCR_AN:                      /* File as-name */
7360         if (q + len + 4 < 58) {         /* Will fit */
7361             move(CW_NAM, 22 + q);
7362             printw(" => %s",s);
7363 #ifdef KUI
7364 #ifndef K95G
7365             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
7366 #endif /* K95G */
7367 #endif /* KUI */
7368         } else {                        /* Too long */
7369             move(CW_NAM, 22);           /* Overwrite previous name */
7370             q = 0;
7371             if (len + 4 > 57) {                                 /* wg15 */
7372                 printw(" => %.51s..",s);                        /* wg15 */
7373                 len = 53;                                       /* wg15 */
7374             } else printw(" => %s",s);                          /* wg15 */
7375 #ifdef KUI
7376 #ifndef K95G
7377             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s  );
7378 #endif /* K95G */
7379 #endif /* KUI */
7380         }
7381         q += len + 4;                   /* Remember horizontal position */
7382         clrtoeol();
7383         refresh();
7384 #ifdef OS2
7385         SaveCmdMode(0, 0);
7386 #endif /* OS2 */
7387         return;
7388
7389       case SCR_FS:                      /* File size */
7390         fsiz = n;
7391         move(CW_SIZ,22);
7392         if (fsiz > -1L) {
7393 #ifdef KUI
7394 #ifndef K95G
7395             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) n );
7396 #endif /* K95G */
7397 #endif /* KUI */
7398             printw("%ld",n);
7399         }
7400         clrtoeol();
7401 #ifdef COMMENT
7402         move(CW_PCD, 8);
7403         if (fsiz > -1L) {               /* Put up percent label */
7404             pctlbl = 1;
7405             clrtoeol();
7406             printw("Percent Done:");
7407         }
7408 #else
7409         move(CW_PCD, 8);
7410         clrtoeol();
7411         if (fsiz > -1L) {               /* Put up percent label */
7412             pctlbl = 1;
7413             printw("Percent Done:");
7414         } else {
7415             pctlbl = 0;
7416             printw("Bytes So Far:");
7417         }
7418 #endif /* COMMENT */
7419         clrtoeol();
7420         scrft();                        /* File type */
7421         refresh();
7422 #ifdef OS2
7423         SaveCmdMode(0, 0);
7424 #endif /* OS2 */
7425         return;
7426
7427       case SCR_PT:                      /* Packet type or pseudotype */
7428         if (spackets < 5) {
7429             extern int sysindex;
7430             extern struct sysdata sysidlist[];
7431             /* Things that won't change after the 4th packet */
7432             move(CW_PAR,22);
7433             printw("%s",parnam((char)parity));
7434 #ifdef KUI
7435 #ifndef K95G
7436             KuiSetProperty( KUI_FILE_TRANSFER,
7437                            (long) CW_PAR,
7438                            (long) parnam((char)parity)
7439                            );
7440 #endif /* K95G */
7441 #endif /* KUI */
7442             clrtoeol();
7443 #ifdef COMMENT
7444             move(CW_PB, 22);            /* Block check on this packet */
7445             if (bctu == 4)
7446               printw("B");
7447             else
7448               printw("%d",bctu);
7449             clrtoeol();
7450 #endif /* COMMENT */
7451             if (
7452 #ifdef NEWFTP
7453                 (ftp && (spackets == 1 || rpackets == 1)) ||
7454 #endif /* NEWFTP */
7455                 spackets == 4
7456                 ) {
7457                 move(CW_LIN,8);
7458                 if (
7459 #ifdef NEWFTP
7460                     ftp ||
7461 #endif /* NEWFTP */
7462                     ((protocol == PROTO_K) && (sysindex > -1))
7463                     ) {
7464                     if (net) {
7465                         move(CW_LIN,8);
7466                         printw("Network Host: %s (%s)",
7467 #ifdef NEWFTP
7468                                ftp ? (ftp_host ? ftp_host : "") :
7469 #endif /* NEWFTP */
7470                                ttname,
7471 #ifdef NEWFTP
7472                                ftp ? ftp_srvtyp :
7473 #endif /* NEWFTP */
7474                                sysidlist[sysindex].sid_name
7475                                );
7476                     } else {
7477                         move(CW_LIN,0);
7478                         printw("Communication Device: %s (remote host is %s)",
7479                              ttname,
7480                              sysidlist[sysindex].sid_name
7481                              );
7482                     }
7483                     clrtoeol();
7484                 }
7485             }
7486         }
7487 #ifdef CK_TIMERS
7488         if (/* rttflg && */ protocol == PROTO_K) {
7489             long xx;
7490             if (
7491 #ifdef STREAMING
7492                 streaming && oldwin != -2
7493 #else
7494                 0
7495 #endif /* STREAMING */
7496                 ) {
7497                 move(CW_TMO, 22);
7498                 printw("00 / 00");
7499                 clrtoeol();
7500             } else {
7501                 xx = (rttdelay + 500) / 1000;
7502                 if (xx != oldrtt || rcvtimo != oldtim) {
7503                     move(CW_TMO, 22);
7504                     printw("%02ld / %02d", xx, rcvtimo);
7505                     oldrtt = xx;
7506                     oldtim = rcvtimo;
7507                     clrtoeol();
7508                 }
7509             }
7510         }
7511 #endif /* CK_TIMERS */
7512
7513         x = (what & W_RECV) ?          /* Packet length */
7514           rpktl+(protocol==PROTO_K?1:0) :
7515             spktl;
7516         if (x != oldlen) {              /* But only if it changed. */
7517             move(CW_PL, 22);
7518             printw("%d",x);
7519 #ifdef KUI
7520 #ifndef K95G
7521             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PL, (long) x );
7522 #endif /* K95G */
7523 #endif /* KUI */
7524             clrtoeol();
7525             oldlen = x;
7526         }
7527         move(CW_PC, 22);                /* Packet count (always). */
7528
7529         printw("%d", (what & W_RECV) ? rpackets : spackets);
7530 #ifdef KUI
7531 #ifndef K95G
7532         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PC, (long) spackets );
7533 #endif /* K95G */
7534 #endif /* KUI */
7535         clrtoeol();
7536
7537         if (protocol == PROTO_K && !ftp) { /* Window slots */
7538             char ws[16];
7539             int flag;
7540             flag = 0;
7541 #ifdef STREAMING
7542             if (streaming) {
7543                 if (oldwin != -2) {
7544                     sprintf(ws,"STREAMING");
7545                     flag = 1;
7546                     oldwin = -2;
7547                 }
7548             } else
7549 #endif /* STREAMING */
7550               if (wcur != oldwin) {
7551                   sprintf(ws, "%d of %d", wcur < 1 ? 1 : wcur, wslotn);
7552                   flag = 1;
7553                   oldwin = wcur;
7554               }
7555             if (flag) {
7556                 move(CW_WS, 22);
7557                 printw("%s", ws);
7558                 clrtoeol();
7559 #ifdef KUI
7560 #ifndef K95G
7561                 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_WS, (long) ws );
7562 #endif /* K95G */
7563 #endif /* KUI */
7564             }
7565         }
7566         errors = retrans + crunched + timeouts;
7567         if (errors != oldtry) {         /* Retry count, if changed */
7568             move(CW_PR, 22);
7569             printw("%d",errors);
7570 #ifdef KUI
7571 #ifndef K95G
7572             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PR, (long) errors );
7573 #endif /* K95G */
7574 #endif /* KUI */
7575             clrtoeol();
7576             oldtry = errors;
7577         }
7578         /* Sender's packet type */
7579         if (!ftp && (c != oldtyp && c != 'Y' && c != 'N')) {
7580             char type[2];
7581             sprintf(type, "%c",c);
7582             move(CW_PT,22);
7583             printw("%s", type);
7584 #ifdef KUI
7585 #ifndef K95G
7586             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PT, (long) type );
7587 #endif /* K95G */
7588 #endif /* KUI */
7589             clrtoeol();
7590             oldtyp = c;
7591         }
7592         switch (c) {                    /* Now handle specific packet types */
7593           case 'S':                     /* Beginning of transfer */
7594             fcnt = fbyt = 0L;           /* Clear counters */
7595 #ifdef GFTIMER
7596             gtv = -1.0;
7597 #else /* GFTIMER */
7598             gtv = -1L;                  /* And old/new things... */
7599 #endif /* GFTIMER */
7600             oldpct = pct = 0L;
7601             break;
7602
7603           case 'Z':                     /* or EOF */
7604             debug(F101,"screenc SCR_PT Z pktnum","",n);
7605             debug(F101,"screenc SCR_PT Z oldpct","",oldpct);
7606             debug(F101,"screenc SCR_PT Z pct","",pct);
7607           case 'D':                     /* Data packet */
7608             if (fsiz > 0L) {            /* Show percent done if known */
7609                 oldpct = pct;           /* Remember previous percent */
7610                 howfar = ffc;
7611 #ifdef CK_RESEND
7612                 if (what & W_SEND)      /* Account for PSEND or RESEND */
7613                   howfar += sendstart;
7614                 else if (what & W_RECV)
7615                   howfar += rs_len;
7616 #endif /* CK_RESEND */
7617                 /* Percent done, to be displayed... */
7618                 if (c == 'Z') {
7619                     if (!discard && !cxseen && !czseen) pct = 100L;
7620                 } else
7621                   pct = (fsiz > 99L) ? (howfar / (fsiz / 100L)) : 0L;
7622                 if (pct > 100L ||       /* Allow for expansion and */
7623                    (oldpct == 99L && pct < 0L)) /* other boundary conditions */
7624                   pct = 100L;
7625                 if (pct != oldpct)      /* Only do this 100 times per file */
7626                   updpct(oldpct, pct);
7627             } else {
7628                 move(CW_PCD,22);
7629                 printw("%ld", ffc);
7630             }
7631 #ifdef KUI
7632 #ifndef K95G
7633             KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) howfar);
7634 #endif /* K95G */
7635 #endif /* KUI */
7636             cps = shocps((int) pct, fsiz, howfar);
7637             /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
7638             break;
7639
7640           case '%':                     /* Timeouts, retransmissions */
7641             cps = shocps((int) pct, fsiz, howfar);
7642             /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
7643
7644             errors = retrans + crunched + timeouts;
7645             if (errors != oldtry) {     /* Error count, if changed */
7646                 move(CW_PR, 22);
7647                 printw("%d",errors);
7648                 clrtoeol();
7649 #ifdef KUI
7650 #ifndef K95G
7651                 KuiSetProperty(KUI_FILE_TRANSFER,
7652                                (long) CW_PR, (long) errors
7653                                );
7654 #endif /* K95G */
7655 #endif /* KUI */
7656                 }
7657                 oldtry = errors;
7658                 if (s) if (*s) {
7659                     move(CW_ERR,22);
7660                     printw("%s",s);
7661                     clrtoeol();
7662 #ifdef KUI
7663 #ifndef K95G
7664                     KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_ERR, (long) s);
7665 #endif /* K95G */
7666 #endif /* KUI */
7667             }
7668             break;
7669
7670           case 'E':                     /* Error packet */
7671 #ifdef COMMENT
7672             move(CW_ERR,22);            /* Print its data field */
7673             if (*s) {
7674                 printw("%s",s);
7675 #ifdef KUI
7676 #ifndef K95G
7677                 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
7678 #endif /* K95G */
7679 #endif /* KUI */
7680             }
7681             clrtoeol();
7682 #endif /* COMMENT */
7683             fcnt = fbyt = 0L;           /* So no bytes for this file */
7684             break;
7685           case 'Q':                     /* Crunched packet */
7686             cps = shocps((int) pct, fsiz, howfar);
7687             /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
7688             move(CW_ERR,22);
7689             printw("Damaged Packet");
7690 #ifdef KUI
7691 #ifndef K95G
7692             KuiSetProperty(KUI_FILE_TRANSFER,
7693                            (long) CW_ERR,
7694                            (long) "Damaged Packet"
7695                            );
7696 #endif /* K95G */
7697 #endif /* KUI */
7698             clrtoeol();
7699             break;
7700           case 'q':                     /* Ctrl-C or connection lost */
7701             move(CW_MSG,22);
7702             clrtoeol();
7703             if (!s) s = "";
7704             printw(*s ? s : "User interruption or connection lost");
7705 #ifdef KUI
7706 #ifndef K95G
7707             KuiSetProperty(KUI_FILE_TRANSFER,
7708                            (long) CW_MSG,
7709                            (long) s
7710                            );
7711 #endif /* K95G */
7712 #endif /* KUI */
7713             break;
7714           case 'T':                     /* Timeout */
7715             cps = shocps((int) pct, fsiz, howfar);
7716             /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
7717             move(CW_ERR,22);
7718             printw("Timeout %d sec",rcvtimo);
7719 #ifdef KUI
7720 #ifndef K95G
7721             KuiSetProperty(KUI_FILE_TRANSFER,
7722                            (long) CW_ERR,
7723                            (long) "Timeout"
7724                            );
7725 #endif /* K95G */
7726 #endif /* KUI */
7727             clrtoeol();
7728             errors = retrans + crunched + timeouts;
7729             if (errors != oldtry) {     /* Error count, if changed */
7730                 move(CW_PR, 22);
7731                 printw("%d",errors);
7732 #ifdef KUI
7733 #ifndef K95G
7734                 KuiSetProperty(KUI_FILE_TRANSFER,
7735                                (long) CW_PR, (long) errors
7736                                );
7737 #endif /* K95G */
7738 #endif /* KUI */
7739                 clrtoeol();
7740                 oldtry = errors;
7741             }
7742             break;
7743           default:                      /* Others, do nothing */
7744             break;
7745         }
7746         refresh();
7747 #ifdef OS2
7748         SaveCmdMode(0, 0);
7749 #endif /* OS2 */
7750         return;
7751
7752       case SCR_ST:                      /* File transfer status */
7753         debug(F101,"screenc SCR_ST c","",c);
7754         debug(F101,"screenc SCR_ST success","",success);
7755         debug(F101,"screenc SCR_ST cxseen","",cxseen);
7756 #ifdef COMMENT
7757         move(CW_PCD,22);                /* Update percent done */
7758         if (c == ST_OK) {               /* OK, print 100 % */
7759             if (pctlbl)
7760               updpct(oldpct,100);
7761             else
7762               printw("%ld", ffc);
7763 #ifdef KUI
7764 #ifndef K95G
7765             KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
7766 #endif /* K95G */
7767 #endif /* KUI */
7768             pct = 100;
7769             oldpct = 0;
7770         } else if (fsiz > 0L)           /* Not OK, update final percent */
7771 /*
7772   The else part writes all over the screen -- howfar and/or fsiz have
7773   been reset as a consequence of the not-OKness of the transfer.
7774 */
7775           if (pctlbl)
7776             updpct(oldpct, (howfar * 100L) / fsiz);
7777         clrtoeol();
7778 #else
7779         if (c == ST_OK) {               /* OK, print 100 % */
7780             move(CW_PCD,22);            /* Update percent done */
7781             if (pctlbl) {
7782                 if (oldpct == 0)        /* Switching from "bytes so far" */
7783                   clrtoeol();           /* to "percent done"... */
7784                 updpct(oldpct,100);
7785             } else
7786               printw("%ld", ffc);
7787 #ifdef KUI
7788 #ifndef K95G
7789             KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
7790 #endif /* K95G */
7791 #endif /* KUI */
7792 #ifdef COMMENT
7793             pct = 100;
7794             oldpct = 0;
7795 #endif /* COMMENT */
7796             clrtoeol();
7797         }
7798 #endif /* COMMENT */
7799
7800 #ifdef COMMENT
7801 /* No, leave it there so they can read it */
7802         move(CW_MSG,22);                /* Remove any previous message */
7803 #ifdef KUI
7804 #ifndef K95G
7805         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_MSG, (long) "" );
7806 #endif /* K95G */
7807 #endif /* KUI */
7808         clrtoeol(); refresh();
7809 #endif /* COMMENT */
7810
7811         move(CW_TR, 22);
7812 #ifdef KUI
7813 #ifndef K95G
7814         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "" );
7815 #endif /* K95G */
7816 #endif /* KUI */
7817         clrtoeol(); refresh();
7818
7819         switch (c) {                    /* Print new status message */
7820           case ST_OK:                   /* Transfer OK */
7821             fcnt++;                     /* Count this file */
7822             if (what == (W_FTP|W_FT_DELE)) {
7823                 move(CW_MSG,22);
7824                 clrtoeol();
7825                 printw("Delete OK");
7826             } else {
7827                 fbyt += ffc;
7828                 move(CW_MSG,22);
7829                 clrtoeol();
7830                 printw("Transfer OK");
7831             }
7832 #ifdef KUI
7833 #ifndef K95G
7834             KuiSetProperty(KUI_FILE_TRANSFER,
7835                            (long) CW_MSG,
7836                            (long) "Transfer OK"
7837                            );
7838 #endif /* K95G */
7839 #endif /* KUI */
7840             clrtoeol(); refresh();
7841             return;
7842
7843           case ST_DISC:                 /* Discarded */
7844             move(CW_ERR,22);
7845             printw("File discarded");
7846 #ifdef KUI
7847 #ifndef K95G
7848             KuiSetProperty(KUI_FILE_TRANSFER,
7849                            (long) CW_ERR,
7850                            (long) "File discarded"
7851                            );
7852 #endif /* K95G */
7853 #endif /* KUI */
7854 #ifdef COMMENT
7855             pct = oldpct = 0;
7856 #endif /* COMMENT */
7857             clrtoeol(); refresh();
7858             return;
7859
7860           case ST_INT:                  /* Interrupted */
7861             move(CW_ERR,22);
7862             printw("Transfer interrupted");
7863 #ifdef KUI
7864 #ifndef K95G
7865             KuiSetProperty(KUI_FILE_TRANSFER,
7866                            (long) CW_ERR,
7867                            (long) "Transfer interrupted"
7868                            );
7869 #endif /* K95G */
7870 #endif /* KUI */
7871 #ifdef COMMENT
7872             pct = oldpct = 0;
7873 #endif /* COMMENT */
7874             clrtoeol(); refresh();
7875             return;
7876
7877           case ST_SKIP:                 /* Skipped */
7878             move(CW_ERR,22);
7879             if (n > 0 && n < nskreason)
7880               printw("File skipped (%s)",skreason[n]);
7881             else
7882               printw("File skipped");
7883 #ifdef KUI
7884 #ifndef K95G
7885             KuiSetProperty(KUI_FILE_TRANSFER,
7886                            (long) CW_ERR,
7887                            (long) "File skipped"
7888                            );
7889 #endif /* K95G */
7890 #endif /* KUI */
7891 #ifdef COMMENT
7892             pct = oldpct = 0;
7893 #endif /* COMMENT */
7894             clrtoeol(); refresh();
7895             return;
7896
7897           case ST_ERR:                  /* Error message */
7898             move(CW_ERR,22);
7899             if (!s) s = (char *)epktmsg;
7900             printw("%s",s);
7901 #ifdef KUI
7902 #ifndef K95G
7903             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
7904 #endif /* K95G */
7905 #endif /* KUI */
7906 #ifdef COMMENT
7907             pct = oldpct = 0;
7908 #endif /* COMMENT */
7909             clrtoeol(); refresh();
7910             return;
7911
7912           case ST_REFU:                 /* Refused */
7913             move(CW_ERR,22);
7914             if (*s) {
7915                 char errbuf[64] ;
7916                 sprintf( errbuf, "Refused, %s", s ) ;
7917                 printw("%s", errbuf);
7918 #ifdef KUI
7919 #ifndef K95G
7920                 KuiSetProperty(KUI_FILE_TRANSFER,(long) CW_ERR,(long) errbuf);
7921 #endif /* K95G */
7922 #endif /* KUI */
7923             } else {
7924                 printw("Refused");
7925 #ifdef KUI
7926 #ifndef K95G
7927                 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Refused");
7928 #endif /* K95G */
7929 #endif /* KUI */
7930             }
7931 #ifdef COMMENT
7932             pct = oldpct = 0;
7933 #endif /* COMMENT */
7934             clrtoeol(); refresh();
7935             return;
7936
7937           case ST_INC:
7938             move(CW_ERR,22);
7939             printw("Incomplete");
7940 #ifdef KUI
7941 #ifndef K95G
7942             KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Incomplete");
7943 #endif /* K95G */
7944 #endif /* KUI */
7945 #ifdef COMMENT
7946             pct = oldpct = 0;
7947 #endif /* COMMENT */
7948             clrtoeol(); refresh();
7949             return;
7950
7951           case ST_MSG:
7952             move(CW_MSG,22);
7953             printw("%s",s);
7954 #ifdef KUI
7955 #ifndef K95G
7956             KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_MSG,(long)s);
7957 #endif /* K95G */
7958 #endif /* KUI */
7959             clrtoeol(); refresh();
7960             return;
7961
7962           default:                      /* Bad call */
7963             move(CW_ERR,22);
7964             printw("*** screen() called with bad status ***");
7965 #ifdef KUI
7966 #ifndef K95G
7967             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR,
7968                        (long) "*** screen() called with bad status ***" );
7969 #endif /* K95G */
7970 #endif /* KUI */
7971             clrtoeol(); refresh(); return;
7972         }
7973
7974       case SCR_TC: {                    /* Transaction complete */
7975           char msgbuf[128];
7976           move(CW_CP,22);               /* Overall transfer rate */
7977 #ifdef KUI
7978 #ifndef K95G
7979           KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, tfcps);
7980 #endif /* K95G */
7981 #endif /* KUI */
7982           printw("%ld", tfcps);
7983           clrtoeol();
7984           if (success) {
7985               move(CW_MSG,22);          /* Print statistics in message line */
7986               clrtoeol();
7987           }
7988           if (success) {
7989               sprintf(msgbuf,
7990                       "SUCCESS.  Files: %ld, Bytes: %ld, %ld CPS",
7991                       filcnt - filrej,
7992                       fbyt,
7993                       tfcps
7994                       );
7995               printw("%s", msgbuf);
7996 #ifdef KUI
7997 #ifndef K95G
7998               KuiSetProperty(KUI_FILE_TRANSFER,
7999                              (long) CW_MSG,
8000                              (long) msgbuf
8001                              );
8002 #endif /* K95G */
8003 #endif /* KUI */
8004               clrtoeol();
8005
8006           }
8007           move(CW_TR, 1);
8008           printw("       Elapsed Time: %s",hhmmss((long)
8009 #ifdef GFTIMER
8010                                                   (fptsecs + 0.5)
8011 #else
8012                                                   tsecs
8013 #endif /* GFTIMER */
8014                                                    ));
8015 #ifdef KUI
8016 #ifndef K95G
8017           KuiSetProperty(KUI_FILE_TRANSFER,
8018                          (long) CW_TR,
8019                          (long) hhmmss((long)
8020 #ifdef GFTIMER
8021                                        (fptsecs + 0.5)
8022 #else
8023                                        tsecs
8024 #endif /* GFTIMER */
8025                                        ));
8026 #endif /* K95G */
8027 #endif /* KUI */
8028           clrtoeol();
8029           move(23,0); clrtoeol();       /* Clear instructions lines */
8030           move(22,0); clrtoeol();       /* to make room for prompt. */
8031           refresh();
8032
8033 #ifdef GFTIMER
8034           oldgtv = (CKFLOAT) -1.0;
8035 #else
8036           oldgtv = -1L;
8037 #endif /* GFTIMER */
8038
8039 #ifndef VMSCURSE
8040           debug(F100,"screenc endwin A","",0);
8041           endwin();
8042 #ifdef COMMENT
8043 /*
8044   Why and when was this call to conres() added?  It makes no sense,
8045   and it breaks echoing on Solaris 8.
8046 */
8047 #ifdef SOLARIS
8048           conres();
8049 #endif /* SOLARIS */
8050 #endif /* COMMENT */
8051 #endif /* VMSCURSE */
8052
8053 #ifdef COMMENT
8054           pct = 100; oldpct = 0;        /* Reset these for next time. */
8055 #endif /* COMMENT */
8056           oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
8057           oldtim = -1;
8058           cendw = 1;
8059           if (xfrbel) bleep(BP_NOTE);   /* Close window, then beep. */
8060 #ifdef UNIX
8061           fflush(stdout);
8062 #endif /* UNIX */
8063           ft_win = 0;                   /* Window closed. */
8064           return;
8065       }
8066       case SCR_EM:                      /* Error packet (fatal) */
8067         move (CW_ERR,22);
8068         printw("FAILURE: %s",s);
8069 #ifdef KUI
8070 #ifndef K95G
8071         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
8072 #endif /* K95G */
8073 #endif /* KUI */
8074         if (xfrbel) bleep(BP_FAIL);
8075 #ifdef COMMENT
8076         pct = oldpct = 0;
8077 #endif /* COMMENT */
8078         clrtoeol(); refresh(); return;
8079
8080       case SCR_QE:                      /* Quantity equals */
8081       case SCR_TU:                      /* Undelimited text */
8082       case SCR_TN:                      /* Text delimited at start */
8083       case SCR_TZ:                      /* Text delimited at end */
8084         return;                         /* (ignored in fullscreen display) */
8085
8086       case SCR_XD:                      /* X-packet data */
8087         pct = oldpct = 0;
8088         move(CW_NAM,22);
8089         printw("%s",s);
8090 #ifdef KUI
8091 #ifndef K95G
8092         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
8093 #endif /* K95G */
8094 #endif /* KUI */
8095         clrtoeol(); refresh(); return;
8096
8097       case SCR_CW:                      /* Close Window */
8098         clrtoeol(); move(23,0); clrtoeol(); move(22,0); clrtoeol();
8099         refresh();
8100 #ifdef COMMENT
8101         pct = 100; oldpct = 0;          /* Reset these for next time. */
8102 #endif /* COMMENT */
8103         oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
8104         oldtim = -1;
8105
8106 #ifndef VMSCURSE
8107         debug(F100,"screenc endwin B","",0);
8108         endwin();
8109 #endif /* VMSCURSE */
8110         ft_win = 0;                     /* Flag that window is closed. */
8111         cendw = 1; return;
8112
8113       case SCR_CD:                      /* Display current directory */
8114         move(CW_DIR,22);
8115          printw("%s", s);
8116 #ifdef KUI
8117 #ifndef K95G
8118         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) s );
8119 #endif /* K95G */
8120 #endif /* KUI */
8121         clrtoeol();
8122         refresh();
8123 #ifdef OS2
8124         SaveCmdMode(0, 0);
8125 #endif /* OS2 */
8126         return;
8127
8128       default:                          /* Bad call */
8129         move (CW_ERR,22);
8130 #ifdef KUI
8131 #ifndef K95G
8132         KuiSetProperty(KUI_FILE_TRANSFER,
8133                        (long) CW_ERR,
8134                        (long) "*** screen() called with bad function code ***"
8135                        );
8136 #endif /* K95G */
8137 #endif /* KUI */
8138         printw("*** screen() called with bad function code ***");
8139         clrtoeol(); refresh(); return;
8140     }
8141 }
8142 #endif /* CK_CURSES */
8143
8144 #ifdef KUI
8145 #ifdef CK_ANSIC
8146 void
8147 screeng(int f, char c,long n,char *s)
8148 #else
8149 VOID
8150 screeng(f,c,n,s)
8151 int f;          /* argument descriptor */
8152 char c;         /* a character or small integer */
8153 long n;         /* a long integer */
8154 char *s;        /* a string */
8155 #endif /* CK_ANSIC */
8156 /* screeng() */ {
8157 #ifdef CK_SSL
8158     extern int tls_active_flag, ssl_active_flag;
8159 #endif /* CK_SSL */
8160 #ifdef RLOGCODE
8161     extern int ttnproto;
8162 #endif /* RLOGCODE */
8163     static int q = 0;
8164     static long fsiz = -1L;   /* Copy of file size */
8165     static long fcnt = 0L;    /* Number of files transferred */
8166     static long fbyt = 0L;    /* Total file bytes of all files transferred */
8167     static long howfar = 0L;  /* How much of current file has been xfer'd. */
8168     static int  pctlbl = 0L;  /* Percent done vs Bytes so far */
8169     long cps = 0L;
8170
8171     int net = 0;
8172     int xnet = 0;
8173     int ftp = 0;
8174     int len;                            /* Length of string */
8175     int errors = 0;                     /* Error counter */
8176     int x;                              /* Worker */
8177
8178     debug(F101,"screeng cinit","",cinit);
8179     debug(F101,"screeng cendw","",cendw);
8180
8181     if (!s) s = "";                     /* Always do this. */
8182
8183     ftp = (what & W_FTP) ? 1 : 0;       /* FTP or Kermit */
8184     net = network || ftp;
8185     xnet = ftp ? 1 : nettype;           /* NET_TCPB == 1 */
8186
8187     if (cinit == 0 || cendw > 0) {      /* Handle borderline cases... */
8188         if (f == SCR_CW) {              /* Close window, but it's not open */
8189             ft_win = 0;
8190             return;
8191         }
8192         debug(F111,"screeng A",s,f);
8193         if (f == SCR_EM ||
8194            (f == SCR_PT && c == 'E')) { /* Fatal error before window open */
8195             conoll(""); conoc('?'); conoll(s); return; /* Regular display */
8196         }
8197     }
8198     if (cinit == 0) {                   /* Only call initscr() once */
8199         /* Check these now -- if they are defined but not numeric */
8200         /* they can crash curses */
8201         cendw = 1;                      /* New window needs repainting */
8202         debug(F100,"screeng calling initscr","",0);
8203         initscr();                      /* Initialize curses. */
8204         debug(F100,"screeng initscr ok","",0);
8205         cinit++;                        /* Remember curses was initialized. */
8206     }
8207     ft_win = 1;                         /* Window is open */
8208     if (repaint) {
8209 #ifdef CK_WREFRESH
8210 /*
8211   This totally repaints the screen, just what we want, but we can only
8212   do this with real curses, and then only if clearok() and wrefresh() are
8213   provided in the curses library.
8214 */
8215         RestoreCmdMode();
8216 #else  /* No CK_WREFRESH */
8217 /*
8218   Kermit's do-it-yourself method, works with all types of fullscreen
8219   support, but does not repaint all the fields.  For example, the filename
8220   is lost, because it arrives at a certain time and never comes again, and
8221   Kermit presently does not save it anywhere.  Making this method work for
8222   all fields would be a rather major recoding task, duplicating what curses
8223   already does, and would add a lot of complexity and storage space.
8224 */
8225         cendw = 1;
8226 #endif /* CK_WREFRESH */
8227         repaint = 0;
8228     }
8229     if (cendw) {                        /* endwin() was called previously */
8230         debug(F100,"screeng setup ok","",0);
8231         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) zgtdir() );
8232         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_LIN,
8233                         (long) (
8234 #ifdef NEWFTP
8235                                 ftp ? (ftp_host ? ftp_host : "(unknown)") :
8236 #endif /* NEWFTP */
8237                                 ttname) );
8238
8239         if (net) {
8240 #ifdef NETCONN
8241             int secure = 0;
8242             char * xname;
8243             if (xnet > nnetname)
8244               xname = "[ERROR]";
8245             else
8246               xname = netname[xnet];
8247 #ifdef NEWFTP
8248             if (ftp) {
8249                 if (ftpissecure())
8250                   secure = 1;
8251             } else
8252 #endif /* NEWFTP */
8253               if (0
8254 #ifdef SSHBUILTIN
8255                 || IS_SSH()
8256 #endif /* SSHBUILTIN */
8257 #ifdef CK_ENCRYPTION
8258                 || ck_tn_encrypting() && ck_tn_decrypting()
8259 #endif /* CK_ENCRYPTION */
8260 #ifdef CK_SSL
8261                 || tls_active_flag || ssl_active_flag
8262 #endif /* CK_SSL */
8263 #ifdef RLOGCODE
8264 #ifdef CK_KERBEROS
8265 #ifdef CK_ENCRYPTION
8266                 || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
8267 #endif /* CK_ENCRYPTION */
8268 #endif /* CK_KERBEROS */
8269 #endif /* RLOGCODE */
8270                  ) {
8271                 secure = 1;
8272             }
8273             if (secure) {
8274                 char buf[30];
8275                 sprintf(buf,"%s (SECURE)",xname);
8276                 KuiSetProperty(KUI_FILE_TRANSFER,
8277                                (long) CW_SPD,
8278                                (long) buf
8279                                );
8280             } else {
8281                 KuiSetProperty(KUI_FILE_TRANSFER,
8282                                (long) CW_SPD,
8283                                (long) xname
8284                                );
8285             }
8286 #else
8287             KuiSetProperty(KUI_FILE_TRANSFER,
8288                            (long) CW_SPD,
8289                            (long) "(network)"
8290                            );
8291 #endif /* NETCONN */
8292         } else {
8293             if (speed < 0L)
8294               speed = ttgspd();
8295             if (speed > 0L) {
8296                 if (speed == 8880) {
8297                     KuiSetProperty(KUI_FILE_TRANSFER,
8298                                    (long) CW_SPD,
8299                                    (long) "75/1200"
8300                                    );
8301                 } else {
8302                     char speedbuf[64] ;
8303                     sprintf(speedbuf, "%ld", speed);
8304                     KuiSetProperty(KUI_FILE_TRANSFER,
8305                                    (long) CW_SPD,
8306                                    (long) speedbuf
8307                                    );
8308                 }
8309             } else {
8310                 KuiSetProperty(KUI_FILE_TRANSFER,
8311                                (long) CW_SPD,
8312                                (long) "(unknown)"
8313                                );
8314             }
8315         }
8316         KuiSetProperty(KUI_FILE_TRANSFER,
8317                        (long) CW_PAR,
8318                        (long) parnam((char)parity)
8319                        );
8320         pctlbl = (what & W_SEND);
8321         cendw = 0;
8322     }
8323     debug(F101,"SCREENC switch","",f);
8324     debug(F000,"SCREENC c","",c);
8325     debug(F101,"SCREENC n","",n);
8326
8327     len = strlen(s);                    /* Length of argument string */
8328     switch (f) {                        /* Handle our function code */
8329       case SCR_FN:                      /* Filename */
8330         oldpct = pct = 0L;              /* Reset percents */
8331 #ifdef GFTIMER
8332         gtv = (CKFLOAT) -1.0;
8333         /* oldgtv = (CKFLOAT) -1.0; */
8334 #else
8335         gtv = -1L;
8336         /* oldgtv = -1L; */
8337 #endif /* GFTIMER */
8338         oldwin = -1;
8339         fsiz = -1L;                     /* Invalidate previous file size */
8340         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) 0 );
8341         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_FFC, (long) 0 );
8342         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) 0 );
8343         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) "" );
8344
8345         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
8346         q = len;                        /* Remember name length for later */
8347         scrft();                        /* Display file type (can change) */
8348 #ifdef OS2
8349         SaveCmdMode(0, 0);
8350 #endif /* OS2 */
8351         return;
8352
8353       case SCR_AN:                      /* File as-name */
8354         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
8355 #ifdef OS2
8356         SaveCmdMode(0, 0);
8357 #endif /* OS2 */
8358         return;
8359
8360       case SCR_FS:                      /* File size */
8361         fsiz = n;
8362         if (fsiz > -1L) {
8363             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) n );
8364         }
8365         if (fsiz > -1L) {               /* Put up percent label */
8366             pctlbl = 1;
8367         } else {
8368             pctlbl = 0;
8369         }
8370         scrft();                        /* File type */
8371 #ifdef OS2
8372         SaveCmdMode(0, 0);
8373 #endif /* OS2 */
8374         return;
8375
8376       case SCR_PT:                      /* Packet type or pseudotype */
8377         if (spackets < 5) {
8378             extern int sysindex;
8379             extern struct sysdata sysidlist[];
8380             /* Things that won't change after the 4th packet */
8381             KuiSetProperty( KUI_FILE_TRANSFER,
8382                            (long) CW_PAR,
8383                            (long) parnam((char)parity)
8384                            );
8385             if (
8386 #ifdef NEWFTP
8387                 (ftp && (spackets == 1 || rpackets == 1)) ||
8388 #endif /* NEWFTP */
8389                 spackets == 4
8390                 ) {
8391                 if (
8392 #ifdef NEWFTP
8393                     ftp ||
8394 #endif /* NEWFTP */
8395                     ((protocol == PROTO_K) && (sysindex > -1))
8396                     ) {
8397                     char msgbuf[128];
8398                     if (net) {
8399                         sprintf(msgbuf,"Network Host: %s (%s)",
8400 #ifdef NEWFTP
8401                                ftp ? (ftp_host ? ftp_host : "") :
8402 #endif /* NEWFTP */
8403                                ttname,
8404 #ifdef NEWFTP
8405                                ftp ? ftp_srvtyp :
8406 #endif /* NEWFTP */
8407                                sysidlist[sysindex].sid_name
8408                                );
8409                     } else {
8410                         sprintf(msgbuf,
8411                                 "Communication Device: %s (remote host is %s)",
8412                                 ttname,
8413                                 sysidlist[sysindex].sid_name
8414                                 );
8415                     }
8416                     KuiSetProperty( KUI_FILE_TRANSFER,
8417                                     (long) CW_LIN,
8418                                     (long) msgbuf
8419                                     );
8420                 }
8421             }
8422         }
8423 #ifdef CK_TIMERS
8424         if (/* rttflg && */ protocol == PROTO_K) {
8425             long xx;
8426             if (
8427 #ifdef STREAMING
8428                 streaming && oldwin != -2
8429 #else
8430                 0
8431 #endif /* STREAMING */
8432                 ) {
8433                 char msgbuf[64];
8434                 sprintf(msgbuf,"00 / 00");
8435                 KuiSetProperty( KUI_FILE_TRANSFER,
8436                                 (long) CW_TMO,
8437                                 (long) msgbuf
8438                                 );
8439             } else {
8440                 xx = (rttdelay + 500) / 1000;
8441                 if (xx != oldrtt || rcvtimo != oldtim) {
8442                     char msgbuf[64];
8443                     sprintf(msgbuf,"%02ld / %02d", xx, rcvtimo);
8444                     KuiSetProperty( KUI_FILE_TRANSFER,
8445                                     (long) CW_TMO,
8446                                     (long) msgbuf
8447                                     );
8448                     oldrtt = xx;
8449                     oldtim = rcvtimo;
8450                     clrtoeol();
8451                 }
8452             }
8453         }
8454 #endif /* CK_TIMERS */
8455
8456         x = (what & W_RECV) ?          /* Packet length */
8457           rpktl+(protocol==PROTO_K?1:0) :
8458             spktl;
8459         if (x != oldlen) {              /* But only if it changed. */
8460             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PL, (long) x );
8461             oldlen = x;
8462         }
8463         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PC, (long) spackets );
8464
8465         if (protocol == PROTO_K && !ftp) { /* Window slots */
8466             char ws[16];
8467             int flag;
8468             flag = 0;
8469 #ifdef STREAMING
8470             if (streaming) {
8471                 if (oldwin != -2) {
8472                     sprintf(ws,"STREAMING");
8473                     flag = 1;
8474                     oldwin = -2;
8475                 }
8476             } else
8477 #endif /* STREAMING */
8478               if (wcur != oldwin) {
8479                   sprintf(ws, "%d of %d", wcur < 1 ? 1 : wcur, wslotn);
8480                   flag = 1;
8481                   oldwin = wcur;
8482               }
8483             if (flag) {
8484                 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_WS, (long) ws );
8485             }
8486         }
8487         errors = retrans + crunched + timeouts;
8488         if (errors != oldtry) {         /* Retry count, if changed */
8489             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PR, (long) errors );
8490             oldtry = errors;
8491         }
8492         /* Sender's packet type */
8493         if (!ftp && (c != oldtyp && c != 'Y' && c != 'N')) {
8494             char type[2];
8495             sprintf(type, "%c",c);
8496             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PT, (long) type );
8497             oldtyp = c;
8498         }
8499         switch (c) {                    /* Now handle specific packet types */
8500           case 'S':                     /* Beginning of transfer */
8501             fcnt = fbyt = 0L;           /* Clear counters */
8502 #ifdef GFTIMER
8503             gtv = -1.0;
8504 #else /* GFTIMER */
8505             gtv = -1L;                  /* And old/new things... */
8506 #endif /* GFTIMER */
8507             oldpct = pct = 0L;
8508             break;
8509
8510           case 'Z':                     /* or EOF */
8511             debug(F101,"screeng SCR_PT Z pktnum","",n);
8512             debug(F101,"screeng SCR_PT Z oldpct","",oldpct);
8513             debug(F101,"screeng SCR_PT Z pct","",pct);
8514           case 'D':                     /* Data packet */
8515             if (fsiz > 0L) {            /* Show percent done if known */
8516                 oldpct = pct;           /* Remember previous percent */
8517                 howfar = ffc;
8518 #ifdef CK_RESEND
8519                 if (what & W_SEND)      /* Account for PSEND or RESEND */
8520                   howfar += sendstart;
8521                 else if (what & W_RECV)
8522                   howfar += rs_len;
8523 #endif /* CK_RESEND */
8524                 /* Percent done, to be displayed... */
8525                 if (c == 'Z') {
8526                     if (!discard && !cxseen && !czseen) pct = 100L;
8527                 } else
8528                   pct = (fsiz > 99L) ? (howfar / (fsiz / 100L)) : 0L;
8529                 if (pct > 100L ||       /* Allow for expansion and */
8530                    (oldpct == 99L && pct < 0L)) /* other boundary conditions */
8531                   pct = 100L;
8532                 if (pct != oldpct)      /* Only do this 100 times per file */
8533                   updpct(oldpct, pct);
8534             } else {
8535                 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8536             }
8537             KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) howfar);
8538             cps = shocps((int) pct, fsiz, howfar);
8539             /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8540             break;
8541
8542           case '%':                     /* Timeouts, retransmissions */
8543             cps = shocps((int) pct, fsiz, howfar);
8544             /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8545
8546             errors = retrans + crunched + timeouts;
8547             if (errors != oldtry) {     /* Error count, if changed */
8548                 KuiSetProperty(KUI_FILE_TRANSFER,
8549                                (long) CW_PR,
8550                                (long) errors
8551                                );
8552                 }
8553                 oldtry = errors;
8554                 if (s) if (*s) {
8555                     KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_ERR, (long) s);
8556             }
8557             break;
8558
8559           case 'E':                     /* Error packet */
8560             if (*s) {
8561                 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
8562             }
8563             fcnt = fbyt = 0L;           /* So no bytes for this file */
8564             break;
8565           case 'Q':                     /* Crunched packet */
8566             cps = shocps((int) pct, fsiz, howfar);
8567             /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8568             KuiSetProperty(KUI_FILE_TRANSFER,
8569                            (long) CW_ERR,
8570                            (long) "Damaged Packet"
8571                            );
8572             break;
8573           case 'q':                     /* Ctrl-C or connection lost */
8574             if (!s) s = "";
8575             if (!*s) s = "User interruption or connection lost";
8576             KuiSetProperty(KUI_FILE_TRANSFER,
8577                            (long) CW_MSG,
8578                            (long) s
8579                            );
8580             break;
8581           case 'T':                     /* Timeout */
8582             cps = shocps((int) pct, fsiz, howfar);
8583             /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8584             KuiSetProperty(KUI_FILE_TRANSFER,
8585                            (long) CW_ERR,
8586                            (long) "Timeout"
8587                            );
8588             errors = retrans + crunched + timeouts;
8589             if (errors != oldtry) {     /* Error count, if changed */
8590                 KuiSetProperty(KUI_FILE_TRANSFER,
8591                                (long) CW_PR, (long) errors
8592                                );
8593                 oldtry = errors;
8594             }
8595             break;
8596           default:                      /* Others, do nothing */
8597             break;
8598         }
8599 #ifdef OS2
8600         SaveCmdMode(0, 0);
8601 #endif /* OS2 */
8602         return;
8603
8604       case SCR_ST:                      /* File transfer status */
8605         debug(F101,"screeng SCR_ST c","",c);
8606         debug(F101,"screeng SCR_ST success","",success);
8607         debug(F101,"screeng SCR_ST cxseen","",cxseen);
8608 #ifdef COMMENT
8609         if (c == ST_OK) {               /* OK, print 100 % */
8610             if (pctlbl)
8611               updpct(oldpct,100);
8612             else
8613                 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8614             pct = 100;
8615             oldpct = 0;
8616         } else if (fsiz > 0L)           /* Not OK, update final percent */
8617 /*
8618   The else part writes all over the screen -- howfar and/or fsiz have
8619   been reset as a consequence of the not-OKness of the transfer.
8620 */
8621           if (pctlbl)
8622             updpct(oldpct, (howfar * 100L) / fsiz);
8623 #else
8624         if (c == ST_OK) {               /* OK, print 100 % */
8625             if (pctlbl) {
8626                 updpct(oldpct,100);
8627             } else
8628                 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8629 #ifdef COMMENT
8630             pct = 100;
8631             oldpct = 0;
8632 #endif /* COMMENT */
8633         }
8634 #endif /* COMMENT */
8635
8636         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "" );
8637
8638         switch (c) {                    /* Print new status message */
8639           case ST_OK:                   /* Transfer OK */
8640             fcnt++;                     /* Count this file */
8641             if (what == (W_FTP|W_FT_DELE)) {
8642                 KuiSetProperty(KUI_FILE_TRANSFER,
8643                                 (long) CW_MSG,
8644                                 (long) "Delete OK"
8645                                 );
8646             } else {
8647                 fbyt += ffc;
8648                 KuiSetProperty(KUI_FILE_TRANSFER,
8649                                 (long) CW_MSG,
8650                                 (long) "Transfer OK"
8651                                 );
8652             }
8653             return;
8654
8655           case ST_DISC:                 /* Discarded */
8656             KuiSetProperty(KUI_FILE_TRANSFER,
8657                            (long) CW_ERR,
8658                            (long) "File discarded"
8659                            );
8660 #ifdef COMMENT
8661             pct = oldpct = 0;
8662 #endif /* COMMENT */
8663             return;
8664
8665           case ST_INT:                  /* Interrupted */
8666             KuiSetProperty(KUI_FILE_TRANSFER,
8667                            (long) CW_ERR,
8668                            (long) "Transfer interrupted"
8669                            );
8670 #ifdef COMMENT
8671             pct = oldpct = 0;
8672 #endif /* COMMENT */
8673             return;
8674
8675         case ST_SKIP: {                /* Skipped */
8676             char errbuf[64] ;
8677             if (n > 0 && n < nskreason)
8678                 sprintf( errbuf, "File skipped, (%s)", skreason[n] ) ;
8679             else
8680                 sprintf( errbuf, "File skipped" ) ;
8681             KuiSetProperty(KUI_FILE_TRANSFER,
8682                            (long) CW_ERR,
8683                            (long) errbuf
8684                            );
8685 #ifdef COMMENT
8686             pct = oldpct = 0;
8687 #endif /* COMMENT */
8688             return;
8689         }
8690           case ST_ERR:                  /* Error message */
8691             if (!s) s = (char *)epktmsg;
8692             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
8693 #ifdef COMMENT
8694             pct = oldpct = 0;
8695 #endif /* COMMENT */
8696             return;
8697
8698           case ST_REFU:                 /* Refused */
8699             if (*s) {
8700                 char errbuf[64] ;
8701                 sprintf( errbuf, "Refused, %s", s ) ;
8702                 KuiSetProperty(KUI_FILE_TRANSFER,(long) CW_ERR,(long) errbuf);
8703             } else {
8704                 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Refused");
8705             }
8706 #ifdef COMMENT
8707             pct = oldpct = 0;
8708 #endif /* COMMENT */
8709             return;
8710
8711           case ST_INC:
8712             KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Incomplete");
8713 #ifdef COMMENT
8714             pct = oldpct = 0;
8715 #endif /* COMMENT */
8716             return;
8717
8718           case ST_MSG:
8719             KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_MSG,(long)s);
8720             return;
8721
8722           default:                      /* Bad call */
8723             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR,
8724                        (long) "*** screen() called with bad status ***" );
8725             return;
8726         }
8727
8728       case SCR_TC: {                    /* Transaction complete */
8729           char msgbuf[128];
8730           KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, tfcps);
8731           if (success) {
8732               sprintf(msgbuf,
8733                       "SUCCESS.  Files: %ld, Bytes: %ld, %ld CPS",
8734                       filcnt - filrej,
8735                       fbyt,
8736                       tfcps
8737                       );
8738               KuiSetProperty(KUI_FILE_TRANSFER,
8739                              (long) CW_MSG,
8740                              (long) msgbuf
8741                              );
8742           }
8743           KuiSetProperty(KUI_FILE_TRANSFER,
8744                          (long) CW_TR,
8745                          (long) hhmmss((long)
8746 #ifdef GFTIMER
8747                                        (fptsecs + 0.5)
8748 #else
8749                                        tsecs
8750 #endif /* GFTIMER */
8751                                        ));
8752
8753 #ifdef GFTIMER
8754           oldgtv = (CKFLOAT) -1.0;
8755 #else
8756           oldgtv = -1L;
8757 #endif /* GFTIMER */
8758
8759 #ifdef COMMENT
8760           pct = 100; oldpct = 0;        /* Reset these for next time. */
8761 #endif /* COMMENT */
8762           oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
8763           oldtim = -1;
8764           cendw = 1;
8765           if (xfrbel) bleep(BP_NOTE);   /* Close window, then beep. */
8766           ft_win = 0;                   /* Window closed. */
8767           return;
8768       }
8769       case SCR_EM:                      /* Error packet (fatal) */
8770         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
8771         if (xfrbel) bleep(BP_FAIL);
8772 #ifdef COMMENT
8773         pct = oldpct = 0;
8774 #endif /* COMMENT */
8775         return;
8776
8777       case SCR_QE:                      /* Quantity equals */
8778       case SCR_TU:                      /* Undelimited text */
8779       case SCR_TN:                      /* Text delimited at start */
8780       case SCR_TZ:                      /* Text delimited at end */
8781         return;                         /* (ignored in fullscreen display) */
8782
8783       case SCR_XD:                      /* X-packet data */
8784         pct = oldpct = 0;
8785         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
8786         return;
8787
8788       case SCR_CW:                      /* Close Window */
8789 #ifdef COMMENT
8790         pct = 100; oldpct = 0;          /* Reset these for next time. */
8791 #endif /* COMMENT */
8792         oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
8793         oldtim = -1;
8794
8795         ft_win = 0;                     /* Flag that window is closed. */
8796         cendw = 1; return;
8797
8798       case SCR_CD:                      /* Display current directory */
8799         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) s );
8800 #ifdef OS2
8801         SaveCmdMode(0, 0);
8802 #endif /* OS2 */
8803         return;
8804
8805       default:                          /* Bad call */
8806         KuiSetProperty(KUI_FILE_TRANSFER,
8807                        (long) CW_ERR,
8808                        (long) "*** screen() called with bad function code ***"
8809                        );
8810         return;
8811     }
8812 }
8813 #endif /* KUI */
8814 #endif /* MAC */
8815
8816 #endif /* NOXFER */
8817
8818 #ifndef CK_CURPOS
8819 /* Dummies for when cursor control is not supported */
8820 int
8821 ck_curpos(row, col) {
8822     return(-1);
8823 }
8824
8825 int
8826 ck_cls() {
8827     return(-1);
8828 }
8829
8830 int
8831 ck_cleol() {
8832     return(-1);
8833 }
8834 #endif /* CK_CURPOS */
8835
8836 #ifndef NOIKSD
8837 #ifdef IKSDB
8838
8839 struct iksdbfld dbfld[] = {
8840    /* Offset    Length    Type   */
8841     { DB_FLAGS, dB_FLAGS, DBT_HEX },    /*  0 db_FLAGS Flags */
8842     { DB_ATYPE, dB_ATYPE, DBT_HEX },    /*  1 db_ATYPE Auth type */
8843     { DB_AMODE, dB_AMODE, DBT_HEX },    /*  3 db_AMODE Auth mode */
8844     { DB_STATE, dB_STATE, DBT_HEX },    /*  2 db_STATE State */
8845     { DB_MYPID, dB_MYPID, DBT_HEX },    /*  5 db_MYPID PID */
8846     { DB_SADDR, dB_SADDR, DBT_HEX },    /*  4 db_SADDR Server address */
8847     { DB_CADDR, dB_CADDR, DBT_HEX },    /*  6 db_CADDR Client address */
8848     { DB_START, dB_START, DBT_DAT },    /*  7 db_START Session start */
8849     { DB_LASTU, dB_LASTU, DBT_DAT },    /*  8 db_LASTU Last update */
8850     { DB_ULEN,  dB_ULEN,  DBT_HEX },    /*  9 db_ULEN  Username length */
8851     { DB_DLEN,  dB_DLEN,  DBT_HEX },    /* 10 db_DLEN  Directory name length */
8852     { DB_ILEN,  dB_ILEN,  DBT_HEX },    /* 11 db_ILEN  Info length */
8853     { DB_PAD1,  dB_PAD1,  DBT_UND },    /* 12 db_PAD1  (Reserved) */
8854     { DB_USER,  dB_USER,  DBT_STR },    /* 13 db_USER  Username */
8855     { DB_DIR,   dB_DIR,   DBT_STR },    /* 14 db_DIR   Current Directory */
8856     { DB_INFO,  dB_INFO,  DBT_STR }     /* 15 db_INFO  State-specific info */
8857 };
8858
8859 static char lcknam[CKMAXPATH+1];        /* Lockfile pathname */
8860 static char tmplck[CKMAXPATH+1];        /* Temporary lockfile name */
8861
8862 static char * updmode =                 /* Update mode for fopen() */
8863 #ifdef OS2
8864   "r+b"
8865 #else
8866 #ifdef VMS
8867   "r+b"
8868 #else
8869   "r+"
8870 #endif /* VMS */
8871 #endif /* OS2 */
8872   ;
8873
8874 /*  D B I N I T  --  Initialize the IKSD database...  */
8875
8876 int
8877 dbinit() {
8878     extern int dbinited;
8879     int x = 0;
8880     debug(F110,"dbinit dbdir 1",dbdir,0);
8881     debug(F110,"dbinit dbfile 1",dbfile,0);
8882     if (dbinited)
8883       return(0);
8884 #ifdef OS2
8885     if (!dbdir) {
8886 #ifdef NT
8887         char * p = NULL;
8888         if (!isWin95()) {
8889             p = getenv("SystemRoot");
8890         } else {
8891             p = getenv("winbootdir");
8892             if (!p)  p = getenv("windir");
8893         }
8894         if (!p) p = "C:/";
8895         dbdir = malloc(strlen(p)+2);
8896         strcpy(dbdir,p);                /* safe */
8897         p = dbdir;
8898         while (*p) {
8899             if (*p == '\\')
8900               *p = '/';
8901             p++;
8902         }
8903         if (*(p-1) != '/' ) {
8904             *p++ = '/';
8905             *p = '\0';
8906         }
8907 #else /* NT */
8908         makestr(&dbdir,"C:/");
8909 #endif /* NT */
8910     }
8911 #else /* OS2 */
8912     if (!dbdir)
8913       makestr(&dbdir,IK_DBASEDIR);
8914 #endif /* OS2 */
8915
8916     if (!dbfile) {
8917         char * s = "";
8918         x = strlen(dbdir);
8919         if (dbdir[x-1] != '/') {
8920             s = "/";
8921             x++;
8922         }
8923         x += (int)strlen(IK_DBASEFIL);
8924         dbfile = (char *)malloc(x+1);
8925         sprintf(dbfile,"%s%s%s",dbdir,s,IK_DBASEFIL);
8926     }
8927     debug(F110,"dbinit dbdir 2",dbdir,0);
8928     debug(F110,"dbinit dbfile 2",dbfile,0);
8929     mypid = getpid();                   /* Get my pid */
8930     debug(F101,"dbinit mypid","",mypid);
8931
8932     if (!myhexip[0]) {                  /* Set my hex IP address */
8933 #ifdef TCPSOCKET
8934         extern unsigned long myxipaddr;
8935         if (getlocalipaddr() > -1) {
8936             myip = myxipaddr;
8937             sprintf(myhexip,"%08lx",myip); /* (Needs fixing for IPv6) */
8938         } else
8939 #endif /* TCPSOCKET */
8940           ckstrncpy(myhexip,"00000000",9);
8941     }
8942     debug(F111,"dbinit myip",myhexip,myip);
8943     if (!peerhexip[0]) {                /* Get peer's  hex IP address */
8944 #ifdef TCPSOCKET
8945         extern unsigned long peerxipaddr;
8946         if (ckgetpeer()) {
8947             peerip = peerxipaddr;
8948             sprintf(peerhexip,"%08lx",peerip); /* (Needs fixing for IPv6) */
8949             debug(F111,"dbinit peerip",peerhexip,peerip);
8950         } else {
8951             debug(F101,"dbinit ckgetpeer failure","",errno);
8952             ckstrncpy(peerhexip,"00000000",9);
8953         }
8954 #else
8955         ckstrncpy(peerhexip,"00000000",9);
8956 #endif /* TCPSOCKET */
8957     }
8958     debug(F111,"dbinit peerip",peerhexip,peerip);
8959     debug(F101,"dbinit dbenabled","",dbenabled);
8960     if (dbenabled && inserver) {
8961         mydbslot = getslot();
8962         debug(F111,"dbinit getslot",ckitoa(ikdbopen),x);
8963         if (ikdbopen) dbinited = 1;
8964     }
8965     return(0);
8966 }
8967
8968 /*  U P D S L O T  --  Update slot n  */
8969
8970 /*
8971   Opens the database if necessary, seeks to slot n, writes current record
8972   and adds current time to last-update field.  n is the record sequence number
8973   (0, 1, 2, ...), not the seek pointer.   Returns -1 on failure, 0 on success.
8974 */
8975 int
8976 updslot(n) int n; {                     /* Update our slot */
8977     int rc = 0;
8978     long position;
8979
8980     debug(F111,"updslot","ikdbopen",ikdbopen);
8981     if (!ikdbopen)                      /* Not if not ok */
8982       return(0);
8983     if (!dbfp) {                        /* Open database if not open */
8984         dbfp = fopen(dbfile,updmode);   /* In update no-truncate mode */
8985         if (!dbfp) {
8986             debug(F110,"updslot fopen failed",dbfile,0);
8987             ikdbopen = 0;
8988             return(-1);
8989         }
8990     }
8991     debug(F111,"updslot dbfile",dbfile,dbfp);
8992     position = n * DB_RECL;
8993     if (fseek(dbfp,position,0) < 0) {   /* Seek to desired slot */
8994         debug(F111,"updslot fseek failed",dbfile,mydbseek);
8995         ikdbopen = 0;
8996         rc = -1;
8997     } else {
8998         /* Update the update time */
8999         strncpy(&dbrec[dbfld[db_LASTU].off],
9000                 ckdate(),
9001                 dbfld[db_LASTU].len
9002                 );
9003         if (fwrite(dbrec,1,DB_RECL,dbfp) < DB_RECL) { /* Write the record */
9004             debug(F110,"updslot fwrite failed",dbfile,0);
9005             ikdbopen = 0;
9006             rc = -1;
9007         } else {                        /* Flush the write */
9008             fflush(dbfp);
9009         }
9010     }
9011     return(rc);
9012 }
9013
9014 /*  I N I T S L O T --  Initialize slot n with my info  */
9015
9016 int
9017 initslot(n) int n; {                    /* Initialize slot */
9018     int k;
9019 #ifdef TCPSOCKET
9020     extern unsigned long peerxipaddr;
9021 #endif /* TCPSOCKET */
9022
9023     debug(F101,"initslot","",n);
9024
9025 #ifdef USE_MEMCPY
9026     memset(dbrec,32,DB_RECL);
9027 #else
9028     for (k = 0; k < DB_RECL; k++)
9029       dbrec[k] = '\040';
9030 #endif /* USE_MEMCPY */
9031
9032     myflags = DBF_INUSE;                /* Set in-use flag */
9033     mystate = W_NOTHING;
9034     myatype = 0L;
9035     myamode = 0L;
9036
9037     k = dbfld[db_FLAGS].len;            /* Length of flags field */
9038     strncpy(&dbrec[dbfld[db_FLAGS].off],ulongtohex(myflags,k),k);
9039
9040     k = dbfld[db_ATYPE].len;
9041     strncpy(&dbrec[dbfld[db_ATYPE].off],ulongtohex(myatype,k),k);
9042
9043     k = dbfld[db_AMODE].len;
9044     strncpy(&dbrec[dbfld[db_AMODE].off],ulongtohex(myamode,k),k);
9045
9046     k = dbfld[db_STATE].len;
9047     strncpy(&dbrec[dbfld[db_STATE].off],ulongtohex(mystate,k),k);
9048
9049     k = dbfld[db_SADDR].len;
9050     strncpy(&dbrec[dbfld[db_SADDR].off],ulongtohex(myip,k),k);
9051
9052 #ifdef TCPSOCKET
9053     ckgetpeer();
9054     k = dbfld[db_CADDR].len;
9055     strncpy(&dbrec[dbfld[db_CADDR].off],ulongtohex(peerxipaddr,k),k);
9056 #else
9057     k = dbfld[db_CADDR].len;
9058     strncpy(&dbrec[dbfld[db_CADDR].off],ulongtohex(0L,k),k);
9059 #endif /* TCPSOCKET */
9060
9061     k = dbfld[db_MYPID].len;
9062     strncpy(&dbrec[dbfld[db_MYPID].off],ulongtohex(mypid,k),k);
9063
9064     k = dbfld[db_START].len;
9065     strncpy(&dbrec[dbfld[db_START].off],ckdate(),k);
9066
9067     k = dbfld[db_ULEN].len;
9068     strncpy(&dbrec[dbfld[db_ULEN].off],"0000",4);
9069
9070     k = dbfld[db_DLEN].len;
9071     strncpy(&dbrec[dbfld[db_DLEN].off],"0000",4);
9072
9073     k = dbfld[db_ILEN].len;
9074     strncpy(&dbrec[dbfld[db_ILEN].off],"0000",4);
9075
9076     strncpy(&dbrec[dbfld[db_INFO].off],"INIT",4);
9077     return(updslot(n));
9078 }
9079
9080 int
9081 slotstate(x,s1,s2,s3) int x; char *s1, *s2, *s3; {
9082     int k, l1, l2, l3, z;
9083     mystate = x;
9084     debug(F101,"slotstate ikdbopen","",ikdbopen);
9085     if (!ikdbopen)
9086       return(-1);
9087     if (!s1) s1 = "";
9088     l1 = strlen(s1);
9089     if (!s2) s2 = "";
9090     l2 = strlen(s2);
9091     if (!s3) s3 = "";
9092     l3 = strlen(s3);
9093     strncpy(&dbrec[DB_STATE],ulongtohex(mystate,4),4);
9094     k = dbfld[db_ILEN].len;
9095     z = l1 + l2 + l3 + 2;
9096     if (z > dB_INFO)
9097       z = dB_INFO;
9098     strncpy(&dbrec[DB_ILEN],ulongtohex((unsigned long)z,k),k);
9099     k = dbfld[db_INFO].len;
9100     z = dbfld[db_INFO].off;
9101     if (l1 <= k) {
9102         lset(&dbrec[z],s1,l1+1,32);
9103         z += l1+1;
9104         k -= l1+1;
9105         if (l2 <= k) {
9106             lset(&dbrec[z],s2,l2+1,32);
9107             z += l2+1;
9108             k -= l2+1;
9109             if (l3 <= k)
9110               lset(&dbrec[z],s3,k,32);
9111         }
9112     }
9113 #ifdef DEBUG
9114     if (deblog) {
9115         char buf[128];
9116         int i;
9117         strncpy(buf,&dbrec[DB_INFO],127);
9118         buf[127] = NUL;
9119         for (i = 126; i > 0 && buf[i] == 32; i--) buf[i] = 0;
9120         debug(F111,"slotstate",buf,mystate);
9121     }
9122 #endif /* DEBUG */
9123     z = updslot(mydbslot);
9124     debug(F101,"slotstate updslot","",z);
9125     return(z);
9126 }
9127
9128 int
9129 slotdir(s1,s2) char * s1, * s2; {       /* Update current directory */
9130     int k, len1, len2;
9131     if (!ikdbopen)
9132       return(-1);
9133     if (!s1) s1 = "";
9134     if (!s2) s2 = "";
9135     len1 = strlen(s1);
9136     len2 = strlen(s2);
9137     k = dbfld[db_DLEN].len;
9138     strncpy(&dbrec[DB_DLEN],ulongtohex((unsigned long)(len1+len2),k),k);
9139     k = dbfld[db_DIR].len;
9140     if (len1 > 0) {
9141         lset(&dbrec[dbfld[db_DIR].off],s1,len1,32);
9142         lset(&dbrec[dbfld[db_DIR].off+len1],s2,k-len1,32);
9143     } else {
9144         lset(&dbrec[dbfld[db_DIR].off],s2,k,32);
9145     }
9146     return(updslot(mydbslot));
9147 }
9148
9149 /*  F R E E S L O T  --  Free slot n  */
9150
9151 int
9152 freeslot(n) int n; {
9153     int k;
9154     if (!ikdbopen)
9155       return(0);
9156     dbflags = 0L;
9157     if (n == mydbslot) {
9158         dbflags = myflags & ~DBF_INUSE;
9159         dbflags &= ~DBF_LOGGED;
9160     }
9161     k = dbfld[db_FLAGS].len;
9162     strncpy(&dbrec[dbfld[db_FLAGS].off],ulongtohex(dbflags,k),k);
9163     return(updslot(n));
9164 }
9165
9166 /*  G E T S L O T  --  Find a free database slot; returns slot number  */
9167
9168 int
9169 getslot() {                             /* Find a free slot for us */
9170     FILE * rfp = NULL;                  /* Returns slot number (0, 1, ...) */
9171     char idstring[64];                  /* PID string buffer (decimal) */
9172     char pidbuf[64], * s;
9173     int j, k, n, x, rc = -1;
9174     int lockfd, tries, haveslot = 0;
9175     long lockpid, i;
9176     /* char ipbuf[17]; */
9177
9178     if (!myhexip[0])                    /* Set my hex IP address if not set */
9179       ckstrncpy((char *)myhexip,"7F000001",33);
9180     sprintf(idstring,"%08lx:%010ld\n",myip,mypid);
9181     debug(F110,"getslot idstring", idstring, 0);
9182
9183     /* Make temporary lockfile name IP.PID (hex.hex) */
9184     /* This should fit in 14 chars -- huge PIDs are usually not possible */
9185     /* on 14-char filename systems. */
9186
9187     sprintf(tmplck,"%s%08lx.%lx",dbdir,myip,mypid);
9188     debug(F110,"getslot tempfile",tmplck,0);
9189
9190     /* Make a temporary file */
9191
9192     lockfd = creat(tmplck, 0600);
9193     if (lockfd < 0) {
9194         debug(F111,"getslock temp lockfile create failure", tmplck, errno);
9195         return(-1);
9196     }
9197     /* Write my (decimal) PID into the temp file */
9198
9199     write(lockfd,idstring,(int)strlen(idstring));
9200     if (close(lockfd) < 0) {            /* Close lockfile */
9201         debug(F101,"getslot error closing temp lockfile", "", errno);
9202         return(-1);
9203     }
9204     sprintf(lcknam,"%s%s",dbdir,IK_LOCKFILE); /* Build lockfile name */
9205     debug(F110,"getslot lockfile",lcknam,0);
9206
9207     rfp = fopen(lcknam,"r");            /* See if lockfile exists */
9208     if (rfp) {                          /* If so... */
9209         rset(pidbuf,"",64,0);
9210         x = fread(pidbuf,1,63,rfp);     /* Read ID string from it */
9211         fclose(rfp);                    /* and close it quickly */
9212         debug(F110,"getslot lock exists",pidbuf,0);
9213         if (x > 0) {                    /* If we have a PID, check it */
9214             char * s = pidbuf;
9215             while (*s) {
9216                 if (islower(*s)) *s = toupper(*s);
9217                 if (*s == ':') {
9218                     *s = NUL;
9219                     debug(F110,"getslot lock IP",pidbuf,0);
9220                     debug(F110,"gteslot my   IP",myhexip,0);
9221                     if (!strcmp(pidbuf,myhexip)) { /* Same IP address? */
9222                         lockpid = atol(s+1); /* Yes, now get PID */
9223                         debug(F101,"getslot lockpid","",lockpid);
9224
9225                         /* Check if PID lockpid on this computer is alive */
9226                         x = zchkpid(lockpid);
9227                         if (!x) {
9228                             debug(F100,"getslot PID stale,removing lock","",0);
9229                             unlink(lcknam);
9230                         }
9231                         break;
9232                     }
9233                 }
9234                 s++;
9235             }
9236         } else {
9237             debug(F111,"getslot lockfile open failure",lcknam,errno);
9238         }
9239     }
9240     /* Try IK_LCKTRIES (16) times to rename temp file to lockfile */
9241
9242     for (tries = IK_LCKTRIES; tries > 0; tries--) {
9243         if (zrename(tmplck,lcknam) == 0)
9244           break;
9245         debug(F101,"getslot database locked by pid", "", dbpid);
9246         sleep(IK_LCKSLEEP);
9247     }
9248     if (tries < 1) {                    /* Couldn't */
9249         debug(F110,"getslot create lock failure",lcknam,0);
9250         return(-1);
9251     }
9252     /* Have lock, open database */
9253
9254     debug(F110,"getslot has lock",lcknam,0); /* Have lock */
9255
9256     if (!dbfile)
9257       return(-1);
9258
9259     /* If database doesn't exist, create it. */
9260
9261     debug(F110,"getslot dbfile",dbfile,0);
9262     if (zchki(dbfile) < 0) {
9263         debug(F110,"getslot creating new database",dbfile,0);
9264         x = creat(dbfile,0660);
9265         if (x < 0) {
9266             debug(F111,"getslot creat() failed", dbfile, errno);
9267             goto xslot;
9268         }
9269         close(x);
9270     }
9271     dbfp = fopen(dbfile,updmode);       /* Open it in update mode */
9272     if (!dbfp) {
9273         debug(F111,"getslot fopen failed",dbfile,errno);
9274         goto xslot;
9275     }
9276     /* Now find a free (or new) slot... */
9277
9278     dblastused = 0L;                    /* Seek pointer to last record inuse */
9279     mydbseek = 0L;                      /* Seek pointer for my record */
9280
9281     /* Quickly read the whole database; n = record counter, i = seek pointer */
9282
9283     for (n = 0, i = 0; !feof(dbfp); i += DB_RECL, n++) {
9284         x = fread(dbrec,1,DB_RECL,dbfp); /* Read a record */
9285         if (x < 1)                      /* EOF not caught by feof() */
9286           break;
9287 #ifndef NOFTRUNCATE
9288         if (x != DB_RECL) {             /* Watch out for trailing junk */
9289             debug(F101,"getslot bad size","",x);  /* (Shouldn't happen...) */
9290 #ifdef COHERENT
9291             chsize(fileno(dbfp),i);
9292 #else
9293             ftruncate(fileno(dbfp),i);
9294 #endif /* COHERENT */
9295             x = 0;
9296             fseek(dbfp,i,0);
9297             break;
9298         }
9299 #endif /* NOFTRUNCATE */
9300         debug(F101,"getslot record","",n);
9301         k = dbfld[db_FLAGS].off;
9302         j = dbfld[db_FLAGS].len;
9303         dbflags = hextoulong(&dbrec[k],j);
9304         debug(F001,"getslot dbflags","",dbflags);
9305         k = dbfld[db_MYPID].off;
9306         j = dbfld[db_MYPID].len;
9307         dbpid  = hextoulong(&dbrec[k],j);
9308         debug(F001,"getslot dbpid","",dbpid);
9309         k = dbfld[db_SADDR].off;
9310         j = dbfld[db_SADDR].len;
9311         dbip = hextoulong(&dbrec[k],j);
9312         debug(F001,"getslot dbip","",dbip);
9313
9314         if (dbflags & DBF_INUSE) {      /* Remember last slot in use */
9315             x = 0;                      /* Make sure it's REALLY in use */
9316             if (dbpid == mypid && dbip == myip) { /* Check for PID == my PID */
9317                 x = 1;
9318                 debug(F101,"getslot record pid","",dbpid);
9319             } else {                    /* Or for stale PID */
9320                 x = zchkpid(dbpid);
9321                 debug(F101,"getslot zchkpid()","",x);
9322             }
9323             if (!x) {                   /* Bogus record */
9324                 x = freeslot(n);
9325                 debug(F101,"getslot stale record pid: freeslot()","",x);
9326                 if (x > -1 && !haveslot)
9327                   dbflags = 0;
9328             } else {                    /* It's really in use */
9329                 dblastused = i;
9330             }
9331         }
9332         if (!haveslot) {                /* If I don't have a slot yet */
9333             if (!(dbflags & DBF_INUSE)) {       /* Claim this one */
9334                 debug(F101,"getslot free slot", "", n);
9335                 haveslot = 1;
9336                 mydbseek = i;
9337                 mydbslot = n;           /* But keep going... */
9338             }
9339         }
9340     }
9341     /* Come here with i == seek pointer to first record after eof */
9342
9343     if (!haveslot) {                    /* Found no free slot so add to end */
9344         debug(F101,"getslot new slot","",n);
9345         haveslot = 1;
9346         mydbseek = i;
9347         mydbslot = n;
9348     }
9349     ikdbopen = 1;                       /* OK to make database entries */
9350     debug(F101,"getslot records","",n);
9351     debug(F101,"getslot dblastused","",dblastused);
9352     debug(F101,"getslot i","",i);
9353
9354     /* Trim stale records from end */
9355
9356 #ifndef NOFTRUNCATE
9357     if (i > dblastused+DB_RECL) {
9358         debug(F101,"getslot truncating at","",dblastused+DB_RECL);
9359 #ifdef COHERENT
9360         x = chsize(fileno(dbfp),dblastused+DB_RECL);
9361 #else
9362         x = ftruncate(fileno(dbfp),dblastused+DB_RECL);
9363 #endif /* COHERENT */
9364         if (x < 0)                      /* (Not fatal) */
9365           debug(F101,"getslot ftruncate failed", "", errno);
9366     }
9367 #endif /* NOFTRUNCATE */
9368
9369     /* Initialize my record */
9370
9371     if (initslot(mydbslot) < 0) {
9372         debug(F101,"getslot initslot() error","",n);
9373         ikdbopen = 0;
9374         goto xslot;
9375     }
9376     debug(F101,"getslot OK","",mydbslot);
9377     rc = mydbslot;                      /* OK return code */
9378
9379   xslot:                                /* Unlock the database and return */
9380     if (unlink(lcknam) < 0) {
9381         debug(F111,"getslot lockfile removal failed",lcknam,errno);
9382         rc = -1;
9383     }
9384     return(rc);
9385 }
9386 #endif /* IKSDB */
9387 #endif /* NOIKSD */