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