Imported Upstream version 302
[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 dialcapas, dialfc;
2365     extern MDMINF * modemp[];
2366     MDMINF * p = NULL;
2367     long bits = 0;
2368 #endif /* NODIAL */
2369
2370     debug(F101,"setflow autoflow","",autoflow);
2371
2372 /* #ifdef COMMENT */
2373 /* WHY WAS THIS COMMENTED OUT? */
2374     if (!autoflow)                      /* Only if FLOW is AUTO */
2375       return;
2376 /* #endif */ /* COMMENT */
2377
2378     debug(F101,"setflow local","",local);
2379     debug(F101,"setflow network","",network);
2380     debug(F101,"setflow cxtype","",cxtype);
2381
2382 #ifdef TN_COMPORT
2383     if (network && istncomport()) {
2384         flow = cxflow[CXT_MODEM];
2385         debug(F101,"setflow TN_COMPORT flow","",flow);
2386         return;
2387     }
2388 #endif /* TN_COMPORT */
2389
2390     if (network || !local || cxtype == CXT_DIRECT) {
2391         flow = cxflow[cxtype];          /* Set appropriate flow control */
2392         debug(F101,"setflow flow","",flow);
2393         return;
2394     }
2395     if (cxtype != CXT_MODEM)            /* Connection type should be modem */
2396       return;
2397
2398 #ifndef NODIAL
2399     bits = dialcapas;                   /* Capability bits */
2400     if (!bits) {                        /* No bits? */
2401         p = modemp[mdmtyp];             /* Look in modem info structure */
2402         if (p)
2403           bits = p->capas;
2404     }
2405     if (dialfc == FLO_AUTO) {           /* If DIAL flow is AUTO */
2406 #ifdef CK_RTSCTS                        /* If we can do RTS/CTS flow control */
2407         if (bits & CKD_HW)              /* and modem can do it too */
2408           flow = FLO_RTSC;              /* then switch to RTS/CTS */
2409         else                            /* otherwise */
2410           flow = FLO_XONX;              /* use Xon/Xoff. */
2411 #else
2412 #ifndef NEXT
2413 #ifndef IRIX
2414         flow = FLO_XONX;                /* Use Xon/Xoff. */
2415 #endif /* IRIX */
2416 #endif /* NEXT */
2417 #endif /* CK_RTSCTS */
2418     }
2419 #endif /* NODIAL */
2420     debug(F101,"setflow modem flow","",flow);
2421     return;
2422 }
2423
2424 #ifndef NOLOCAL
2425 #ifdef CK_TRIGGER
2426
2427 /*  A U T O E X I T C H K  --  Check for CONNECT-mode trigger string  */
2428 /*
2429   Returns -1 if trigger not found, or else the trigger index, 0 or greater.
2430   (Replace with fancier and more efficient matcher later...)
2431   NOTE: to prevent unnecessary function call overhead, call this way:
2432
2433     x = tt_trigger[0] ? autoexitchk(c) : -1;
2434
2435 */
2436 int
2437 #ifdef CK_ANSIC
2438 autoexitchk(CHAR c)
2439 #else
2440 autoexitchk(c) CHAR c;
2441 #endif /* CK_ANSIC */
2442 /* autoexitchk */ {
2443     extern CHAR * tt_trmatch[];
2444     extern char * tt_trigger[];
2445     int i;
2446     for (i = 0; i < TRIGGERS; i++) {
2447         if (!tt_trigger[i]) {           /* No more triggers in list */
2448             break;
2449         } else if (*tt_trigger[i]) {
2450             if (!tt_trmatch[i])         /* Just starting? */
2451               tt_trmatch[i] = (CHAR *)tt_trigger[i]; /* Set match pointer */
2452             if (c == *tt_trmatch[i]) {  /* Compare this character */
2453                 tt_trmatch[i]++;        /* It matches */
2454                 if (!*tt_trmatch[i]) {  /* End of match string? */
2455                     tt_trmatch[i] = (CHAR *) tt_trigger[i]; /* Yes, rewind, */
2456                     debug(F101,"autoexitchk",tt_trigger[i],i); /* log, */
2457                     return(i);          /* and return success */
2458                 }
2459             } else                      /* No match */
2460               tt_trmatch[i] = (CHAR *) tt_trigger[i]; /* Rewind match string */
2461         } /* and go on the next match string */
2462     }
2463     return(-1);                         /* No match found */
2464 }
2465 #endif /* CK_TRIGGER */
2466
2467 #ifndef NOSHOW
2468 /*  S H O M D M  --  Show modem signals  */
2469
2470 VOID
2471 shomdm() {
2472 /*
2473   Note use of "\r\n" to make sure this report prints right, even when
2474   called during CONNECT mode.
2475 */
2476     int y;
2477     y = ttgmdm();
2478     switch (y) {
2479       case -3: printf(
2480                  "Modem signals unavailable in this version of Kermit\r\n");
2481                break;
2482       case -2: printf("No modem control for this device\r\n"); break;
2483       case -1: printf("Modem signals unavailable\r\n"); break;
2484       default:
2485 #ifndef MAC
2486         printf(
2487           " Carrier Detect      (CD):  %s\r\n",(y & BM_DCD) ? "On": "Off");
2488         printf(
2489           " Dataset Ready       (DSR): %s\r\n",(y & BM_DSR) ? "On": "Off");
2490 #endif /* MAC */
2491         printf(
2492           " Clear To Send       (CTS): %s\r\n",(y & BM_CTS) ? "On": "Off");
2493 #ifndef STRATUS
2494 #ifndef MAC
2495         printf(
2496           " Ring Indicator      (RI):  %s\r\n",(y & BM_RNG) ? "On": "Off");
2497 #endif /* MAC */
2498         printf(
2499           " Data Terminal Ready (DTR): %s\r\n",
2500 #ifdef NT
2501           "(unknown)"
2502 #else /* NT */
2503           (y & BM_DTR) ? "On": "Off"
2504 #endif /* NT */
2505           );
2506 #ifndef MAC
2507         printf(
2508           " Request To Send     (RTS): %s\r\n",
2509 #ifdef NT
2510           "(unknown)"
2511 #else /* NT */
2512           (y & BM_RTS) ? "On": "Off"
2513 #endif /* NT */
2514           );
2515 #endif /* MAC */
2516 #endif /* STRATUS */
2517     }
2518 #ifdef BETADEBUG
2519 #ifdef CK_TAPI
2520     if (tttapi && !tapipass) {
2521         LPDEVCFG        lpDevCfg = NULL;
2522         LPCOMMCONFIG    lpCommConfig = NULL;
2523         LPMODEMSETTINGS lpModemSettings = NULL;
2524         DCB *           lpDCB = NULL;
2525
2526         if (cktapiGetModemSettings(&lpDevCfg,&lpModemSettings,
2527                                     &lpCommConfig,&lpDCB)) {
2528             printf("\n");
2529             cktapiDisplayModemSettings(lpDevCfg,lpModemSettings,
2530                                        lpCommConfig,lpDCB);
2531         }
2532     }
2533 #endif /* CK_TAPI */
2534 #endif /* BETADEBUG */
2535 }
2536 #endif /* NOSHOW */
2537 #endif /* NOLOCAL */
2538
2539 #ifndef NOXFER
2540 /*  S D E B U  -- Record spar results in debugging log  */
2541
2542 VOID
2543 sdebu(len) int len; {
2544     debug(F111,"spar: data",(char *) rdatap,len);
2545     debug(F101," spsiz ","", spsiz);
2546     debug(F101," timint","",timint);
2547     debug(F101," npad  ","",  npad);
2548     debug(F101," padch ","", padch);
2549     debug(F101," seol  ","",  seol);
2550     debug(F101," ctlq  ","",  ctlq);
2551     debug(F101," ebq   ","",   ebq);
2552     debug(F101," ebqflg","",ebqflg);
2553     debug(F101," bctr  ","",  bctr);
2554     debug(F101," rptq  ","",  rptq);
2555     debug(F101," rptflg","",rptflg);
2556     debug(F101," lscapu","",lscapu);
2557     debug(F101," atcapu","",atcapu);
2558     debug(F101," lpcapu","",lpcapu);
2559     debug(F101," swcapu","",swcapu);
2560     debug(F101," wslotn","", wslotn);
2561     debug(F101," whatru","", whatru);
2562 }
2563 /*  R D E B U -- Debugging display of rpar() values  */
2564
2565 VOID
2566 rdebu(d,len) CHAR *d; int len; {
2567     debug(F111,"rpar: data",d,len);
2568     debug(F101," rpsiz ","", xunchar(d[0]));
2569     debug(F101," rtimo ","", rtimo);
2570     debug(F101," mypadn","",mypadn);
2571     debug(F101," mypadc","",mypadc);
2572     debug(F101," eol   ","",   eol);
2573     debug(F101," ctlq  ","",  ctlq);
2574     debug(F101," sq    ","",    sq);
2575     debug(F101," ebq   ","",   ebq);
2576     debug(F101," ebqflg","",ebqflg);
2577     debug(F101," bctr  ","",  bctr);
2578     debug(F101," rptq  ","",  d[8]);
2579     debug(F101," rptflg","",rptflg);
2580     debug(F101," capas ","", capas);
2581     debug(F101," bits  ","",d[capas]);
2582     debug(F101," lscapu","",lscapu);
2583     debug(F101," atcapu","",atcapu);
2584     debug(F101," lpcapu","",lpcapu);
2585     debug(F101," swcapu","",swcapu);
2586     debug(F101," wslotr","", wslotr);
2587     debug(F101," rpsiz(extended)","",rpsiz);
2588 }
2589
2590 #ifdef COMMENT
2591 /*  C H K E R R  --  Decide whether to exit upon a protocol error  */
2592
2593 VOID
2594 chkerr() {
2595     if (backgrd && !server) fatal("Protocol error");
2596 }
2597 #endif /* COMMENT */
2598 #endif /* NOXFER */
2599
2600 /*  F A T A L  --  Fatal error message */
2601
2602 VOID
2603 fatal(msg) char *msg; {
2604     extern int initflg;
2605     static int initing = 0;
2606     if (!msg) msg = "";
2607     debug(F111,"fatal",msg,initflg);
2608
2609     if (!initflg) {                     /* If called from prescan */
2610         if (initing)                    /* or called from sysinit() */
2611           exit(253);
2612         initing = 1;
2613         sysinit();
2614     }
2615
2616     debug(F111,"fatal",msg,xitsta);
2617     tlog(F110,"Fatal:",msg,0L);
2618 #ifdef VMS
2619     if (strncmp(msg,"%CKERMIT",8))
2620       conol("%CKERMIT-E-FATAL, ");
2621     conoll(msg);
2622 #else /* !VMS */
2623     conoll(msg);
2624 #endif /* VMS */
2625 #ifdef OS2
2626 #ifndef NOXFER
2627     if (xfrbel) {
2628         bleep(BP_FAIL);
2629         sleep(1);
2630         bleep(BP_FAIL);
2631     }
2632 #endif /* NOXFER */
2633
2634 #endif /* OS2 */
2635     doexit(BAD_EXIT,xitsta | 1);        /* Exit indicating failure */
2636 }
2637
2638 #ifndef NOXFER
2639 /*  B L D L E N  --  Make length-encoded copy of string  */
2640
2641 char *
2642 bldlen(str,dest) char *str, *dest; {
2643     int len;
2644     len = (int)strlen(str);
2645     if (len > 94)
2646       *dest = SP;
2647     else
2648       *dest = (char) tochar(len);
2649     strcpy(dest+1,str);                 /* Checked below in setgen() */
2650     return(dest+len+1);
2651 }
2652
2653
2654 /*  S E T G E N  --  Construct a generic command  */
2655 /*
2656   Call with Generic command character followed by three string arguments.
2657   Trailing strings are allowed to be empty ("").  Each string except the last
2658   non-empty string must be less than 95 characters long.  The final nonempty
2659   string is allowed to be longer.
2660 */
2661 CHAR
2662 #ifdef CK_ANSIC
2663 setgen(char type, char * arg1, char * arg2, char * arg3)
2664 #else
2665 setgen(type,arg1,arg2,arg3) char type, *arg1, *arg2, *arg3;
2666 #endif /* CK_ANSIC */
2667 /* setgen */ {
2668     char *upstr, *cp;
2669 #ifdef DYNAMIC
2670     if (!cmdstr)
2671       if (!(cmdstr = malloc(MAXSP + 1)))
2672         fatal("setgen: can't allocate memory");
2673 #endif /* DYNAMIC */
2674
2675     cp = cmdstr;
2676     *cp++ = type;
2677     *cp = NUL;
2678     if (!arg1) arg1 = "";
2679     if (!arg2) arg2 = "";
2680     if (!arg3) arg3 = "";
2681     if (((int)strlen(arg1)+(int)strlen(arg2)+(int)strlen(arg3)+4) < MAXSP) {
2682         if (*arg1 != NUL) {
2683             upstr = bldlen(arg1,cp);
2684             if (*arg2 != NUL) {
2685                 upstr = bldlen(arg2,upstr);
2686                 if (*arg3 != NUL) bldlen(arg3,upstr);
2687             }
2688         }
2689         cmarg = cmdstr;
2690         debug(F110,"setgen",cmarg,0);
2691         return('g');
2692     }
2693     return('E');
2694 }
2695 #endif /* NOXFER */
2696
2697 #ifndef NOMSEND
2698 static char *mgbufp = NULL;
2699
2700 /*  F N P A R S E  --  */
2701
2702 /*
2703   Argument is a character string containing one or more filespecs.
2704   This function breaks the string apart into an array of pointers, one
2705   to each filespec, and returns the number of filespecs.  Used by server
2706   when it receives a GET command to allow it to process multiple file
2707   specifications in one transaction.  Sets cmlist to point to a list of
2708   file pointers, exactly as if they were command line arguments.
2709
2710   This version of fnparse treats spaces as filename separators.  If your
2711   operating system allows spaces in filenames, you'll need a different
2712   separator.
2713
2714   This version of fnparse mallocs a string buffer to contain the names.  It
2715   cannot assume that the string that is pointed to by the argument is safe.
2716 */
2717 int
2718 fnparse(string) char *string; {
2719     char *p, *s, *q;
2720     int r = 0, x;                       /* Return code */
2721 #ifdef RECURSIVE
2722     debug(F111,"fnparse",string,recursive);
2723 #endif /* RECURSIVE */
2724
2725     if (mgbufp) free(mgbufp);           /* Free this from last time. */
2726     mgbufp = malloc((int)strlen(string)+2);
2727     if (!mgbufp) {
2728         debug(F100,"fnparse malloc error","",0);
2729         return(0);
2730     }
2731 #ifndef NOICP
2732 #ifndef NOSPL
2733     ckstrncpy(fspec,string,fspeclen);   /* Make copy for \v(filespec) */
2734 #endif /* NOSPL */
2735 #endif /* NOICP */
2736     s = string;                         /* Input string */
2737     p = q = mgbufp;                     /* Point to the copy */
2738     r = 0;                              /* Initialize our return code */
2739     while (*s == SP || *s == HT)        /* Skip leading spaces and tabs */
2740       s++;
2741     for (x = strlen(s);                 /* Strip trailing spaces */
2742          (x > 1) && (s[x-1] == SP || s[x-1] == HT);
2743          x--)
2744       s[x-1] = NUL;
2745     while (1) {                         /* Loop through rest of string */
2746         if (*s == CMDQ) {               /* Backslash (quote character)? */
2747             if ((x = xxesc(&s)) > -1) { /* Go interpret it. */
2748                 *q++ = (char) x;        /* Numeric backslash code, ok */
2749             } else {                    /* Just let it quote next char */
2750                 s++;                    /* get past the backslash */
2751                 *q++ = *s++;            /* deposit next char */
2752             }
2753             continue;
2754         } else if (*s == SP || *s == NUL) { /* Unquoted space or NUL? */
2755             *q++ = NUL;                 /* End of output filename. */
2756             msfiles[r] = p;             /* Add this filename to the list */
2757             debug(F111,"fnparse",msfiles[r],r);
2758             r++;                        /* Count it */
2759             if (*s == NUL) break;       /* End of string? */
2760             while (*s == SP) s++;       /* Skip repeated spaces */
2761             p = q;                      /* Start of next name */
2762             continue;
2763         } else *q++ = *s;               /* Otherwise copy the character */
2764         s++;                            /* Next input character */
2765     }
2766     debug(F101,"fnparse r","",r);
2767     msfiles[r] = "";                    /* Put empty string at end of list */
2768     cmlist = msfiles;
2769     return(r);
2770 }
2771 #endif /* NOMSEND */
2772
2773 char *                                  /* dbchr() for DEBUG SESSION */
2774 dbchr(c) int c; {
2775     static char s[8];
2776     char *cp = s;
2777
2778     c &= 0xff;
2779     if (c & 0x80) {                     /* 8th bit on */
2780         *cp++ = '~';
2781         c &= 0x7f;
2782     }
2783     if (c < SP) {                       /* Control character */
2784         *cp++ = '^';
2785         *cp++ = (char) ctl(c);
2786     } else if (c == DEL) {
2787         *cp++ = '^';
2788         *cp++ = '?';
2789     } else {                            /* Printing character */
2790         *cp++ = (char) c;
2791     }
2792     *cp = '\0';                         /* Terminate string */
2793     cp = s;                             /* Return pointer to it */
2794     return(cp);
2795 }
2796
2797 /*  C K H O S T  --  Get name of local host (where C-Kermit is running)  */
2798
2799 /*
2800   Call with pointer to buffer to put hostname in, and length of buffer.
2801   Copies hostname into buffer on success, puts null string in buffer on
2802   failure.
2803 */
2804 #ifdef BSD44
2805 #define BSD4
2806 #undef ATTSV
2807 #endif /* BSD44 */
2808
2809 #ifdef SVORPOSIX
2810 #ifndef BSD44
2811 #ifndef apollo
2812 #include <sys/utsname.h>
2813 #endif /* apollo */
2814 #endif /* BSD44 */
2815 #else
2816 #ifdef BELLV10
2817 #include <utsname.h>
2818 #endif /* BELLV10 */
2819 #endif /* SVORPOSIX*/
2820
2821 #ifdef CKSYSLOG
2822 extern char uidbuf[], * clienthost;
2823 #endif /* CKSYSLOG */
2824
2825 VOID
2826 ckhost(vvbuf,vvlen) char * vvbuf; int vvlen; {
2827
2828 #ifndef NOPUSH
2829     extern int nopush;
2830 #ifndef NOSERVER
2831     extern int en_hos;
2832 #endif /* NOSERVER */
2833 #endif /* NOPUSH */
2834
2835 #ifdef pdp11
2836     *vvbuf = NUL;
2837 #else  /* Everything else - rest of this routine */
2838
2839     char *g;
2840     int havefull = 0;
2841 #ifdef VMS
2842     int x;
2843 #endif /* VMS */
2844
2845 #ifdef SVORPOSIX
2846 #ifndef BSD44
2847 #ifndef _386BSD
2848 #ifndef APOLLOSR10
2849     struct utsname hname;
2850 #endif /* APOLLOSR10 */
2851 #endif /* _386BSD */
2852 #endif /* BSD44 */
2853 #endif /* SVORPOSIX */
2854 #ifdef datageneral
2855     int ac0 = (char *) vvbuf, ac1 = -1, ac2 = 0;
2856 #endif /* datageneral */
2857
2858 #ifndef NOPUSH
2859     if (getenv("CK_NOPUSH")) {          /* No shell access allowed */
2860         nopush = 1;                     /* on this host... */
2861 #ifndef NOSERVER
2862         en_hos = 0;
2863 #endif /* NOSERVER */
2864     }
2865 #endif /* NOPUSH */
2866
2867     *vvbuf = NUL;                       /* How let's get our host name ... */
2868
2869 #ifndef BELLV10                         /* Does not have gethostname() */
2870 #ifndef OXOS
2871 #ifdef SVORPOSIX
2872 #ifdef APOLLOSR10
2873     ckstrncpy(vvbuf,"Apollo",vvlen);
2874 #else
2875 #ifdef BSD44
2876     if (gethostname(vvbuf,vvlen) < 0)
2877       *vvbuf = NUL;
2878 #else
2879 #ifdef _386BSD
2880     if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
2881 #else
2882 #ifdef QNX
2883 #ifdef TCPSOCKET
2884     if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
2885 #else
2886     if (uname(&hname) > -1) ckstrncpy(vvbuf,hname.nodename,vvlen);
2887 #endif /* TCPSOCKET */
2888 #else /* SVORPOSIX but not _386BSD or BSD44 */
2889 #ifdef __ia64__
2890     if (uname(&hname) > -1) ckstrncpy(vvbuf,hname.nodename,vvlen);
2891 #else
2892     if (uname(&hname) > -1) {
2893         char * p;
2894         p = hname.nodename;
2895 #ifdef TCPSOCKET
2896 #ifndef NOCKGETFQHOST
2897         if (!ckstrchr(p,'.'))
2898           p = (char *)ckgetfqhostname(p);
2899 #endif /* NOCKGETFQHOST */
2900 #endif /* TCPSOCKET */
2901         if (!p) p = "";
2902         if (!*p) p = "(unknown)";
2903         ckstrncpy(vvbuf,p,vvlen);
2904     }
2905 #endif /* __ia64__ */
2906 #endif /* QNX */
2907 #endif /* _386BSD */
2908 #endif /* BSD44 */
2909 #endif /* APOLLOSR10 */
2910 #else /* !SVORPOSIX */
2911 #ifdef BSD4
2912     if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
2913 #else /* !BSD4 */
2914 #ifdef VMS
2915     g = getenv("SYS$NODE");
2916     if (g) ckstrncpy(vvbuf,g,vvlen);
2917     x = (int)strlen(vvbuf);
2918     if (x > 1 && vvbuf[x-1] == ':' && vvbuf[x-2] == ':') vvbuf[x-2] = NUL;
2919 #else
2920 #ifdef datageneral
2921     if (sys($HNAME,&ac0,&ac1,&ac2) == 0) /* successful */
2922         vvlen = ac2 + 1;                /* enh - have to add one */
2923 #else
2924 #ifdef OS2                              /* OS/2 */
2925     g = os2_gethostname();
2926     if (g) ckstrncpy(vvbuf,g,vvlen);
2927 #else /* OS2 */
2928 #ifdef OSK
2929 #ifdef TCPSOCKET
2930         if (gethostname(vvbuf, vvlen) < 0) *vvbuf = NUL;
2931 #endif /* TCPSOCKET */
2932 #endif /* OSK */
2933 #endif /* OS2 */
2934 #endif /* datageneral */
2935 #endif /* VMS */
2936 #endif /* BSD4 */
2937 #endif /* SVORPOSIX */
2938 #else /* OXOS */
2939     /* If TCP/IP is not installed, gethostname() fails, use uname() */
2940     if (gethostname(vvbuf,vvlen) < 0) {
2941         if (uname(&hname) > -1)
2942             ckstrncpy(vvbuf,hname.nodename,vvlen);
2943         else
2944             *vvbuf = NUL;
2945     }
2946 #endif /* OXOS */
2947 #endif /* BELLV10 */
2948     if (*vvbuf == NUL) {                /* If it's still empty */
2949         g = getenv("HOST");             /* try this */
2950         if (g) ckstrncpy(vvbuf,g,vvlen);
2951     }
2952     vvbuf[vvlen-1] = NUL;               /* Make sure result is terminated. */
2953 #endif /* pdp11 */
2954 }
2955 #ifdef BSD44
2956 #undef BSD4
2957 #define ATTSV
2958 #endif /* BSD44 */
2959
2960 /*
2961   A S K M O R E  --  Poor person's "more".
2962   Returns 0 if no more, 1 if more wanted.
2963 */
2964 int
2965 askmore() {
2966     char c;
2967     int rv, cx;
2968 #ifdef IKSD
2969     extern int timelimit;
2970 #endif /* IKSD */
2971 #ifdef IKSDCONF
2972     extern int iksdcf;
2973 #endif /* IKSDCONF */
2974 #ifdef CK_APC
2975     extern int apcstatus, apcactive;
2976 #endif /* CK_APC */
2977
2978 #ifdef NOICP
2979     return(1);
2980 #else
2981     if (!xaskmore)
2982       return(1);
2983 #ifdef IKSDCONF
2984     if (inserver && !iksdcf)
2985       return(1);
2986 #endif /* IKSDCONF */
2987 #ifdef CK_APC
2988     if (apcactive == APC_LOCAL ||
2989         (apcactive == APC_REMOTE && (apcstatus & APC_NOINP)))
2990         return(1);
2991 #endif /* CK_APC */
2992 #ifdef VMS
2993     if (batch)
2994       return(1);
2995 #else
2996 #ifdef UNIX
2997     if (backgrd)
2998       return(1);
2999 #endif /* UNIX */
3000 #endif /* VMS */
3001
3002 #ifndef VMS
3003     concb((char)escape);                /* Force CBREAK mode. */
3004 #endif /* VMS */
3005
3006     rv = -1;
3007     while (rv < 0) {
3008 #ifndef OS2
3009         printf("more? ");
3010 #ifdef UNIX
3011 #ifdef NOSETBUF
3012         fflush(stdout);
3013 #endif /* NOSETBUF */
3014 #endif /* UNIX */
3015 #else
3016         printf("more? ");
3017         fflush(stdout);
3018 #endif /* OS2 */
3019
3020 #ifdef IKSD
3021         if (inserver) {
3022             cx = cmdgetc(timelimit);
3023             if (cx < -1 && timelimit) {
3024                 printf("\n?IKS idle timeout - Goodbye.\n");
3025                 doexit(GOOD_EXIT,0);
3026             } else if (cx == -1) {      /* Connection lost */
3027                 doexit(BAD_EXIT,0);
3028             }
3029             c = (char) cx;
3030         } else {
3031 #endif /* IKSD */
3032 #ifdef VMS
3033             conbin((char)escape);       /* Protect against Ctrl-Z */
3034             cx = coninc(0);
3035             concb((char)escape);
3036 #else
3037             cx = cmdgetc(0);
3038 #endif /* VMS */
3039             debug(F101,"askmore cmdgetc","",cx);
3040             if (cx == EOF) {
3041                 debug(F100,"askmore EOF","",0);
3042 #ifdef VMS
3043                 c = '\032';
3044 #else
3045                 c = 'n';
3046 #endif /* VMS */
3047             } else {
3048                 c = (char)cx;
3049             }
3050             debug(F101,"askmore c","",c);
3051
3052 #ifdef IKSD
3053         }
3054 #endif /* IKSD */
3055         switch (c) {
3056           /* Yes */
3057           case 'p': case 'P': case 'g': case 'G': /* Proceed or Go */
3058             xaskmore = 0;
3059             /* fall thru on purpose */
3060
3061           case SP: case 'y': case 'Y': case 012:  case 015:
3062 #ifdef OSK
3063             write(1, "\015      \015", sizeof "\015      \015" - 1);
3064 #else
3065             printf("\015      \015");
3066 #endif /* OSK */
3067             rv = 1;
3068             break;
3069           /* No */
3070           case 'n': case 'N': case 'q': case 'Q':
3071 #ifdef OSK
3072             printf("\n");
3073 #else
3074             printf("\015\012");
3075 #endif /* OSK */
3076             rv = 0;
3077             break;
3078           case '\003':
3079           case '\004':
3080           case '\032':
3081 #ifdef OSK
3082             printf("^%c...\n", (c + 0100));
3083 #else
3084             printf("^%c...\015\012", (c + 0100));
3085 #endif /* OSK */
3086             rv = 0;
3087             break;
3088           /* Invalid answer */
3089           default:
3090             debug(F111,"askmore","invalid answer",c);
3091             printf("Y or space-bar for yes, N for no, G to show the rest\n");
3092             continue;
3093         }
3094 #ifdef OS2
3095         printf("\r                                                   \r");
3096         fflush(stdout);
3097 #endif /* OS2 */
3098     }
3099     return(rv);
3100 #endif /* NOICP */
3101 }
3102
3103 /*  T R A P  --  Terminal interrupt handler */
3104
3105 SIGTYP
3106 #ifdef CK_ANSIC
3107 trap(int sig)
3108 #else
3109 trap(sig) int sig;
3110 #endif /* CK_ANSIC */
3111 /* trap */ {
3112     extern int b_save, f_save;
3113 #ifndef NOICP
3114     extern int timelimit;
3115 #endif /* NOICP */
3116 #ifdef OS2
3117     extern unsigned long startflags;
3118 #ifndef NOSETKEY
3119     extern int os2gks;
3120 #endif /* NOSETKEY */
3121     int i;
3122 #endif /* OS2 */
3123 #ifndef NOSPL
3124     extern int i_active, instatus;
3125 #endif /* NOSPL */
3126 #ifdef VMS
3127     int i; FILE *f;
3128 #endif /* VMS */
3129     extern int zchkod, zchkid;
3130 #ifndef NOSPL
3131     extern int unkmacro;
3132 #endif /* NOSPL */
3133
3134     debok = 1;
3135 #ifdef NTSIG
3136     connoi();
3137 #endif /* NTSIG */
3138 #ifdef __EMX__
3139     signal(SIGINT, SIG_ACK);
3140 #endif
3141 #ifdef GEMDOS
3142 /* GEM is not reentrant, no i/o from interrupt level */
3143     cklongjmp(cmjbuf,1);                /* Jump back to parser now! */
3144 #endif /* GEMDOS */
3145
3146 #ifdef DEBUG
3147     if (deblog) {
3148         debug(F100,"*********************","",0);
3149         if (sig == SIGINT)
3150           debug(F101,"trap caught SIGINT","",sig);
3151         else 
3152           debug(F101,"trap caught signal","",sig);
3153         debug(F100,"*********************","",0);
3154     }
3155 #endif /* DEBUG */
3156
3157 #ifdef OS2
3158     if ( sig == SIGBREAK && (startflags & 128) ) {
3159         debug(F101,"trap ignoring SIGBREAK","",sig);
3160         return;
3161     }
3162 #endif /* OS2 */
3163
3164 #ifndef NOICP
3165     timelimit = 0;                      /* In case timed ASK interrupted */
3166 #ifndef NOSPL
3167     unkmacro = 0;                       /* Or ON_UNKNOWN_MACRO interrupted.. */
3168 #endif /* NOSPL */
3169 #endif /* NOICP */
3170     zchkod = 0;                         /* Or file expansion interrupted... */
3171     zchkid = 0;
3172     interrupted = 1;
3173
3174     if (what & W_CONNECT) {             /* Are we in CONNECT mode? */
3175 /*
3176   The HP workstation Reset key sends some kind of ueber-SIGINT that can not
3177   be SIG_IGNored, so we wind up here somehow (even though this is *not* the
3178   current SIGINT handler).  Just return.
3179 */
3180         debug(F101,"trap: SIGINT caught during CONNECT","",sig);
3181         SIGRETURN;
3182     }
3183 #ifndef NOSPL
3184     if (i_active) {                     /* INPUT command was active? */
3185         i_active = 0;                   /* Not any more... */
3186         instatus = INP_UI;              /* INPUT status = User Interrupted */
3187     }
3188 #endif /* NOSPL */
3189
3190 #ifndef NOXFER
3191     ftreset();                          /* Restore global protocol settings */
3192     binary = b_save;                    /* Then restore these */
3193     fncnv  = f_save;
3194     bye_active = 0;
3195     diractive = 0;
3196     cdactive = 0;
3197 #endif /* NOXFER */
3198     zclose(ZIFILE);                     /* If we were transferring a file, */
3199     zclose(ZOFILE);                     /* close it. */
3200 #ifndef NOICP
3201     cmdsquo(cmd_quoting);               /* If command quoting was turned off */
3202 #ifdef CKLEARN
3203     {
3204         extern FILE * learnfp;
3205         extern int learning;
3206         if (learnfp) {
3207             fclose(learnfp);
3208             learnfp = NULL;
3209             learning = 0;
3210         }
3211     }
3212 #endif /* CKLEARN */
3213 #endif /* NOICP */
3214 #ifdef CK_APC
3215     delmac("_apc_commands",1);
3216     apcactive = APC_INACTIVE;
3217 #endif /* CK_APC */
3218
3219 #ifdef VMS
3220 /*
3221   Fix terminal.
3222 */
3223     if (ft_win) {                       /* If curses window open */
3224         debug(F100,"^C trap() curses","",0);
3225         xxscreen(SCR_CW,0,0L,"");       /* Close it */
3226         conres();                       /* Restore terminal */
3227         i = printf("^C...");            /* Echo ^C to standard output */
3228     } else {
3229         conres();
3230         i = printf("^C...\n");          /* Echo ^C to standard output */
3231     }
3232     if (i < 1 && ferror(stdout)) {      /* If there was an error */
3233         debug(F100,"^C trap() error","",0);
3234         fclose(stdout);                 /* close standard output */
3235         f = fopen(dftty, "w");          /* open the controlling terminal */
3236         if (f) stdout = f;              /* and make it standard output */
3237         printf("^C...\n");              /* and echo the ^C again. */
3238     }
3239 #else                                   /* Not VMS */
3240 #ifdef STRATUS
3241     conres();                           /* Set console back to normal mode */
3242 #endif /* STRATUS */
3243 #ifndef NOXFER
3244     if (ft_win) {                       /* If curses window open, */
3245         debug(F100,"^C trap() curses","",0);
3246         xxscreen(SCR_CW,0,0L,"");       /* close it. */
3247         printf("^C...");                /* Echo ^C to standard output */
3248     } else {
3249 #endif /* NOXFER */
3250         printf("^C...\n");
3251 #ifndef NOXFER
3252     }
3253 #endif /* NOXFER */
3254 #endif /* VMS */
3255 #ifdef datageneral
3256     connoi_mt();                        /* Kill asynch task that listens to */
3257     ttimoff();
3258     conres();                           /* the keyboard */
3259 #endif /* datageneral */
3260
3261 #ifndef NOCCTRAP
3262 /*  This is stupid -- every version should have ttimoff()...  */
3263 #ifdef UNIX
3264     ttimoff();                          /* Turn off any timer interrupts */
3265 #else
3266 #ifdef OSK
3267     ttimoff();                          /* Turn off any timer interrupts */
3268 #else
3269 #ifdef STRATUS
3270     ttimoff();                          /* Turn off any timer interrupts */
3271 #else
3272 #ifdef OS2
3273 #ifndef NOSETKEY
3274     os2gks = 1;                         /* Turn back on keycode mapping  */
3275 #endif /* NOSETKEY */
3276 #ifndef NOLOCAL
3277     for (i = 0; i < VNUM; i++)
3278       VscrnResetPopup(i);
3279 #endif /* NOLOCAL */
3280 #ifdef TCPSOCKET
3281 #ifdef NT
3282     /* WSAIsBlocking() returns FALSE in Win95 during a blocking accept call */
3283     if ( WSASafeToCancel /* && WSAIsBlocking() */ ) {
3284         WSACancelBlockingCall();
3285     }
3286 #endif /* NT */
3287 #endif /* TCPSOCKET */
3288 #ifdef CK_NETBIOS
3289     NCBCancelOutstanding();
3290 #endif /* CK_NETBIOS */
3291     ttimoff();                          /* Turn off any timer interrupts */
3292 #else
3293 #ifdef VMS
3294     ttimoff();                          /* Turn off any timer interrupts */
3295 #endif /* VMS */
3296 #endif /* OS2 */
3297 #endif /* STRATUS */
3298 #endif /* OSK */
3299 #endif /* UNIX */
3300
3301 #ifdef NETPTY
3302     /* Clean up Ctrl-C out of REDIRECT or external protocol */
3303     {
3304         extern PID_T pty_fork_pid;
3305         extern int pty_master_fd, pty_slave_fd;
3306         int x;
3307
3308         signal(SIGCHLD,SIG_IGN);        /* We don't want this any more */
3309
3310         debug(F101,"trap pty_master_fd","",pty_master_fd);
3311         if (pty_master_fd > 2) {
3312             x = close(pty_master_fd);
3313             debug(F101,"trap pty_master_fd close","",x);
3314         }
3315         pty_master_fd = -1;
3316         debug(F101,"trap pty_slave_fd","",pty_slave_fd);
3317         if (pty_slave_fd > 2) {
3318             x = close(pty_slave_fd);
3319             debug(F101,"trap pty_slave_fd close","",x);
3320         }
3321         pty_slave_fd = -1;
3322         debug(F101,"trap pty_fork_pid","",pty_fork_pid);
3323         if (pty_fork_pid > 0) {
3324             x = kill(pty_fork_pid,0);   /* See if the fork is really there */
3325             debug(F111,"trap pty_fork_pid kill 0 errno",ckitoa(x),errno);
3326             if (x == 0) {               /* Seems to be active */
3327                 x = kill(pty_fork_pid,SIGHUP); /* Ask it to clean up & exit */
3328                 debug(F101,"trap pty_fork_pid kill SIGHUP","",x);
3329                 msleep(100);
3330                 errno = 0;
3331                 x = kill(pty_fork_pid,0); /* Is it still there? */
3332                 if (x == 0
3333 #ifdef ESRCH
3334                     /* This module is not always exposed to <errno.h> */
3335                     || errno != ESRCH
3336 #endif  /* ESRCH */
3337                     ) {
3338                     x = kill(pty_fork_pid,SIGKILL);
3339                     debug(F101,"trap pty_fork_pid kill SIGKILL","",x);
3340                 }
3341             }
3342             pty_fork_pid = -1;
3343         }
3344     }
3345 #endif  /* NETPTY */
3346
3347 #ifdef OSK
3348     sigmask(-1);
3349 /*
3350   We are in an intercept routine but do not perform a F$RTE (done implicitly
3351   by rts).  We have to decrement the sigmask as F$RTE does.  Warning: longjump
3352   only restores the cpu registers, NOT the fpu registers.  So don't use fpu at
3353   all or at least don't use common fpu (double or float) register variables.
3354 */
3355 #endif /* OSK */
3356
3357 #ifdef NTSIG
3358     PostCtrlCSem();
3359 #else /* NTSIG */
3360     debug(F100,"trap about to longjmp","",0);
3361 #ifdef NT
3362     cklongjmp(ckjaddr(cmjbuf),1);
3363 #else /* NT */
3364     cklongjmp(cmjbuf,1);
3365 #endif /* NT */
3366 #endif /* NTSIG */
3367 #else /* NOCCTRAP */
3368 /* No Ctrl-C trap, just exit. */
3369 #ifdef CK_CURSES                        /* Curses support? */
3370     xxscreen(SCR_CW,0,0L,"");           /* Close curses window */
3371 #endif /* CK_CURSES */
3372     doexit(BAD_EXIT,what);              /* Exit poorly */
3373 #endif /* NOCCTRAP */
3374     SIGRETURN;
3375 }
3376
3377
3378 /*  C K _ T I M E  -- Returns pointer to current time. */
3379
3380 char *
3381 ck_time() {
3382     static char tbuf[10];
3383     char *p;
3384     int x;
3385
3386     ztime(&p);                          /* "Thu Feb  8 12:00:00 1990" */
3387     if (!p)                             /* like asctime()! */
3388       return("");
3389     if (*p) {
3390         for (x = 11; x < 19; x++)       /* copy hh:mm:ss */
3391           tbuf[x - 11] = p[x];          /* to tbuf */
3392         tbuf[8] = NUL;                  /* terminate */
3393     }
3394     return(tbuf);                       /* and return it */
3395 }
3396
3397 /*  C C _ C L E A N  --  Cleanup after terminal interrupt handler */
3398
3399 #ifdef GEMDOS
3400 int
3401 cc_clean() {
3402     zclose(ZIFILE);                     /* If we were transferring a file, */
3403     zclose(ZOFILE);                     /* close it. */
3404     printf("^C...\n");                  /* Not VMS, no problem... */
3405 }
3406 #endif /* GEMDOS */
3407
3408
3409 /*  S T P T R A P -- Handle SIGTSTP (suspend) signals */
3410
3411 SIGTYP
3412 #ifdef CK_ANSIC
3413 stptrap(int sig)
3414 #else
3415 stptrap(sig) int sig;
3416 #endif /* CK_ANSIC */
3417 /* stptrap */ {
3418
3419 #ifndef NOJC
3420     int x; extern int cmflgs;
3421     debug(F101,"stptrap() caught signal","",sig);
3422     if (!xsuspend) {
3423         printf("\r\nsuspend disabled\r\n");
3424 #ifndef NOICP
3425         if (what & W_COMMAND) {         /* If we were parsing commands */
3426             prompt(xxstring);           /* reissue the prompt and partial */
3427             if (!cmflgs)                /* command (if any) */
3428               printf("%s",cmdbuf);
3429         }
3430 #endif /* NOICP */
3431     } else {
3432         conres();                       /* Reset the console */
3433 #ifndef OS2
3434         /* Flush pending output first, in case we are continued */
3435         /* in the background, which could make us block */
3436         fflush(stdout);
3437
3438         x = psuspend(xsuspend);         /* Try to suspend. */
3439         if (x < 0)
3440 #endif /* OS2 */
3441           printf("Job control not supported\r\n");
3442         conint(trap,stptrap);           /* Rearm the trap. */
3443         debug(F100,"stptrap back from suspend","",0);
3444         switch (what) {
3445           case W_CONNECT:               /* If suspended during CONNECT? */
3446             conbin((char)escape);       /* put console back in binary mode */
3447             debug(F100,"stptrap W_CONNECT","",0);
3448             break;
3449 #ifndef NOICP
3450           case W_COMMAND:               /* Suspended in command mode */
3451             debug(F101,"stptrap W_COMMAND pflag","",pflag);
3452             concb((char)escape);        /* Put back CBREAK tty mode */
3453             if (pflag) {                /* If command parsing was */
3454                 prompt(xxstring);       /* reissue the prompt and partial */
3455                 if (!cmflgs)            /* command (if any) */
3456                   printf("%s",cmdbuf);
3457             }
3458             break;
3459 #endif /* NOICP */
3460           default:                      /* All other cases... */
3461             debug(F100,"stptrap default","",0);
3462             concb((char)escape);        /* Put it back in CBREAK mode */
3463             break;
3464         }
3465     }
3466 #endif /* NOJC */
3467     SIGRETURN;
3468 }
3469
3470 #ifdef TLOG
3471 #define TBUFL 300
3472
3473 /*  T L O G  --  Log a record in the transaction file  */
3474 /*
3475  Call with a format and 3 arguments: two strings and a number:
3476    f     - Format, a bit string in range 0-7, bit x is on, arg #x is printed.
3477    s1,s2 - String arguments 0 and 1.
3478    n     - Long, argument 2.
3479 */
3480 VOID
3481 #ifdef CK_ANSIC
3482 dotlog(int f, char *s1, char *s2, CK_OFF_T n)
3483 #else
3484 dotlog(f,s1,s2,n) int f; CK_OFF_T n; char *s1, *s2;
3485 #endif /* CK_ANSIC */
3486 /* dotlog */ {
3487     static char s[TBUFL];
3488     extern int tlogfmt;
3489     char *sp = s; int x;
3490     if (!s1) s1 = "";
3491     if (!s2) s2 = "";
3492
3493     if (!tralog) return;                /* If no transaction log, don't */
3494     if (tlogfmt != 1) return;
3495     switch (f) {
3496       case F000:                        /* 0 (special) "s1 n s2"  */
3497         if ((int)strlen(s1) + (int)strlen(s2) + 15 > TBUFL)
3498           sprintf(sp,"?T-Log string too long");
3499         else
3500           sprintf(sp,"%s %s %s",s1,ckfstoa(n),s2);
3501         if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3502         break;
3503       case F001:                        /* 1, " n" */
3504         sprintf(sp," %s",ckfstoa(n));
3505         if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3506         break;
3507       case F010:                        /* 2, "[s2]" */
3508         x = (int)strlen(s2);
3509         if (s2[x] == '\n') s2[x] = '\0';
3510         if (x + 6 > TBUFL)
3511           sprintf(sp,"?String too long");
3512         else sprintf(sp,"[%s]",s2);
3513         if (zsoutl(ZTFILE,"") < 0) tralog = 0;
3514         break;
3515       case F011:                        /* 3, "[s2] n" */
3516         x = (int)strlen(s2);
3517         if (s2[x] == '\n') s2[x] = '\0';
3518         if (x + 6 > TBUFL)
3519           sprintf(sp,"?String too long");
3520         else sprintf(sp,"[%s] %s",s2,ckfstoa(n));
3521         if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3522         break;
3523       case F100:                        /* 4, "s1" */
3524         if (zsoutl(ZTFILE,s1) < 0) tralog = 0;
3525         break;
3526       case F101:                        /* 5, "s1: n" */
3527         if ((int)strlen(s1) + 15 > TBUFL)
3528           sprintf(sp,"?String too long");
3529         else sprintf(sp,"%s: %s",s1,ckfstoa(n));
3530         if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3531         break;
3532       case F110:                        /* 6, "s1 s2" */
3533         x = (int)strlen(s2);
3534         if (s2[x] == '\n') s2[x] = '\0';
3535         if ((int)strlen(s1) + x + 4 > TBUFL)
3536           sprintf(sp,"?String too long");
3537         else
3538           sprintf(sp,"%s%s%s",s1,((*s2 == ':') ? "" : " "),s2);
3539         if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3540         break;
3541       case F111:                        /* 7, "s1 s2: n" */
3542         x = (int)strlen(s2);
3543         if (s2[x] == '\n') s2[x] = '\0';
3544         if ((int)strlen(s1) + x + 15 > TBUFL)
3545           sprintf(sp,"?String too long");
3546         else
3547           sprintf(sp,"%s%s%s: %s",s1,((*s2 == ':') ? "" : " "),s2,ckfstoa(n));
3548         if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3549         break;
3550       default:
3551         sprintf(sp,"?Invalid format for tlog() - %d",f);
3552         if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3553     }
3554 }
3555
3556 /*
3557   D O X L O G
3558
3559   This is the transaction-log writer for BRIEF format.
3560   The idea is produce one record (line) per file.  Each record
3561   has the following delimited fields:
3562     Date (yyyymmdd)
3563     Time (hh:mm:ss)
3564     Action: SEND or RECV
3565     File name
3566     File size
3567     Transfer mode (text, binary, image, labeled, etc).
3568     Status: OK or FAILED
3569     Free-form comments in doublequotes
3570   The default separator is comma.
3571   If a field contains the separator, it is enclosed in doublequotes.
3572 */
3573 VOID
3574 #ifdef CK_ANSIC
3575 doxlog(int x, char * fn, CK_OFF_T fs, int fm, int status, char * msg)
3576 #else
3577 doxlog(x, fn, fs, fm, status, msg)
3578     int x; char * fn; CK_OFF_T fs; int fm; int status; char * msg;
3579 #endif /* CK_ANSIC */
3580 /* doxlog */ {
3581     extern int tlogsep;
3582     char sep[2];
3583     char buf[CKMAXPATH+256], * bufp;
3584     char tmpbuf[32];
3585     char * s, * p;
3586     int len, left, ftp = 0, k;
3587
3588     if (!tralog) return;                /* If no transaction log, don't */
3589
3590     if (!fn) fn = "";                   /* Protect against null pointers */
3591     if (!msg) msg = "";
3592     if (x & W_FTP)
3593       ftp++;
3594
3595     sep[0] = (char) tlogsep;
3596     sep[1] = NUL;
3597     if (!sep[0]) sep[0] = ',';
3598
3599     bufp = buf;
3600     left = sizeof(buf);
3601     debug(F101,"XXX doxlog left 1","",left);
3602
3603     p = zzndate();                      /* Date */
3604     ckmakmsg(buf, left, p ? p : "00000000", sep, NULL, NULL);
3605     bufp += 9;
3606     left -= 9;
3607     debug(F111,"XXX doxlog left 2",buf,left);
3608
3609     ztime(&p);
3610     ckstrncpy(bufp,p+11,left);
3611     bufp += 8;
3612     left -= 8;
3613     debug(F111,"XXX doxlog left 3",buf,left);
3614
3615     if (ftp) {
3616         if (!(x & (W_SEND|W_RECV)))
3617           return;
3618         s =  (x & W_SEND) ? "PUT" : "GET";
3619         k = 3;
3620     } else {
3621         s =  (x & W_SEND) ? "SEND" : "RECV";
3622         k = 4;
3623     }
3624     ckmakmsg(bufp,left,sep,s,sep,NULL);
3625     bufp += k + 2;
3626     left -= (k + 2);
3627     debug(F111,"XXX doxlog left 4",buf,left);
3628
3629     s = "";
3630     if (ckstrchr(fn,sep[0]))            /* Filename */
3631       s = "\"";
3632     ckmakmsg(bufp,left,s,fn,s,sep);
3633     sprintf(tmpbuf,"%s",ckfstoa(fs));   /* Size */
3634     ckstrncat(buf,tmpbuf,CKMAXPATH);
3635     ckstrncat(buf,sep,CKMAXPATH);
3636     debug(F110,"doxlog 4",buf,0);
3637
3638 #ifdef NOICP
3639     /* Transfer mode */
3640     ckstrncpy(tmpbuf, (binary ? "binary" : "text"), TMPBUFSIZ);
3641 #else
3642     ckstrncpy(tmpbuf,gfmode(fm,0),TMPBUFSIZ);
3643 #endif /* NOICP */
3644     if (ckstrchr(tmpbuf,sep[0])) {      /* Might contain spaces */
3645         ckstrncat(buf,"\"",CKMAXPATH);
3646         ckstrncat(buf,tmpbuf,CKMAXPATH);
3647         ckstrncat(buf,"\"",CKMAXPATH);
3648     } else
3649       ckstrncat(buf,tmpbuf,CKMAXPATH);
3650     ckstrncat(buf,sep,CKMAXPATH);
3651     debug(F110,"doxlog 5",buf,0);
3652
3653     ckstrncat(buf, status ? "FAILED" : "OK",CKMAXPATH);
3654     len = strlen(buf);
3655     left = CKMAXPATH+256 - len;
3656     if (left < 2) fatal("doxlog buffer overlow");
3657
3658     debug(F111,"XXX doxlog left 5",buf,left);
3659
3660     debug(F110,"doxlog buf 1", buf, len);
3661     s = buf + len;
3662     if (status == 0 && left > 32) {
3663         long cps = 0L;
3664 #ifdef GFTIMER
3665         debug(F101,"DOXLOG fpxfsecs","",(long)(fpxfsecs * 1000));
3666         if (fpxfsecs) cps = (long)((CKFLOAT) fs / fpxfsecs);
3667         sprintf(s,"%s\"%0.3fsec %ldcps\"",sep,fpxfsecs,cps);
3668 #else
3669         if (xfsecs) cps = fs / xfsecs;
3670         sprintf(s,"%s\"%ldsec %ldcps\"",sep,xfsecs,cps);
3671 #endif /* GFTIMER */
3672     } else if ((int)strlen(msg) + 4 < left) {
3673         sprintf(s,"%s\"%s\"",sep,msg);
3674     }
3675     debug(F111,"XXX doxlog left 5",buf,left);
3676
3677     debug(F110,"doxlog 5",buf,0);
3678     x = zsoutl(ZTFILE,buf);
3679     debug(F101,"doxlog zsoutl","",x);
3680     if (x < 0) tralog = 0;
3681 }
3682 #endif /* TLOG */
3683
3684 #ifndef MAC
3685 /*
3686   The rest of this file is for all implementations but the Macintosh.
3687 */
3688
3689 #ifdef CK_CURSES
3690 static int repaint = 0;                 /* Transfer display needs repainting */
3691 #endif /* CK_CURSES */
3692
3693 #ifndef NOXFER
3694 /*  C H K I N T  --  Check for console interrupts  */
3695
3696 /*
3697   Used during file transfer in local mode only:
3698   . If user has not touched the keyboard, returns 0 with no side effects.
3699   . If user typed S or A (etc, see below) prints status message and returns 0.
3700   . If user typed X or F (etc, see below) returns 0 with cxseen set to 1.
3701   . If user typed Z or B (etc, see below) returns 0 with czseen set to 1.
3702   . If user typed E or C (etc, see below) returns -1.
3703 */
3704 int
3705 chkint() {
3706     int ch, cn, ofd; long zz;
3707     if (!xfrint)
3708       return(0);
3709     if ((!local) || (quiet)) return(0); /* Only do this if local & not quiet */
3710 #ifdef datageneral
3711     if (con_reads_mt)                   /* if conint_mt task is active */
3712       if (conint_avl) {                 /* and there's an interrupt pending */
3713           cn = 1;                       /* process it */
3714           ch = conint_ch;
3715           conint_avl = 0;               /* turn off flag so conint_mt can */
3716       } else                            /* proceed */
3717         return(0);
3718     else                                /* if conint_mt not active */
3719       if ((ch = coninc(2)) < 0)         /* try to get char manually */
3720         return(0);                      /* I/O error, or no data */
3721       else                              /* if successful, set cn so we */
3722         cn = 1;                         /* know we got one */
3723     debug(F101,"chkint got keyboard character",ch,cn);
3724 #else /* !datageneral */
3725 #ifdef NTSIG
3726     {
3727         extern int TlsIndex;
3728         struct _threadinfo * threadinfo;
3729         threadinfo = (struct _threadinfo *) TlsGetValue(TlsIndex);
3730         if (threadinfo) {
3731             if (!WaitSem(threadinfo->DieSem,0))
3732               return -1;                /* Cancel Immediately */
3733         }
3734     }
3735 #endif /* NTSIG */
3736     cn = conchk();                      /* Any input waiting? */
3737     debug(F101,"conchk","",cn);
3738     if (cn < 1) return(0);
3739     ch = coninc(5) ;
3740     debug(F101,"coninc","",ch);
3741     if (ch < 0) return(0);
3742 #endif /* datageneral */
3743
3744     ch &= 0177;
3745     switch (ch) {
3746       case 'A': case 'a': case 0001:    /* Status report */
3747       case 'S': case 's':
3748         if (fdispla != XYFD_R && fdispla != XYFD_S && fdispla != XYFD_N)
3749           return(0);                    /* Only for serial, simple or none */
3750         ofd = fdispla;                  /* [MF] Save file display type */
3751         if (fdispla == XYFD_N)
3752           fdispla = XYFD_R;             /* [MF] Pretend serial if no display */
3753         xxscreen(SCR_TN,0,0l,"Status report:");
3754         xxscreen(SCR_TN,0,0l," file type: ");
3755         if (binary) {
3756             switch(binary) {
3757               case XYFT_L: xxscreen(SCR_TZ,0,0l,"labeled"); break;
3758               case XYFT_I: xxscreen(SCR_TZ,0,0l,"image"); break;
3759               case XYFT_U: xxscreen(SCR_TZ,0,0l,"binary undefined"); break;
3760               default:
3761               case XYFT_B: xxscreen(SCR_TZ,0,0l,"binary"); break;
3762             }
3763         } else {
3764 #ifdef NOCSETS
3765             xxscreen(SCR_TZ,0,0l,"text");
3766 #else
3767             xxscreen(SCR_TU,0,0l,"text, ");
3768             if (tcharset == TC_TRANSP || xfrxla == 0) {
3769                 xxscreen(SCR_TZ,0,0l,"transparent");
3770             } else {
3771                 if (what & W_SEND) {
3772                     xxscreen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword);
3773                     xxscreen(SCR_TU,0,0l," => ");
3774                     xxscreen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword);
3775                 } else {
3776                     xxscreen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword);
3777                     xxscreen(SCR_TU,0,0l," => ");
3778                     xxscreen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword);
3779                 }
3780             }
3781 #endif /* NOCSETS */
3782         }
3783         xxscreen(SCR_QE,0,filcnt," file number");
3784         if (fsize) xxscreen(SCR_QE,0,fsize," size");
3785         xxscreen(SCR_QE,0,ffc," characters so far");
3786         if (fsize > 0L) {
3787 #ifdef CK_RESEND
3788             zz = what & W_SEND ? sendstart : what & W_RECV ? rs_len : 0;
3789             zz = ( (ffc + zz) * 100L ) / fsize;
3790 #else
3791             zz = ( ffc * 100L ) / fsize;
3792 #endif /* CK_RESEND */
3793             xxscreen(SCR_QE,0,zz,      " percent done");
3794         }
3795         if (bctu == 4) {                /* Block check */
3796             xxscreen(SCR_TU,0,0L," block check: ");
3797             xxscreen(SCR_TZ,0,0L,"blank-free-2");
3798         } else xxscreen(SCR_QE,0,(long)bctu,  " block check");
3799         xxscreen(SCR_QE,0,(long)rptflg," compression");
3800         xxscreen(SCR_QE,0,(long)ebqflg," 8th-bit prefixing");
3801         xxscreen(SCR_QE,0,(long)lscapu," locking shifts");
3802         if (!network)
3803           xxscreen(SCR_QE,0, speed, " speed");
3804         if (what & W_SEND)
3805
3806           xxscreen(SCR_QE,0,spsiz, " packet length");
3807         else if (what & W_RECV || what & W_REMO)
3808           xxscreen(SCR_QE,0,urpsiz," packet length");
3809         xxscreen(SCR_QE,0,wslots,  " window slots");
3810         fdispla = ofd; /* [MF] Restore file display type */
3811         return(0);
3812
3813       case 'B': case 'b': case 0002:    /* Cancel batch */
3814       case 'Z': case 'z': case 0032:
3815         czseen = 1;
3816         interrupted = 1;
3817         xxscreen(SCR_ST,ST_MSG,0l,
3818                  (((what & W_RECV) && (wslots > 1)) ?
3819                   "Canceling batch, wait... " :
3820                   "Canceling batch... ")
3821                  );
3822         return(0);
3823
3824       case 'F': case 'f': case 0006:    /* Cancel file */
3825       case 'X': case 'x': case 0030:
3826         cxseen = 1;
3827         interrupted = 1;
3828         xxscreen(SCR_ST,ST_MSG,0l,
3829                  (((what & W_RECV) && (wslots > 1)) ?
3830                   "Canceling file, wait... " :
3831                   "Canceling file... ")
3832                  );
3833         return(0);
3834
3835       case 'R': case 'r': case 0022:    /* Resend packet */
3836       case 0015: case 0012:
3837 #ifdef STREAMING
3838         if (streaming)
3839           return(0);
3840 #endif /* STREAMING */
3841         xxscreen(SCR_ST,ST_MSG,0l,"Resending packet... ");
3842         numerrs++;
3843         resend(winlo);
3844         return(0);
3845
3846 #ifdef datageneral
3847       case '\03':                       /* We're not trapping ^C's with */
3848         trap(0);                        /* signals, so we check here    */
3849 #endif /* datageneral */
3850
3851       case 'C': case 'c':               /* Ctrl-C */
3852 #ifndef datageneral
3853       case '\03':
3854 #endif /* datageneral */
3855
3856       case 'E': case 'e':               /* Send error packet */
3857       case 0005:
3858         interrupted = 1;
3859         return(-1);
3860
3861 #ifdef CK_CURSES
3862       case 0014:                        /* Ctrl-L to refresh screen */
3863       case 'L': case 'l':               /* Also accept L (upper, lower) */
3864       case 0027:                        /* Ctrl-W synonym for VMS & Ingres */
3865         repaint = 1;
3866         return(0);
3867 #endif /* CK_CURSES */
3868
3869       case 'T':
3870       case 't':                         /* Turn on debug-log timestamps */
3871 #ifdef DEBUG
3872         {
3873             extern int debtim;
3874             if (ch == 'T') {
3875                 debtim = 1;
3876                 xxscreen(SCR_ST,ST_MSG,0l,
3877                          "Debug timestamps On... ");
3878             } else {
3879                 debtim = 1;
3880                 xxscreen(SCR_ST,ST_MSG,0l,
3881                          "Debug timestamps Off... ");
3882             }
3883         }
3884 #endif /* DEBUG */
3885         return(0);
3886
3887       case 'D':
3888 #ifdef DEBUG
3889         if (!deblog) {
3890             debopn("debug.log",0);
3891             if (deblog) {
3892                 xxscreen(SCR_ST,ST_MSG,0l,"debug.log open... ");
3893             } else {
3894                 xxscreen(SCR_ST,ST_MSG,0l,"debug.log open FAILED... ");
3895             }
3896         } else {
3897             xxscreen(SCR_ST,ST_MSG,0l,"Debug log On... ");
3898         }
3899         if (deblog)
3900           debok = 1;
3901 #endif /* DEBUG */
3902         return(0);
3903
3904       case 'd':                         /* Turn off debugging */
3905 #ifdef DEBUG
3906         if (deblog)
3907           xxscreen(SCR_ST,ST_MSG,0l,"Debug log Off... ");
3908         debok = 0;
3909 #endif /* DEBUG */
3910         return(0);
3911
3912       default:                          /* Anything else, print message */
3913         intmsg(1L);
3914         return(0);
3915     }
3916 }
3917
3918 /*  I N T M S G  --  Issue message about terminal interrupts  */
3919
3920 VOID
3921 #ifdef CK_ANSIC
3922 intmsg(long n)
3923 #else
3924 intmsg(n) long n;
3925 #endif /* CK_ANSIC */
3926 /* intmsg */ {
3927 #ifdef CK_NEED_SIG
3928     char buf[80];
3929 #endif /* CK_NEED_SIG */
3930
3931     if (!displa || quiet)               /* Not if we're being quiet */
3932       return;
3933     if (server && (!srvdis || n > -1L)) /* Special for server */
3934       return;
3935 #ifdef CK_NEED_SIG
3936     buf[0] = NUL;                       /* Keep compilers happy */
3937 #endif /* CK_NEED_SIG */
3938 #ifndef OXOS
3939 #ifdef SVORPOSIX
3940     conchk();                           /* Clear out pending escape-signals */
3941 #endif /* SVORPOSIX */
3942 #endif /* ! OXOS */
3943 #ifdef VMS
3944     conres();                           /* So Ctrl-C will work */
3945 #endif /* VMS */
3946     if ((!server && n == 1L) || (server && n < 0L)) {
3947
3948 #ifdef CK_NEED_SIG
3949         if (xfrint) {
3950             ckmakmsg(buf,
3951                      80,
3952                      "Type escape character (",
3953                      dbchr(escape),
3954                      ") followed by:",
3955                      NULL
3956                      );
3957             xxscreen(SCR_TN,0,0l,buf);
3958         }
3959 #endif /* CK_NEED_SIG */
3960
3961         if (xfrint) {
3962             if (protocol == PROTO_K) {
3963  xxscreen(SCR_TN,0,0l,"X to cancel file,  CR to resend current packet");
3964  xxscreen(SCR_TN,0,0l,"Z to cancel group, A for status report");
3965  xxscreen(SCR_TN,0,0l,"E to send Error packet, Ctrl-C to quit immediately: ");
3966             } else {
3967                 xxscreen(SCR_TN,0,0l,"Ctrl-C to cancel file transfer: ");
3968             }
3969         } else {
3970             xxscreen(SCR_TN,0,0l,"Transfer interruption disabled. ");
3971         }
3972     }
3973     else xxscreen(SCR_TU,0,0l," ");
3974 }
3975
3976 #ifndef NODISPLAY
3977 static int newdpy = 0;                  /* New display flag */
3978 static char fbuf[80];                   /* Filename buffer */
3979 static char abuf[80];                   /* As-name buffer */
3980 static char a2buf[80];                  /* Second As-name buffer */
3981 static CK_OFF_T oldffc = 0L;
3982 static CK_OFF_T dots = 0L;
3983 static int hpos = 0;
3984
3985 static VOID                             /* Initialize Serial or CRT display */
3986 dpyinit() {
3987     int m = 0, n = 0;
3988     char * s = "";
3989
3990     newdpy = 0;                         /*  Don't do this again */
3991     oldffc = (CK_OFF_T)0;               /*  Reset this */
3992     dots = (CK_OFF_T)0;                 /*  and this.. */
3993     oldcps = cps = 0L;
3994
3995     conoll("");                         /* New line */
3996     if (what & W_SEND) s = "Sending: "; /* Action */
3997     else if (what & W_RECV) s = "Receiving: ";
3998     n = (int)strlen(s) + (int)strlen(fbuf);
3999     conol(fbuf);
4000     m = (int)strlen(abuf) + 4;
4001     if (n + m > cmd_cols) {
4002         conoll("");
4003         n = 0;
4004     } else
4005       n += m;
4006     if (*abuf) {
4007         conol(" => ");
4008         conol(abuf);
4009     }
4010     m = (int)strlen(a2buf) + 4;
4011     if (n + m > cmd_cols) {
4012         conoll("");
4013         n = 0;
4014     } else
4015       n += m;
4016     if (*a2buf) {
4017         conol(" => ");
4018         conol(a2buf);
4019     }
4020     *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
4021     conoll("");
4022     if (fsize > (CK_OFF_T)-1) {         /* Size */
4023         sprintf(fbuf,"Size: %s, Type: ",ckfstoa(fsize)); /* SAFE (80) */
4024         conol(fbuf); *fbuf = NUL;
4025     } else conol("Size: unknown, Type: ");
4026     if (binary) {                       /* Type */
4027         switch(binary) {
4028               case XYFT_L: conol("labeled"); break;
4029               case XYFT_I: conol("image"); break;
4030               case XYFT_U: conol("binary undefined"); break;
4031               default:
4032               case XYFT_B: conol("binary"); break;
4033         }
4034     } else {
4035 #ifdef NOCSETS
4036         conol("text");
4037 #else
4038         conol("text, ");
4039         if (tcharset == TC_TRANSP || xfrxla == 0) {
4040             conol("transparent");
4041         } else {
4042             if (what & W_SEND) {
4043                 conol(fcsinfo[fcharset].keyword);
4044                 conol(" => ");
4045                 conol(tcsinfo[tcharset].keyword);
4046             } else {
4047                 conol(tcsinfo[tcharset].keyword);
4048                 conol(" => ");
4049                 conol(fcsinfo[fcharset].keyword);
4050             }
4051         }
4052 #endif /* NOCSETS */
4053     }
4054 #ifdef STREAMING
4055     if (streaming)
4056       conol(", STREAMING");
4057 #endif /* STREAMING */
4058     conoll("");
4059
4060     if (fdispla == XYFD_S) {            /* CRT field headings */
4061 /*
4062   Define CK_CPS to show current transfer rate.
4063   Leave it undefined to show estimated time remaining.
4064   Estimated-time-remaining code from Andy Fyfe, not tested on
4065   pathological cases.
4066 */
4067 #define CK_CPS
4068
4069 #ifdef CK_CPS
4070         conoll("    File   Percent       Packet");
4071         conoll("    Bytes  Done     CPS  Length");
4072 #else
4073         conoll("    File   Percent  Secs Packet");
4074         conoll("    Bytes  Done     Left Length");
4075 #endif /* CK_CPS */
4076         newdpy = 0;
4077     }
4078     hpos = 0;
4079 }
4080
4081 /*
4082   showpkt(c)
4083   c = completion code: 0 means transfer in progress, nonzero means it's done.
4084   Show the file transfer progress counter and perhaps verbose packet type.
4085 */
4086 VOID
4087 #ifdef CK_ANSIC
4088 showpkt(char c)
4089 #else
4090 showpkt(c) char c;
4091 #endif /* CK_ANSIC */
4092 /* showpkt */ {
4093
4094 #ifndef GFTIMER
4095     long et;                            /* Elapsed time, entire batch  */
4096 #endif /* GFTIMER */
4097     CK_OFF_T howfar;                    /* How far into file */
4098     long pd;                            /* Percent done, this file     */
4099     long tp;                            /* Transfer rate, entire batch */
4100     long ps;                            /* Packet size, current packet */
4101     CK_OFF_T mytfc;                     /* Local copy of byte counter  */
4102
4103 #ifdef GFTIMER
4104     CKFLOAT tnow;
4105 #endif /* GFTIMER */
4106
4107     if (newdpy)                         /* Put up filenames, etc, */
4108       dpyinit();                        /* if they're not there already. */
4109
4110     howfar = ffc;                       /* How far */
4111 /*
4112   Calculate CPS rate even if not displaying on screen for use in file
4113   transfer statistics.
4114 */
4115 #ifdef GFTIMER
4116     tnow = gftimer();                   /* Time since we started */
4117     ps = (what & W_RECV) ? rpktl : spktl; /* Packet size */
4118 #ifdef CK_RESEND
4119     if (what & W_SEND)                  /* In case we didn't start at */
4120       howfar += sendstart;              /*  the beginning... */
4121     else if (what & W_RECV)
4122       howfar += rs_len;
4123 #endif /* CK_RESEND */
4124     pd = -1;                            /* Percent done. */
4125     if (c == NUL) {                     /* Still going, figure % done */
4126         if (!fsize) return;             /* Empty file, don't bother */
4127         pd = (fsize > 99) ? (howfar / (fsize / (CK_OFF_T)100)) : 0;
4128         if (pd > 100) pd = 100;         /* Expansion */
4129     }
4130     if (c != NUL)
4131       if (!cxseen && !discard && !czseen)
4132         pd = 100;                       /* File complete, so 100%. */
4133
4134     mytfc = (pd < 100) ? tfc + ffc : tfc;    /* CPS */
4135     tp = (long)((tnow > 0.0) ? (CKFLOAT) mytfc / tnow : 0);
4136     if (c && (tp == 0))
4137       tp = ffc;
4138
4139     cps = tp;                           /* Set global variable */
4140     if (cps > peakcps &&                /* Peak transfer rate */
4141          ((what & W_SEND && spackets > wslots + 4) ||
4142           (!(what & W_SEND) && spackets > 10))) {
4143         peakcps = cps;
4144     }
4145
4146 #else  /* Not GFTIMER */
4147
4148     et = gtimer();                      /* Elapsed time  */
4149     ps = (what & W_RECV) ? rpktl : spktl; /* Packet length */
4150 #ifdef CK_RESEND
4151     if (what & W_SEND)                  /* And if we didn't start at */
4152       howfar += sendstart;              /*  the beginning... */
4153     else if (what & W_RECV)
4154       howfar += rs_len;
4155 #endif /* CK_RESEND */
4156     pd = -1;                            /* Percent done. */
4157     if (c == NUL) {                     /* Still going, figure % done */
4158         if (fsize == 0L) return;        /* Empty file, don't bother */
4159         pd = (fsize > 99) ? (howfar / (fsize / (CK_OFF_T)100)) : 0;
4160         if (pd > 100) pd = 100;         /* Expansion */
4161     }
4162     if (c != NUL)
4163       if (!cxseen && !discard && !czseen)
4164         pd = 100;                       /* File complete, so 100%. */
4165
4166
4167 #ifndef CK_CPS
4168 /*
4169   fsecs = time (from gtimer) that this file started (set in sfile()).
4170   Rate so far is ffc / (et - fsecs),  estimated time for remaining bytes
4171   is (fsize - ffc) / (ffc / (et - fsecs)).
4172 */
4173     tp = (howfar > 0) ? (fsize - howfar) * (et - fsecs) / howfar : 0;
4174 #endif /* CK_CPS */
4175
4176 #ifdef CK_CPS
4177     mytfc = (pd < 100) ? tfc + ffc : tfc;
4178     tp = (et > 0) ? mytfc / et : 0;     /* Transfer rate */
4179     if (c && (tp == 0))                 /* Watch out for subsecond times */
4180         tp = ffc;
4181
4182     cps = tp;                           /* Set global variable */
4183     if (cps > peakcps &&                /* Peak transfer rate */
4184          ((what & W_SEND && spackets > wslots + 4) ||
4185           (!(what & W_SEND) && spackets > 10))) {
4186         peakcps = cps;
4187     }
4188 #endif /* CK_CPS */
4189
4190 #endif /* GFTIMER */
4191
4192     if (fdispla == XYFD_S) {            /* CRT display */
4193         char buffer[128];
4194         /* These sprintfs should be safe until we have 32-digit numbers */
4195
4196         if (pd > -1L)
4197           sprintf(buffer, "%c%9s%5ld%%%8ld%8ld ", CR,ckfstoa(howfar),pd,tp,ps);
4198         else
4199           sprintf(buffer, "%c%9s      %8ld%8ld ", CR,ckfstoa(howfar),tp,ps);
4200         conol(buffer);
4201         hpos = 31;
4202     } else if (fdispla == XYFD_R) {     /* SERIAL */
4203         long i, k;
4204         if (howfar - oldffc < 1024)     /* Update display every 1K */
4205           return;
4206         oldffc = howfar;                /* Time for new display */
4207         k = (howfar / 1024L) - dots;    /* How many K so far */
4208         for (i = 0L; i < k; i++) {
4209             if (hpos++ > (cmd_cols - 3)) { /* Time to wrap? */
4210                 conoll("");
4211                 hpos = 0;
4212             }
4213             conoc('.');                 /* Print a dot for this K */
4214             dots++;                     /* Count it */
4215         }
4216     }
4217 }
4218
4219
4220 /*  C K S C R E E N  --  Screen display function  */
4221
4222 /*
4223   ckscreen(f,c,n,s)
4224     f - argument descriptor
4225     c - a character or small integer
4226     n - a long integer
4227     s - a string.
4228
4229   and global fdispla = SET FILE DISPLAY value:
4230
4231     XYFD_N = NONE
4232     XYFD_R = SERIAL:     Dots, etc, works on any terminal, even hardcopy.
4233     XYFD_S = CRT:        Works on any CRT, writes over current line.
4234     XYFD_C = FULLSCREEN: Requires terminal-dependent screen control.
4235     XYFD_B = BRIEF:      Like SERIAL but only filename & completion status.
4236     XYFD_G = GUI;        Windows GUI, same behavior as FULLSCREEN
4237 */
4238 VOID
4239 #ifdef CK_ANSIC
4240 ckscreen(int f, char c,CK_OFF_T n,char *s)
4241 #else
4242 ckscreen(f,c,n,s) int f; char c; CK_OFF_T n; char *s;
4243 #endif /* CK_ANSIC */
4244 /* screen */ {
4245     char buf[80];
4246     int len;                            /* Length of string */
4247 #ifdef UNIX
4248 #ifndef NOJC
4249     int obg;
4250 _PROTOTYP( VOID conbgt, (int) );
4251 #endif /* NOJC */
4252 #endif /* UNIX */
4253     int ftp = 0;
4254
4255     ftp = (what & W_FTP) ? 1 : 0;       /* FTP or Kermit? */
4256
4257     if (!local && !ftp)                 /* In remote mode - don't do this */
4258       return;
4259
4260     if (!s) s = "";
4261
4262     if (!fxd_inited)                    /* Initialize if necessary */
4263       fxdinit(fdispla);
4264
4265 #ifdef UNIX
4266 #ifndef NOJC
4267     obg = backgrd;                      /* Previous background status */
4268     conbgt(1);                          /* See if running in background */
4269     if (!backgrd && obg) {              /* Just came into foreground? */
4270         concb((char)escape);            /* Put console back in CBREAK mode */
4271         setint();                       /* Restore interrupts */
4272     }
4273 #endif /* NOJC */
4274 #endif /* UNIX */
4275
4276     if ((f != SCR_WM) && (f != SCR_EM)) /* Always update warnings & errors */
4277       if (!displa ||
4278           (backgrd && bgset) ||
4279           fdispla == XYFD_N ||
4280           (server && !srvdis)
4281           )
4282         return;
4283
4284 #ifdef VMS
4285     if (f == SCR_FN)                    /* VMS - shorten the name */
4286       s = zrelname(s,zgtdir());
4287 #endif /* VMS */
4288
4289     if (dest == DEST_S)                 /* SET DESTINATION SCREEN */
4290       return;                           /*  would interfere... */
4291
4292 #ifdef KUI
4293     if (fdispla == XYFD_G) {            /* If gui display selected */
4294         screeng(f,c,n,s);               /* call the gui version */
4295         return;
4296     }
4297 #endif /* KUI */
4298 #ifdef CK_CURSES
4299     if (fdispla == XYFD_C) {            /* If fullscreen display selected */
4300         screenc(f,c,n,s);               /* call the fullscreen version */
4301         return;
4302     }
4303 #endif /* CK_CURSES */
4304
4305     len = (int)strlen(s);               /* Length of string */
4306
4307     switch (f) {                        /* Handle our function code */
4308       case SCR_FN:                      /* Filename */
4309         if (fdispla == XYFD_B) {
4310 #ifdef NEWFTP
4311             if (ftp)
4312               printf(" %s %s", what & W_SEND ? "PUT" : "GET", s);
4313             else
4314 #endif /* NEWFTP */
4315               printf(" %s %s", what & W_SEND ? "SEND" : "RECV", s);
4316 #ifdef UNIX
4317             fflush(stdout);
4318 #endif /* UNIX */
4319             return;
4320         }
4321 #ifdef MAC
4322         conoll(""); conol(s); conoc(SP); hpos = len + 1;
4323 #else
4324         ckstrncpy(fbuf,s,80);
4325         abuf[0] = a2buf[0] = NUL;
4326         newdpy = 1;                     /* New file so refresh display */
4327 #endif /* MAC */
4328         return;
4329
4330       case SCR_AN:                      /* As-name */
4331         if (fdispla == XYFD_B) {
4332 #ifdef COMMENT
4333             printf("(as %s) ",s);
4334 #endif /* COMMENT */
4335             return;
4336         }
4337 #ifdef MAC
4338         if (hpos + len > 75) { conoll(""); hpos = 0; }
4339         conol("=> "); conol(s);
4340         if ((hpos += (len + 3)) > 78) { conoll(""); hpos = 0; }
4341 #else
4342         if (abuf[0]) {
4343             ckstrncpy(a2buf,s,80);
4344         } else {
4345             ckstrncpy(abuf,s,80);
4346         }
4347 #endif /* MAC */
4348         return;
4349
4350       case SCR_FS:                      /* File-size */
4351         if (fdispla == XYFD_B) {
4352             printf(" (%s) (%s byte%s)",
4353 #ifdef NOICP
4354                    (binary ? "binary" : "text")
4355 #else
4356                    gfmode(binary,0)
4357 #endif /* NOICP */
4358                    , ckfstoa(n), n == 1 ? "" : "s");
4359 #ifdef UNIX
4360             fflush(stdout);
4361 #endif /* UNIX */
4362             return;
4363         }
4364 #ifdef MAC
4365         sprintf(buf,", Size: %s",ckfstoa(n));  conoll(buf);  hpos = 0;
4366 #endif /* MAC */
4367         return;
4368
4369       case SCR_XD:                      /* X-packet data */
4370         if (fdispla == XYFD_B)
4371           return;
4372 #ifdef MAC
4373         conoll(""); conoll(s); hpos = 0;
4374 #else
4375         ckstrncpy(fbuf,s,80);
4376         abuf[0] = a2buf[0] = NUL;
4377 #endif /* MAC */
4378         return;
4379
4380       case SCR_ST:                      /* File status */
4381         switch (c) {
4382           case ST_OK:                   /* Transferred OK */
4383             showpkt('Z');               /* Update numbers one last time */
4384             if (fdispla == XYFD_B) {
4385 #ifdef GFTIMER
4386                 if (fpxfsecs)
4387                   printf(": OK (%0.3f sec, %ld cps)",fpxfsecs,
4388                          (long)((CKFLOAT)ffc / fpxfsecs));
4389 #else
4390                 if (xfsecs)
4391                   printf(": OK (%d sec, %ld cps)",xfsecs,ffc/xfsecs);
4392 #endif /* GFTIMER */
4393                 printf("\n");
4394                 return;
4395             }
4396             if ((hpos += 5) > 78) conoll(""); /* Wrap screen line. */
4397             conoll(" [OK]"); hpos = 0;  /* Print OK message. */
4398             if (fdispla == XYFD_S) {    /* We didn't show Z packet when */
4399                 conoc('Z');             /* it came, so show it now. */
4400                 hpos = 1;
4401             }
4402             return;
4403
4404           case ST_DISC:                 /*  Discarded */
4405             if (fdispla == XYFD_B) {
4406                 printf(": DISCARDED\n");
4407                 return;
4408             }
4409             if ((hpos += 12) > 78) conoll("");
4410             conoll(" [discarded]"); hpos = 0;
4411             return;
4412
4413           case ST_INT:                  /*  Interrupted */
4414             if (fdispla == XYFD_B) {
4415                 printf(": INTERRUPTED\n");
4416                 return;
4417             }
4418             if ((hpos += 14) > 78) conoll("");
4419             conoll(" [interrupted]"); hpos = 0;
4420             return;
4421
4422           case ST_SIM:
4423             if (fdispla == XYFD_B) {
4424                 if (n == SKP_XNX)
4425                   printf(": WOULD BE TRANSFERRED (New file)\n");
4426                 else if (n == SKP_XUP)
4427                   printf(": WOULD BE TRANSFERRED (Remote file older)\n");
4428                 else if (n == SKP_SIM)
4429                   printf(": WOULD BE TRANSFERRED\n");
4430                 else if (n > 0 && n < nskreason)
4431                   printf(": SKIPPED (%s)\n",skreason[n]);
4432                 else
4433                   printf(": SKIPPED\n");
4434                 return;
4435             } else if (fdispla == XYFD_S) {
4436                 if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
4437                     conoll("");         /* New line */
4438                     if (what & W_SEND) conol("Would Send: "); /* Action */
4439                     else if (what & W_RECV) conol("Would Receive: ");
4440                     conol(fbuf);
4441                     if (*abuf) conol(" => "); conol(abuf); /* Names */
4442                     if (*a2buf) conol(" => "); conol(a2buf); /* Names */
4443                     *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
4444                 }
4445                 conoll(" [simulated]");
4446                 return;
4447             }
4448             if ((hpos += 10) > 78) conoll("");
4449             conol(" [simulated]"); hpos = 0;
4450             return;
4451
4452           case ST_SKIP:                 /*  Skipped */
4453             if (fdispla == XYFD_B) {
4454                 if (n == SKP_XNX)
4455                   printf(": WOULD BE TRANSFERRED (New file)\n");
4456                 else if (n == SKP_XUP)
4457                   printf(": WOULD BE TRANSFERRED (Remote file older)\n");
4458                 else if (n == SKP_SIM)
4459                   printf(": WOULD BE TRANSFERRED\n");
4460                 else if (n > 0 && n < nskreason)
4461                   printf(": SKIPPED (%s)\n",skreason[n]);
4462                 else
4463                   printf(": SKIPPED\n");
4464                 return;
4465             } else if (fdispla == XYFD_S) {
4466                 if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
4467                     conoll("");         /* New line */
4468                     if (what & W_SEND) conol("Sending: "); /* Action */
4469                     else if (what & W_RECV) conol("Receiving: ");
4470                     conol(fbuf);
4471                     if (*abuf) conol(" => "); conol(abuf); /* Names */
4472                     if (*a2buf) conol(" => "); conol(a2buf); /* Names */
4473                     *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
4474                 }
4475                 conoll(" [skipped]");
4476                 return;
4477             }
4478             if ((hpos += 10) > 78) conoll("");
4479             conol(" "); conol(fbuf);
4480             conoll(" [skipped]"); hpos = 0;
4481             return;
4482
4483           case ST_ERR:                  /* Error */
4484             if (fdispla == XYFD_B) {
4485                 printf(": ERROR: %s\n",s);
4486                 return;
4487             }
4488             conoll("");
4489             conol("Error: "); conoll(s); hpos = 0;
4490             return;
4491
4492           case ST_MSG:                  /* Message */
4493 #ifdef NEWFTP
4494             if (fdispla == XYFD_B) {
4495                 if (ftp && ftp_deb)
4496                   printf(": MESSAGE: %s\n",s);
4497                 return;
4498             }
4499 #endif /* NEWFTP */
4500             conoll("");
4501             conol("Message: ");
4502             conoll(s);
4503             hpos = 0;
4504             return;
4505
4506           case ST_REFU:                 /* Refused */
4507             if (fdispla == XYFD_B) {
4508                 printf(": REFUSED\n");
4509                 return;
4510             } else if (fdispla == XYFD_S) {
4511                 if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
4512                     conoll("");         /* New line */
4513                     if (what & W_SEND) conol("Sending: "); /* Action */
4514                     else if (what & W_RECV) conol("Receiving: ");
4515                     conol(fbuf);
4516                     if (*abuf) conol(" => "); conol(abuf);      /* Names */
4517                     if (*a2buf) conol(" => "); conol(a2buf);    /* Names */
4518                     *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
4519                     conoll("");
4520                 }
4521                 conol("Refused: "); conoll(s);
4522                 return;
4523             }
4524             conoll("");
4525             conol("Refused: "); conoll(s); hpos = 0;
4526             return;
4527
4528           case ST_INC:                  /* Incomplete */
4529             if (fdispla == XYFD_B) {
4530                 printf(": INCOMPLETE\n");
4531                 return;
4532             }
4533             if ((hpos += 12) > 78) conoll("");
4534             conoll(" [incomplete]"); hpos = 0;
4535             return;
4536
4537           default:
4538             conoll("*** screen() called with bad status ***");
4539             hpos = 0;
4540             return;
4541         }
4542
4543 #ifdef MAC
4544       case SCR_PN:                      /* Packet number */
4545         if (fdispla == XYFD_B) {
4546             return;
4547         }
4548         ckmakmsg(buf,80,s,": ",ckltoa(n),NULL);
4549         conol(buf); hpos += (int)strlen(buf); return;
4550 #endif /* MAC */
4551
4552       case SCR_PT:                      /* Packet type or pseudotype */
4553         if (fdispla == XYFD_B)
4554           return;
4555         if (c == 'Y') return;           /* Don't bother with ACKs */
4556         if (c == 'D') {                 /* In data transfer phase, */
4557             showpkt(NUL);               /* show progress. */
4558             return;
4559         }
4560 #ifndef AMIGA
4561         if (hpos++ > 77) {              /* If near right margin, */
4562             conoll("");                 /* Start new line */
4563             hpos = 0;                   /* and reset counter. */
4564         }
4565 #endif /* AMIGA */
4566         if (c == 'Z' && fdispla == XYFD_S)
4567           return;
4568         else
4569           conoc(c);                     /* Display the packet type. */
4570 #ifdef AMIGA
4571         if (c == 'G') conoll("");       /* New line after G packets */
4572 #endif /* AMIGA */
4573         return;
4574
4575       case SCR_TC:                      /* Transaction complete */
4576         if (xfrbel) bleep(BP_NOTE);
4577         if (fdispla == XYFD_B) {        /* Brief display... */
4578             if (filcnt > 1) {
4579                 long fx;
4580                 fx = filcnt - filrej;
4581                 printf(" SUMMARY: %ld file%s", fx, ((fx == 1) ? "" : "s"));
4582                 printf(", %s byte%s", ckfstoa(tfc), ((tfc == 1) ? "" : "s"));
4583 #ifdef GFTIMER
4584                 printf(", %0.3f sec, %ld cps", fptsecs, tfcps);
4585 #else
4586                 printf(", %ld sec, %ld cps", tsecs, tfcps);
4587 #endif /* GFTIMER */
4588                 printf(".\n");
4589             }
4590         } else {
4591             conoll("");
4592         }
4593 #ifdef UNIX
4594         fflush(stdout);
4595 #endif /* UNIX */
4596         return;
4597
4598       case SCR_EM:                      /* Error message */
4599         if (fdispla == XYFD_B) {
4600             printf(" ERROR: %s\n",s);
4601             return;
4602         }
4603         conoll(""); conoc('?'); conoll(s); hpos = 0; return;
4604
4605       case SCR_WM:                      /* Warning message */
4606         if (fdispla == XYFD_B) {
4607             printf(" WARNING: %s\n",s);
4608             return;
4609         }
4610         conoll(""); conoll(s); hpos = 0; return;
4611
4612       case SCR_MS:                      /* Message from other Kermit */
4613         if (fdispla == XYFD_B) {
4614             printf(" MESSAGE: %s\n",s);
4615             return;
4616         }
4617         conoll(""); conoll(s); hpos = 0; return;
4618
4619       case SCR_TU:                      /* Undelimited text */
4620         if (fdispla == XYFD_B)
4621           return;
4622         if ((hpos += len) > 77) { conoll(""); hpos = len; }
4623         conol(s); return;
4624
4625       case SCR_TN:                      /* Text delimited at beginning */
4626         if (fdispla == XYFD_B)
4627           return;
4628         conoll(""); conol(s); hpos = len; return;
4629
4630       case SCR_TZ:                      /* Text delimited at end */
4631         if (fdispla == XYFD_B)
4632           return;
4633         if ((hpos += len) > 77) { conoll(""); hpos = len; }
4634         conoll(s); return;
4635
4636       case SCR_QE:                      /* Quantity equals */
4637         if (fdispla == XYFD_B)
4638           return;
4639         ckmakmsg(buf,80,s,": ",ckltoa(n),NULL);
4640         conoll(buf); hpos = 0; return;
4641
4642       case SCR_CW:                      /* Close fullscreen window */
4643         return;                         /* No window to close */
4644
4645       case SCR_CD:
4646         return;
4647
4648       default:
4649         conoll("*** screen() called with bad object ***");
4650         hpos = 0;
4651         return;
4652     }
4653 }
4654 #endif /* NODISPLAY */
4655
4656 /*  E R M S G  --  Nonfatal error message  */
4657
4658 /* Should be used only for printing the message text from an Error packet. */
4659
4660 VOID
4661 ermsg(msg) char *msg; {                 /* Print error message */
4662     debug(F110,"ermsg",msg,0);
4663     if (local)
4664       xxscreen(SCR_EM,0,0L,msg);
4665     tlog(F110,"Protocol Error:",msg,0L);
4666 }
4667 #endif /* NOXFER */
4668
4669 VOID
4670 setseslog(x) int x; {
4671     seslog = x;
4672 #ifdef KUI
4673     KuiSetProperty(KUI_TERM_CAPTURE,x,0);
4674 #endif /* KUI */
4675 }
4676
4677 VOID
4678 doclean(fc) int fc; {                   /* General cleanup */
4679 #ifdef OS2ORUNIX
4680     extern int ttyfd;
4681 #endif /* OS2ORUNIX */
4682     extern int  keep;
4683     extern int exithangup;
4684 #ifndef NOXFER
4685     extern char filnam[];
4686 #endif /* NOXFER */
4687 #ifndef NOICP
4688     int x;
4689
4690     if (fc > 0)
4691       dostop();                 /* Stop all command files and end macros */
4692 #endif /* NOICP */
4693
4694 #ifndef NOXFER
4695     if (pktlog) {
4696         *pktfil = '\0';
4697         pktlog = 0;
4698         zclose(ZPFILE);
4699     }
4700 #endif /* NOXFER */
4701     if (seslog) {
4702         *sesfil = '\0';
4703         setseslog(0);
4704         zclose(ZSFILE);
4705     }
4706 #ifdef TLOG
4707     if (tralog) {
4708         tlog(F100,"Transaction Log Closed","",0L);
4709         *trafil = '\0';
4710         tralog = 0;
4711         zclose(ZTFILE);
4712     }
4713 #endif /* TLOG */
4714
4715     debug(F100,"doclean calling dologend","",0);
4716     dologend();                         /* End current log record if any */
4717 #ifdef COMMENT
4718     if (dialog) {                       /* If connection log open */
4719         dialog = 0;
4720         *diafil = '\0';                 /* close it. */
4721         zclose(ZDIFIL);
4722     }
4723 #endif /* COMMENT */
4724
4725 #ifndef NOICP
4726 #ifndef NOSPL
4727     zclose(ZRFILE);                     /* READ and WRITE files, if any. */
4728     zclose(ZWFILE);
4729 #ifndef NOXFER
4730     zclose(ZIFILE);                     /* And other files too */
4731     x = chkfn(ZOFILE);                  /* Download in progress? */
4732     debug(F111,"doclean chkfn ZOFILE",filnam,x);
4733     debug(F111,"doclean keep","",keep);
4734     zclose(ZOFILE);                     /* Close output file */
4735     if (x > 0 && !keep) {               /* If it was being downloaded */
4736         if (filnam[0])
4737           x = zdelet(filnam);           /* Delete if INCOMPLETE = DISCARD */
4738         debug(F111,"doclean download filename",filnam,x);
4739     }
4740 #endif /* NOXFER */
4741     zclose(ZSYSFN);
4742     zclose(ZMFILE);
4743
4744     if (fc < 1) {                       /* RESETing, not EXITing */
4745 #ifdef DEBUG
4746         if (deblog) {                   /* Close the debug log. */
4747             *debfil = '\0';
4748             deblog = 0;
4749             zclose(ZDFILE);
4750         }
4751 #endif /* DEBUG */
4752         return;
4753     }
4754 #endif /* NOSPL */
4755 #endif /* NOICP */
4756
4757 #ifndef NOLOCAL
4758     debug(F101,"doclean exithangup","",exithangup);
4759     if (local && exithangup) {          /* Close communication connection */
4760         extern int haslock;
4761         int x;
4762         
4763         x = ttchk();
4764         debug(F101,"doclean ttchk()","",x);
4765 #ifdef OS2ORUNIX
4766         debug(F101,"doclean ttyfd","",ttyfd);
4767 #endif /* OS2ORUNIX */
4768         if (x >= 0
4769 #ifdef OS2
4770             || ttyfd != -1
4771 #else
4772 #ifdef UNIX
4773             || haslock                  /* Make sure we get lockfile! */
4774             || (!network && ttyfd > -1)
4775 #endif /* UNIX */
4776 #endif /* OS2 */
4777             ) {
4778             extern int wasclosed, whyclosed;
4779             debug(F100,"doclean hanging up and closing","",0);
4780             if (msgflg) {
4781 #ifdef UNIX
4782                 fflush(stdout);
4783 #endif /* UNIX */
4784                 printf("Closing %s...",ttname);
4785             }
4786 #ifndef NODIAL
4787             mdmhup();                   /* Hangup the modem??? */
4788 #endif /* NODIAL */
4789             ttclos(0);                  /* Close external line, if any */
4790             if (msgflg) {
4791                 printf("OK\n");
4792 #ifdef UNIX
4793                 fflush(stdout);
4794 #endif /* UNIX */
4795             }
4796             if (wasclosed) {
4797                 whyclosed = WC_CLOS;
4798 #ifndef NOSPL
4799                 if (nmac) {             /* Any macros defined? */
4800                     int k;              /* Yes */
4801                     k = mlook(mactab,"on_close",nmac);  /* Look this up */
4802                     if (k >= 0) {                       /* If found, */
4803                         wasclosed = 0;
4804                         /* printf("ON_CLOSE DOCLEAN\n"); */
4805                         *(mactab[k].kwd) = NUL;         /* See comment below */
4806                         if (dodo(k,ckitoa(whyclosed),0) > -1) /* set it up, */
4807                           parser(1);                    /* and execute it */
4808                     }
4809                 }
4810 #endif /* NOSPL */
4811                 wasclosed = 0;
4812             }
4813         }
4814         ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default tty */
4815         local = dfloc;                  /* And default remote/local status */
4816     }
4817 #ifdef DEBUG
4818     else if (local) debug(F100,"doclean hangup/close skipped","",0);
4819 #endif /* DEBUG */
4820 #endif /* NOLOCAL */
4821
4822 #ifdef NEWFTP
4823     ftpbye();                           /* If FTP connection open, close it */
4824 #endif /* NEWFTP */
4825
4826 #ifdef IKSD
4827     if (inserver)
4828       ttclos(0);                        /* If IKSD, close socket */
4829 #endif /* IKSD */
4830
4831 #ifndef NOSPL
4832 /*
4833   If a macro named "on_exit" is defined, execute it.  Also remove it from the
4834   macro table, in case its definition includes an EXIT or QUIT command, which
4835   would cause much recursion and would prevent the program from ever actually
4836   EXITing.
4837 */
4838     if (nmac) {                         /* Any macros defined? */
4839         int k;                          /* Yes */
4840         char * cmd = "on_exit";         /* MSVC 2.x compiler error */
4841         k = mlook(mactab,cmd,nmac);     /* Look up "on_exit" */
4842         if (k >= 0) {                   /* If found, */
4843 #ifdef COMMENT
4844             /* This makes a mess if ON_EXIT itself executes macros */
4845             *(mactab[k].kwd) = NUL;     /* poke its name from the table, */
4846 #else
4847             /* Replace the keyword with something that doesn't wreck the */
4848             /* order of the keyword table */
4849             ckstrncpy(mactab[k].kwd,"on_exxx",8);
4850 #endif /* COMMENT */
4851             if (dodo(k,"",0) > -1)      /* set it up, */
4852               parser(1);                /* and execute it */
4853         }
4854     }
4855 #endif /* NOSPL */
4856 /*
4857   Put console terminal back to normal.  This is done here because the
4858   ON_EXIT macro calls the parser, which meddles with console terminal modes.
4859 */
4860     conres();                           /* Restore console terminal. */
4861
4862 #ifdef COMMENT
4863 /* Should be no need for this, and maybe it's screwing things up? */
4864     connoi();                           /* Turn off console interrupt traps */
4865 #endif /* COMMENT */
4866
4867     /* Delete the Startup File if we are supposed to. */
4868 #ifndef NOICP
4869     {
4870         extern int DeleteStartupFile;
4871         debug(F111,"doclean DeleteStartupFile",cmdfil,DeleteStartupFile);
4872         if (DeleteStartupFile) {
4873             int rc = zdelet(cmdfil);
4874             debug(F111,"doclean zdelet",cmdfil,rc);
4875         }
4876     }
4877 #endif /* NOICP */
4878     syscleanup();                       /* System-dependent cleanup, last */
4879 }
4880
4881 /*  D O E X I T  --  Exit from the program.  */
4882
4883 /*
4884   First arg is general, system-independent symbol: GOOD_EXIT or BAD_EXIT.
4885   If second arg is -1, take 1st arg literally.
4886   If second arg is not -1, work it into the exit code.
4887 */
4888 VOID
4889 doexit(exitstat,code) int exitstat, code; {
4890     extern int x_logged, quitting;
4891 #ifdef OS2
4892     extern int display_demo;
4893     extern int SysInited;
4894 #endif /* OS2 */
4895 #ifdef CK_KERBEROS
4896 #ifdef KRB4
4897     extern int krb4_autodel;
4898 #endif /* KRB4 */
4899 #ifdef KRB5
4900     extern int krb5_autodel;
4901 #endif /* KRB5 */
4902 #endif /* CK_KERBEROS */
4903
4904 #ifdef VMS
4905     char envstr[64];
4906     static $DESCRIPTOR(symnam,"CKERMIT_STATUS");
4907     static struct dsc$descriptor_s symval;
4908 #endif /* VMS */
4909     int i;
4910
4911 #ifdef DEBUG
4912 #ifdef USE_LUCACHE
4913     extern long lucalls, luhits, xxhits, luloop;
4914     extern int lusize;
4915 #endif /* USE_LUCACHE */
4916 #ifndef NOSPL
4917     extern int cmdstats[];
4918 #endif /* NOSPL */
4919
4920     quitting++;
4921
4922 #ifdef OS2
4923     if ( !SysInited ) {
4924         static int initing = 0;
4925         if ( initing )
4926           exit(253);
4927         initing = 1;
4928         sysinit();
4929     }
4930 #endif /* OS2 */
4931
4932     if (deblog) {
4933 #ifdef USE_LUCACHE
4934         debug(F101,"lookup cache size","",lusize);
4935         debug(F101,"lookup calls ....","",lucalls);
4936         debug(F101,"lookup cache hits","",luhits);
4937         debug(F101,"lookup start hits","",xxhits);
4938         debug(F101,"lookup loop iterations","",luloop);
4939 #endif /* USE_LUCACHE */
4940 #ifndef NOSPL
4941         for (i = 0; i < 256; i++) {
4942             if (cmdstats[i])
4943               debug(F111,"CMSTATS",ckitoa(i),cmdstats[i]);
4944         }
4945 #endif /* NOSPL */
4946         debug(F101,"doexit exitstat","",exitstat);
4947         debug(F101,"doexit code","",code);
4948         debug(F101,"doexit xitsta","",xitsta);
4949     }
4950 #endif /* DEBUG */
4951
4952 #ifdef CK_KERBEROS
4953     /* If we are automatically destroying Kerberos credentials on Exit */
4954     /* do it now. */
4955 #ifdef KRB4
4956     if (krb4_autodel == KRB_DEL_EX) {
4957         extern struct krb_op_data krb_op;
4958         krb_op.version = 4;
4959         krb_op.cache = NULL;
4960         ck_krb4_destroy(&krb_op);
4961     }
4962 #endif /* KRB4 */
4963 #ifdef KRB5
4964     if (krb5_autodel == KRB_DEL_EX) {
4965         extern struct krb_op_data krb_op;
4966         extern char * krb5_d_cc;
4967         krb_op.version = 5;
4968         krb_op.cache = krb5_d_cc;
4969         ck_krb5_destroy(&krb_op);
4970     }
4971 #endif /* KRB5 */
4972 #endif /* CK_KERBEROS */
4973
4974 #ifndef NOLOCAL
4975 #ifdef OS2
4976     if (SysInited)
4977     {
4978 #ifdef DCMDBUF
4979         extern struct cmdptr *cmdstk;
4980 #else
4981         extern struct cmdptr cmdstk[];
4982 #endif /* DCMDBUF */
4983         extern int tt_status[];
4984         extern int vmode;
4985
4986         /* If there is a demo screen to be displayed, display it */
4987         if (display_demo) {
4988             demoscrn(VCMD);
4989             display_demo = 0;
4990         }
4991 #ifndef KUI
4992         /* This is going to be hideous.  If we have a status line */
4993         /* in the command window turn it off before we exit.      */
4994
4995         if ( tt_status[VCMD] && vmode == VCMD ) {
4996             domac("_clear_statusline","set command statusline off",
4997                    cmdstk[cmdlvl].ccflgs);
4998             delmac("_clear_statusline",1);
4999             RequestScreenMutex(-1);
5000             VscrnIsDirty(vmode);
5001             ReleaseScreenMutex();
5002             while ( IsVscrnDirty(vmode) )
5003                 msleep(200);
5004             RequestScreenMutex(-1);
5005             ReleaseScreenMutex();
5006         }
5007 #endif /* KUI */
5008         DialerSend(OPT_KERMIT_EXIT,exitstat);
5009 #ifndef KUI
5010         debug(F100,"doexit about to msleep","",0);
5011
5012         if ( isWin95() )
5013             msleep(250);
5014 #endif /* KUI */
5015     }
5016 #endif /* OS2 */
5017 #endif /* NOLOCAL */
5018
5019 #ifdef IKSD
5020 #ifdef CK_LOGIN
5021     if (inserver && x_logged) {
5022 #ifndef NOSPL
5023 /*
5024   If a macro named "on_logout" is defined, execute it.  Also remove it from the
5025   macro table, in case its definition includes an EXIT or QUIT command, which
5026   would cause much recursion and would prevent the program from ever actually
5027   EXITing.
5028 */
5029         if (nmac) {                     /* Any macros defined? */
5030             int k;                      /* Yes */
5031             char * cmd = "on_logout";   /* MSVC 2.x compiler error */
5032             k = mlook(mactab,cmd,nmac); /* Look up "on_logout" */
5033             if (k >= 0) {               /* If found, */
5034                 *(mactab[k].kwd) = NUL; /* poke its name from the table, */
5035                 if (dodo(k,"",0) > -1)  /* set it up, */
5036                   parser(1);            /* and execute it */
5037             }
5038         }
5039 #endif /* NOSPL */
5040         zvlogout();
5041     }
5042 #endif /* CK_LOGIN */
5043 #endif /* IKSD */
5044
5045     debug(F100,"doexit about to doclean","",0);
5046     doclean(1);                         /* Clean up most things */
5047
5048 #ifdef VMS
5049     if (code == -1)
5050       code = 0;                         /* Since we set two different items */
5051     sprintf(envstr,"%d", exitstat | code); /* SAFE */
5052     symval.dsc$w_length = (int)strlen(envstr);
5053     symval.dsc$a_pointer = envstr;
5054     symval.dsc$b_class = DSC$K_CLASS_S;
5055     symval.dsc$b_dtype = DSC$K_DTYPE_T;
5056     i = 2;                              /* Store in global table */
5057 #ifdef COMMENT                          /* Martin Zinser */
5058     LIB$SET_SYMBOL(&symnam, &symval, &i);
5059 #else
5060     lib$set_symbol(&symnam, &symval, &i);
5061 #endif /* COMMENT */
5062     if (exitstat == BAD_EXIT)
5063       exitstat = SS$_ABORT | STS$M_INHIB_MSG;
5064     if (exitstat == GOOD_EXIT)
5065       exitstat = SS$_NORMAL | STS$M_INHIB_MSG;
5066 #else /* Not VMS */
5067     if (code != -1)                     /* Take 1st arg literally */
5068       exitstat |= code;
5069 #endif /* VMS */
5070
5071 #ifdef IKSD
5072 #ifdef IKSDB
5073     debug(F101,"doexit ikdbopen","",ikdbopen);
5074     if (ikdbopen && dbfp) {             /* If IKSD database open */
5075         int x;
5076         x = freeslot(mydbslot);         /* Free our slot... */
5077         debug(F101,"doexit freeslot","",x);
5078         fclose(dbfp);                   /* and close it. */
5079     }
5080 #endif /* IKSDB */
5081 #endif /* IKSD */
5082
5083 /* We have put this off till the very last moment... */
5084
5085 #ifdef DEBUG
5086     if (deblog) {                       /* Close the debug log. */
5087         debug(F101,"C-Kermit EXIT status","",exitstat);
5088         *debfil = '\0';
5089         deblog = 0;
5090         zclose(ZDFILE);
5091     }
5092 #endif /* DEBUG */
5093
5094 #ifdef OS2
5095     _exit(exitstat);            /* Exit from C-Kermit (no matter what) */
5096 #else /* OS2 */
5097     exit(exitstat);                     /* Exit from C-Kermit */
5098 #endif /* OS2 */
5099 }
5100
5101 VOID
5102 bgchk() {                               /* Check background status */
5103     if (bgset < 0) {                    /* They didn't type SET BACKGROUND */
5104 #ifdef VMS                              /* Set prompt flag based on */
5105         pflag = !batch;                 /* what we detected at startup. */
5106 #else
5107         pflag = !backgrd;
5108 #endif /* VMS */
5109     } else {                            /* Otherwise SET BACKGROUND value */
5110         pflag = (bgset == 0 ? 1 : 0);
5111     }
5112
5113 #ifndef NOICP
5114     /* Message flag on only if at top level, pflag is on, and QUIET is OFF */
5115     if (!xcmdsrc)
5116       msgflg = (pflag == 0) ? 0 : !quiet;
5117     else msgflg = 0;
5118 #else
5119     msgflg = 0;
5120 #endif /* NOICP */
5121 }
5122
5123 /* Set console interrupts */
5124
5125 VOID
5126 setint() {                              /* According to SET COMMAND INTERRUP */
5127     int x = 0;
5128     if (cmdint)  x |= 1;
5129     if (xsuspend) x |= 2;
5130     debug(F101,"setint","",x);
5131
5132     switch (x) {                        /* Set the desired combination */
5133       case 0: connoi(); break;          /* No interrupts */
5134       case 1: conint(trap,SIG_IGN); break;
5135       case 2: conint(SIG_IGN,stptrap); break;
5136       case 3: conint(trap,stptrap); break;
5137     }
5138     bgchk();                            /* Check background status */
5139 }
5140
5141 #ifdef DEBUG
5142 /*  D E B U G  --  Enter a record in the debugging log  */
5143
5144 /*
5145  Call with a format, two strings, and a number:
5146    f  - Format, a bit string in range 0-7.
5147         If bit x is on, then argument number x is printed.
5148    s1 - String, argument number 1.  If selected, printed as is.
5149    s2 - String, argument number 2.  If selected, printed in brackets.
5150    n  - Long int, argument 3.  If selected, printed preceded by equals sign.
5151
5152    f=0 is special: print s1,s2, and interpret n as a char.
5153
5154    f=F011 (3) is also special; in this case s2 is interpeted as a counted
5155    string that might contain NULs.  n is the length.  If n is negative, this
5156    means the string has been truncated and ".." should be printed after the
5157    first n bytes.  NUL and LF bytes are printed as "<NUL>" and "<LF>".
5158
5159    Globals:
5160      deblog: nonzero if debug log open.
5161      debok:  nonzero if ok to write entries.
5162 */
5163 /*
5164   WARNING: Don't change DEBUFL without changing sprintf() formats below,
5165   accordingly.
5166 */
5167 #define DBUFL 4000
5168 /*
5169   WARNING: This routine is not thread-safe, especially when Kermit is
5170   executing on multiple CPUs -- as different threads write to the same
5171   static buffer, the debug statements are all interleaved.  To be fixed
5172   later...
5173 */
5174 static char *dbptr = (char *)0;
5175
5176 int
5177 #ifdef CK_ANSIC
5178 dodebug(int f, char *s1, char *s2, CK_OFF_T n)
5179 #else
5180 dodebug(f,s1,s2,n) int f; char *s1, *s2; CK_OFF_T n;
5181 #endif /* CK_ANSIC */
5182 /* dodebug */ {
5183     char *sp;
5184     int len1, len2;
5185     extern int debtim;
5186 #ifdef OS2
5187     extern int SysInited;
5188 #endif /* OS2 */
5189
5190     if (!deblog || !debok)
5191       return(0);
5192
5193 #ifdef COMMENT
5194     /* expensive... */
5195     if (!chkfn(ZDFILE))                 /* Debug log not open, don't. */
5196       return(0);
5197 #endif /* COMMENT */
5198     if (!dbptr) {                       /* Allocate memory buffer */
5199         dbptr = malloc(DBUFL+4);        /* This only happens once */
5200         if (!dbptr) {
5201             zclose(ZDFILE);
5202             return(0);
5203         }
5204     }
5205 /*
5206   This prevents infinite recursion in case we accidentally put a debug()
5207   call in this routine, or call another routine that contains debug() calls.
5208   From this point on, all returns from this return must be via goto xdebug,
5209   which sets deblog back to 1.
5210 */
5211 #ifdef OS2
5212     if (SysInited) {
5213         if (RequestDebugMutex(30000))
5214             goto xdebug;
5215     }
5216 #else /* OS2 */
5217     deblog = 0;                         /* Prevent infinite recursion */
5218 #endif /* OS2 */
5219
5220     if (debtim) {                       /* Timestamp */
5221         char *tb, tsbuf[48];
5222         ztime(&tb);
5223         ckstrncpy(tsbuf,tb,32);
5224         if (ztmsec > -1L) {
5225             sprintf(tsbuf+19,".%03ld ",ztmsec); /* SAFE */
5226         } else {
5227             tsbuf[19] = ':';
5228             tsbuf[20] = SP;
5229             tsbuf[21] = NUL;
5230         }
5231         zsout(ZDFILE,tsbuf+11);
5232     }
5233     if (!s1) s1="(NULL)";
5234     if (!s2) s2="(NULL)";
5235
5236     len1 = strlen(s1);
5237     len2 = strlen(s2);
5238
5239 #ifdef COMMENT
5240 /*
5241   This should work, but it doesn't.
5242   So instead we'll cope with overflow via sprintf formats.
5243   N.B.: UNFORTUNATELY, this means we have to put constants in the
5244   sprintf formats.
5245 */
5246     if (f != F011 && (!f || (f & 6))) { /* String argument(s) included? */
5247         x = (int) strlen(s1) + (int) strlen(s2) + 18;
5248         if (x > dbufl) {                /* Longer than buffer? */
5249             if (dbptr)                  /* Yes, free previous buffer */
5250               free(dbptr);
5251             dbptr = (char *) malloc(x + 2); /* Allocate a new one */
5252             if (!dbptr) {
5253                 zsoutl(ZDFILE,"DEBUG: Memory allocation failure");
5254                 deblog = 0;
5255                 zclose(ZDFILE);
5256                 goto xdebug;
5257             } else {
5258                 dbufl = x;
5259                 sprintf(dbptr,"DEBUG: Buffer expanded to %d\n", x + 18);
5260                 zsoutl(ZDFILE,dbptr);
5261             }
5262         }
5263     }
5264 #endif /* COMMENT */
5265
5266 #ifdef COMMENT
5267 /* The aforementioned sprintf() formats were like this: */
5268         if (n > 31 && n < 127)
5269           sprintf(sp,"%.100s%.2000s:%c\n",s1,s2,(CHAR) n);
5270         else if (n < 32 || n == 127)
5271           sprintf(sp,"%.100s%.2000s:^%c\n",s1,s2,(CHAR) ((n+64) & 0x7F));
5272         else if (n > 127 && n < 160)
5273           sprintf(sp,"%.100s%.2000s:~^%c\n",s1,s2,(CHAR)((n-64) & 0x7F));
5274         else if (n > 159 && n < 256)
5275           sprintf(sp,"%.100s%.2000s:~%c\n",s1,s2,(CHAR) (n & 0x7F));
5276         else sprintf(sp,"%.100s%.2000s:%ld\n",s1,s2,n);
5277 /*
5278   But, naturally, it turns out these are not portable either, so now
5279   we do the stupidest possible thing.
5280 */
5281 #endif /* COMMENT */
5282
5283 #ifdef BIGBUFOK
5284 /* Need to accept longer strings when debugging authenticated connections */
5285     if (f == F010) {
5286         if (len2 + 2 >= DBUFL) s2 = "(string too long)";
5287     } else if (f != F011 && f != F100) {
5288         if (len1 > 100) s1 = "(string too long)";
5289         if (len2 + 101 >= DBUFL) s2 = "(string too long)";
5290     }
5291 #else
5292     if (f != F011) {
5293         if (len1 > 100) s1 = "(string too long)";
5294         if (len2 + 101 >= DBUFL) s2 = "(string too long)";
5295     }
5296 #endif /* BIGBUFOK */
5297
5298     sp = dbptr;
5299
5300     switch (f) {                /* Write log record according to format. */
5301       case F000:                /* 0 = print both strings, and n as a char. */
5302         if (len2 > 0) {
5303             if ((n > 31 && n < 127) || (n > 159 && n < 256))
5304               sprintf(sp,"%s[%s]=%c\n",s1,s2,(CHAR) n);
5305             else if (n < 32 || n == 127)
5306               sprintf(sp,"%s[%s]=^%c\n",s1,s2,(CHAR) ((n+64) & 0x7F));
5307             else if (n > 127 && n < 160)
5308               sprintf(sp,"%s[%s]=~^%c\n",s1,s2,(CHAR)((n-64) & 0x7F));
5309             else sprintf(sp,"%s[%s]=0x%lX\n",s1,s2,(long)n);
5310         } else {
5311             if ((n > 31 && n < 127) || (n > 159 && n < 256))
5312               sprintf(sp,"%s=%c\n",s1,(CHAR) n);
5313             else if (n < 32 || n == 127)
5314               sprintf(sp,"%s=^%c\n",s1,(CHAR) ((n+64) & 0x7F));
5315             else if (n > 127 && n < 160)
5316               sprintf(sp,"%s=~^%c\n",s1,(CHAR)((n-64) & 0x7F));
5317             else sprintf(sp,"%s=0x%lX\n",s1,(long)n);
5318         }
5319         if (zsout(ZDFILE,dbptr) < 0) {
5320             deblog = 0;
5321             zclose(ZDFILE);
5322         }
5323 #ifdef CKSYSLOG
5324         if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5325             cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5326         }
5327 #endif /* CKSYSLOG */
5328         break;
5329
5330       case F001:                        /* 1, "=n" */
5331 #ifdef COMMENT
5332         /* This was never used */
5333         sprintf(sp,"=%s\n",ckfstoa(n));
5334 #else
5335         /* Like F111, but shows number n in hex */
5336         ckmakxmsg(sp,DBUFL,
5337                   s1,
5338                   (*s1 ? ":" : ""),
5339                   s2,
5340                   (*s2 ? ":" : ""),
5341                   ckltox(n),
5342                   "\n",
5343                   NULL,NULL,NULL,NULL,NULL,NULL
5344                   );
5345 #endif /* COMMENT */
5346         if (zsout(ZDFILE,dbptr) < 0) {
5347             deblog = 0;
5348             zclose(ZDFILE);
5349         }
5350 #ifdef CKSYSLOG
5351         if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5352             cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5353         }
5354 #endif /* CKSYSLOG */
5355         break;
5356
5357 /*
5358   This one was never used so (October 2000) we now use it like F011,
5359   except in this case we treat s2 as NUL terminated.
5360 */
5361       case F010:
5362         n = -debxlen;
5363 /*
5364   This one treats n as the length of the string s2, which may contain NULs.
5365   It's good for logging NUL-bearing data in the debug log.
5366 */
5367       case F011: {
5368           int i, j, contd = 0;
5369           char * p = s2, *pbuf = NULL;  /* p = source pointer */
5370           int m;                        /* pbuf = destination pointer */
5371
5372           if (f == F011) {
5373               if (n < 0) {              /* n = size of source */
5374                   n = 0 - n;            /* Negative means to add "..." */
5375                   contd = 1;
5376               }
5377           } else {
5378               int x, flag = 0;
5379               x = strlen(s2);
5380               if (n < 0) {
5381                   flag = 1;
5382                   n = 0 - n;
5383               }
5384               if (x < n)
5385                 n = x;
5386           }
5387           if (n == 0)                   /* 0 means do nothing */
5388             goto xdebug;
5389           m = DBUFL - 8;                /* Get size for interpreted part */
5390           if (n > m)                    /* Ensure requested size not too big */
5391             n = m;
5392           pbuf = dbptr;                 /* Construction pointer */
5393           i = 0;
5394           pbuf[i++] = '[';              /* Interpret the string into it */
5395           for (j = 0; j < n && i < m-4; p++,j++) { /* char by char... */
5396               if (*p == LF) {
5397                   if (i >= m-4)
5398                     break;
5399                   pbuf[i++] = '<';
5400                   pbuf[i++] = 'L';
5401                   pbuf[i++] = 'F';
5402                   pbuf[i++] = '>';
5403                   continue;
5404               } else if (*p == CR) {
5405                   if (i >= m-4)
5406                     break;
5407                   pbuf[i++] = '<';
5408                   pbuf[i++] = 'C';
5409                   pbuf[i++] = 'R';
5410                   pbuf[i++] = '>';
5411                   continue;
5412               } else if (*p == HT) {
5413                   if (i >= m-5)
5414                     break;
5415                   pbuf[i++] = '<';
5416                   pbuf[i++] = 'T';
5417                   pbuf[i++] = 'A';
5418                   pbuf[i++] = 'B';
5419                   pbuf[i++] = '>';
5420                   continue;
5421               } else if (*p) {
5422                   pbuf[i++] = *p;
5423                   continue;
5424               } else {
5425                   if (i >= m-5)
5426                     break;
5427                   pbuf[i++] = '<';
5428                   pbuf[i++] = 'N';
5429                   pbuf[i++] = 'U';
5430                   pbuf[i++] = 'L';
5431                   pbuf[i++] = '>';
5432                   continue;
5433               }
5434           }
5435           if (i < m-2 && (*p || contd)) {
5436               pbuf[i++] = '.';
5437               pbuf[i++] = '.';
5438           }
5439           pbuf[i++] = ']';
5440           pbuf[i] = NUL;
5441           if (zsout(ZDFILE,s1) < 0) {
5442               deblog = 0;
5443               zclose(ZDFILE);
5444           }
5445           if (zsoutl(ZDFILE,pbuf) < 0) {
5446               deblog = 0;
5447               zclose(ZDFILE);
5448           }
5449 #ifdef CKSYSLOG
5450           if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5451               cksyslog(SYSLG_DB,1,"debug",s1,pbuf);
5452           }
5453 #endif /* CKSYSLOG */
5454         }
5455         break;
5456
5457       case F100:                        /* 4, "s1" */
5458         if (zsoutl(ZDFILE,s1) < 0) {
5459             deblog = 0;
5460             zclose(ZDFILE);
5461         }
5462 #ifdef CKSYSLOG
5463         if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5464             cksyslog(SYSLG_DB,1,"debug",s1,NULL);
5465         }
5466 #endif /* CKSYSLOG */
5467         break;
5468       case F101:                        /* 5, "s1=n" */
5469         sprintf(sp,"%s=%s\n",s1,ckfstoa(n));
5470         if (zsout(ZDFILE,dbptr) < 0) {
5471             deblog = 0;
5472             zclose(ZDFILE);
5473         }
5474 #ifdef CKSYSLOG
5475         if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5476             cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5477         }
5478 #endif /* CKSYSLOG */
5479         break;
5480       case F110:                        /* 6, "s1[s2]" */
5481         sprintf(sp,"%s[%s]\n",s1,s2);
5482         if (zsout(ZDFILE,dbptr) < 0) {
5483             deblog = 0;
5484             zclose(ZDFILE);
5485         }
5486 #ifdef CKSYSLOG
5487         if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5488             cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5489         }
5490 #endif /* CKSYSLOG */
5491         break;
5492       case F111:                        /* 7, "s1[s2]=n" */
5493         sprintf(sp,"%s[%s]=%s\n",s1,s2,ckfstoa(n));
5494         if (zsout(ZDFILE,dbptr) < 0) {
5495             deblog = 0;
5496             zclose(ZDFILE);
5497         }
5498 #ifdef CKSYSLOG
5499         if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5500             cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5501         }
5502 #endif /* CKSYSLOG */
5503         break;
5504       default:
5505         sprintf(sp,"\n?Invalid format for debug() - %d\n",f);
5506         if (zsout(ZDFILE,dbptr) < 0) {
5507             deblog = 0;
5508             zclose(ZDFILE);
5509         }
5510 #ifdef CKSYSLOG
5511         if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5512             cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5513         }
5514 #endif /* CKSYSLOG */
5515         break;
5516     }
5517   xdebug:                               /* Common exit point */
5518 #ifdef OS2
5519     if (SysInited)
5520         ReleaseDebugMutex();
5521 #else /* OS2 */
5522     deblog = 1;                         /* Restore this */
5523 #endif /* OS2 */
5524     return(0);
5525 }
5526
5527 int
5528 #ifdef CK_ANSIC
5529 dohexdump(CHAR *msg, CHAR *st, int cnt)
5530 #else
5531 dohexdump(msg,st,cnt) CHAR *msg; CHAR *st; int cnt;
5532 #endif /* CK_ANSIC */
5533 /* dohexdump */ {
5534     int i = 0, j = 0, k = 0;
5535     char tmp[8];
5536 #ifdef OS2
5537     extern int SysInited;
5538 #endif /* OS2 */
5539
5540     if (!deblog) return(0);             /* If no debug log, don't. */
5541     if (!dbptr) {                       /* Allocate memory buffer */
5542         dbptr = malloc(DBUFL+1);        /* This only happens once */
5543         if (!dbptr) {
5544             deblog = 0;
5545             zclose(ZDFILE);
5546             return(0);
5547         }
5548     }
5549
5550 #ifdef OS2
5551     if (SysInited) {
5552         if (RequestDebugMutex(30000))
5553             goto xdebug;
5554     }
5555 #else /* OS2 */
5556     deblog = 0;                         /* Prevent infinite recursion */
5557 #endif /* OS2 */
5558
5559     if (msg != NULL) {
5560         ckmakxmsg(dbptr,
5561                   DBUFL,
5562                   "HEXDUMP: ",
5563                   (char *)msg,
5564                   " (",
5565                   ckitoa(cnt),
5566                   " bytes)\n",
5567                   NULL,NULL,NULL,NULL,NULL,NULL,NULL
5568                  );
5569         if (zsout(ZDFILE,dbptr) < 0) {
5570             deblog = 0;
5571             zclose(ZDFILE);
5572             goto xdebug;
5573         }
5574     } else {
5575         ckmakmsg(dbptr,
5576                  DBUFL,
5577                  "HEXDUMP: (",
5578                  ckitoa(cnt),
5579                  " bytes)\n",
5580                  NULL
5581                  );
5582         zsout(ZDFILE,dbptr);
5583         if (zsout(ZDFILE,dbptr) < 0) {
5584             deblog = 0;
5585             zclose(ZDFILE);
5586             goto xdebug;
5587         }
5588     }
5589     for (i = 0; i < cnt; i++) {
5590         dbptr[0] = '\0';
5591         for (j = 0 ; (j < 16); j++) {
5592             if ((i + j) < cnt)
5593               sprintf(tmp,
5594                       "%s%02x ",
5595                       (j == 8 ? "| " : ""),
5596                       (CHAR) st[i + j]
5597                       );
5598             else
5599               sprintf(tmp,
5600                       "%s   ",
5601                       (j == 8 ? "| " : "")
5602                       );
5603             ckstrncat(dbptr,tmp,DBUFL+1);
5604         }
5605         ckstrncat(dbptr," ",DBUFL+1);
5606         for (k = 0; (k < 16) && ((i + k) < cnt); k++) {
5607             sprintf(tmp,
5608                     "%s%c",
5609                     (k == 8 ? " " : ""),
5610                     isprint(st[i + k]) ? st[i + k] : '.'
5611                     );
5612             ckstrncat(dbptr,tmp,DBUFL+1);
5613         }
5614         ckstrncat(dbptr,"\n",DBUFL+1);
5615         i += j - 1;
5616         if (zsout(ZDFILE,dbptr) < 0) {
5617             deblog = 0;
5618             zclose(ZDFILE);
5619             goto xdebug;
5620         }
5621     } /* end for */
5622
5623
5624   xdebug:
5625 #ifdef OS2
5626     if (SysInited)
5627       ReleaseDebugMutex();
5628 #else /* OS2 */
5629     deblog = 1;
5630 #endif /* OS2 */
5631     return(0);
5632 }
5633 #endif /* DEBUG */
5634
5635 /*  Session Log... */
5636
5637 int tsstate = 0;
5638
5639 VOID
5640 #ifdef OS2
5641 logchar(unsigned short c)
5642 #else /* OS2 */
5643 #ifdef CK_ANSIC
5644 logchar(char c)
5645 #else
5646 logchar(c) char c;
5647 #endif /* CK_ANSIC */
5648 #endif /* OS2 */
5649 /* logchar */ {                         /* Log character c to session log */
5650     extern int slognul;
5651     int oktolog = 0;
5652 #ifndef NOLOCAL
5653     if (!seslog)
5654       return;
5655
5656     if ((sessft != XYFT_T) || (
5657 #ifdef UNIX
5658          c != '\r' &&
5659 #else
5660 #ifdef datageneral
5661          c != '\r' &&
5662 #else
5663 #ifdef STRATUS
5664          c != '\r' &&
5665 #else
5666 #ifdef AMIGA
5667          c != '\r' &&
5668 #else
5669 #ifdef GEMDOS
5670          c != '\r' &&
5671 #endif /* GEMDOS */
5672 #endif /* AMIGA */
5673 #endif /* STRATUS */
5674 #endif /* datageneral */
5675 #endif /* UNIX */
5676 #ifdef OSK
5677          c != '\n' &&
5678 #else
5679 #ifdef MAC
5680          c != '\n' &&
5681 #endif /* MAC */
5682 #endif /* OSK */
5683          c != XON &&
5684          c != XOFF))
5685       oktolog = 1;
5686     if (c == '\0' && !sessft)           /* NUL in text mode */
5687       if (slognul) oktolog = 1;         /* only if padding (2009/10/22) */
5688     if (!oktolog)
5689       return;
5690     if (slogts) {                       /* Log is timestamped */
5691         if (tsstate == 0) {             /* State = between-lines */
5692             char * p;                   /* zstime() pointer */
5693             char ts[48];                /* timestamp buffer */
5694             ztime(&p);                  /* Get asctime() string */
5695             ckstrncpy(ts,p,32);         /* Make safe copy */
5696             if (ztmsec > -1L) {         /* Add msecs if we have them */
5697                 sprintf(&ts[19],".%03ld: ",ztmsec); /* SAFE */
5698             } else {
5699                 ts[19] = ':';
5700                 ts[20] = SP;
5701                 ts[21] = NUL;
5702             }
5703             if (zsout(ZSFILE,&ts[11]) < 0)
5704               goto xlogchar;
5705         }
5706     }
5707     if (c == '\n')                      /* At end of line? */
5708       tsstate = 0;                      /* yes */
5709     else
5710       tsstate = 1;                      /* no */
5711     if (zchout(ZSFILE,(CHAR)(c & 0xFF)) < 0) /* Log the character */
5712       goto xlogchar;
5713     if (tsstate == 0 && slognul != 0) { /* Null-terminating lines? */
5714         if (zchout(ZSFILE,(CHAR)0) < 0) /* Add a NUL */
5715           goto xlogchar;
5716     }
5717     return;
5718
5719   xlogchar:
5720     conoll("");
5721     conoll("ERROR WRITING SESSION LOG, LOG CLOSED!");
5722     setseslog(0);
5723     zclose(ZSFILE);
5724 #endif /* NOLOCAL */
5725 }
5726
5727 VOID
5728 logstr(s, len) char * s; int len; {     /* Log string to session log */
5729 #ifndef NOLOCAL
5730     int n = 0;
5731     if (!s)
5732       return;
5733     while (seslog && (n < len))
5734       logchar(s[n++]);
5735 #endif /* NOLOCAL */
5736 }
5737
5738 #ifdef CK_CURSES
5739 int
5740 ck_repaint() {
5741     repaint = 1;
5742     return(0);
5743 }
5744
5745 #ifdef STRATUS
5746 /* VOS has curses but no tgetent() */
5747 int
5748 tgetent(s1, s2) char * s1, * s2; {
5749     return(1);
5750 }
5751 #endif /* STRATUS */
5752
5753 #ifdef VMS
5754 #ifdef __DECC
5755 _PROTOTYP(int tgetent,(char *, char *));
5756 #endif /* __DECC */
5757 #endif /* VMS */
5758
5759 /*
5760   There are three different ways to do fullscreen on VMS.
5761   1. Use the real curses library, VAXCCURSE.
5762   2. Use do-it-yourself code.
5763   3. Use the Screen Manager, SMG$.
5764
5765   Method 1 doesn't work quite right; you can't call endwin(), so once you've
5766   started curses mode, you can never leave.
5767
5768   Method 2 doesn't optimize the screen, and so much more time is spent in
5769   screen writes.  This actually causes file transfers to fail because the
5770   tty device input buffer can be overrun while the screen is being updated,
5771   especially on a slow MicroVAX that has small typeahead buffers.
5772
5773   In the following #ifdef block, #define one of them and #undef the other 2.
5774
5775   So now let's try method 3...
5776 */
5777 #ifdef VMS
5778 #define CK_SMG                          /* Screen Manager */
5779 #undef MYCURSES                         /* Do-it-yourself */
5780 #undef VMSCURSE                         /* VAXCCURSE library */
5781 #endif /* VMS */
5782 /*
5783   But just before New Years, 2000, the SMG library seemed to break on
5784   both VMS systems we have here (an Alpha with VMS 7.1 and a VAX with 5.5).
5785   So back to MYCURSES, which works fine.
5786 */
5787 #ifdef VMS
5788 #undef CK_SMG
5789 #define MYCURSES
5790 #endif /* VMS */
5791
5792 #ifdef MYCURSES
5793 #define stdscr 0
5794 #ifdef CK_WREFRESH
5795 #undef CK_WREFRESH
5796 #endif /* CK_WREFRESH */
5797 #endif /* MYCURSES */
5798
5799 /*  S C R E E N C  --  Screen display function, uses curses  */
5800
5801 /* Idea for curses display contributed by Chris Pratt of APV Baker, UK */
5802
5803 /* Avoid conficts with curses.h */
5804
5805 #ifdef QNX
5806 /* Same as ckcasc.h, but in a different radix... */
5807 #ifdef ESC
5808 #undef ESC
5809 #endif /* ESC */
5810 #endif /* QNX */
5811
5812 #ifndef MYCURSES
5813 #undef VOID                             /* This was defined in ckcdeb.h */
5814 #endif /* MYCURSES */
5815
5816 #undef BS                               /* These were defined in ckcasc.h */
5817 #undef CR
5818 #undef NL
5819 #undef SO
5820 #ifdef US
5821 #undef US
5822 #endif  /* US */
5823 #undef SP                               /* Used in ncurses */
5824 #define CHR_SP 32                       /* Use this instead */
5825
5826 #ifdef VMS                              /* VMS fullscreen display */
5827 #ifdef MYCURSES                         /* Do-it-yourself method */
5828 extern int isvt52;                      /* From CKVTIO.C */
5829 #define printw printf
5830 #else
5831 #ifdef VMSCURSE                         /* VMS curses library VAXCCURSE */
5832 #include <curses.h>
5833 /* Note: Screen manager doesn't need a header file */
5834 #endif /* VMSCURSE */
5835 #endif /* MYCURSES */
5836 #else                                   /* Not VMS */
5837 #ifdef MYCURSES                         /* Do-it-yourself method */
5838 #define isvt52 0                        /* Used by OS/2, VT-100/ANSI always */
5839 #ifdef CKXPRINTF
5840 #define printw ckxprintf
5841 #else /* CKXPRINTF */
5842 #ifdef KUI
5843 #define printw Vscrnprintw
5844 #else /* KUI */
5845 #define printw printf
5846 #endif /* KUI */
5847 #endif /* CKXPRINTF */
5848 #else                                   /* Use real curses */
5849 #ifdef CK_NCURSES                       /* or ncurses... */
5850 #ifdef CKXPRINTF                        /* Our printf macro conflicts with */
5851 #undef printf                           /* use of "printf" in ncurses.h */
5852 #endif /* CKXPRINTF */
5853 #include <ncurses.h>
5854 #ifdef CKXPRINTF
5855 #define printf ckxprintf
5856 #endif /* CKXPRINTF */
5857 #else  /* Not ncurses */
5858 #ifdef CKXPRINTF                        /* Our printf macro conflicts with */
5859 #undef printf                           /* use of "printf" in curses.h */
5860 #endif /* CKXPRINTF */
5861 #ifdef M_XENIX                          /* SCO XENIX... */
5862 #ifdef M_TERMCAP
5863 #undef M_TERMCAP
5864 #endif /* M_TERMCAP */
5865 #ifndef M_TERMINFO
5866 #define M_TERMINFO
5867 #endif /* M_TERMINFO */
5868 #endif /* M_XENIX */
5869 #ifdef RTAIX
5870 #undef NLS                              /* Avoid 'redeclaration of free'. */
5871 #endif /* RTAIX */
5872 #include <curses.h>
5873 #ifdef CKXPRINTF
5874 #define printf ckxprintf
5875 #endif /* CKXPRINTF */
5876 #endif /* CK_NCURSES */
5877 #endif /* MYCURSES */
5878 #endif /* VMS */
5879
5880 #ifdef BUG999
5881 _PROTOTYP(int tgetent,(char *, char *));
5882 _PROTOTYP(char *tgetstr,(char *, char **));
5883 _PROTOTYP(int tputs,(char *, int, int (*)()));
5884 _PROTOTYP(char *tgoto,(const char *, int, int));
5885 #endif  /* BUG999 */
5886
5887 #endif /* CK_CURSES */
5888
5889 /*  F X D I N I T  --  File Xfer Display Initialization  */
5890
5891 #ifdef CK_CURSES
5892 #ifndef MYCURSES
5893 #ifndef CK_SMG
5894 static
5895 #ifdef CK_ANSIC
5896 /* Can't use VOID because of curses.h */
5897 void
5898 ck_termset(int);
5899 #else
5900 ck_termset();
5901 #endif /* CK_ANSIC */
5902 #endif /* CK_SMG */
5903 #endif /* MYCURSES */
5904 #endif /* CK_CURSES */
5905
5906 #ifdef NOTERMCAP
5907 static int notermcap = 1;
5908 #else
5909 static int notermcap = 0;
5910 #endif /* NOTERMCAP */
5911
5912 #ifndef NODISPLAY
5913 CKVOID
5914 fxdinit(xdispla) int xdispla; {
5915 #ifndef COHERENT
5916 #ifndef OS2
5917 #ifndef STRATUS
5918     char *s;
5919     int x, dummy;
5920
5921     debug(F101,"fxdinit xdispla","",xdispla);
5922     debug(F101,"fxdinit fxd_inited","",fxd_inited);
5923
5924 #ifdef IKSD
5925 #ifndef NOXFER
5926     /* No curses for IKSD */
5927     if (inserver) {
5928         fdispla = XYFD_N;
5929         return;
5930     }
5931     if (fxd_inited)                     /* Only do this once */
5932       return;
5933 #endif /* NOXFER */
5934 #endif /* IKSD */
5935
5936     if (xdispla == XYFD_R || xdispla == XYFD_S || xdispla == XYFD_B) {
5937         if (xfrmsg) {
5938             printf("%s\n",xfrmsg);
5939             makestr(&xfrmsg,NULL);
5940         }
5941     }
5942
5943 #ifdef CK_CURSES
5944 #ifdef VMS
5945     /* Force BRIEF in Batch logs */
5946     if (batch && (xdispla == XYFD_C || xdispla == XYFD_S))
5947       xdispla = XYFD_B;
5948 #else
5949     if (xdispla == XYFD_C || xdispla == 9999) {
5950
5951 #ifdef DYNAMIC
5952         if (!trmbuf) {
5953 /*
5954   Allocate tgetent() buffer.  Make it big -- some termcaps can be huge;
5955   tgetent() merrily writes past the end of the buffer, causing core dumps
5956   or worse.
5957 */
5958             trmbuf = (char *)malloc(TRMBUFL);
5959             if (!trmbuf) {
5960                 notermcap = 1;
5961                 debug(F101,"fxdinit malloc trmbuf","FAILED",TRMBUFL);
5962                 fdispla = XYFD_S;
5963                 return;
5964             }
5965 #ifdef COMMENT
5966             debug(F111,"fxdinit malloc trmbuf","OK",TRMBUFL);
5967             debug(F001,"fxdinit trmbuf","",trmbuf);
5968             memset(trmbuf,'\0',(size_t)TRMBUFL);
5969             debug(F100,"fxdinit memset OK","",0);
5970 #endif /* COMMENT */
5971         }
5972 #endif /* DYNAMIC */
5973
5974         debug(F100,"fxdinit before getenv(TERM)","",0);
5975         s = getenv("TERM");
5976         debug(F110,"fxdinit after getenv(TERM)",s,0);
5977         if (!s) s = "";
5978         if (*s) {
5979             debug(F110,"fxdinit before tgetent()",s,0);
5980             x = tgetent(trmbuf,s);
5981             debug(F111,"fxdinit tgetent",s,x);
5982         } else {
5983             x = 0;
5984             notermcap = 1;
5985             debug(F110,"fxdinit TERM null - no tgetent",s,0);
5986         }
5987         if (x < 1 && !quiet && !backgrd
5988 #ifdef VMS
5989             && !batch
5990 #endif /* VMS */
5991             ) {
5992             printf("Warning: terminal type unknown: \"%s\"\n",s);
5993 #ifdef COMMENT
5994             /* Confusing - nobody knows what this means */
5995             printf("SCREEN command will use ANSI sequences.\n");
5996 #endif /* COMMENT */
5997             if (local)
5998               printf("Fullscreen file transfer display disabled.\n");
5999             fdispla = XYFD_S;
6000         }
6001 #ifndef MYCURSES
6002 #ifndef CK_SMG
6003         ck_termset(x);
6004 #endif /* CK_SMG */
6005 #endif /* MYCURSES */
6006         fxd_inited = 1;
6007     }
6008 #endif /* CK_CURSES */
6009 #endif /* VMS */
6010 #endif /* STRATUS */
6011 #endif /* OS2 */
6012 #endif /* COHERENT */
6013 }
6014 #endif /* NODISPLAY */
6015
6016 #ifdef CK_CURSES
6017 #ifdef CK_SMG
6018 /*
6019   Long section for Screen Manager starts here...
6020   By William Bader.
6021 */
6022 #include "ckvvms.h"
6023 #ifdef OLD_VMS
6024 #include <smgdef.h>                     /* use this on VAX C 2.4 */
6025 /* #include <smgmsg.h> */
6026 #else
6027 #include <smg$routines.h>               /* Martin Zinser */
6028 #endif /* OLD_VMS */
6029
6030 extern unsigned int vms_status;     /* Used for system service return status */
6031
6032 static long smg_pasteboard_id = -1;     /* pasteboard identifier */
6033 static long smg_display_id = -1;        /* display identifier */
6034 static int smg_open = 0;                /* flag if smg current open */
6035 static int smg_inited = 0;              /* flag if smg initialized */
6036
6037 #ifdef COMMENT
6038 #define clrtoeol()      SMG$ERASE_LINE(&smg_display_id, 0, 0)
6039
6040 #define clear()         SMG$ERASE_DISPLAY(&smg_display_id, 0, 0, 0, 0)
6041
6042 #define touchwin(scr)   SMG$REPAINT_SCREEN(&smg_pasteboard_id)
6043
6044 #else  /* Not COMMENT */
6045
6046 #define clrtoeol()      smg$erase_line(&smg_display_id, 0, 0)
6047
6048 #define clear()         smg$erase_display(&smg_display_id, 0, 0, 0, 0)
6049
6050 #define touchwin(scr)   smg$repaint_screen(&smg_pasteboard_id)
6051 #endif /* COMMENT */
6052
6053 #define clearok(curscr,ok)              /* Let wrefresh() do the work */
6054
6055 #define wrefresh(cursrc) touchwin(scr)
6056
6057 static void
6058 move(row, col) int row, col; {
6059     /* Change from 0-based for curses to 1-based for SMG */
6060     if (!smg_open)
6061       return;
6062     ++row; ++col;
6063     debug(F111,"VMS smg move",ckitoa(row),col);
6064 #ifdef COMMENT                          /* Martin Zinser */
6065     CHECK_ERR("move: smg$set_cursor_abs",
6066               SMG$SET_CURSOR_ABS(&smg_display_id, &row, &col));
6067 #else
6068     CHECK_ERR("move: smg$set_cursor_abs",
6069               smg$set_cursor_abs(&smg_display_id, &row, &col));
6070 #endif /* COMMENT */
6071     debug(F101,"VMS smg move vms_status","",vms_status);
6072 }
6073
6074 #ifdef VMS_V40
6075 #define OLD_VMS
6076 #endif /* VMS_V40 */
6077 #ifdef VMS_V42
6078 #define OLD_VMS
6079 #endif /* VMS_V42 */
6080 #ifdef VMS_V44
6081 #define OLD_VMS
6082 #endif /* VMS_V44 */
6083
6084 static int
6085 initscr() {
6086     int rows = 24, cols = 80;
6087     int row = 1, col = 1;
6088
6089     debug(F101,"VMS initscr smg_pasteboard_id A","",smg_pasteboard_id);
6090
6091     if (smg_pasteboard_id == -1) { /* Open the screen */
6092 #ifdef OLD_VMS                     /* Note: Routine calls lowercased 9/96 */
6093         CHECK_ERR("initscr: smg$create_pasteboard",
6094                   smg$create_pasteboard(&smg_pasteboard_id, 0, 0, 0, 0));
6095 #else
6096         /* For VMS V5, not tested */
6097         CHECK_ERR("initscr: smg$create_pasteboard",
6098                   smg$create_pasteboard(&smg_pasteboard_id, 0, 0, 0, 0, 0));
6099 #endif /* OLD_VMS */
6100     }
6101     debug(F101,"VMS initscr smg_pasteboard_id B","",smg_pasteboard_id);
6102     if (smg_pasteboard_id == -1) {
6103         printf("?Error initializing fullscreen display\n");
6104         fdispla = XYFD_S;
6105         dpyinit();
6106         return(0);
6107     }
6108     debug(F101,"VMS initscr smg_display_id","",smg_display_id);
6109     if (smg_display_id == -1) {         /* Create a display window */
6110
6111 #ifdef COMMENT                          /* Martin Zinser */
6112         CHECK_ERR("initscr: smg$create_virtual_display",
6113                   SMG$CREATE_VIRTUAL_DISPLAY(&rows, &cols, &smg_display_id,
6114                                              0, 0, 0));
6115
6116         /* Connect the display window to the screen */
6117         CHECK_ERR("initscr: smg$paste_virtual_display",
6118                   SMG$PASTE_VIRTUAL_DISPLAY(&smg_display_id,&smg_pasteboard_id,
6119                                             &row,&col));
6120 #else
6121         CHECK_ERR("initscr: smg$create_virtual_display",
6122                   smg$create_virtual_display(&rows, &cols, &smg_display_id,
6123                                              0, 0, 0));
6124
6125         /* Connect the display window to the screen */
6126         CHECK_ERR("initscr: smg$paste_virtual_display",
6127                   smg$paste_virtual_display(&smg_display_id,&smg_pasteboard_id,
6128                                             &row,&col));
6129 #endif /* COMMENT */
6130     }
6131     debug(F101,"VMS initscr smg_open A","",smg_open);
6132     if (!smg_open) {                    /* Start a batch update */
6133         smg_open = 1;
6134 #ifdef COMMENT
6135         CHECK_ERR("initscr: smg$begin_pasteboard_update",
6136                   SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id));
6137 #else
6138         CHECK_ERR("initscr: smg$begin_pasteboard_update",
6139                   smg$begin_pasteboard_update(&smg_pasteboard_id));
6140 #endif /* COMMENT */
6141         debug(F101,"VMS initscr smg$begin_pasteboard_update","",vms_status);
6142     }
6143     debug(F101,"VMS initscr smg_open B","",smg_open);
6144     smg_inited = 1;
6145     return(1);
6146 }
6147
6148 static void
6149 refresh() {
6150     debug(F101,"refresh smg_pasteboard_id","",smg_pasteboard_id);
6151
6152     if (smg_open == 0 || smg_pasteboard_id == -1)
6153       return;
6154
6155 #ifdef COMMENT                          /* Martin Zinser */
6156     CHECK_ERR("refresh: smg$end_pasteboard_update",
6157               SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id));
6158     CHECK_ERR("refresh: smg$begin_pasteboard_update",
6159               SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id));
6160 #else
6161     CHECK_ERR("refresh: smg$end_pasteboard_update",
6162               smg$end_pasteboard_update(&smg_pasteboard_id));
6163     CHECK_ERR("refresh: smg$begin_pasteboard_update",
6164               smg$begin_pasteboard_update(&smg_pasteboard_id));
6165 #endif /* COMMENT */
6166 }
6167
6168 static void
6169 endwin() {
6170     if (!smg_open)
6171       return;
6172
6173     smg_open = 0;
6174
6175 #ifdef COMMENT
6176     CHECK_ERR("endwin: smg$end_pasteboard_update",
6177               SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id));
6178 #else
6179     CHECK_ERR("endwin: smg$end_pasteboard_update",
6180               smg$end_pasteboard_update(&smg_pasteboard_id));
6181 #endif /* COMMENT */
6182
6183     move(22, 0);
6184
6185 #ifdef COMMENT
6186 /*
6187   These calls clear the screen.
6188   (convert routine calls to lowercase - Martin Zinser)
6189 */
6190     CHECK_ERR("endwin: smg$delete_virtual_display",
6191               SMG$DELETE_VIRTUAL_DISPLAY(&smg_display_id));
6192     smg_display_id = -1;
6193
6194     CHECK_ERR("endwin: smg$delete_pasteboard",
6195               SMG$DELETE_PASTEBOARD(&smg_pasteboard_id, 0));
6196     smg_pasteboard_id = -1;
6197 #endif /* COMMENT */
6198 }
6199
6200 #ifdef COMMENT
6201 /* DECC 6.2 screams bloody murder about printw ("not enough args") */
6202 /* but adding the following prototype only makes it holler louder. */
6203 #ifdef __DECC
6204 /* "varargs" prototype for printw */
6205 _PROTOTYP(static int printw,(char *, ...));
6206 #endif /* __DECC */
6207 #endif /* COMMENT */
6208
6209 #ifdef __DECC
6210 #include <stdarg.h>
6211 _PROTOTYP(static void printw,(char *, ...));
6212 static void
6213 printw(char *str,...) {
6214     char buf[255];
6215     va_list ap;
6216     $DESCRIPTOR(text_dsc, 0);
6217     text_dsc.dsc$a_pointer=buf;
6218     if (!smg_open)
6219       return;
6220     va_start(ap,str);
6221     text_dsc.dsc$w_length = vsprintf(buf, str, ap);
6222     va_end(ap);
6223     CHECK_ERR("printw: smg$put_chars",
6224               smg$put_chars(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0));
6225 }
6226 #else
6227 static void
6228 printw(str, a1, a2, a3, a4, a5, a6, a7, a8)
6229     char *str;
6230     long a1, a2, a3, a4, a5, a6, a7, a8;
6231 /* printw */ {
6232     char buf[255];
6233     $DESCRIPTOR(text_dsc, 0);
6234     if (!smg_open)
6235       return;
6236     text_dsc.dsc$a_pointer=buf;
6237     text_dsc.dsc$w_length = sprintf(buf, str, a1, a2, a3, a4, a5, a6, a7, a8);
6238     CHECK_ERR("printw: smg$put_chars",
6239               smg$put_chars(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0));
6240 }
6241 #endif /* __DECC */
6242
6243 #define CK_CURPOS
6244 int
6245 ck_curpos(row, col) {
6246     debug(F111,"VMS smg ck_curpos",ckitoa(row),col);
6247     if (!smg_inited || !smg_open) {
6248         initscr();
6249     }
6250     debug(F101,"VMS smg curpos smg_open","",smg_open);
6251     if (!smg_open)
6252       return(0);
6253     debug(F111,"VMS smg ck_curpos",ckitoa(row-1),col-1);
6254     move(row - 1, col - 1);             /* SMG is 0-based */
6255     refresh();
6256     /* endwin(); */
6257     return(0);
6258 }
6259
6260 int
6261 ck_cls() {
6262     debug(F101,"VMS smg ck_cls smg_inited","",smg_inited);
6263     if (!smg_inited || !smg_open) {
6264         initscr();
6265     }
6266     debug(F101,"VMS smg ck_cls smg_open","",smg_open);
6267     if (!smg_open)
6268       return(0);
6269     clear();
6270     refresh();
6271     /* endwin(); */
6272     return(0);
6273 }
6274
6275 int
6276 ck_cleol() {
6277     debug(F101,"VMS smg ck_cleol smg_inited","",smg_inited);
6278     if (!smg_inited || !smg_open) {
6279         initscr();
6280     }
6281     debug(F101,"VMS smg ck_cleol smg_open","",smg_open);
6282     if (!smg_open)
6283       return(0);
6284     clrtoeol();
6285     refresh();
6286     /* endwin(); */
6287     return(0);
6288 }
6289 #endif /* CK_SMG */
6290
6291 #ifdef MYCURSES
6292 /*
6293   Do-it-yourself curses implementation for VMS, OS/2 and other ANSI/VT-100's.
6294   Supports only the VT52 and VT1xx (and later VT2xx/3xx/4xx) terminals.
6295   By Terry Kennedy, St Peters College.
6296
6297   First, some stuff we can just ignore:
6298 */
6299
6300 static int
6301 touchwin(x) int x; {
6302     return(0);
6303 }
6304 static int
6305 initscr() {
6306     return(0);
6307 }
6308 static int
6309 refresh() {
6310     return(0);
6311 }
6312 static int
6313 endwin() {
6314     return(0);
6315 }
6316
6317 /*
6318  * Now, some stuff we need to do:
6319  */
6320
6321 _PROTOTYP( int move, (int, int) );
6322 #ifndef OS2
6323 int
6324 move(row, col) int row, col; {
6325     if (isvt52)
6326       printf("\033Y%c%c", row + 037, col + 037);
6327     else
6328       printf("\033[%d;%dH", row + 1, col + 1);
6329     return(0);
6330 }
6331
6332 int
6333 clear() {
6334     move(0,0);
6335     if (isvt52)
6336       printf("\033J");
6337     else
6338       printf("\033[J");
6339     return(0);
6340 }
6341
6342 int
6343 clrtoeol() {
6344     if (isvt52)
6345       printf("\033K");
6346     else
6347       printf("\033[K");
6348     return(0);
6349 }
6350
6351 #define CK_CURPOS
6352 int
6353 ck_cls() {
6354     return(clear());
6355 }
6356
6357 int
6358 ck_cleol() {
6359     return(clrtoeol());
6360 }
6361
6362 int
6363 ck_curpos(row, col) int row, col; {
6364     move(row, col);
6365     return(0);
6366 }
6367
6368 #else /* OS2 */
6369 /* Windows NT and Windows 95 do not provide ANSI emulation */
6370 /* Therefore we might as well not use it for OS/2 either   */
6371
6372 int
6373 move(row, col) int row, col; {
6374 #ifndef ONETERMUPD
6375     SetCurPos(row, col);
6376 #endif /* ONETERMUPD */
6377     lgotoxy( VCMD, col+1, row+1);
6378     VscrnIsDirty(VCMD);
6379     return(0);
6380 }
6381
6382 int
6383 clear() {
6384     viocell cell;
6385     move(0,0);
6386 #ifdef ONETERMUPD
6387     if (VscrnGetBufferSize(VCMD) > 0) {
6388         VscrnScroll(VCMD, UPWARD, 0,
6389                     VscrnGetHeight(VCMD)-(1),
6390                     VscrnGetHeight(VCMD)-(0), TRUE, CHR_SP);
6391         cleartermscreen(VCMD);
6392     }
6393 #else
6394     cell.c = ' ';
6395     cell.a = colorcmd;
6396     WrtNCell(cell, cmd_rows * cmd_cols, 0, 0);
6397 #endif /* ONETERMUPD */
6398     return(0);
6399 }
6400
6401 int
6402 clrtoeol() {
6403     USHORT row, col;
6404     viocell cell;
6405
6406     cell.c = ' ';
6407     cell.a = colorcmd;
6408 #ifndef ONETERMUPD
6409     GetCurPos(&row, &col );
6410     WrtNCell(cell, cmd_cols - col -1, row, col);
6411 #endif /* ONETERMUPD */
6412     clrtoeoln(VCMD,CHR_SP);
6413     return(0);
6414 }
6415
6416 #define CK_CURPOS
6417 int
6418 ck_curpos(row, col) int row, col; {
6419     move(row, col);
6420     return(0);
6421 }
6422
6423 int
6424 ck_cls() {
6425     return(clear());
6426 }
6427
6428 int
6429 ck_cleol() {
6430     return(clrtoeol());
6431 }
6432
6433 #endif /* OS2 */
6434 #endif /* MYCURSES */
6435
6436 #ifndef NOTERMCAP
6437 #ifndef CK_CURPOS
6438 #define CK_CURPOS
6439
6440 /* Termcap/Terminfo section */
6441
6442 static char cur_cls[32] = { NUL, NUL };
6443 static char cur_cleol[32] = { NUL, NUL };
6444 static char cur_cm[64] = { NUL, NUL };
6445 static char tgsbuf[128] = { NUL, NUL };
6446
6447 static
6448 #ifdef CK_ANSIC
6449 void
6450 #endif /* CK_ANSIC */
6451 ck_termset(x) int x; {
6452     cur_cls[0] = NUL;
6453     cur_cleol[0] = NUL;
6454     cur_cm[0] = NUL;
6455 #ifdef tgetent
6456     debug(F100,"tgetent is a macro","",0);
6457 #endif /* tgetent */
6458 #ifdef tgetstr
6459     debug(F100,"tgetstr is a macro","",0);
6460 #endif /* tgetstr */
6461 #ifdef tputs
6462     debug(F100,"tputs is a macro","",0);
6463 #endif /* tputs */
6464 #ifdef tgoto
6465     debug(F100,"tgoto is a macro","",0);
6466 #endif /* tgoto */
6467 #ifdef NOTERMCAP
6468     /* tgetstr() gets a segmentation fault on OSF/1 */
6469     debug(F100,"ck_termset NOTERMCAP","",0);
6470 #else
6471     if (notermcap) {
6472         debug(F100,"ck_termset notermcap","",0);
6473         return;
6474     }
6475     debug(F101,"ck_termset x","",x);
6476     if (x > 0) {
6477         char * bp;
6478         bp = tgsbuf;
6479         *bp = NUL;
6480         debug(F110,"ck_termset calling tgetstr","cl",0);
6481         if (tgetstr("cl", &bp)) {       /* Get clear-screen code */
6482             debug(F110,"ck_termset tgetstr cl",tgsbuf,"");
6483             if ((int)strlen(tgsbuf) < 32)
6484               ckstrncpy(cur_cls,tgsbuf,32);
6485         } else
6486           return;
6487         bp = tgsbuf;
6488         if (tgetstr("ce", &bp)) {       /* Get clear-to-end-of-line code */
6489             debug(F110,"ck_termset tgetstr ce",tgsbuf,"");
6490             if ((int)strlen(tgsbuf) < 32)
6491               ckstrncpy(cur_cleol,tgsbuf,32);
6492         } else
6493           return;
6494         bp = tgsbuf;
6495         if (tgetstr("cm", &bp)) {       /* Get cursor-movement code */
6496             debug(F110,"ck_termset tgetstr cm",tgsbuf,"");
6497             if ((int)strlen(tgsbuf) < 64)
6498               ckstrncpy(cur_cm,tgsbuf,64);
6499         } else
6500           return;
6501     }
6502 #endif /* NOTERMCAP */
6503 }
6504
6505 #ifndef TPUTSFNTYPE
6506 #ifdef TPUTSISVOID
6507 #define TPUTSFNTYPE void
6508 #else
6509 #define TPUTSFNTYPE int
6510 #endif /* TPUTSISVOID */
6511 #endif /* TPUTSFNTYPE */
6512
6513 #ifndef TPUTSARGTYPE
6514 #ifdef HPUX9
6515 #define TPUTSARGTYPE char
6516 #else
6517 #ifdef HPUX10
6518 #define TPUTSARGTYPE char
6519 #else
6520 #define TPUTSARGTYPE int
6521 #endif /* HPUX10 */
6522 #endif /* HPUX9 */
6523 #endif /* TPUTSARGTYPE */
6524
6525 static TPUTSFNTYPE
6526 #ifdef CK_ANSIC
6527 ck_outc(TPUTSARGTYPE x)
6528 #else
6529 ck_outc(x) TPUTSARGTYPE x;
6530 #endif /* CK_ANSIC */
6531 {                                       /* To satisfy tputs() arg3 prototype */
6532     int rc;
6533     char c;
6534     c = (char) x;
6535     rc = (inserver) ? ttoc(c) : conoc(c);
6536 #ifndef TPUTSISVOID
6537     return(rc);
6538 #endif /* TPUTSISVOID */
6539 }
6540
6541 int
6542 ck_curpos(row, col) int row, col; {
6543 #ifdef CK_ANSIC
6544     TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
6545 #else
6546     TPUTSFNTYPE (*fn)();
6547 #endif /* CK_ANSIC */
6548     if (!fxd_inited)
6549       fxdinit(9999);
6550     if (!cur_cm[0]) {                   /* We don't have escape sequences */
6551 #ifdef COMMENT
6552         return(-1);                     /* Do nothing */
6553 #else
6554         /* Both C-Kermit's SCREEN command and ANSI/VT100 are 1-based */
6555         printf("\033[%d;%dH", row, col); /* Or default to ANSI */
6556 #endif /* COMMENT */
6557     } else {
6558         fn = ck_outc;
6559         /* termcap/terminfo is 0-based */
6560         tputs(
6561 #ifdef TPUTSARG1CONST
6562               (const char *)
6563 #endif /* TPUTSARG1CONST */
6564               tgoto(cur_cm,col-1,row-1),1,fn);
6565     }
6566     return(0);
6567 }
6568
6569 int
6570 ck_cls() {
6571 #ifdef CK_ANSIC
6572     TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
6573 #else
6574     TPUTSFNTYPE (*fn)();
6575 #endif /* CK_ANSIC */
6576     if (!fxd_inited)
6577       fxdinit(9999);
6578     if (!cur_cls[0]) {                  /* If we don't have escape sequences */
6579 #ifdef COMMENT
6580         return(-1);                     /* Do nothing */
6581 #else
6582         printf("\033[;H\033[2J");       /* Or default to ANSI */
6583 #endif /* COMMENT */
6584     } else {
6585         fn = ck_outc;
6586         debug(F111,"ck_cls 2",cur_cls,fxd_inited);
6587         tputs(cur_cls,cmd_rows,fn);
6588     }
6589     return(0);
6590 }
6591
6592 int
6593 ck_cleol() {
6594 #ifdef CK_ANSIC
6595     TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
6596 #else
6597     TPUTSFNTYPE (*fn)();
6598 #endif /* CK_ANSIC */
6599     if (!fxd_inited)
6600       fxdinit(9999);
6601     if (!cur_cleol[0]) {                /* If we don't have escape sequences */
6602 #ifdef COMMENT
6603         return(-1);                     /* Do nothing */
6604 #else
6605         printf("\033[K");               /* Or use ANSI */
6606 #endif /* COMMENT */
6607     } else {
6608         fn = ck_outc;
6609         tputs(cur_cleol,1,fn);
6610     }
6611     return(0);
6612 }
6613 #endif /* CK_CURPOS */
6614 #else
6615 static void
6616 ck_termset(x) int x; {
6617     if (x) return;
6618 }
6619 #endif /* NOTERMCAP */
6620
6621 #ifndef CK_CURPOS
6622 #define CK_CURPOS
6623 int
6624 ck_cls() {
6625     printf("\033[;H\033[2J");
6626     return(0);
6627 }
6628
6629 int
6630 ck_cleol() {
6631     printf("\033[K");
6632     return(0);
6633 }
6634
6635 int
6636 ck_curpos(row, col) int row, col; {
6637     printf("\033[%d;%dH", row, col);
6638     return(0);
6639 }
6640 #endif /* CK_CURPOS */
6641
6642
6643 #ifndef NOXFER
6644 static int cinit = 0;                   /* Flag for curses init'd */
6645 static int cendw = 0;                   /* endwin() was called */
6646
6647 static
6648 #ifdef CK_ANSIC                         /* Because VOID used by curses.h */
6649 void
6650 #else
6651 #ifdef MYCURSES
6652 VOID
6653 #else
6654 int
6655 #endif /* MYCURSES */
6656 #endif /* CK_ANSIC */
6657 #ifdef CK_ANSIC                         /* Update % transfered and % bar */
6658 updpct(long old, long new)
6659 #else /* CK_ANSIC */
6660 updpct(old, new) long old, new;
6661 #endif /* CK_ANSIC */
6662 /* updpct */ {
6663 #ifdef COMMENT
6664     int m, n;
6665     move(CW_PCD,22);
6666     printw("%ld", new);
6667 #ifdef KUI
6668 #ifndef K95G
6669     KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_PCD, (long) new);
6670 #endif /* K95G */
6671 #endif /* KUI */
6672 #ifdef CK_PCT_BAR
6673     if (thermometer) {
6674         if (old > new) {
6675             old = 0;
6676             move(CW_PCD, 26);
6677             clrtoeol();
6678         }
6679         m = old/2;
6680         move(CW_PCD, 26 + m);
6681         n = new / 2 - m;
6682 #ifndef OS2
6683         while (n > 0) {
6684             if ((m + 1) % 5 == 0)
6685               printw("*");
6686             else
6687               printw("=");
6688             m++;
6689             n--;
6690         }
6691         if (new % 2 != 0) printw("-");
6692         /* move(CW_PCD, 22+53); */
6693 #else /* OS2 */
6694         while (n > 0) {
6695             printw("%c", '\333');
6696             m++; n--;
6697         }
6698         if (new % 2 != 0)
6699           printw("%c", '\261');
6700 #endif /* OS2 */
6701     }
6702 #endif /* CK_PCT_BAR */
6703     /* clrtoeol(); */
6704 #else  /* !COMMENT */
6705 #ifdef OS2
6706 #define CHAR1   '\333'          /* OS2 - CP437 */
6707 #define CHAR2   '\261'
6708 #else
6709 #define CHAR1   '/'             /* Default */
6710 #define CHAR2   '-'
6711 #endif /* OS2 */
6712     debug(F101,"updpct old","",old);
6713     debug(F101,"updpct new","",new);
6714     move(CW_PCD,22);
6715     printw("%-3ld", new); /*  (was)   printw("%ld", new);  */
6716 #ifdef KUI
6717 #ifndef K95G
6718     KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) new );
6719 #endif /* K95G */
6720 #endif /* KUI */
6721 #ifdef CK_PCT_BAR
6722     if (thermometer) {
6723         int m, n;
6724
6725         if (old > new) {
6726             old = 0 ;
6727             move(CW_PCD, 26);
6728             clrtoeol();
6729         }
6730         if (new <= 100L) {
6731             m = old / 2;
6732             n = new / 2 - m;
6733             move(CW_PCD, 26+m);
6734             while (n-- > 0)
6735               printw("%c", CHAR1);
6736             if (new % 2 != 0)
6737               printw("%c", CHAR2);
6738         }
6739     }
6740 #endif /* CK_PCT_BAR */
6741 #endif /* COMMENT */
6742 }
6743
6744 static CK_OFF_T old_tr = (CK_OFF_T)-1;  /* Time remaining previously */
6745
6746 static CK_OFF_T
6747 #ifdef CK_ANSIC
6748 shoetl(CK_OFF_T old_tr, long cps, CK_OFF_T fsiz, CK_OFF_T howfar)
6749 #else
6750     shoetl(old_tr, cps, fsiz, howfar) long cps; CK_OFF_T old_tr, fsiz, howfar;
6751 #endif /* CK_ANSIC */
6752 /* shoetl */ {                          /* Estimated time left in transfer */
6753     CK_OFF_T tr;                        /* Time remaining, seconds */
6754
6755 #ifdef GFTIMER
6756     if (fsiz > 0L && cps > 0L)
6757       tr = (CK_OFF_T)((CKFLOAT)(fsiz - howfar) / (CKFLOAT)cps);
6758     else
6759       tr = (CK_OFF_T)-1;
6760 #else
6761     tr = (fsiz > 0L && cps > 0L) ?
6762       ((fsiz - howfar) / cps) :
6763         (CK_OFF_T)-1;
6764 #endif /* GFTIMER */
6765     move(CW_TR,22);
6766     if (tr > (CK_OFF_T)-1) {
6767         if (tr != old_tr) {
6768             printw("%s",hhmmss(tr));
6769 #ifdef KUI
6770 #ifndef K95G
6771             KuiSetProperty(KUI_FILE_TRANSFER, (long)CW_TR, (long)hhmmss(tr));
6772 #endif /* K95G */
6773 #endif /* KUI */
6774             clrtoeol();
6775         }
6776     } else {
6777         printw("(unknown)");
6778 #ifdef KUI
6779 #ifndef K95G
6780         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "(unknown)" );
6781 #endif /* K95G */
6782 #endif /* KUI */
6783         clrtoeol();
6784     }
6785     return(tr);
6786 }
6787
6788 static long
6789 #ifdef CK_ANSIC
6790 shocps(int pct, CK_OFF_T fsiz, CK_OFF_T howfar)
6791 #else
6792 shocps(pct, fsiz, howfar) int pct; CK_OFF_T fsiz, howfar;
6793 #endif /* CK_ANSIC */
6794 /* shocps */ {
6795 #ifdef CPS_WEIGHTED
6796     static CK_OFF_T oldffc = 0L;
6797 #endif /* CPS_WEIGHTED */
6798 #ifdef GFTIMER
6799     CKFLOAT secs, xx;
6800 #else
6801     CK_OFF_T secs, xx;
6802 #endif /* GFTIMER */
6803
6804 #ifdef GFTIMER
6805     xx = (gtv >= 0.0) ? gtv : 0.0;      /* Floating-point version */
6806     gtv = gftimer();
6807     if ((gtv - oldgtv) < (CKFLOAT) 1.0) /* Only do this once per second */
6808       return(oldcps);
6809     oldgtv = xx;
6810 #else
6811     xx = (gtv >= 0) ? gtv : 0;          /* Whole-number version */
6812     gtv = gtimer();
6813     if ((gtv - oldgtv) < 1)
6814       return(oldcps);
6815     oldgtv = xx;
6816 #endif /* GFTIMER */
6817
6818 #ifdef CPS_WEIGHTED
6819     /* debug(F100,"SHOCPS: WEIGHTED","",0); */
6820     if (gtv != oldgtv) {                /* The first packet is ignored */
6821         if (ffc < oldffc)
6822           oldffc = ffc;
6823         oldcps = cps;
6824         if (oldcps && oldgtv >
6825 #ifdef GFTIMER
6826             1.0
6827 #else
6828             1
6829 #endif /* GFTIMER */
6830             ) {                         /* The first second is ignored */
6831 /*
6832   This version of shocps() produces a weighted average that some
6833   people like, but most people find it disconcerting and bombard us
6834   with questions and complaints about why the CPS figure fluctuates so
6835   wildly.  So now you only get the weighted average if you build the
6836   program yourself with CPS_WEIGHTED defined.
6837 */
6838 #ifndef CPS_VINCE
6839 #ifdef GFTIMER
6840             cps = (long)((((CKFLOAT)oldcps * 3.0) +
6841                    (CKFLOAT)(ffc - oldffc) / (gtv-oldgtv) ) / 4.0);
6842 #else
6843             cps = ( (oldcps * 3) + (ffc - oldffc) / (gtv-oldgtv) ) / 4;
6844 #endif /* GFTIMER */
6845 #else
6846 /* And an alternate weighting scheme from Vincent Fatica... */
6847             cps = (3 *
6848              ((1+pct/300)*oldffc/oldgtv+(1-pct/100)*(ffc-oldffc)/(gtv-oldgtv)))
6849               / 4;
6850 #endif /* CPS_VINCE */
6851         } else {
6852             /* No weighted average since there is nothing to weigh */
6853 #ifdef GFTIMER
6854             cps = (long)(gtv != 0.0 ?
6855               (CKFLOAT)(ffc - oldffc) / (gtv - oldgtv) :
6856                 (ffc - oldffc)) ;
6857 #else
6858             cps = gtv ? (ffc - oldffc) / (gtv - oldgtv) : (ffc - oldffc) ;
6859 #endif /* GFTIMER */
6860         }
6861 #ifdef COMMENT
6862 #ifdef DEBUG
6863         if (deblog) {
6864             debug(F101,"SHOCPS: pct   ","",pct);
6865             debug(F101,"SHOCPS: gtv   ","",gtv);
6866             debug(F101,"SHOCPS: oldgtv","",oldgtv);
6867             debug(F101,"SHOCPS: dgtv  ","",(long)(gtv-oldgtv));
6868             debug(F101,"SHOCPS: ffc   ","",ffc);
6869             debug(F101,"SHOCPS: oldffc","",oldffc);
6870             debug(F101,"SHOCPS: dffc  ","",ffc-oldffc);
6871             debug(F101,"SHOCPS: cps   ","",cps);
6872         }
6873 #endif /* DEBUG */
6874 #endif /* COMMENT */
6875         move(CW_CP,22);
6876         printw("%ld", cps);
6877 #ifdef KUI
6878 #ifndef K95G
6879         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
6880 #endif /* K95G */
6881 #endif /* KUI */
6882         clrtoeol();
6883         oldffc = ffc;
6884     }
6885 #else /* !CPS_WEIGHTED */
6886 #ifdef COMMENT
6887 #ifdef DEBUG
6888     if (deblog) {
6889         debug(F100,"SHOCPS: NOT WEIGHTED","",0);
6890         debug(F101,"SHOCPS: pct    ","",pct);
6891         debug(F101,"SHOCPS: gtv    ","",gtv);
6892         debug(F101,"SHOCPS: oldgtv ","",oldgtv);
6893         debug(F101,"SHOCPS: dgtv   ","",(long)gtv - (long)oldgtv);
6894         debug(F101,"SHOCPS: ffc    ","",ffc);
6895         debug(F101,"SHOCPS: oldffc ","",oldffc);
6896         debug(F101,"SHOCPS: dffc   ","",ffc-oldffc);
6897         debug(F101,"SHOCPS: cps    ","",cps);
6898         debug(F101,"SHOCPS: filcnt ","",filcnt);
6899 #ifdef GFTIMER
6900         debug(F101,"SHOCPS: fpfsecs","",fpfsecs);
6901 #endif /* GFTIMER */
6902     }
6903     debug(F101,"shocps gtv","",gtv);
6904 #endif /* DEBUG */
6905 #ifdef GFTIMER
6906 #endif /* COMMENT */
6907     /* debug(F101,"shocps fpfsecs","",fpfsecs); */
6908     secs = gtv - fpfsecs;
6909     /* debug(F101,"shocps secs","",(long)secs); */
6910     if (secs > 0.0) {
6911         cps = (long)((CKFLOAT) ffc / secs);
6912         /* debug(F101,"shocps cps","",cps); */
6913         move(CW_CP,22);
6914 #ifdef KUI
6915 #ifndef K95G
6916         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
6917 #endif /* K95G */
6918 #endif /* KUI */
6919         printw("%ld", cps);
6920         clrtoeol();
6921     }
6922 #else  /* Not GFTIMER */
6923     if ((secs = gtv - fsecs) > 0) {
6924         cps = (secs < 1L) ? ffc : ffc / secs;
6925         move(CW_CP,22);
6926 #ifdef KUI
6927 #ifndef K95G
6928         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
6929 #endif /* K95G */
6930 #endif /* KUI */
6931         printw("%ld", cps);
6932         clrtoeol();
6933     }
6934 #endif /* GFTIMER */
6935 #endif /* CPS_WEIGHTED */
6936
6937     if (cps > peakcps &&                /* Peak transfer rate */
6938         ((what & W_SEND && spackets > wslots + 4) ||
6939          (!(what & W_SEND) && spackets > 10))) {
6940         peakcps = cps;
6941     }
6942     old_tr = shoetl(old_tr, cps, fsiz, howfar);
6943     return(cps);
6944 }
6945
6946 static
6947 #ifdef CK_ANSIC                         /* Because VOID used by curses.h */
6948 void
6949 #else
6950 #ifdef MYCURSES
6951 VOID
6952 #else
6953 int
6954 #endif /* MYCURSES */
6955 #endif /* CK_ANSIC */
6956 scrft() {                               /* Display file type */
6957     char xferstr[256];
6958     xferstr[0] = NUL;
6959     debug(F101,"scrft binary","",binary);
6960     if (binary) {
6961         switch(binary) {
6962           case XYFT_L:
6963             ckstrncpy(xferstr,"LABELED",256);
6964             break;
6965           case XYFT_I:
6966             ckstrncpy(xferstr,"IMAGE",256);
6967             break;
6968           case XYFT_U:
6969             ckstrncpy(xferstr,"BINARY UNDEFINED",256);
6970             break;
6971           case XYFT_M:
6972             ckstrncpy(xferstr,"MACBINARY",256);
6973             break;
6974           case XYFT_X:
6975             ckstrncpy(xferstr,"TENEX",256);
6976             break;
6977           default:
6978           case XYFT_B:
6979             ckstrncpy(xferstr,"BINARY",256);
6980             break;
6981         }
6982 #ifdef CK_RESEND
6983         if (what & W_SEND && sendstart > 0L) {
6984             if (sendmode == SM_PSEND) {
6985                 ckstrncat(xferstr, " / partial", 256);
6986             } else if (sendmode == SM_RESEND) {
6987                 ckstrncat(xferstr, " / resend", 256);
6988             }
6989         } else if (what & W_RECV && rs_len > 0L) {
6990             ckstrncat(xferstr, " / resend", 256);
6991         }
6992 #endif /* CK_RESEND */
6993     } else {
6994
6995 #ifndef NOCSETS
6996         ckstrncpy(xferstr,"TEXT",256);
6997 #ifdef NEWFTP
6998 #ifndef NOUNICODE
6999         if (what & W_FTP) {
7000             if (ftp_csx < 0)
7001               ckstrncat(xferstr," (no translation)", 256);
7002             else
7003               ckmakxmsg(&xferstr[4],252,
7004                        " (",
7005                        fcsinfo[(what & W_SEND) ? ftp_csl : ftp_csx].keyword,
7006                        " => ",
7007                        fcsinfo[(what & W_SEND) ? ftp_csx : ftp_csl].keyword,
7008                        ")",
7009                        NULL,NULL,NULL,NULL,NULL,NULL,NULL
7010                        );
7011         } else
7012 #endif /* NOUNICODE */
7013 #endif /* NEWFTP */
7014           if (tcharset == TC_TRANSP) {
7015             ckstrncat(xferstr, " (no translation)", 256);
7016         } else {
7017             if (what & W_SEND) {
7018                 sprintf( &xferstr[strlen(xferstr)], /* safe */
7019                         " (%s => %s)",
7020                         fcsinfo[fcharset].keyword, /* built-in keywords */
7021                         tcsinfo[tcharset].keyword  /* lengths are controlled */
7022                         );
7023             } else {
7024                 sprintf( &xferstr[strlen(xferstr)], /* safe */
7025                         " (%s => %s)",
7026                         tcsinfo[tcharset].keyword, /* built-in keywords */
7027                         fcsinfo[fcharset].keyword); /* lengths controlled */
7028             }
7029         }
7030 #endif /* NOCSETS */
7031     }
7032     move(CW_TYP,22);
7033     printw("%s", xferstr);
7034     clrtoeol();
7035 #ifdef KUI
7036 #ifndef K95G
7037     KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TYP, (long) xferstr );
7038 #endif /* K95G */
7039 #endif /* KUI */
7040     return;
7041 }
7042
7043 #ifdef CK_NEWTERM
7044 static FILE *ck_stdout = NULL;
7045 static int ck_fd = -1;
7046 #endif /* CK_NEWTERM */
7047
7048 static long pct = 0L, oldpct = 0L, oldrtt = -1L;
7049 static int oldtyp = 0, oldwin = -1, oldtry = -1, oldlen = -1, oldtim = -1;
7050
7051 #ifdef NETCONN
7052 static char *netname[] = {
7053     "none",                             /* 00 */
7054     "TCP/IP",                           /* 01 TCP (Sockets) */
7055     "TCP/IP",                           /* 02 TCP (Streams) */
7056     "X.25",                             /* 03 SunLink X.24  */
7057     "DECnet",                           /* 04 DECnet  */
7058     "VAX PSI",                          /* 05 VAX PSI */
7059     "Named Pipes",                      /* 06 LAN Manager Named Pipe */
7060     "X.25",                             /* 07 Stratus VOS X.25 */
7061     "NetBIOS",                          /* 08 IBM NETBIOS */
7062     "SuperLAT",                         /* 07 Meridian SuperLAT */
7063     "File",                             /* 10 File */
7064     "Command",                          /* 11 Subprocess (pipe) */
7065     "DLL",                              /* 12 DLL does i/o */
7066     "X.25",                             /* 13 IBM AIXLink X.25 */
7067     "X.25",                             /* 14 HP-UX X.25 */
7068     "PTY",                              /* 15 Pseudoterminal */
7069     "SSH",                              /* 16 SSH */
7070     "<ERROR>",                          /* 17 In case new types are added */
7071     "<ERROR>",                          /* 18 but nobody remembers to update */
7072     "<ERROR>",                          /* 19 this table ... */
7073     NULL                                /* 20 */
7074 };
7075 static int nnetname = (sizeof(netname) / sizeof(char *));
7076
7077 #endif /* NETCONN */
7078
7079 #ifdef CK_ANSIC
7080 void
7081 screenc(int f, char c,CK_OFF_T n,char *s)
7082 #else
7083 CKVOID
7084 screenc(f,c,n,s)
7085 int f;          /* argument descriptor */
7086 char c;         /* a character or small integer */
7087 CK_OFF_T n;     /* a long integer */
7088 char *s;        /* a string */
7089 #endif /* CK_ANSIC */
7090 /* screenc() */ {
7091 #ifdef CK_SSL
7092     extern int tls_active_flag, ssl_active_flag;
7093 #endif /* CK_SSL */
7094 #ifdef RLOGCODE
7095     extern int ttnproto;
7096 #endif /* RLOGCODE */
7097     static int q = 0;
7098     static long fcnt = 0L;              /* Number of files transferred */
7099     static CK_OFF_T fsiz = (CK_OFF_T)-1; /* Copy of file size */
7100     static CK_OFF_T fbyt = 0L; /* Total file bytes of all files transferred */
7101     static CK_OFF_T howfar = 0L; /* How much of current file has been xfer'd */
7102     static int  pctlbl = 0L;  /* Percent done vs Bytes so far */
7103     long cps = 0L;
7104
7105     int net = 0;
7106     int xnet = 0;
7107     int ftp = 0;
7108     int len;                            /* Length of string */
7109     int errors = 0;                     /* Error counter */
7110     int x;                              /* Worker */
7111
7112     debug(F101,"screenc cinit","",cinit);
7113     debug(F101,"screenc cendw","",cendw);
7114
7115     if (!s) s = "";                     /* Always do this. */
7116
7117     ftp = (what & W_FTP) ? 1 : 0;       /* FTP or Kermit */
7118     net = network || ftp;
7119     xnet = ftp ? 1 : nettype;           /* NET_TCPB == 1 */
7120
7121     if (cinit == 0 || cendw > 0) {      /* Handle borderline cases... */
7122         if (f == SCR_CW) {              /* Close window, but it's not open */
7123             ft_win = 0;
7124             return;
7125         }
7126         debug(F111,"screenc A",s,f);
7127         if (f == SCR_EM ||
7128            (f == SCR_PT && c == 'E')) { /* Fatal error before window open */
7129             conoll(""); conoc('?'); conoll(s); return; /* Regular display */
7130         }
7131     }
7132     if (cinit == 0) {                   /* Only call initscr() once */
7133         char * s;
7134         /* Check these now -- if they are defined but not numeric */
7135         /* they can crash curses */
7136         s = getenv("LINES");
7137         if (s) if (!rdigits(s)) {
7138             printf("?LINES variable not numeric: \"%s\".\n",s);
7139             printf("(Fullscreen display disabled)\n");
7140             fdispla = XYFD_S;
7141             return;
7142         }
7143         s = getenv("COLUMNS");
7144         if (s) if (!rdigits(s)) {
7145             printf("?COLUMNS variable not numeric: \"%s\".\n",s);
7146             printf("(Fullscreen display disabled)\n");
7147             fdispla = XYFD_S;
7148             return;
7149         }
7150         cendw = 1;                      /* New window needs repainting */
7151 #ifdef COMMENT
7152         if (!initscr()) {               /* Oops, can't initialize window? */
7153 /*
7154   In fact, this doesn't happen.  "man curses" says initscr() halts the
7155   entire program if it fails, which is true on the systems where I've
7156   tested it.  It will fail if your terminal type is not known to it.
7157   That's why SET FILE DISPLAY FULLSCREEN calls tgetent() to make sure the
7158   terminal type is known before allowing a curses display.
7159 */
7160             fprintf(stderr,"CURSES INITSCR ERROR\r\n");
7161             fdispla = XYFD_S;           /* Fall back to CRT display */
7162             return;
7163         } else {
7164             cinit++;                    /* Window initialized ok */
7165             debug(F100,"CURSES INITSCR OK","",0);
7166         }
7167 #else                                   /* Save some memory. */
7168 #ifdef CK_NEWTERM
7169         /* (From Andy Fyfe <andy@vlsi.cs.caltech.edu>)
7170            System V curses seems to reserve the right to alter the buffering
7171            on the output FILE* without restoring it.  Fortunately System V
7172            curses provides newterm(), an alternative to initscr(), that
7173            allows us to specify explicitly the terminal type and input and
7174            output FILE pointers.  Thus we duplicate stdout, and let curses
7175            have the copy.  The original remains unaltered.  Unfortunately,
7176            newterm() seems to be particular to System V.
7177         */
7178         s = getenv("TERM");
7179         if (ck_fd < 0) {
7180             ck_fd = dup(fileno(stdout));
7181             ck_stdout = (ck_fd >= 0) ? (FILE *)fdopen(ck_fd, "w") : NULL;
7182         }
7183         debug(F100,"screenc newterm...","",0);
7184
7185 /* NOTE: It might be necessary to do this with stdin too! */
7186 /* This would have been the case in FreeBSD 4.1 but they fixed the */
7187 /* problem by restoring the buffering of stdin before the final release. */
7188 /* (But T.E. Dickey says stdin is not buffered?) */
7189
7190         if (ck_stdout == NULL || newterm(s, ck_stdout, stdin) == 0) {
7191             fprintf(stderr,
7192               "Fullscreen display not supported for terminal type: %s\r\n",s);
7193             fdispla = XYFD_S;           /* Use CRT instead */
7194             return;
7195         }
7196         debug(F100,"screenc newterm ok","",0);
7197 #else
7198         debug(F100,"screen calling initscr","",0);
7199         initscr();                      /* Initialize curses. */
7200         debug(F100,"screen initscr ok","",0);
7201 #endif /* CK_NEWTERM */
7202         cinit++;                        /* Remember curses was initialized. */
7203 #endif /* COMMENT */
7204     }
7205     ft_win = 1;                         /* Window is open */
7206     if (repaint) {
7207 #ifdef CK_WREFRESH
7208 /*
7209   This totally repaints the screen, just what we want, but we can only
7210   do this with real curses, and then only if clearok() and wrefresh() are
7211   provided in the curses library.
7212 */
7213 #ifdef OS2
7214         RestoreCmdMode();
7215 #else
7216 #ifdef QNX
7217 #ifndef QNX16
7218         clearok(stdscr, 1);             /* QNX doesn't have curscr */
7219 #endif /* QNX16 */
7220         wrefresh(stdscr);
7221 #else
7222         wrefresh(curscr);
7223 #endif /* QNX */
7224 #endif /* OS2 */
7225 #else  /* No CK_WREFRESH */
7226 /*
7227   Kermit's do-it-yourself method, works with all types of fullscreen
7228   support, but does not repaint all the fields.  For example, the filename
7229   is lost, because it arrives at a certain time and never comes again, and
7230   Kermit presently does not save it anywhere.  Making this method work for
7231   all fields would be a rather major recoding task, duplicating what curses
7232   already does, and would add a lot of complexity and storage space.
7233 */
7234         cendw = 1;
7235 #endif /* CK_WREFRESH */
7236         repaint = 0;
7237     }
7238     if (cendw) {                        /* endwin() was called previously */
7239 #ifdef VMS
7240         initscr();                      /* (or should have been!) */
7241         clear();
7242         touchwin(stdscr);
7243         refresh();
7244 #else
7245 #ifdef QNX
7246 /*
7247   In QNX, if we don't call initscr() here we core dump.
7248   I don't have any QNX curses documentation, but other curses manuals
7249   say that initscr() should be called only once per application, and
7250   experience shows that on other systems, calling initscr() here generally
7251   results in a core dump.
7252 */
7253         debug(F100,"screenc re-calling initscr QNX","",0);
7254         initscr();
7255         clear();
7256         refresh();
7257 #ifdef COMMENT
7258 /*
7259   But even so, second and subsequent curses displays are messed up.
7260   Calling touchwin, refresh, etc, doesn't make any difference.
7261 */
7262         debug(F100,"screenc calling touchwin QNX","",0);
7263         touchwin(stdscr);
7264         debug(F100,"screenc calling refresh QNX","",0);
7265         refresh();
7266 #endif /* COMMENT */
7267
7268 #else /* All others... */
7269         debug(F100,"screenc calling clear","",0);
7270         clear();
7271         debug(F100,"screenc clear ok","",0);
7272 #endif /* QNX */
7273 #endif /* VMS */
7274         debug(F100,"screenc setup ok","",0);
7275         debug(F100,"screenc doing first move","",0);
7276         move(CW_BAN,0);                 /* Display the banner */
7277         debug(F110,"screenc myhost",myhost,0);
7278 #ifdef TCPSOCKET
7279         debug(F110,"screenc myipaddr",myipaddr,0);
7280 #endif /* TCPSOCKET */
7281 #ifdef HPUX1010
7282         debug(F100,"screenc calling first printw...","",0);
7283 /* Right here is where HP-UX 10.10 libxcurse.1 Rev 76.20 hangs... */
7284 #endif /* HPUX1010 */
7285         if (myhost[0]) {
7286 #ifdef TCPSOCKET
7287             if (!myipaddr[0]
7288 #ifdef OS2
7289                  /* We need to perform this test because on non-TCP/IP */
7290                  /* systems the call to getlocalipaddr() results in a  */
7291                  /* DNS Lookup which takes several minutes to time out */
7292                  && net &&
7293                  (xnet == NET_TCPA || xnet == NET_TCPB
7294 #ifdef SSHBUILTIN
7295                   || xnet == NET_SSH
7296 #endif /* SSHBUILTIN */
7297                   )
7298 #endif /* OS2 */
7299                  )
7300               getlocalipaddr();
7301             if (myipaddr[0] && strcmp((char *)myhost,(char *)myipaddr))
7302               printw("%s, %s [%s]",versio,(char *)myhost,(char *)myipaddr);
7303             else
7304 #endif /* TCPSOCKET */
7305               printw("%s, %s",versio,(char *)myhost);
7306         } else {
7307             printw("%s",versio);
7308         }
7309 #ifdef HPUX1010
7310         debug(F100,"screenc first printw returns","",0);
7311 #endif /* HPUX1010 */
7312         move(CW_DIR,3);
7313         printw("Current Directory: %s",zgtdir());
7314 #ifdef KUI
7315 #ifndef K95G
7316         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) zgtdir() );
7317 #endif /* K95G */
7318 #endif /* KUI */
7319         if (net) {
7320             move(CW_LIN,8);
7321             printw("Network Host: %s",
7322 #ifdef NEWFTP
7323                    ftp ? (ftp_host ? ftp_host : "(unknown)") :
7324 #endif /* NEWFTP */
7325                    ttname
7326                    );
7327         } else {
7328             move(CW_LIN,0);
7329             printw("Communication Device: %s",ttname);
7330         }
7331 #ifdef KUI
7332 #ifndef K95G
7333         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_LIN, (long) ttname );
7334 #endif /* K95G */
7335 #endif /* KUI */
7336
7337         if (net) {
7338             move(CW_SPD,8);
7339             printw("Network Type: ");
7340         } else {
7341             move(CW_SPD,1);
7342             printw("Communication Speed: ");
7343         }
7344         move(CW_SPD,22);                /* Serial speed or network type */
7345         if (net) {
7346 #ifdef NETCONN
7347             int secure = 0;
7348             char * xname;
7349             if (xnet > nnetname)
7350               xname = "[ERROR]";
7351             else
7352               xname = netname[xnet];
7353 #ifdef NEWFTP
7354             if (ftp) {
7355                 if (ftpissecure())
7356                   secure = 1;
7357             } else
7358 #endif /* NEWFTP */
7359               if (0
7360 #ifdef SSHBUILTIN
7361                 || IS_SSH()
7362 #endif /* SSHBUILTIN */
7363 #ifdef CK_ENCRYPTION
7364                 || ck_tn_encrypting() && ck_tn_decrypting()
7365 #endif /* CK_ENCRYPTION */
7366 #ifdef CK_SSL
7367                 || tls_active_flag || ssl_active_flag
7368 #endif /* CK_SSL */
7369 #ifdef RLOGCODE
7370 #ifdef CK_KERBEROS
7371 #ifdef CK_ENCRYPTION
7372                 || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
7373 #endif /* CK_ENCRYPTION */
7374 #endif /* CK_KERBEROS */
7375 #endif /* RLOGCODE */
7376                  ) {
7377                 secure = 1;
7378             }
7379             if (secure) {
7380 #ifdef KUI
7381 #ifndef K95G
7382                 char buf[30];
7383                 sprintf(buf,"%s (SECURE)",xname);
7384                 KuiSetProperty(KUI_FILE_TRANSFER,
7385                                (long) CW_SPD,
7386                                (long) buf
7387                                );
7388 #endif /* K95G */
7389 #endif /* KUI */
7390                 printw("%s (SECURE)",xname);
7391             } else {
7392                 printw("%s",xname);
7393 #ifdef KUI
7394 #ifndef K95G
7395                 KuiSetProperty(KUI_FILE_TRANSFER,
7396                                (long) CW_SPD,
7397                                (long) xname
7398                                );
7399 #endif /* K95G */
7400 #endif /* KUI */
7401             }
7402 #else
7403             printw("(network)");
7404 #ifdef KUI
7405 #ifndef K95G
7406             KuiSetProperty(KUI_FILE_TRANSFER,
7407                            (long) CW_SPD,
7408                            (long) "(network)"
7409                            );
7410 #endif /* K95G */
7411 #endif /* KUI */
7412 #endif /* NETCONN */
7413         } else {
7414             if (speed < 0L)
7415               speed = ttgspd();
7416             if (speed > 0L) {
7417                 if (speed == 8880) {
7418                     printw("75/1200");
7419 #ifdef KUI
7420 #ifndef K95G
7421                     KuiSetProperty(KUI_FILE_TRANSFER,
7422                                    (long) CW_SPD,
7423                                    (long) "75/1200"
7424                                    );
7425 #endif /* K95G */
7426 #endif /* KUI */
7427                 } else {
7428                     char speedbuf[64] ;
7429                     sprintf(speedbuf, "%ld", speed);
7430                     printw("%s",speedbuf);
7431 #ifdef KUI
7432 #ifndef K95G
7433                     KuiSetProperty(KUI_FILE_TRANSFER,
7434                                    (long) CW_SPD,
7435                                    (long) speedbuf
7436                                    );
7437 #endif /* K95G */
7438 #endif /* KUI */
7439                 }
7440             } else {
7441                 printw("unknown");
7442 #ifdef KUI
7443 #ifndef K95G
7444                 KuiSetProperty(KUI_FILE_TRANSFER,
7445                                (long) CW_SPD,
7446                                (long) "(unknown)"
7447                                );
7448 #endif /* K95G */
7449 #endif /* KUI */
7450             }
7451         }
7452         move(CW_PAR,14);
7453         printw("Parity: %s",ftp ? "none" : parnam((char)parity));
7454 #ifdef KUI
7455 #ifndef K95G
7456         KuiSetProperty(KUI_FILE_TRANSFER,
7457                        (long) CW_PAR,
7458                        (long) parnam((char)parity)
7459                        );
7460 #endif /* K95G */
7461 #endif /* KUI */
7462 #ifdef CK_TIMERS
7463         if (/* rttflg && */ protocol == PROTO_K) {
7464             move(CW_TMO, 9); printw("RTT/Timeout:"); }
7465 #endif /* CK_TIMERS */
7466         move(CW_TYP,11); printw("File Type:");
7467         move(CW_SIZ,11); printw("File Size:");
7468         move(CW_PCD, 8);
7469         clrtoeol();
7470         pctlbl = (what & W_SEND);
7471         printw("%s:", pctlbl ? "Percent Done" : "Bytes So Far");
7472
7473 #ifdef XYZ_INTERNAL
7474         move(CW_BAR, 1);
7475         printw("%10s Protocol:", ftp ? "FTP" : ptab[protocol].p_name);
7476 #endif /* XYZ_INTERNAL */
7477 #ifdef CK_PCT_BAR
7478         if (thermometer) {
7479             oldpct = pct = 0;
7480             move(CW_BAR,22);
7481             printw("    ...10...20...30...40...50...60...70...80...90..100");
7482             move(CW_BAR,22+56);
7483         }
7484 #endif /* CK_PCT_BAR */
7485         move(CW_TR,  1); printw("Estimated Time Left:");
7486         move(CW_CP,  2); printw("Transfer Rate, CPS:");
7487         move(CW_WS,  8); printw("Window Slots:%s",
7488                                 ((protocol == PROTO_K) && !ftp) ?
7489                                 "" : " N/A"
7490                                 );
7491         move(CW_PT,  9); printw("Packet Type:");
7492         if (ftp || protocol != PROTO_K) {
7493             move(CW_PT,22);
7494             printw("%s", "N/A");
7495             move(CW_PC,  11); printw("I/O Count:");
7496             move(CW_PL,  10); printw("I/O Length:");
7497         } else {
7498             move(CW_PC,  8); printw("Packet Count:");
7499             move(CW_PL,  7); printw("Packet Length:");
7500         }
7501 #ifndef COMMENT
7502         move(CW_PR,  9); printw("Error Count:");
7503 #else
7504         move(CW_PR,  2); printw("Packet Retry Count:");
7505 #endif
7506 #ifdef COMMENT
7507         move(CW_PB,  2); printw("Packet Block Check:");
7508 #endif /* COMMENT */
7509         move(CW_ERR,10); printw("Last Error:");
7510         move(CW_MSG, 8); printw("Last Message:");
7511         if (xfrmsg) {
7512             move(CW_MSG, 22); printw("%s",xfrmsg);
7513             makestr(&xfrmsg,NULL);
7514         }
7515         move(CW_INT, 0);
7516         if (!xfrint) {
7517             printw("(Transfer interruption is disabled)");
7518         } else {
7519 #ifdef CK_NEED_SIG
7520             printw(
7521 "<%s>X to cancel file, <%s>Z to cancel group, <%s><CR> to resend last packet",
7522                    dbchr(escape), dbchr(escape), dbchr(escape)
7523                    );
7524             move(CW_INT + 1, 0);
7525             printw(
7526 "<%s>E to send Error packet, ^C to quit immediately, <%s>L to refresh screen.",
7527                    dbchr(escape), dbchr(escape)
7528                    );
7529 #else /* !CK_NEED_SIG */
7530             move(CW_INT, 0);
7531 #ifdef OS2
7532             if (protocol == PROTO_K) {
7533                 printw(
7534 "X to cancel file, Z to cancel group, <Enter> to resend last packet,"
7535                        );
7536             }
7537 #else /* !OS2 */
7538 #ifdef VMS                              /* In VMS avoid bottom line */
7539             printw(
7540 "X: Cancel this file; E: Cancel transfer; ^C: Quit now; ^W: Refresh screen."
7541                    );
7542 #else
7543             printw(
7544 "X to cancel file, Z to cancel group, <CR> to resend last packet,"
7545                    );
7546 #endif /* VMS */
7547 #endif /* OS2 */
7548
7549 #ifndef VMS
7550             move(CW_INT + 1, 0);
7551             if (protocol == PROTO_K) {
7552                 printw(
7553 "E to send Error packet, ^C to quit immediately, ^L to refresh screen."
7554                        );
7555             } else {
7556                 printw("^C to cancel file transfer.");
7557             }
7558 #endif /* VMS */
7559 #endif /* CK_NEED_SIG */
7560         }
7561         refresh();
7562         cendw = 0;
7563     }
7564     debug(F101,"SCREENC switch","",f);
7565     debug(F000,"SCREENC c","",c);
7566     debug(F101,"SCREENC n","",n);
7567
7568     len = strlen(s);                    /* Length of argument string */
7569     switch (f) {                        /* Handle our function code */
7570       case SCR_FN:                      /* Filename */
7571         oldpct = pct = 0L;              /* Reset percents */
7572 #ifdef GFTIMER
7573         gtv = (CKFLOAT) -1.0;
7574         /* oldgtv = (CKFLOAT) -1.0; */
7575 #else
7576         gtv = -1L;
7577         /* oldgtv = -1L; */
7578 #endif /* GFTIMER */
7579         oldwin = -1;
7580         fsiz = (CK_OFF_T)-1;            /* Invalidate previous file size */
7581         move(CW_PCD,22);                /* Erase percent done from last time */
7582 #ifdef KUI
7583 #ifndef K95G
7584         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) 0 );
7585         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_FFC, (long) 0 );
7586 #endif /* K95G */
7587 #endif /* KUI */
7588         clrtoeol();
7589         move(CW_SIZ,22);                /* Erase file size from last time */
7590 #ifdef KUI
7591 #ifndef K95G
7592         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) 0 );
7593 #endif /* K95G */
7594 #endif /* KUI */
7595         clrtoeol();
7596         move(CW_ERR,22);                /* And last error message */
7597 #ifdef KUI
7598 #ifndef K95G
7599         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) "" );
7600 #endif /* K95G */
7601 #endif /* KUI */
7602         clrtoeol();
7603 #ifdef COMMENT
7604 #ifdef STREAMING
7605         if (protocol == PROTO_K && streamok) {
7606             move(CW_BAR, 1);
7607 #ifdef XYZ_INTERNAL
7608             printw("   Kermit STREAMING:");
7609 #else
7610             printw("          STREAMING:");
7611 #endif /* XYZ_INTERNAL */
7612         }
7613 #endif /* STREAMING */
7614 #endif /* COMMENT */
7615
7616         if (what & W_SEND) {            /* If we're sending... */
7617 #ifdef NEWFTP
7618             if (what & W_FTP) {         /* FTP */
7619                 move(CW_NAM,10);
7620                 printw("   FTP PUT:");
7621             } else
7622 #endif /* NEWFTP */
7623 #ifdef CK_RESEND
7624             switch (sendmode) {         /* Kermit */
7625               case SM_RESEND:
7626                 move(CW_NAM,10);
7627                 printw(" RESENDING:");
7628                 break;
7629               default:
7630                 move(CW_NAM,10);
7631                 printw("   SENDING:");
7632                 break;
7633             }
7634 #else
7635             move(CW_NAM,10);
7636             printw("   SENDING:");
7637 #endif /* CK_RESEND */
7638
7639         } else if (what & W_RECV) {     /* If we're receiving... */
7640 #ifdef NEWFTP
7641             if (what & W_FTP) {         /* FTP */
7642                 move(CW_NAM,10);
7643                 printw("   FTP GET:");
7644             } else {
7645 #endif /* NEWFTP */
7646                 move(CW_NAM,10);
7647                 printw(" RECEIVING:");
7648 #ifdef NEWFTP
7649             }
7650         } else if (what == (W_FTP|W_FT_DELE)) {
7651                 move(CW_NAM,10);
7652                 printw("FTP DELETE:");
7653 #endif /* NEWFTP */
7654         } else {                        /* If we don't know... */
7655             move(CW_NAM,10);            /* (should never see this) */
7656             printw(" File Name:");
7657         }
7658         move(CW_NAM,22);                /* Display the filename */
7659         if (len > 57) {
7660             printw("%.55s..",s);
7661             len = 57;
7662         } else printw("%s",s);
7663 #ifdef KUI
7664 #ifndef K95G
7665         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
7666 #endif /* K95G */
7667 #endif /* KUI */
7668         q = len;                        /* Remember name length for later */
7669         clrtoeol();
7670         scrft();                        /* Display file type (can change) */
7671         refresh();
7672 #ifdef OS2
7673         SaveCmdMode(0, 0);
7674 #endif /* OS2 */
7675         return;
7676
7677       case SCR_AN:                      /* File as-name */
7678         if (q + len + 4 < 58) {         /* Will fit */
7679             move(CW_NAM, 22 + q);
7680             printw(" => %s",s);
7681 #ifdef KUI
7682 #ifndef K95G
7683             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
7684 #endif /* K95G */
7685 #endif /* KUI */
7686         } else {                        /* Too long */
7687             move(CW_NAM, 22);           /* Overwrite previous name */
7688             q = 0;
7689             if (len + 4 > 57) {                                 /* wg15 */
7690                 printw(" => %.51s..",s);                        /* wg15 */
7691                 len = 53;                                       /* wg15 */
7692             } else printw(" => %s",s);                          /* wg15 */
7693 #ifdef KUI
7694 #ifndef K95G
7695             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s  );
7696 #endif /* K95G */
7697 #endif /* KUI */
7698         }
7699         q += len + 4;                   /* Remember horizontal position */
7700         clrtoeol();
7701         refresh();
7702 #ifdef OS2
7703         SaveCmdMode(0, 0);
7704 #endif /* OS2 */
7705         return;
7706
7707       case SCR_FS:                      /* File size */
7708         fsiz = n;
7709         move(CW_SIZ,22);
7710         if (fsiz > (CK_OFF_T)-1) {
7711 #ifdef KUI
7712 #ifndef K95G
7713             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) n );
7714 #endif /* K95G */
7715 #endif /* KUI */
7716             printw("%s",ckfstoa(n));
7717         }
7718         if (fsiz == -2L) {
7719             printw("POSSIBLY EXCEEDS LOCAL FILE SIZE LIMIT");
7720         }
7721         clrtoeol();
7722 #ifdef COMMENT
7723         move(CW_PCD, 8);
7724         if (fsiz > (CK_OFF_T)-1) {      /* Put up percent label */
7725             pctlbl = 1;
7726             clrtoeol();
7727             printw("Percent Done:");
7728         }
7729 #else
7730         move(CW_PCD, 8);
7731         clrtoeol();
7732         if (fsiz > (CK_OFF_T)-1) {      /* Put up percent label */
7733             pctlbl = 1;
7734             printw("Percent Done:");
7735         } else {
7736             pctlbl = 0;
7737             printw("Bytes So Far:");
7738         }
7739 #endif /* COMMENT */
7740         clrtoeol();
7741         scrft();                        /* File type */
7742         refresh();
7743 #ifdef OS2
7744         SaveCmdMode(0, 0);
7745 #endif /* OS2 */
7746         return;
7747
7748       case SCR_PT:                      /* Packet type or pseudotype */
7749         if (spackets < 5) {
7750             extern int sysindex;
7751             extern struct sysdata sysidlist[];
7752             /* Things that won't change after the 4th packet */
7753             move(CW_PAR,22);
7754             printw("%s",parnam((char)parity));
7755 #ifdef KUI
7756 #ifndef K95G
7757             KuiSetProperty( KUI_FILE_TRANSFER,
7758                            (long) CW_PAR,
7759                            (long) parnam((char)parity)
7760                            );
7761 #endif /* K95G */
7762 #endif /* KUI */
7763             clrtoeol();
7764 #ifdef COMMENT
7765             move(CW_PB, 22);            /* Block check on this packet */
7766             if (bctu == 4)
7767               printw("B");
7768             else
7769               printw("%d",bctu);
7770             clrtoeol();
7771 #endif /* COMMENT */
7772             if (
7773 #ifdef NEWFTP
7774                 (ftp && (spackets == 1 || rpackets == 1)) ||
7775 #endif /* NEWFTP */
7776                 spackets == 4
7777                 ) {
7778                 move(CW_LIN,8);
7779                 if (
7780 #ifdef NEWFTP
7781                     ftp ||
7782 #endif /* NEWFTP */
7783                     ((protocol == PROTO_K) && (sysindex > -1))
7784                     ) {
7785                     if (net) {
7786                         move(CW_LIN,8);
7787                         printw("Network Host: %s (%s)",
7788 #ifdef NEWFTP
7789                                ftp ? (ftp_host ? ftp_host : "") :
7790 #endif /* NEWFTP */
7791                                ttname,
7792 #ifdef NEWFTP
7793                                ftp ? ftp_srvtyp :
7794 #endif /* NEWFTP */
7795                                sysidlist[sysindex].sid_name
7796                                );
7797                     } else {
7798                         move(CW_LIN,0);
7799                         printw("Communication Device: %s (remote host is %s)",
7800                              ttname,
7801                              sysidlist[sysindex].sid_name
7802                              );
7803                     }
7804                     clrtoeol();
7805                 }
7806             }
7807         }
7808 #ifdef CK_TIMERS
7809         if (/* rttflg && */ protocol == PROTO_K) {
7810             long xx;
7811             if (
7812 #ifdef STREAMING
7813                 streaming && oldwin != -2
7814 #else
7815                 0
7816 #endif /* STREAMING */
7817                 ) {
7818                 move(CW_TMO, 22);
7819                 printw("00 / 00");
7820                 clrtoeol();
7821             } else {
7822                 xx = (rttdelay + 500) / 1000;
7823                 if (xx != oldrtt || rcvtimo != oldtim) {
7824                     move(CW_TMO, 22);
7825                     printw("%02ld / %02d", xx, rcvtimo);
7826                     oldrtt = xx;
7827                     oldtim = rcvtimo;
7828                     clrtoeol();
7829                 }
7830             }
7831         }
7832 #endif /* CK_TIMERS */
7833
7834         x = (what & W_RECV) ?          /* Packet length */
7835           rpktl+(protocol==PROTO_K?1:0) :
7836             spktl;
7837         if (x != oldlen) {              /* But only if it changed. */
7838             move(CW_PL, 22);
7839             printw("%d",x);
7840 #ifdef KUI
7841 #ifndef K95G
7842             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PL, (long) x );
7843 #endif /* K95G */
7844 #endif /* KUI */
7845             clrtoeol();
7846             oldlen = x;
7847         }
7848         move(CW_PC, 22);                /* Packet count (always). */
7849
7850         printw("%d", (what & W_RECV) ? rpackets : spackets);
7851 #ifdef KUI
7852 #ifndef K95G
7853         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PC, (long) spackets );
7854 #endif /* K95G */
7855 #endif /* KUI */
7856         clrtoeol();
7857
7858         if (protocol == PROTO_K && !ftp) { /* Window slots */
7859             char ws[16];
7860             int flag;
7861             flag = 0;
7862 #ifdef STREAMING
7863             if (streaming) {
7864                 if (oldwin != -2) {
7865                     sprintf(ws,"STREAMING");
7866                     flag = 1;
7867                     oldwin = -2;
7868                 }
7869             } else
7870 #endif /* STREAMING */
7871               if (wcur != oldwin) {
7872                   sprintf(ws, "%d of %d", wcur < 1 ? 1 : wcur, wslotn);
7873                   flag = 1;
7874                   oldwin = wcur;
7875               }
7876             if (flag) {
7877                 move(CW_WS, 22);
7878                 printw("%s", ws);
7879                 clrtoeol();
7880 #ifdef KUI
7881 #ifndef K95G
7882                 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_WS, (long) ws );
7883 #endif /* K95G */
7884 #endif /* KUI */
7885             }
7886         }
7887         errors = retrans + crunched + timeouts;
7888         if (errors != oldtry) {         /* Retry count, if changed */
7889             move(CW_PR, 22);
7890             printw("%d",errors);
7891 #ifdef KUI
7892 #ifndef K95G
7893             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PR, (long) errors );
7894 #endif /* K95G */
7895 #endif /* KUI */
7896             clrtoeol();
7897             oldtry = errors;
7898         }
7899         /* Sender's packet type */
7900         if (!ftp && (c != oldtyp && c != 'Y' && c != 'N')) {
7901             char type[2];
7902             sprintf(type, "%c",c);
7903             move(CW_PT,22);
7904             printw("%s", type);
7905 #ifdef KUI
7906 #ifndef K95G
7907             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PT, (long) type );
7908 #endif /* K95G */
7909 #endif /* KUI */
7910             clrtoeol();
7911             oldtyp = c;
7912         }
7913         switch (c) {                    /* Now handle specific packet types */
7914           case 'S':                     /* Beginning of transfer */
7915             fcnt = fbyt = 0L;           /* Clear counters */
7916 #ifdef GFTIMER
7917             gtv = -1.0;
7918 #else /* GFTIMER */
7919             gtv = -1L;                  /* And old/new things... */
7920 #endif /* GFTIMER */
7921             oldpct = pct = 0L;
7922             break;
7923
7924           case 'Z':                     /* or EOF */
7925             debug(F101,"screenc SCR_PT Z pktnum","",n);
7926             debug(F101,"screenc SCR_PT Z oldpct","",oldpct);
7927             debug(F101,"screenc SCR_PT Z pct","",pct);
7928           case 'D':                     /* Data packet */
7929             if (fsiz > 0L) {            /* Show percent done if known */
7930                 oldpct = pct;           /* Remember previous percent */
7931                 howfar = ffc;
7932 #ifdef CK_RESEND
7933                 if (what & W_SEND)      /* Account for PSEND or RESEND */
7934                   howfar += sendstart;
7935                 else if (what & W_RECV)
7936                   howfar += rs_len;
7937 #endif /* CK_RESEND */
7938                 /* Percent done, to be displayed... */
7939                 if (c == 'Z') {
7940                     if (!discard && !cxseen && !czseen) pct = 100L;
7941                 } else
7942                   pct = (fsiz > 99L) ? (howfar / (fsiz / 100L)) : 0L;
7943                 if (pct > 100L ||       /* Allow for expansion and */
7944                    (oldpct == 99L && pct < 0L)) /* other boundary conditions */
7945                   pct = 100L;
7946                 if (pct != oldpct)      /* Only do this 100 times per file */
7947                   updpct(oldpct, pct);
7948             } else {
7949                 move(CW_PCD,22);
7950                 printw("%s", ckfstoa(ffc));
7951             }
7952 #ifdef KUI
7953 #ifndef K95G
7954             KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) howfar);
7955 #endif /* K95G */
7956 #endif /* KUI */
7957             cps = shocps((int) pct, fsiz, howfar);
7958             /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
7959             break;
7960
7961           case '%':                     /* Timeouts, retransmissions */
7962             cps = shocps((int) pct, fsiz, howfar);
7963             /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
7964
7965             errors = retrans + crunched + timeouts;
7966             if (errors != oldtry) {     /* Error count, if changed */
7967                 move(CW_PR, 22);
7968                 printw("%d",errors);
7969                 clrtoeol();
7970 #ifdef KUI
7971 #ifndef K95G
7972                 KuiSetProperty(KUI_FILE_TRANSFER,
7973                                (long) CW_PR, (long) errors
7974                                );
7975 #endif /* K95G */
7976 #endif /* KUI */
7977                 }
7978                 oldtry = errors;
7979                 if (s) if (*s) {
7980                     move(CW_ERR,22);
7981                     printw("%s",s);
7982                     clrtoeol();
7983 #ifdef KUI
7984 #ifndef K95G
7985                     KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_ERR, (long) s);
7986 #endif /* K95G */
7987 #endif /* KUI */
7988             }
7989             break;
7990
7991           case 'E':                     /* Error packet */
7992 #ifdef COMMENT
7993             move(CW_ERR,22);            /* Print its data field */
7994             if (*s) {
7995                 printw("%s",s);
7996 #ifdef KUI
7997 #ifndef K95G
7998                 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
7999 #endif /* K95G */
8000 #endif /* KUI */
8001             }
8002             clrtoeol();
8003 #endif /* COMMENT */
8004             fcnt = fbyt = 0L;           /* So no bytes for this file */
8005             break;
8006           case 'Q':                     /* Crunched packet */
8007             cps = shocps((int) pct, fsiz, howfar);
8008             /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8009             move(CW_ERR,22);
8010             printw("Damaged Packet");
8011 #ifdef KUI
8012 #ifndef K95G
8013             KuiSetProperty(KUI_FILE_TRANSFER,
8014                            (long) CW_ERR,
8015                            (long) "Damaged Packet"
8016                            );
8017 #endif /* K95G */
8018 #endif /* KUI */
8019             clrtoeol();
8020             break;
8021           case 'q':                     /* Ctrl-C or connection lost */
8022             move(CW_MSG,22);
8023             clrtoeol();
8024             if (!s) s = "";
8025             printw(*s ? s : "User interruption or connection lost");
8026 #ifdef KUI
8027 #ifndef K95G
8028             KuiSetProperty(KUI_FILE_TRANSFER,
8029                            (long) CW_MSG,
8030                            (long) s
8031                            );
8032 #endif /* K95G */
8033 #endif /* KUI */
8034             break;
8035           case 'T':                     /* Timeout */
8036             cps = shocps((int) pct, fsiz, howfar);
8037             /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8038             move(CW_ERR,22);
8039             printw("Timeout %d sec",rcvtimo);
8040 #ifdef KUI
8041 #ifndef K95G
8042             KuiSetProperty(KUI_FILE_TRANSFER,
8043                            (long) CW_ERR,
8044                            (long) "Timeout"
8045                            );
8046 #endif /* K95G */
8047 #endif /* KUI */
8048             clrtoeol();
8049             errors = retrans + crunched + timeouts;
8050             if (errors != oldtry) {     /* Error count, if changed */
8051                 move(CW_PR, 22);
8052                 printw("%d",errors);
8053 #ifdef KUI
8054 #ifndef K95G
8055                 KuiSetProperty(KUI_FILE_TRANSFER,
8056                                (long) CW_PR, (long) errors
8057                                );
8058 #endif /* K95G */
8059 #endif /* KUI */
8060                 clrtoeol();
8061                 oldtry = errors;
8062             }
8063             break;
8064           default:                      /* Others, do nothing */
8065             break;
8066         }
8067         refresh();
8068 #ifdef OS2
8069         SaveCmdMode(0, 0);
8070 #endif /* OS2 */
8071         return;
8072
8073       case SCR_ST:                      /* File transfer status */
8074         debug(F101,"screenc SCR_ST c","",c);
8075         debug(F101,"screenc SCR_ST success","",success);
8076         debug(F101,"screenc SCR_ST cxseen","",cxseen);
8077 #ifdef COMMENT
8078         move(CW_PCD,22);                /* Update percent done */
8079         if (c == ST_OK) {               /* OK, print 100 % */
8080             if (pctlbl)
8081               updpct(oldpct,100);
8082             else
8083               printw("%s", ckfstoa(ffc));
8084 #ifdef KUI
8085 #ifndef K95G
8086             KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8087 #endif /* K95G */
8088 #endif /* KUI */
8089             pct = 100;
8090             oldpct = 0;
8091         } else if (fsiz > 0L)           /* Not OK, update final percent */
8092 /*
8093   The else part writes all over the screen -- howfar and/or fsiz have
8094   been reset as a consequence of the not-OKness of the transfer.
8095 */
8096           if (pctlbl)
8097             updpct(oldpct, (howfar * 100L) / fsiz);
8098         clrtoeol();
8099 #else
8100         if (c == ST_OK) {               /* OK, print 100 % */
8101             move(CW_PCD,22);            /* Update percent done */
8102             if (pctlbl) {
8103                 if (oldpct == 0)        /* Switching from "bytes so far" */
8104                   clrtoeol();           /* to "percent done"... */
8105                 updpct(oldpct,100);
8106             } else
8107               printw("%s", ckfstoa(ffc));
8108 #ifdef KUI
8109 #ifndef K95G
8110             KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8111 #endif /* K95G */
8112 #endif /* KUI */
8113 #ifdef COMMENT
8114             pct = 100;
8115             oldpct = 0;
8116 #endif /* COMMENT */
8117             clrtoeol();
8118         }
8119 #endif /* COMMENT */
8120
8121 #ifdef COMMENT
8122 /* No, leave it there so they can read it */
8123         move(CW_MSG,22);                /* Remove any previous message */
8124 #ifdef KUI
8125 #ifndef K95G
8126         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_MSG, (long) "" );
8127 #endif /* K95G */
8128 #endif /* KUI */
8129         clrtoeol(); refresh();
8130 #endif /* COMMENT */
8131
8132         move(CW_TR, 22);
8133 #ifdef KUI
8134 #ifndef K95G
8135         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "" );
8136 #endif /* K95G */
8137 #endif /* KUI */
8138         clrtoeol(); refresh();
8139
8140         switch (c) {                    /* Print new status message */
8141           case ST_OK:                   /* Transfer OK */
8142             fcnt++;                     /* Count this file */
8143             if (what == (W_FTP|W_FT_DELE)) {
8144                 move(CW_MSG,22);
8145                 clrtoeol();
8146                 printw("Delete OK");
8147             } else {
8148                 fbyt += ffc;
8149                 move(CW_MSG,22);
8150                 clrtoeol();
8151                 printw("Transfer OK");
8152             }
8153 #ifdef KUI
8154 #ifndef K95G
8155             KuiSetProperty(KUI_FILE_TRANSFER,
8156                            (long) CW_MSG,
8157                            (long) "Transfer OK"
8158                            );
8159 #endif /* K95G */
8160 #endif /* KUI */
8161             clrtoeol(); refresh();
8162             return;
8163
8164           case ST_DISC:                 /* Discarded */
8165             move(CW_ERR,22);
8166             printw("File discarded");
8167 #ifdef KUI
8168 #ifndef K95G
8169             KuiSetProperty(KUI_FILE_TRANSFER,
8170                            (long) CW_ERR,
8171                            (long) "File discarded"
8172                            );
8173 #endif /* K95G */
8174 #endif /* KUI */
8175 #ifdef COMMENT
8176             pct = oldpct = 0;
8177 #endif /* COMMENT */
8178             clrtoeol(); refresh();
8179             return;
8180
8181           case ST_INT:                  /* Interrupted */
8182             move(CW_ERR,22);
8183             printw("Transfer interrupted");
8184 #ifdef KUI
8185 #ifndef K95G
8186             KuiSetProperty(KUI_FILE_TRANSFER,
8187                            (long) CW_ERR,
8188                            (long) "Transfer interrupted"
8189                            );
8190 #endif /* K95G */
8191 #endif /* KUI */
8192 #ifdef COMMENT
8193             pct = oldpct = 0;
8194 #endif /* COMMENT */
8195             clrtoeol(); refresh();
8196             return;
8197
8198           case ST_SKIP:                 /* Skipped */
8199             move(CW_ERR,22);
8200             if (n > 0 && n < nskreason)
8201               printw("File skipped (%s)",skreason[n]);
8202             else
8203               printw("File skipped");
8204 #ifdef KUI
8205 #ifndef K95G
8206             KuiSetProperty(KUI_FILE_TRANSFER,
8207                            (long) CW_ERR,
8208                            (long) "File skipped"
8209                            );
8210 #endif /* K95G */
8211 #endif /* KUI */
8212 #ifdef COMMENT
8213             pct = oldpct = 0;
8214 #endif /* COMMENT */
8215             clrtoeol(); refresh();
8216             return;
8217
8218           case ST_ERR:                  /* Error message */
8219             move(CW_ERR,22);
8220             if (!s) s = (char *)epktmsg;
8221             printw("%s",s);
8222 #ifdef KUI
8223 #ifndef K95G
8224             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
8225 #endif /* K95G */
8226 #endif /* KUI */
8227 #ifdef COMMENT
8228             pct = oldpct = 0;
8229 #endif /* COMMENT */
8230             clrtoeol(); refresh();
8231             return;
8232
8233           case ST_REFU:                 /* Refused */
8234             move(CW_ERR,22);
8235             if (*s) {
8236                 char errbuf[64] ;
8237                 sprintf( errbuf, "Refused, %s", s ) ;
8238                 printw("%s", errbuf);
8239 #ifdef KUI
8240 #ifndef K95G
8241                 KuiSetProperty(KUI_FILE_TRANSFER,(long) CW_ERR,(long) errbuf);
8242 #endif /* K95G */
8243 #endif /* KUI */
8244             } else {
8245                 printw("Refused");
8246 #ifdef KUI
8247 #ifndef K95G
8248                 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Refused");
8249 #endif /* K95G */
8250 #endif /* KUI */
8251             }
8252 #ifdef COMMENT
8253             pct = oldpct = 0;
8254 #endif /* COMMENT */
8255             clrtoeol(); refresh();
8256             return;
8257
8258           case ST_INC:
8259             move(CW_ERR,22);
8260             printw("Incomplete");
8261 #ifdef KUI
8262 #ifndef K95G
8263             KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Incomplete");
8264 #endif /* K95G */
8265 #endif /* KUI */
8266 #ifdef COMMENT
8267             pct = oldpct = 0;
8268 #endif /* COMMENT */
8269             clrtoeol(); refresh();
8270             return;
8271
8272           case ST_MSG:
8273             move(CW_MSG,22);
8274             printw("%s",s);
8275 #ifdef KUI
8276 #ifndef K95G
8277             KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_MSG,(long)s);
8278 #endif /* K95G */
8279 #endif /* KUI */
8280             clrtoeol(); refresh();
8281             return;
8282
8283           default:                      /* Bad call */
8284             move(CW_ERR,22);
8285             printw("*** screen() called with bad status ***");
8286 #ifdef KUI
8287 #ifndef K95G
8288             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR,
8289                        (long) "*** screen() called with bad status ***" );
8290 #endif /* K95G */
8291 #endif /* KUI */
8292             clrtoeol(); refresh(); return;
8293         }
8294
8295       case SCR_TC: {                    /* Transaction complete */
8296           char msgbuf[128];
8297           move(CW_CP,22);               /* Overall transfer rate */
8298 #ifdef KUI
8299 #ifndef K95G
8300           KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, tfcps);
8301 #endif /* K95G */
8302 #endif /* KUI */
8303           printw("%s", ckfstoa(tfcps));
8304           clrtoeol();
8305           if (success) {
8306               move(CW_MSG,22);          /* Print statistics in message line */
8307               clrtoeol();
8308           }
8309           if (success) {
8310               sprintf(msgbuf,
8311                       "SUCCESS.  Files: %ld, Bytes: %s, %ld CPS",
8312                       filcnt - filrej,
8313                       ckfstoa(fbyt),
8314                       tfcps
8315                       );
8316               printw("%s", msgbuf);
8317 #ifdef KUI
8318 #ifndef K95G
8319               KuiSetProperty(KUI_FILE_TRANSFER,
8320                              (long) CW_MSG,
8321                              (long) msgbuf
8322                              );
8323 #endif /* K95G */
8324 #endif /* KUI */
8325               clrtoeol();
8326
8327           }
8328           move(CW_TR, 1);
8329           printw("       Elapsed Time: %s",hhmmss((long)
8330 #ifdef GFTIMER
8331                                                   (fptsecs + 0.5)
8332 #else
8333                                                   tsecs
8334 #endif /* GFTIMER */
8335                                                    ));
8336 #ifdef KUI
8337 #ifndef K95G
8338           KuiSetProperty(KUI_FILE_TRANSFER,
8339                          (long) CW_TR,
8340                          (long) hhmmss((long)
8341 #ifdef GFTIMER
8342                                        (fptsecs + 0.5)
8343 #else
8344                                        tsecs
8345 #endif /* GFTIMER */
8346                                        ));
8347 #endif /* K95G */
8348 #endif /* KUI */
8349           clrtoeol();
8350           move(23,0); clrtoeol();       /* Clear instructions lines */
8351           move(22,0); clrtoeol();       /* to make room for prompt. */
8352           refresh();
8353
8354 #ifdef GFTIMER
8355           oldgtv = (CKFLOAT) -1.0;
8356 #else
8357           oldgtv = -1L;
8358 #endif /* GFTIMER */
8359
8360 #ifndef VMSCURSE
8361           debug(F100,"screenc endwin A","",0);
8362           endwin();
8363 #ifdef COMMENT
8364 /*
8365   Why and when was this call to conres() added?  It makes no sense,
8366   and it breaks echoing on Solaris 8.
8367 */
8368 #ifdef SOLARIS
8369           conres();
8370 #endif /* SOLARIS */
8371 #endif /* COMMENT */
8372 #endif /* VMSCURSE */
8373
8374 #ifdef COMMENT
8375           pct = 100; oldpct = 0;        /* Reset these for next time. */
8376 #endif /* COMMENT */
8377           oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
8378           oldtim = -1;
8379           cendw = 1;
8380           if (xfrbel) bleep(BP_NOTE);   /* Close window, then beep. */
8381 #ifdef UNIX
8382           fflush(stdout);
8383 #endif /* UNIX */
8384           ft_win = 0;                   /* Window closed. */
8385           return;
8386       }
8387       case SCR_EM:                      /* Error packet (fatal) */
8388         move (CW_ERR,22);
8389         printw("FAILURE: %s",s);
8390 #ifdef KUI
8391 #ifndef K95G
8392         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
8393 #endif /* K95G */
8394 #endif /* KUI */
8395         if (xfrbel) bleep(BP_FAIL);
8396 #ifdef COMMENT
8397         pct = oldpct = 0;
8398 #endif /* COMMENT */
8399         clrtoeol(); refresh(); return;
8400
8401       case SCR_QE:                      /* Quantity equals */
8402       case SCR_TU:                      /* Undelimited text */
8403       case SCR_TN:                      /* Text delimited at start */
8404       case SCR_TZ:                      /* Text delimited at end */
8405         return;                         /* (ignored in fullscreen display) */
8406
8407       case SCR_MS:                      /* Message from Kermit partner */
8408         move(CW_MSG,22);
8409         printw("%s",s);
8410         clrtoeol(); refresh(); return;
8411
8412       case SCR_XD:                      /* X-packet data */
8413         pct = oldpct = 0;
8414         move(CW_NAM,22);
8415         printw("%s",s);
8416 #ifdef KUI
8417 #ifndef K95G
8418         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
8419 #endif /* K95G */
8420 #endif /* KUI */
8421         clrtoeol(); refresh(); return;
8422
8423       case SCR_CW:                      /* Close Window */
8424         clrtoeol(); move(23,0); clrtoeol(); move(22,0); clrtoeol();
8425         refresh();
8426 #ifdef COMMENT
8427         pct = 100; oldpct = 0;          /* Reset these for next time. */
8428 #endif /* COMMENT */
8429         oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
8430         oldtim = -1;
8431
8432 #ifndef VMSCURSE
8433         debug(F100,"screenc endwin B","",0);
8434         endwin();
8435 #endif /* VMSCURSE */
8436         ft_win = 0;                     /* Flag that window is closed. */
8437         cendw = 1; return;
8438
8439       case SCR_CD:                      /* Display current directory */
8440         move(CW_DIR,22);
8441          printw("%s", s);
8442 #ifdef KUI
8443 #ifndef K95G
8444         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) s );
8445 #endif /* K95G */
8446 #endif /* KUI */
8447         clrtoeol();
8448         refresh();
8449 #ifdef OS2
8450         SaveCmdMode(0, 0);
8451 #endif /* OS2 */
8452         return;
8453
8454       default:                          /* Bad call */
8455         move (CW_ERR,22);
8456 #ifdef KUI
8457 #ifndef K95G
8458         KuiSetProperty(KUI_FILE_TRANSFER,
8459                        (long) CW_ERR,
8460                        (long) "*** screen() called with bad function code ***"
8461                        );
8462 #endif /* K95G */
8463 #endif /* KUI */
8464         printw("*** screen() called with bad function code ***");
8465         clrtoeol(); refresh(); return;
8466     }
8467 }
8468 #endif /* CK_CURSES */
8469
8470 #ifdef KUI
8471 #ifdef CK_ANSIC
8472 void
8473 screeng(int f, char c,long n,char *s)
8474 #else
8475 CKVOID
8476 screeng(f,c,n,s)
8477 int f;          /* argument descriptor */
8478 char c;         /* a character or small integer */
8479 long n;         /* a long integer */
8480 char *s;        /* a string */
8481 #endif /* CK_ANSIC */
8482 /* screeng() */ {
8483 #ifdef CK_SSL
8484     extern int tls_active_flag, ssl_active_flag;
8485 #endif /* CK_SSL */
8486 #ifdef RLOGCODE
8487     extern int ttnproto;
8488 #endif /* RLOGCODE */
8489     static int q = 0;
8490     static CK_OFF_T fsiz = (CK_OFF_T)-1; /* Copy of file size */
8491     static long fcnt = 0L;    /* Number of files transferred */
8492     static long fbyt = 0L;    /* Total file bytes of all files transferred */
8493     static CK_OFF_T howfar = (CK_OFF_T)0; /* How much of file xfer'd so far */
8494     static int  pctlbl = 0L;  /* Percent done vs Bytes so far */
8495     long cps = 0L;
8496
8497     int net = 0;
8498     int xnet = 0;
8499     int ftp = 0;
8500     int len;                            /* Length of string */
8501     int errors = 0;                     /* Error counter */
8502     int x;                              /* Worker */
8503
8504     debug(F101,"screeng cinit","",cinit);
8505     debug(F101,"screeng cendw","",cendw);
8506
8507     if (!s) s = "";                     /* Always do this. */
8508
8509     ftp = (what & W_FTP) ? 1 : 0;       /* FTP or Kermit */
8510     net = network || ftp;
8511     xnet = ftp ? 1 : nettype;           /* NET_TCPB == 1 */
8512
8513     if (cinit == 0 || cendw > 0) {      /* Handle borderline cases... */
8514         if (f == SCR_CW) {              /* Close window, but it's not open */
8515             ft_win = 0;
8516             return;
8517         }
8518         debug(F111,"screeng A",s,f);
8519         if (f == SCR_EM ||
8520            (f == SCR_PT && c == 'E')) { /* Fatal error before window open */
8521             conoll(""); conoc('?'); conoll(s); return; /* Regular display */
8522         }
8523     }
8524     if (cinit == 0) {                   /* Only call initscr() once */
8525         /* Check these now -- if they are defined but not numeric */
8526         /* they can crash curses */
8527         cendw = 1;                      /* New window needs repainting */
8528         debug(F100,"screeng calling initscr","",0);
8529         initscr();                      /* Initialize curses. */
8530         debug(F100,"screeng initscr ok","",0);
8531         cinit++;                        /* Remember curses was initialized. */
8532     }
8533     ft_win = 1;                         /* Window is open */
8534     if (repaint) {
8535 #ifdef CK_WREFRESH
8536 /*
8537   This totally repaints the screen, just what we want, but we can only
8538   do this with real curses, and then only if clearok() and wrefresh() are
8539   provided in the curses library.
8540 */
8541         RestoreCmdMode();
8542 #else  /* No CK_WREFRESH */
8543 /*
8544   Kermit's do-it-yourself method, works with all types of fullscreen
8545   support, but does not repaint all the fields.  For example, the filename
8546   is lost, because it arrives at a certain time and never comes again, and
8547   Kermit presently does not save it anywhere.  Making this method work for
8548   all fields would be a rather major recoding task, duplicating what curses
8549   already does, and would add a lot of complexity and storage space.
8550 */
8551         cendw = 1;
8552 #endif /* CK_WREFRESH */
8553         repaint = 0;
8554     }
8555     if (cendw) {                        /* endwin() was called previously */
8556         debug(F100,"screeng setup ok","",0);
8557         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) zgtdir() );
8558         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_LIN,
8559                         (long) (
8560 #ifdef NEWFTP
8561                                 ftp ? (ftp_host ? ftp_host : "(unknown)") :
8562 #endif /* NEWFTP */
8563                                 ttname) );
8564
8565         if (net) {
8566 #ifdef NETCONN
8567             int secure = 0;
8568             char * xname;
8569             if (xnet > nnetname)
8570               xname = "[ERROR]";
8571             else
8572               xname = netname[xnet];
8573 #ifdef NEWFTP
8574             if (ftp) {
8575                 if (ftpissecure())
8576                   secure = 1;
8577             } else
8578 #endif /* NEWFTP */
8579               if (0
8580 #ifdef SSHBUILTIN
8581                 || IS_SSH()
8582 #endif /* SSHBUILTIN */
8583 #ifdef CK_ENCRYPTION
8584                 || ck_tn_encrypting() && ck_tn_decrypting()
8585 #endif /* CK_ENCRYPTION */
8586 #ifdef CK_SSL
8587                 || tls_active_flag || ssl_active_flag
8588 #endif /* CK_SSL */
8589 #ifdef RLOGCODE
8590 #ifdef CK_KERBEROS
8591 #ifdef CK_ENCRYPTION
8592                 || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
8593 #endif /* CK_ENCRYPTION */
8594 #endif /* CK_KERBEROS */
8595 #endif /* RLOGCODE */
8596                  ) {
8597                 secure = 1;
8598             }
8599             if (secure) {
8600                 char buf[30];
8601                 sprintf(buf,"%s (SECURE)",xname);
8602                 KuiSetProperty(KUI_FILE_TRANSFER,
8603                                (long) CW_SPD,
8604                                (long) buf
8605                                );
8606             } else {
8607                 KuiSetProperty(KUI_FILE_TRANSFER,
8608                                (long) CW_SPD,
8609                                (long) xname
8610                                );
8611             }
8612 #else
8613             KuiSetProperty(KUI_FILE_TRANSFER,
8614                            (long) CW_SPD,
8615                            (long) "(network)"
8616                            );
8617 #endif /* NETCONN */
8618         } else {
8619             if (speed < 0L)
8620               speed = ttgspd();
8621             if (speed > 0L) {
8622                 if (speed == 8880) {
8623                     KuiSetProperty(KUI_FILE_TRANSFER,
8624                                    (long) CW_SPD,
8625                                    (long) "75/1200"
8626                                    );
8627                 } else {
8628                     char speedbuf[64] ;
8629                     sprintf(speedbuf, "%ld", speed);
8630                     KuiSetProperty(KUI_FILE_TRANSFER,
8631                                    (long) CW_SPD,
8632                                    (long) speedbuf
8633                                    );
8634                 }
8635             } else {
8636                 KuiSetProperty(KUI_FILE_TRANSFER,
8637                                (long) CW_SPD,
8638                                (long) "(unknown)"
8639                                );
8640             }
8641         }
8642         KuiSetProperty(KUI_FILE_TRANSFER,
8643                        (long) CW_PAR,
8644                        (long) parnam((char)parity)
8645                        );
8646         pctlbl = (what & W_SEND);
8647         cendw = 0;
8648     }
8649     debug(F101,"SCREENC switch","",f);
8650     debug(F000,"SCREENC c","",c);
8651     debug(F101,"SCREENC n","",n);
8652
8653     len = strlen(s);                    /* Length of argument string */
8654     switch (f) {                        /* Handle our function code */
8655       case SCR_FN:                      /* Filename */
8656         oldpct = pct = 0L;              /* Reset percents */
8657 #ifdef GFTIMER
8658         gtv = (CKFLOAT) -1.0;
8659         /* oldgtv = (CKFLOAT) -1.0; */
8660 #else
8661         gtv = -1L;
8662         /* oldgtv = -1L; */
8663 #endif /* GFTIMER */
8664         oldwin = -1;
8665         fsiz = (CK_OFF_T)-1L;           /* Invalidate previous file size */
8666         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) 0 );
8667         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_FFC, (long) 0 );
8668         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) 0 );
8669         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) "" );
8670
8671         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
8672         q = len;                        /* Remember name length for later */
8673         scrft();                        /* Display file type (can change) */
8674 #ifdef OS2
8675         SaveCmdMode(0, 0);
8676 #endif /* OS2 */
8677         return;
8678
8679       case SCR_AN:                      /* File as-name */
8680         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
8681 #ifdef OS2
8682         SaveCmdMode(0, 0);
8683 #endif /* OS2 */
8684         return;
8685
8686       case SCR_FS:                      /* File size */
8687         fsiz = n;
8688         if (fsiz > (CK_OFF_T)-1) {
8689             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) n );
8690         }
8691         if (fsiz > (CK_OFF_T)-1) {      /* Put up percent label */
8692             pctlbl = 1;
8693         } else {
8694             pctlbl = 0;
8695         }
8696         scrft();                        /* File type */
8697 #ifdef OS2
8698         SaveCmdMode(0, 0);
8699 #endif /* OS2 */
8700         return;
8701
8702       case SCR_PT:                      /* Packet type or pseudotype */
8703         if (spackets < 5) {
8704             extern int sysindex;
8705             extern struct sysdata sysidlist[];
8706             /* Things that won't change after the 4th packet */
8707             KuiSetProperty( KUI_FILE_TRANSFER,
8708                            (long) CW_PAR,
8709                            (long) parnam((char)parity)
8710                            );
8711             if (
8712 #ifdef NEWFTP
8713                 (ftp && (spackets == 1 || rpackets == 1)) ||
8714 #endif /* NEWFTP */
8715                 spackets == 4
8716                 ) {
8717                 if (
8718 #ifdef NEWFTP
8719                     ftp ||
8720 #endif /* NEWFTP */
8721                     ((protocol == PROTO_K) && (sysindex > -1))
8722                     ) {
8723                     char msgbuf[128];
8724                     if (net) {
8725                         sprintf(msgbuf,"Network Host: %s (%s)",
8726 #ifdef NEWFTP
8727                                ftp ? (ftp_host ? ftp_host : "") :
8728 #endif /* NEWFTP */
8729                                ttname,
8730 #ifdef NEWFTP
8731                                ftp ? ftp_srvtyp :
8732 #endif /* NEWFTP */
8733                                sysidlist[sysindex].sid_name
8734                                );
8735                     } else {
8736                         sprintf(msgbuf,
8737                                 "Communication Device: %s (remote host is %s)",
8738                                 ttname,
8739                                 sysidlist[sysindex].sid_name
8740                                 );
8741                     }
8742                     KuiSetProperty( KUI_FILE_TRANSFER,
8743                                     (long) CW_LIN,
8744                                     (long) msgbuf
8745                                     );
8746                 }
8747             }
8748         }
8749 #ifdef CK_TIMERS
8750         if (/* rttflg && */ protocol == PROTO_K) {
8751             long xx;
8752             if (
8753 #ifdef STREAMING
8754                 streaming && oldwin != -2
8755 #else
8756                 0
8757 #endif /* STREAMING */
8758                 ) {
8759                 char msgbuf[64];
8760                 sprintf(msgbuf,"00 / 00");
8761                 KuiSetProperty( KUI_FILE_TRANSFER,
8762                                 (long) CW_TMO,
8763                                 (long) msgbuf
8764                                 );
8765             } else {
8766                 xx = (rttdelay + 500) / 1000;
8767                 if (xx != oldrtt || rcvtimo != oldtim) {
8768                     char msgbuf[64];
8769                     sprintf(msgbuf,"%02ld / %02d", xx, rcvtimo);
8770                     KuiSetProperty( KUI_FILE_TRANSFER,
8771                                     (long) CW_TMO,
8772                                     (long) msgbuf
8773                                     );
8774                     oldrtt = xx;
8775                     oldtim = rcvtimo;
8776                     clrtoeol();
8777                 }
8778             }
8779         }
8780 #endif /* CK_TIMERS */
8781
8782         x = (what & W_RECV) ?          /* Packet length */
8783           rpktl+(protocol==PROTO_K?1:0) :
8784             spktl;
8785         if (x != oldlen) {              /* But only if it changed. */
8786             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PL, (long) x );
8787             oldlen = x;
8788         }
8789         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PC, (long) spackets );
8790
8791         if (protocol == PROTO_K && !ftp) { /* Window slots */
8792             char ws[16];
8793             int flag;
8794             flag = 0;
8795 #ifdef STREAMING
8796             if (streaming) {
8797                 if (oldwin != -2) {
8798                     sprintf(ws,"STREAMING");
8799                     flag = 1;
8800                     oldwin = -2;
8801                 }
8802             } else
8803 #endif /* STREAMING */
8804               if (wcur != oldwin) {
8805                   sprintf(ws, "%d of %d", wcur < 1 ? 1 : wcur, wslotn);
8806                   flag = 1;
8807                   oldwin = wcur;
8808               }
8809             if (flag) {
8810                 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_WS, (long) ws );
8811             }
8812         }
8813         errors = retrans + crunched + timeouts;
8814         if (errors != oldtry) {         /* Retry count, if changed */
8815             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PR, (long) errors );
8816             oldtry = errors;
8817         }
8818         /* Sender's packet type */
8819         if (!ftp && (c != oldtyp && c != 'Y' && c != 'N')) {
8820             char type[2];
8821             sprintf(type, "%c",c);
8822             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PT, (long) type );
8823             oldtyp = c;
8824         }
8825         switch (c) {                    /* Now handle specific packet types */
8826           case 'S':                     /* Beginning of transfer */
8827             fcnt = fbyt = 0L;           /* Clear counters */
8828 #ifdef GFTIMER
8829             gtv = -1.0;
8830 #else /* GFTIMER */
8831             gtv = -1L;                  /* And old/new things... */
8832 #endif /* GFTIMER */
8833             oldpct = pct = 0L;
8834             break;
8835
8836           case 'Z':                     /* or EOF */
8837             debug(F101,"screeng SCR_PT Z pktnum","",n);
8838             debug(F101,"screeng SCR_PT Z oldpct","",oldpct);
8839             debug(F101,"screeng SCR_PT Z pct","",pct);
8840           case 'D':                     /* Data packet */
8841             if (fsiz > 0L) {            /* Show percent done if known */
8842                 oldpct = pct;           /* Remember previous percent */
8843                 howfar = ffc;
8844 #ifdef CK_RESEND
8845                 if (what & W_SEND)      /* Account for PSEND or RESEND */
8846                   howfar += sendstart;
8847                 else if (what & W_RECV)
8848                   howfar += rs_len;
8849 #endif /* CK_RESEND */
8850                 /* Percent done, to be displayed... */
8851                 if (c == 'Z') {
8852                     if (!discard && !cxseen && !czseen) pct = 100L;
8853                 } else
8854                   pct = (fsiz > 99L) ? (howfar / (fsiz / 100L)) : 0L;
8855                 if (pct > 100L ||       /* Allow for expansion and */
8856                    (oldpct == 99L && pct < 0L)) /* other boundary conditions */
8857                   pct = 100L;
8858                 if (pct != oldpct)      /* Only do this 100 times per file */
8859                   updpct(oldpct, pct);
8860             } else {
8861                 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8862             }
8863             KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) howfar);
8864             cps = shocps((int) pct, fsiz, howfar);
8865             /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8866             break;
8867
8868           case '%':                     /* Timeouts, retransmissions */
8869             cps = shocps((int) pct, fsiz, howfar);
8870             /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8871
8872             errors = retrans + crunched + timeouts;
8873             if (errors != oldtry) {     /* Error count, if changed */
8874                 KuiSetProperty(KUI_FILE_TRANSFER,
8875                                (long) CW_PR,
8876                                (long) errors
8877                                );
8878                 }
8879                 oldtry = errors;
8880                 if (s) if (*s) {
8881                     KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_ERR, (long) s);
8882             }
8883             break;
8884
8885           case 'E':                     /* Error packet */
8886             if (*s) {
8887                 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
8888             }
8889             fcnt = fbyt = 0L;           /* So no bytes for this file */
8890             break;
8891           case 'Q':                     /* Crunched packet */
8892             cps = shocps((int) pct, fsiz, howfar);
8893             /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8894             KuiSetProperty(KUI_FILE_TRANSFER,
8895                            (long) CW_ERR,
8896                            (long) "Damaged Packet"
8897                            );
8898             break;
8899           case 'q':                     /* Ctrl-C or connection lost */
8900             if (!s) s = "";
8901             if (!*s) s = "User interruption or connection lost";
8902             KuiSetProperty(KUI_FILE_TRANSFER,
8903                            (long) CW_MSG,
8904                            (long) s
8905                            );
8906             break;
8907           case 'T':                     /* Timeout */
8908             cps = shocps((int) pct, fsiz, howfar);
8909             /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8910             KuiSetProperty(KUI_FILE_TRANSFER,
8911                            (long) CW_ERR,
8912                            (long) "Timeout"
8913                            );
8914             errors = retrans + crunched + timeouts;
8915             if (errors != oldtry) {     /* Error count, if changed */
8916                 KuiSetProperty(KUI_FILE_TRANSFER,
8917                                (long) CW_PR, (long) errors
8918                                );
8919                 oldtry = errors;
8920             }
8921             break;
8922           default:                      /* Others, do nothing */
8923             break;
8924         }
8925 #ifdef OS2
8926         SaveCmdMode(0, 0);
8927 #endif /* OS2 */
8928         return;
8929
8930       case SCR_ST:                      /* File transfer status */
8931         debug(F101,"screeng SCR_ST c","",c);
8932         debug(F101,"screeng SCR_ST success","",success);
8933         debug(F101,"screeng SCR_ST cxseen","",cxseen);
8934 #ifdef COMMENT
8935         if (c == ST_OK) {               /* OK, print 100 % */
8936             if (pctlbl)
8937               updpct(oldpct,100);
8938             else
8939                 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8940             pct = 100;
8941             oldpct = 0;
8942         } else if (fsiz > 0L)           /* Not OK, update final percent */
8943 /*
8944   The else part writes all over the screen -- howfar and/or fsiz have
8945   been reset as a consequence of the not-OKness of the transfer.
8946 */
8947           if (pctlbl)
8948             updpct(oldpct, (howfar * 100L) / fsiz);
8949 #else
8950         if (c == ST_OK) {               /* OK, print 100 % */
8951             if (pctlbl) {
8952                 updpct(oldpct,100);
8953             } else
8954                 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8955 #ifdef COMMENT
8956             pct = 100;
8957             oldpct = 0;
8958 #endif /* COMMENT */
8959         }
8960 #endif /* COMMENT */
8961
8962         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "" );
8963
8964         switch (c) {                    /* Print new status message */
8965           case ST_OK:                   /* Transfer OK */
8966             fcnt++;                     /* Count this file */
8967             if (what == (W_FTP|W_FT_DELE)) {
8968                 KuiSetProperty(KUI_FILE_TRANSFER,
8969                                 (long) CW_MSG,
8970                                 (long) "Delete OK"
8971                                 );
8972             } else {
8973                 fbyt += ffc;
8974                 KuiSetProperty(KUI_FILE_TRANSFER,
8975                                 (long) CW_MSG,
8976                                 (long) "Transfer OK"
8977                                 );
8978             }
8979             return;
8980
8981           case ST_DISC:                 /* Discarded */
8982             KuiSetProperty(KUI_FILE_TRANSFER,
8983                            (long) CW_ERR,
8984                            (long) "File discarded"
8985                            );
8986 #ifdef COMMENT
8987             pct = oldpct = 0;
8988 #endif /* COMMENT */
8989             return;
8990
8991           case ST_INT:                  /* Interrupted */
8992             KuiSetProperty(KUI_FILE_TRANSFER,
8993                            (long) CW_ERR,
8994                            (long) "Transfer interrupted"
8995                            );
8996 #ifdef COMMENT
8997             pct = oldpct = 0;
8998 #endif /* COMMENT */
8999             return;
9000
9001         case ST_SKIP: {                /* Skipped */
9002             char errbuf[64] ;
9003             if (n > 0 && n < nskreason)
9004                 sprintf( errbuf, "File skipped, (%s)", skreason[n] ) ;
9005             else
9006                 sprintf( errbuf, "File skipped" ) ;
9007             KuiSetProperty(KUI_FILE_TRANSFER,
9008                            (long) CW_ERR,
9009                            (long) errbuf
9010                            );
9011 #ifdef COMMENT
9012             pct = oldpct = 0;
9013 #endif /* COMMENT */
9014             return;
9015         }
9016           case ST_ERR:                  /* Error message */
9017             if (!s) s = (char *)epktmsg;
9018             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
9019 #ifdef COMMENT
9020             pct = oldpct = 0;
9021 #endif /* COMMENT */
9022             return;
9023
9024           case ST_REFU:                 /* Refused */
9025             if (*s) {
9026                 char errbuf[64] ;
9027                 sprintf( errbuf, "Refused, %s", s ) ;
9028                 KuiSetProperty(KUI_FILE_TRANSFER,(long) CW_ERR,(long) errbuf);
9029             } else {
9030                 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Refused");
9031             }
9032 #ifdef COMMENT
9033             pct = oldpct = 0;
9034 #endif /* COMMENT */
9035             return;
9036
9037           case ST_INC:
9038             KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Incomplete");
9039 #ifdef COMMENT
9040             pct = oldpct = 0;
9041 #endif /* COMMENT */
9042             return;
9043
9044           case ST_MSG:
9045             KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_MSG,(long)s);
9046             return;
9047
9048           default:                      /* Bad call */
9049             KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR,
9050                        (long) "*** screen() called with bad status ***" );
9051             return;
9052         }
9053
9054       case SCR_TC: {                    /* Transaction complete */
9055           char msgbuf[128];
9056           KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, tfcps);
9057           if (success) {
9058               sprintf(msgbuf,
9059                       "SUCCESS.  Files: %s, Bytes: %ld, %ld CPS",
9060                       filcnt - filrej,
9061                       ckfstoa(fbyt),
9062                       tfcps
9063                       );
9064               KuiSetProperty(KUI_FILE_TRANSFER,
9065                              (long) CW_MSG,
9066                              (long) msgbuf
9067                              );
9068           }
9069           KuiSetProperty(KUI_FILE_TRANSFER,
9070                          (long) CW_TR,
9071                          (long) hhmmss((long)
9072 #ifdef GFTIMER
9073                                        (fptsecs + 0.5)
9074 #else
9075                                        tsecs
9076 #endif /* GFTIMER */
9077                                        ));
9078
9079 #ifdef GFTIMER
9080           oldgtv = (CKFLOAT) -1.0;
9081 #else
9082           oldgtv = -1L;
9083 #endif /* GFTIMER */
9084
9085 #ifdef COMMENT
9086           pct = 100; oldpct = 0;        /* Reset these for next time. */
9087 #endif /* COMMENT */
9088           oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
9089           oldtim = -1;
9090           cendw = 1;
9091           if (xfrbel) bleep(BP_NOTE);   /* Close window, then beep. */
9092           ft_win = 0;                   /* Window closed. */
9093           return;
9094       }
9095       case SCR_EM:                      /* Error packet (fatal) */
9096         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
9097         if (xfrbel) bleep(BP_FAIL);
9098 #ifdef COMMENT
9099         pct = oldpct = 0;
9100 #endif /* COMMENT */
9101         return;
9102
9103       case SCR_QE:                      /* Quantity equals */
9104       case SCR_TU:                      /* Undelimited text */
9105       case SCR_TN:                      /* Text delimited at start */
9106       case SCR_TZ:                      /* Text delimited at end */
9107         return;                         /* (ignored in fullscreen display) */
9108
9109       case SCR_XD:                      /* X-packet data */
9110         pct = oldpct = 0;
9111         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
9112         return;
9113
9114       case SCR_CW:                      /* Close Window */
9115 #ifdef COMMENT
9116         pct = 100; oldpct = 0;          /* Reset these for next time. */
9117 #endif /* COMMENT */
9118         oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
9119         oldtim = -1;
9120
9121         ft_win = 0;                     /* Flag that window is closed. */
9122         cendw = 1; return;
9123
9124       case SCR_CD:                      /* Display current directory */
9125         KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) s );
9126 #ifdef OS2
9127         SaveCmdMode(0, 0);
9128 #endif /* OS2 */
9129         return;
9130
9131       default:                          /* Bad call */
9132         KuiSetProperty(KUI_FILE_TRANSFER,
9133                        (long) CW_ERR,
9134                        (long) "*** screen() called with bad function code ***"
9135                        );
9136         return;
9137     }
9138 }
9139 #endif /* KUI */
9140 #endif /* MAC */
9141
9142 #endif /* NOXFER */
9143
9144 #ifndef CK_CURPOS
9145 /* Dummies for when cursor control is not supported */
9146 int
9147 ck_curpos(row, col) {
9148     return(-1);
9149 }
9150
9151 int
9152 ck_cls() {
9153     return(-1);
9154 }
9155
9156 int
9157 ck_cleol() {
9158     return(-1);
9159 }
9160 #endif /* CK_CURPOS */
9161
9162 #ifndef NOIKSD
9163 #ifdef IKSDB
9164
9165 struct iksdbfld dbfld[] = {
9166    /* Offset    Length    Type   */
9167     { DB_FLAGS, dB_FLAGS, DBT_HEX },    /*  0 db_FLAGS Flags */
9168     { DB_ATYPE, dB_ATYPE, DBT_HEX },    /*  1 db_ATYPE Auth type */
9169     { DB_AMODE, dB_AMODE, DBT_HEX },    /*  3 db_AMODE Auth mode */
9170     { DB_STATE, dB_STATE, DBT_HEX },    /*  2 db_STATE State */
9171     { DB_MYPID, dB_MYPID, DBT_HEX },    /*  5 db_MYPID PID */
9172     { DB_SADDR, dB_SADDR, DBT_HEX },    /*  4 db_SADDR Server address */
9173     { DB_CADDR, dB_CADDR, DBT_HEX },    /*  6 db_CADDR Client address */
9174     { DB_START, dB_START, DBT_DAT },    /*  7 db_START Session start */
9175     { DB_LASTU, dB_LASTU, DBT_DAT },    /*  8 db_LASTU Last update */
9176     { DB_ULEN,  dB_ULEN,  DBT_HEX },    /*  9 db_ULEN  Username length */
9177     { DB_DLEN,  dB_DLEN,  DBT_HEX },    /* 10 db_DLEN  Directory name length */
9178     { DB_ILEN,  dB_ILEN,  DBT_HEX },    /* 11 db_ILEN  Info length */
9179     { DB_PAD1,  dB_PAD1,  DBT_UND },    /* 12 db_PAD1  (Reserved) */
9180     { DB_USER,  dB_USER,  DBT_STR },    /* 13 db_USER  Username */
9181     { DB_DIR,   dB_DIR,   DBT_STR },    /* 14 db_DIR   Current Directory */
9182     { DB_INFO,  dB_INFO,  DBT_STR }     /* 15 db_INFO  State-specific info */
9183 };
9184
9185 static char lcknam[CKMAXPATH+1];        /* Lockfile pathname */
9186 static char tmplck[CKMAXPATH+1];        /* Temporary lockfile name */
9187
9188 static char * updmode =                 /* Update mode for fopen() */
9189 #ifdef OS2
9190   "r+b"
9191 #else
9192 #ifdef VMS
9193   "r+b"
9194 #else
9195   "r+"
9196 #endif /* VMS */
9197 #endif /* OS2 */
9198   ;
9199
9200 /*  D B I N I T  --  Initialize the IKSD database...  */
9201
9202 int
9203 dbinit() {
9204     extern int dbinited;
9205     int x = 0;
9206     debug(F110,"dbinit dbdir 1",dbdir,0);
9207     debug(F110,"dbinit dbfile 1",dbfile,0);
9208     if (dbinited)
9209       return(0);
9210 #ifdef OS2
9211     if (!dbdir) {
9212 #ifdef NT
9213         char * p = NULL;
9214         if (!isWin95()) {
9215             p = getenv("SystemRoot");
9216         } else {
9217             p = getenv("winbootdir");
9218             if (!p)  p = getenv("windir");
9219         }
9220         if (!p) p = "C:/";
9221         dbdir = malloc(strlen(p)+2);
9222         strcpy(dbdir,p);                /* safe */
9223         p = dbdir;
9224         while (*p) {
9225             if (*p == '\\')
9226               *p = '/';
9227             p++;
9228         }
9229         if (*(p-1) != '/' ) {
9230             *p++ = '/';
9231             *p = '\0';
9232         }
9233 #else /* NT */
9234         makestr(&dbdir,"C:/");
9235 #endif /* NT */
9236     }
9237 #else /* OS2 */
9238     if (!dbdir)
9239       makestr(&dbdir,IK_DBASEDIR);
9240 #endif /* OS2 */
9241
9242     if (!dbfile) {
9243         char * s = "";
9244         x = strlen(dbdir);
9245         if (dbdir[x-1] != '/') {
9246             s = "/";
9247             x++;
9248         }
9249         x += (int)strlen(IK_DBASEFIL);
9250         dbfile = (char *)malloc(x+1);
9251         sprintf(dbfile,"%s%s%s",dbdir,s,IK_DBASEFIL);
9252     }
9253     debug(F110,"dbinit dbdir 2",dbdir,0);
9254     debug(F110,"dbinit dbfile 2",dbfile,0);
9255     mypid = getpid();                   /* Get my pid */
9256     debug(F101,"dbinit mypid","",mypid);
9257
9258     if (!myhexip[0]) {                  /* Set my hex IP address */
9259 #ifdef TCPSOCKET
9260         extern unsigned long myxipaddr;
9261         if (getlocalipaddr() > -1) {
9262             myip = myxipaddr;
9263             sprintf(myhexip,"%08lx",myip); /* (Needs fixing for IPv6) */
9264         } else
9265 #endif /* TCPSOCKET */
9266           ckstrncpy(myhexip,"00000000",9);
9267     }
9268     debug(F111,"dbinit myip",myhexip,myip);
9269     if (!peerhexip[0]) {                /* Get peer's  hex IP address */
9270 #ifdef TCPSOCKET
9271         extern unsigned long peerxipaddr;
9272         if (ckgetpeer()) {
9273             peerip = peerxipaddr;
9274             sprintf(peerhexip,"%08lx",peerip); /* (Needs fixing for IPv6) */
9275             debug(F111,"dbinit peerip",peerhexip,peerip);
9276         } else {
9277             debug(F101,"dbinit ckgetpeer failure","",errno);
9278             ckstrncpy(peerhexip,"00000000",9);
9279         }
9280 #else
9281         ckstrncpy(peerhexip,"00000000",9);
9282 #endif /* TCPSOCKET */
9283     }
9284     debug(F111,"dbinit peerip",peerhexip,peerip);
9285     debug(F101,"dbinit dbenabled","",dbenabled);
9286     if (dbenabled && inserver) {
9287         mydbslot = getslot();
9288         debug(F111,"dbinit getslot",ckitoa(ikdbopen),x);
9289         if (ikdbopen) dbinited = 1;
9290     }
9291     return(0);
9292 }
9293
9294 /*  U P D S L O T  --  Update slot n  */
9295
9296 /*
9297   Opens the database if necessary, seeks to slot n, writes current record
9298   and adds current time to last-update field.  n is the record sequence number
9299   (0, 1, 2, ...), not the seek pointer.   Returns -1 on failure, 0 on success.
9300 */
9301 int
9302 updslot(n) int n; {                     /* Update our slot */
9303     int rc = 0;
9304     CK_OFF_T position;
9305
9306     debug(F111,"updslot","ikdbopen",ikdbopen);
9307     if (!ikdbopen)                      /* Not if not ok */
9308       return(0);
9309     if (!dbfp) {                        /* Open database if not open */
9310         dbfp = fopen(dbfile,updmode);   /* In update no-truncate mode */
9311         if (!dbfp) {
9312             debug(F110,"updslot fopen failed",dbfile,0);
9313             ikdbopen = 0;
9314             return(-1);
9315         }
9316     }
9317     /* debug(F111,"updslot dbfile",dbfile,dbfp); */
9318     position = n * DB_RECL;
9319     if (CKFSEEK(dbfp,position,0) < 0) { /* Seek to desired slot */
9320         debug(F111,"updslot fseek failed",dbfile,mydbseek);
9321         ikdbopen = 0;
9322         rc = -1;
9323     } else {
9324         /* Update the update time */
9325         strncpy(&dbrec[dbfld[db_LASTU].off],
9326                 ckdate(),
9327                 dbfld[db_LASTU].len
9328                 );
9329         if (fwrite(dbrec,1,DB_RECL,dbfp) < DB_RECL) { /* Write the record */
9330             debug(F110,"updslot fwrite failed",dbfile,0);
9331             ikdbopen = 0;
9332             rc = -1;
9333         } else {                        /* Flush the write */
9334             fflush(dbfp);
9335         }
9336     }
9337     return(rc);
9338 }
9339
9340 /*  I N I T S L O T --  Initialize slot n with my info  */
9341
9342 int
9343 initslot(n) int n; {                    /* Initialize slot */
9344     int k;
9345 #ifdef TCPSOCKET
9346     extern unsigned long peerxipaddr;
9347 #endif /* TCPSOCKET */
9348
9349     debug(F101,"initslot","",n);
9350
9351 #ifdef USE_MEMCPY
9352     memset(dbrec,32,DB_RECL);
9353 #else
9354     for (k = 0; k < DB_RECL; k++)
9355       dbrec[k] = '\040';
9356 #endif /* USE_MEMCPY */
9357
9358     myflags = DBF_INUSE;                /* Set in-use flag */
9359     mystate = W_NOTHING;
9360     myatype = 0L;
9361     myamode = 0L;
9362
9363     k = dbfld[db_FLAGS].len;            /* Length of flags field */
9364     strncpy(&dbrec[dbfld[db_FLAGS].off],ulongtohex(myflags,k),k);
9365
9366     k = dbfld[db_ATYPE].len;
9367     strncpy(&dbrec[dbfld[db_ATYPE].off],ulongtohex(myatype,k),k);
9368
9369     k = dbfld[db_AMODE].len;
9370     strncpy(&dbrec[dbfld[db_AMODE].off],ulongtohex(myamode,k),k);
9371
9372     k = dbfld[db_STATE].len;
9373     strncpy(&dbrec[dbfld[db_STATE].off],ulongtohex(mystate,k),k);
9374
9375     k = dbfld[db_SADDR].len;
9376     strncpy(&dbrec[dbfld[db_SADDR].off],ulongtohex(myip,k),k);
9377
9378 #ifdef TCPSOCKET
9379     ckgetpeer();
9380     k = dbfld[db_CADDR].len;
9381     strncpy(&dbrec[dbfld[db_CADDR].off],ulongtohex(peerxipaddr,k),k);
9382 #else
9383     k = dbfld[db_CADDR].len;
9384     strncpy(&dbrec[dbfld[db_CADDR].off],ulongtohex(0L,k),k);
9385 #endif /* TCPSOCKET */
9386
9387     k = dbfld[db_MYPID].len;
9388     strncpy(&dbrec[dbfld[db_MYPID].off],ulongtohex(mypid,k),k);
9389
9390     k = dbfld[db_START].len;
9391     strncpy(&dbrec[dbfld[db_START].off],ckdate(),k);
9392
9393     k = dbfld[db_ULEN].len;
9394     strncpy(&dbrec[dbfld[db_ULEN].off],"0000",4);
9395
9396     k = dbfld[db_DLEN].len;
9397     strncpy(&dbrec[dbfld[db_DLEN].off],"0000",4);
9398
9399     k = dbfld[db_ILEN].len;
9400     strncpy(&dbrec[dbfld[db_ILEN].off],"0000",4);
9401
9402     strncpy(&dbrec[dbfld[db_INFO].off],"INIT",4);
9403     return(updslot(n));
9404 }
9405
9406 int
9407 slotstate(x,s1,s2,s3) int x; char *s1, *s2, *s3; {
9408     int k, l1, l2, l3, z;
9409     mystate = x;
9410     debug(F101,"slotstate ikdbopen","",ikdbopen);
9411     if (!ikdbopen)
9412       return(-1);
9413     if (!s1) s1 = "";
9414     l1 = strlen(s1);
9415     if (!s2) s2 = "";
9416     l2 = strlen(s2);
9417     if (!s3) s3 = "";
9418     l3 = strlen(s3);
9419     strncpy(&dbrec[DB_STATE],ulongtohex(mystate,4),4);
9420     k = dbfld[db_ILEN].len;
9421     z = l1 + l2 + l3 + 2;
9422     if (z > dB_INFO)
9423       z = dB_INFO;
9424     strncpy(&dbrec[DB_ILEN],ulongtohex((unsigned long)z,k),k);
9425     k = dbfld[db_INFO].len;
9426     z = dbfld[db_INFO].off;
9427     if (l1 <= k) {
9428         lset(&dbrec[z],s1,l1+1,32);
9429         z += l1+1;
9430         k -= l1+1;
9431         if (l2 <= k) {
9432             lset(&dbrec[z],s2,l2+1,32);
9433             z += l2+1;
9434             k -= l2+1;
9435             if (l3 <= k)
9436               lset(&dbrec[z],s3,k,32);
9437         }
9438     }
9439 #ifdef DEBUG
9440     if (deblog) {
9441         char buf[128];
9442         int i;
9443         strncpy(buf,&dbrec[DB_INFO],127);
9444         buf[127] = NUL;
9445         for (i = 126; i > 0 && buf[i] == 32; i--) buf[i] = 0;
9446         debug(F111,"slotstate",buf,mystate);
9447     }
9448 #endif /* DEBUG */
9449     z = updslot(mydbslot);
9450     debug(F101,"slotstate updslot","",z);
9451     return(z);
9452 }
9453
9454 int
9455 slotdir(s1,s2) char * s1, * s2; {       /* Update current directory */
9456     int k, len1, len2;
9457     if (!ikdbopen)
9458       return(-1);
9459     if (!s1) s1 = "";
9460     if (!s2) s2 = "";
9461     len1 = strlen(s1);
9462     len2 = strlen(s2);
9463     k = dbfld[db_DLEN].len;
9464     strncpy(&dbrec[DB_DLEN],ulongtohex((unsigned long)(len1+len2),k),k);
9465     k = dbfld[db_DIR].len;
9466     if (len1 > 0) {
9467         lset(&dbrec[dbfld[db_DIR].off],s1,len1,32);
9468         lset(&dbrec[dbfld[db_DIR].off+len1],s2,k-len1,32);
9469     } else {
9470         lset(&dbrec[dbfld[db_DIR].off],s2,k,32);
9471     }
9472     return(updslot(mydbslot));
9473 }
9474
9475 /*  F R E E S L O T  --  Free slot n  */
9476
9477 int
9478 freeslot(n) int n; {
9479     int k;
9480     if (!ikdbopen)
9481       return(0);
9482     dbflags = 0L;
9483     if (n == mydbslot) {
9484         dbflags = myflags & ~DBF_INUSE;
9485         dbflags &= ~DBF_LOGGED;
9486     }
9487     k = dbfld[db_FLAGS].len;
9488     strncpy(&dbrec[dbfld[db_FLAGS].off],ulongtohex(dbflags,k),k);
9489     return(updslot(n));
9490 }
9491
9492 /*  G E T S L O T  --  Find a free database slot; returns slot number  */
9493
9494 #ifdef UNIX
9495 #include <fcntl.h>                      /* For creat() */
9496 #endif  /* UNIX */
9497
9498 int
9499 getslot() {                             /* Find a free slot for us */
9500     FILE * rfp = NULL;                  /* Returns slot number (0, 1, ...) */
9501     char idstring[64];                  /* PID string buffer (decimal) */
9502     char pidbuf[64], * s;
9503     int j, k, n, x, rc = -1;
9504     int lockfd, tries, haveslot = 0;
9505     long lockpid;
9506     CK_OFF_T i;
9507     /* char ipbuf[17]; */
9508
9509     if (!myhexip[0])                    /* Set my hex IP address if not set */
9510       ckstrncpy((char *)myhexip,"7F000001",33);
9511     sprintf(idstring,"%08lx:%010ld\n",myip,mypid);
9512     debug(F110,"getslot idstring", idstring, 0);
9513
9514     /* Make temporary lockfile name IP.PID (hex.hex) */
9515     /* This should fit in 14 chars -- huge PIDs are usually not possible */
9516     /* on 14-char filename systems. */
9517
9518     sprintf(tmplck,"%s%08lx.%lx",dbdir,myip,mypid);
9519     debug(F110,"getslot tempfile",tmplck,0);
9520
9521     /* Make a temporary file */
9522
9523     lockfd = creat(tmplck, 0600);       /* BUT THIS ISN'T PORTABLE */
9524     if (lockfd < 0) {
9525         debug(F111,"getslock temp lockfile create failure", tmplck, errno);
9526         return(-1);
9527     }
9528     /* Write my (decimal) PID into the temp file */
9529
9530     write(lockfd,idstring,(int)strlen(idstring));
9531     if (close(lockfd) < 0) {            /* Close lockfile */
9532         debug(F101,"getslot error closing temp lockfile", "", errno);
9533         return(-1);
9534     }
9535     sprintf(lcknam,"%s%s",dbdir,IK_LOCKFILE); /* Build lockfile name */
9536     debug(F110,"getslot lockfile",lcknam,0);
9537
9538     rfp = fopen(lcknam,"r");            /* See if lockfile exists */
9539     if (rfp) {                          /* If so... */
9540         rset(pidbuf,"",64,0);
9541         x = fread(pidbuf,1,63,rfp);     /* Read ID string from it */
9542         fclose(rfp);                    /* and close it quickly */
9543         debug(F110,"getslot lock exists",pidbuf,0);
9544         if (x > 0) {                    /* If we have a PID, check it */
9545             char * s = pidbuf;
9546             while (*s) {
9547                 if (islower(*s)) *s = toupper(*s);
9548                 if (*s == ':') {
9549                     *s = NUL;
9550                     debug(F110,"getslot lock IP",pidbuf,0);
9551                     debug(F110,"gteslot my   IP",myhexip,0);
9552                     if (!strcmp(pidbuf,myhexip)) { /* Same IP address? */
9553                         lockpid = atol(s+1); /* Yes, now get PID */
9554                         debug(F101,"getslot lockpid","",lockpid);
9555
9556                         /* Check if PID lockpid on this computer is alive */
9557                         x = zchkpid(lockpid);
9558                         if (!x) {
9559                             debug(F100,"getslot PID stale,removing lock","",0);
9560                             unlink(lcknam);
9561                         }
9562                         break;
9563                     }
9564                 }
9565                 s++;
9566             }
9567         } else {
9568             debug(F111,"getslot lockfile open failure",lcknam,errno);
9569         }
9570     }
9571     /* Try IK_LCKTRIES (16) times to rename temp file to lockfile */
9572
9573     for (tries = IK_LCKTRIES; tries > 0; tries--) {
9574         if (zrename(tmplck,lcknam) == 0)
9575           break;
9576         debug(F101,"getslot database locked by pid", "", dbpid);
9577         sleep(IK_LCKSLEEP);
9578     }
9579     if (tries < 1) {                    /* Couldn't */
9580         debug(F110,"getslot create lock failure",lcknam,0);
9581         return(-1);
9582     }
9583     /* Have lock, open database */
9584
9585     debug(F110,"getslot has lock",lcknam,0); /* Have lock */
9586
9587     if (!dbfile)
9588       return(-1);
9589
9590     /* If database doesn't exist, create it. */
9591
9592     debug(F110,"getslot dbfile",dbfile,0);
9593     if (zchki(dbfile) < 0) {
9594         debug(F110,"getslot creating new database",dbfile,0);
9595         x = creat(dbfile,0660);
9596         if (x < 0) {
9597             debug(F111,"getslot creat() failed", dbfile, errno);
9598             goto xslot;
9599         }
9600         close(x);
9601     }
9602     dbfp = fopen(dbfile,updmode);       /* Open it in update mode */
9603     if (!dbfp) {
9604         debug(F111,"getslot fopen failed",dbfile,errno);
9605         goto xslot;
9606     }
9607     /* Now find a free (or new) slot... */
9608
9609     dblastused = 0L;                    /* Seek pointer to last record inuse */
9610     mydbseek = 0L;                      /* Seek pointer for my record */
9611
9612     /* Quickly read the whole database; n = record counter, i = seek pointer */
9613
9614     for (n = 0, i = 0; !feof(dbfp); i += DB_RECL, n++) {
9615         x = fread(dbrec,1,DB_RECL,dbfp); /* Read a record */
9616         if (x < 1)                      /* EOF not caught by feof() */
9617           break;
9618 #ifndef NOFTRUNCATE
9619         if (x != DB_RECL) {             /* Watch out for trailing junk */
9620             debug(F101,"getslot bad size","",x);  /* (Shouldn't happen...) */
9621 #ifdef COHERENT
9622             chsize(fileno(dbfp),i);
9623 #else
9624             ftruncate(fileno(dbfp),(CK_OFF_T)i);
9625 #endif /* COHERENT */
9626             x = 0;
9627             CKFSEEK(dbfp,i,0);
9628             break;
9629         }
9630 #endif /* NOFTRUNCATE */
9631         debug(F101,"getslot record","",n);
9632         k = dbfld[db_FLAGS].off;
9633         j = dbfld[db_FLAGS].len;
9634         dbflags = hextoulong(&dbrec[k],j);
9635         debug(F001,"getslot dbflags","",dbflags);
9636         k = dbfld[db_MYPID].off;
9637         j = dbfld[db_MYPID].len;
9638         dbpid  = hextoulong(&dbrec[k],j);
9639         debug(F001,"getslot dbpid","",dbpid);
9640         k = dbfld[db_SADDR].off;
9641         j = dbfld[db_SADDR].len;
9642         dbip = hextoulong(&dbrec[k],j);
9643         debug(F001,"getslot dbip","",dbip);
9644
9645         if (dbflags & DBF_INUSE) {      /* Remember last slot in use */
9646             x = 0;                      /* Make sure it's REALLY in use */
9647             if (dbpid == mypid && dbip == myip) { /* Check for PID == my PID */
9648                 x = 1;
9649                 debug(F101,"getslot record pid","",dbpid);
9650             } else {                    /* Or for stale PID */
9651                 x = zchkpid(dbpid);
9652                 debug(F101,"getslot zchkpid()","",x);
9653             }
9654             if (!x) {                   /* Bogus record */
9655                 x = freeslot(n);
9656                 debug(F101,"getslot stale record pid: freeslot()","",x);
9657                 if (x > -1 && !haveslot)
9658                   dbflags = 0;
9659             } else {                    /* It's really in use */
9660                 dblastused = i;
9661             }
9662         }
9663         if (!haveslot) {                /* If I don't have a slot yet */
9664             if (!(dbflags & DBF_INUSE)) {       /* Claim this one */
9665                 debug(F101,"getslot free slot", "", n);
9666                 haveslot = 1;
9667                 mydbseek = i;
9668                 mydbslot = n;           /* But keep going... */
9669             }
9670         }
9671     }
9672     /* Come here with i == seek pointer to first record after eof */
9673
9674     if (!haveslot) {                    /* Found no free slot so add to end */
9675         debug(F101,"getslot new slot","",n);
9676         haveslot = 1;
9677         mydbseek = i;
9678         mydbslot = n;
9679     }
9680     ikdbopen = 1;                       /* OK to make database entries */
9681     debug(F101,"getslot records","",n);
9682     debug(F101,"getslot dblastused","",dblastused);
9683     debug(F101,"getslot i","",i);
9684
9685     /* Trim stale records from end */
9686
9687 #ifndef NOFTRUNCATE
9688     if (i > dblastused+DB_RECL) {
9689         debug(F101,"getslot truncating at","",dblastused+DB_RECL);
9690 #ifdef COHERENT
9691         x = chsize(fileno(dbfp),dblastused+DB_RECL);
9692 #else
9693         x = ftruncate(fileno(dbfp),(CK_OFF_T)(dblastused+DB_RECL));
9694 #endif /* COHERENT */
9695         if (x < 0)                      /* (Not fatal) */
9696           debug(F101,"getslot ftruncate failed", "", errno);
9697     }
9698 #endif /* NOFTRUNCATE */
9699
9700     /* Initialize my record */
9701
9702     if (initslot(mydbslot) < 0) {
9703         debug(F101,"getslot initslot() error","",n);
9704         ikdbopen = 0;
9705         goto xslot;
9706     }
9707     debug(F101,"getslot OK","",mydbslot);
9708     rc = mydbslot;                      /* OK return code */
9709
9710   xslot:                                /* Unlock the database and return */
9711     if (unlink(lcknam) < 0) {
9712         debug(F111,"getslot lockfile removal failed",lcknam,errno);
9713         rc = -1;
9714     }
9715     return(rc);
9716 }
9717 #endif /* IKSDB */
9718 #endif /* NOIKSD */