3 /* C K U U S X -- "User Interface" common functions. */
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
12 Copyright (C) 1985, 2004,
13 Trustees of Columbia University in the City of New York.
14 All rights reserved. See the C-Kermit COPYING.TXT file or the
15 copyright text in the ckcmai.c module for disclaimer and permissions.
19 This module contains user interface functions needed by both the interactive
20 user interface and the command-line-only user interface.
50 #endif /* NOTERMCAP */
51 #endif /* NOHTERMCAP */
57 #endif /* NOHTERMCAP */
63 #endif /* NOTERMCAP */
67 _PROTOTYP(char * os2_gethostname, (void));
68 #define getpid _getpid
74 extern xx_strp xxstring;
79 _PROTOTYP(int getlocalipaddr, (void));
80 _PROTOTYP(int istncomport, (void));
82 _PROTOTYP( char * ckgetfqhostname,(char *));
83 #endif /* NOCKGETFQHOST */
86 We should just pull in ckcnet.h here, but it causes a conflict with curses.h.
114 #endif /* SUPERLAT */
115 #endif /* TCPSOCKET */
117 #endif /* STRATUSX25 */
122 #endif /* CK_NETBIOS */
129 #endif /* MULTINET */
132 #endif /* DEC_TCPIP */
139 #endif /* TCPSOCKET */
150 #ifdef COMMENT /* Would you believe */
151 #undef COMMENT /* <os2.h> defines this ? */
155 #endif /* CK_NETBIOS */
158 extern ascreen commandscreen;
179 #endif /* CK_KERBEROS */
190 #include <lib$routines.h> /* Not for VAX C 2.3 */
200 /* fdopen() needs declaring because it's not declared in <stdio.h> */
201 _PROTOTYP( FILE * fdopen, (int, char *) );
202 #endif /* DCLFDOPEN */
205 /* popen() needs declaring because it's not declared in <stdio.h> */
206 _PROTOTYP( FILE * popen, (char *, char *) );
207 #endif /* DCLPOPEN */
209 int tt_crd = 0; /* Carriage return display */
210 int interrupted = 0; /* Interrupted from keyboard flag */
211 static int fxd_inited = 0; /* Fullscreen stuff initialized */
214 char debfil[CKMAXPATH+1]; /* Debugging log file name */
218 char trafil[CKMAXPATH+1]; /* Transaction log file name */
221 char sesfil[CKMAXPATH+1]; /* Session log file name */
224 char diafil[CKMAXPATH+1]; /* Connection log file name */
225 char cxlogbuf[CXLOGBUFL+1]; /* Connection log record buffer */
226 int cx_active = 0; /* Connection is active */
228 #endif /* CKLOGDIAL */
231 static char *cmdstr = NULL; /* Place to build generic command */
234 static char cmdstr[256];
236 static char cmdstr[4096];
241 char fspec[CMDBL+4]; /* Filename string for \v(filespec) */
242 int fspeclen = CMDBL;
244 char fspec[CKMAXPATH+4];
245 int fspeclen = CKMAXPATH;
248 char * rfspec = NULL; /* Received filespec: local */
249 char * prfspec = NULL; /* Preliminary rfspec */
250 char * sfspec = NULL; /* Sent filespec: local */
251 char * psfspec = NULL; /* Preliminary sfspec */
252 char * srfspec = NULL; /* Received filespec: remote */
253 char * psrfspec = NULL; /* Preliminary srfspec */
254 char * rrfspec = NULL; /* Sent filespec: remote */
255 char * prrfspec = NULL; /* Preliminary rrfspec */
257 int success = 1, /* Command success/failure flag */
258 cmdlvl = 0, /* Command level */
259 action = 0, /* Action selected on command line */
260 slogts = 0, /* Session-log timestamps on/off */
262 sessft = XYFT_T, /* Session log file type */
264 sessft = XYFT_B, /* (text for UNIX binary for others) */
266 pflag = 1, /* Print prompt */
267 msgflg = 1; /* Print informational messages */
269 extern int xaskmore, saveask; /* More-prompting */
272 extern int apcactive;
274 /* External variables */
276 extern int local, quiet, binary, network, what, parity, xitsta, escape,
277 tlevel, bgset, backgrd, xsuspend, cmdint, nettype, seslog, dfloc;
279 extern int cmd_rows, cmd_cols, xcmdsrc;
281 extern char cmdfil[];
287 #ifdef datageneral /* 2/12/92 ENH */
289 extern int con_reads_mt, conint_ch, conint_avl;
290 #endif /* datageneral */
294 extern char ttname[], *dftty, *cmarg, **cmlist, *versio, myhost[];
297 extern int fcharset, tcharset, xfrxla;
298 extern struct csinfo fcsinfo[], tcsinfo[];
302 extern unsigned char colorcmd;
307 int fdispla = XYFD_N;
309 #else /* NOXFER is not defined */
311 #ifdef OS2 /* File transfer display type */
312 int fdispla = XYFD_C; /* Curses (fullscreen) if we have it */
315 int fdispla = XYFD_C;
317 int fdispla = XYFD_S; /* Otherwise CRT */
318 #endif /* CK_CURSES */
321 extern struct ck_p ptab[];
322 extern int protocol, xfrbel, xfrint;
325 extern int streaming, streamok;
326 #endif /* STREAMING */
328 /* Used internally */
330 _PROTOTYP( VOID screenc, (int, char, long, char *) );
331 _PROTOTYP( VOID screeng, (int, char, long, char *) );
335 static char xtrmbuf[TRMBUFL]; /* tgetent() buffer */
336 char * trmbuf = xtrmbuf;
338 char * trmbuf = NULL;
340 _PROTOTYP( static VOID dpyinit, (void) );
341 _PROTOTYP( static long shocps, (int, long, long) );
342 _PROTOTYP( static long shoetl, (long, long, long, long) );
343 #endif /* CK_CURSES */
345 static int ft_win = 0; /* Fullscreen file transfer display window is active */
347 /* Variables declared here */
349 static char * skreason[] = {
351 "Remote file not older", /* SKP_DAT */
352 "Identical modification times", /* SKP_EQU */
353 "Type", /* SKP_TYP */
354 "Size", /* SKP_SIZ */
355 "Name collision", /* SKP_NAM */
356 "Exception List", /* SKP_EXL */
357 "Dot file", /* SKP_DOT */
358 "Backup file", /* SKP_BKU */
359 "Recovery not needed", /* SKP_RES */
360 "Access denied", /* SKP_ACC */
361 "Not a regular file", /* SKP_NRF */
362 "Simulated", /* SKP_SIM */
363 "Simulated - Remote file older", /* SKP_XUP */
364 "Simulated - No remote file", /* SKP_XNX */
366 static int nskreason = (sizeof(skreason) / sizeof(char *));
369 gskreason(n) int n; {
370 return((n > 0 && n < nskreason) ? skreason[n] : "");
373 char pktfil[CKMAXPATH+1]; /* Packet log file name */
375 #ifndef NOMSEND /* Multiple SEND */
376 char *msfiles[MSENDMAX];
380 extern long rttdelay;
382 #endif /* CK_TIMERS */
387 extern long sendstart, rs_len;
388 #endif /* CK_RESEND */
390 #ifdef CK_PCT_BAR /* File transfer thermometer */
391 int thermometer = 1; /* ON by default */
392 #endif /* CK_PCT_BAR */
395 CKFLOAT gtv = -1.0, oldgtv = -1.0;
400 long gtv = -1L, oldgtv = -1L;
403 extern int server, bctu, rptflg, ebqflg, spsiz, urpsiz, wmax, czseen, cxseen,
404 winlo, displa, timint, npad, ebq, bctr, rptq, atcapu, lpcapu,
405 swcapu, wslotn, wslotr, rtimo, mypadn, sq, capas, rpsiz, tsecs,
406 pktlog, lscapu, dest, srvdis, wslots, spackets, spktl, rpktl,
407 retrans, wcur, numerrs, fsecs, whatru, crunched, timeouts,
408 rpackets, fncnv, bye_active, discard, inserver, diractive, cdactive;
410 extern long filcnt, filrej, ffc, tfc, rptn, fsize, filcps, tfcps, cps, peakcps;
414 extern CHAR *rdatap, padch, seol, ctlq, mypadc, eol, *epktmsg;
418 FILE * dbfp = NULL; /* File pointer to database file */
420 int dbenabled = 1; /* Flag for database is enabled */
421 extern int ikdbopen; /* Flag for database is open */
423 unsigned long mydbseek = 0L; /* Seek pointer to my record */
424 int mydbslot = 0; /* My slot number */
425 unsigned long myflags = 0L; /* My flags */
426 unsigned long myatype = 0L; /* My authorization type */
427 unsigned long myamode = 0L; /* My authorization mode */
428 unsigned long mystate = 0L; /* My state (SEND, RECEIVE, etc) */
429 unsigned long mypid = 0L; /* My PID */
430 unsigned long myip = 0L; /* My IP address */
431 unsigned long peerip = 0L; /* My peer's IP address */
433 unsigned long dbip = 0L; /* IP address in db record */
434 unsigned long dbpid = 0L; /* PID in db record */
435 unsigned long dbflags = 0L; /* Flags field in db record */
436 unsigned long dblastused = 0L; /* Last in-use record in db */
437 char dbrec[DB_RECL]; /* Database record buffer */
439 char * dbdir = NULL; /* Database directory */
440 char * dbfile = NULL; /* Database file full pathname */
441 char myhexip[33] = { NUL, NUL }; /* My IP address in hex */
442 char peerhexip[33] = { NUL, NUL }; /* Client's IP address in hex */
446 extern CKFLOAT fpfsecs, fptsecs, fpxfsecs;
454 extern char * ftp_host, ftp_srvtyp[];
455 extern int ftp_csx, ftp_csl, ftp_deb;
457 extern char myipaddr[];
458 #endif /* TCPSOCKET */
462 extern struct mtab *mactab; /* For ON_EXIT macro. */
466 extern char *cmdbuf; /* Command buffer */
468 extern char cmdbuf[]; /* Command buffer */
470 extern int cmd_quoting;
475 #include <setjmpex.h>
480 extern ckjmpbuf cmjbuf;
481 #endif /* NOCCTRAP */
483 extern int xfiletype, nscanfile;
486 shoesc(escape) int escape; {
487 extern char * ccntab[]; /* C0 control character name table */
488 extern int tt_escape;
489 if ((escape > 0 && escape < 32) || (escape == 127)) {
490 printf(" Escape character: Ctrl-%c (ASCII %d, %s): %s\r\n",
493 (escape == 127 ? "DEL" : ccntab[escape]),
494 tt_escape ? "enabled" : "disabled"
497 printf(" Escape character: Code %d",escape);
498 if (escape > 160 && escape < 256)
499 printf(" (%c)",escape);
500 printf(": %s\r\n", tt_escape ? "enabled" : "disabled");
506 /* P R E S E T -- Reset global protocol variables */
508 extern int recursive;
511 int patterns = SET_AUTO; /* Whether to use filename patterns */
512 extern int g_patterns; /* For saving and restoring */
514 int patterns = SET_OFF;
515 #endif /* PATTERNS */
519 extern int g_lf_opts, lf_opts;
520 #endif /* CK_LABELED */
521 extern int g_matchdot, g_usepipes, usepipes;
522 extern int g_binary, g_proto, g_displa, g_spath, g_rpath, g_fncnv;
523 extern int g_recursive;
524 extern int g_xfermode, xfermode;
525 extern int g_urpsiz, g_spsizf, g_spsiz;
526 extern int g_spsizr, g_spmax, g_wslotr, g_prefixing, g_fncact;
527 extern int g_fnspath, g_fnrpath, g_skipbup;
530 extern int zgfs_link;
531 #endif /* CKSYMLINK */
533 extern int g_pflg, pwflg, g_pcpt, pwcrypt;
534 extern char * g_pswd, pwbuf[];
538 extern int spsizf, spsizr, spmax, prefixing, fncact, fnspath, fnrpath;
539 extern int moving; /* SEND criteria */
540 extern char sndafter[], sndbefore[], *sndexcept[], *rcvexcept[];
541 extern long sndlarger, sndsmaller, calibrate, skipbup;
542 extern int rmailf, rprintf;
543 extern char optbuf[];
546 extern char * g_sfilter, * g_rfilter;
547 extern char * sndfilter, * rcvfilter;
548 #endif /* PIPESEND */
549 extern char ** sndarray;
555 extern char * filefile;
556 extern int reliable, xreliable, c_save, ss_save, slostart, urclear;
557 extern int oopts, omode, oname, opath, kactive, autopath;
558 extern char * snd_move; /* Directory to move sent files to */
559 extern char * snd_rename; /* What to rename sent files to */
560 extern char * rcv_move;
561 extern char * rcv_rename;
562 extern char * g_snd_move;
563 extern char * g_snd_rename;
564 extern char * g_rcv_move;
565 extern char * g_rcv_rename;
569 extern char savdir[];
570 #endif /* CK_TMPDIR */
575 extern short s_ctlp[], ctlp[];
577 #endif /* CK_SPEED */
580 extern int fcs_save, tcs_save;
581 extern int g_xfrxla, xfrxla;
584 /* Restore / reset per-command file-transfer switches */
586 makestr(&snd_move,g_snd_move);
587 makestr(&rcv_move,g_rcv_move);
588 makestr(&snd_rename,g_snd_rename);
589 makestr(&rcv_rename,g_rcv_rename);
591 kactive = 0; /* Kermit protocol no longer active */
592 oopts = -1; /* O-Packet Options */
593 omode = -1; /* O-Packet Transfer Mode */
594 oname = -1; /* O-Packet Filename Options */
595 opath = -1; /* O-Packet Pathname Options */
598 rs_len = 0L; /* REGET position */
599 #endif /* CK_RESEND */
604 for (i = 0; i < 256; i++)
608 #endif /* CK_SPEED */
612 if (f_tmpdir) { /* If we changed to download dir */
613 zchdir((char *) savdir); /* Go back where we came from */
616 #endif /* CK_TMPDIR */
618 calibrate = 0L; /* Calibration run */
619 if (xreliable > -1) {
620 reliable = xreliable;
621 debug(F101,"ftreset reliable","",reliable);
625 if (autopath) { /* SET RECEIVE PATHNAMES AUTO */
629 if (filefile) { /* File list */
631 makestr(&filefile,NULL);
633 if (c_save > -1) { /* Block Check Type */
637 if (ss_save > -1) { /* Slow Start */
642 if (g_lf_opts > -1) {
643 lf_opts = g_lf_opts; /* Restore labeled transfer options */
646 #endif /* CK_LABELED */
649 if (tcs_save > -1) { /* Character sets */
661 setxlatype(tcharset,fcharset); /* Translation type */
667 ckstrncpy(pwbuf,g_pswd,PWBUFL);
668 makestr(&g_pswd,NULL);
681 if (g_binary > -1) { /* File type */
685 if (g_xfermode > -1) { /* Transfer mode */
686 xfermode = g_xfermode;
690 if (g_patterns > -1) { /* Filename patterns */
691 patterns = g_patterns;
694 #endif /* PATTERNS */
696 if (g_usepipes > -1) {
697 usepipes = g_usepipes;
700 if (g_matchdot > -1) {
701 matchdot = g_matchdot;
704 if (g_proto > -1) { /* Protocol */
710 debug(F101,"ftreset restoring urpsiz","",urpsiz);
715 debug(F101,"ftreset restoring spsizf","",spsizf);
720 debug(F101,"ftreset restoring spsiz","",spsiz);
725 debug(F101,"ftreset restoring spsizr","",spsizr);
736 if (g_prefixing > -1) {
737 prefixing = g_prefixing;
748 if (g_fnspath > -1) {
752 if (g_fnrpath > -1) {
756 if (g_skipbup > -1) {
760 nolinks = 2; /* /FOLLOWLINKS is never global */
761 recursive = 0; /* /RECURSIVE can never be global */
764 if (g_displa > -1) { /* File transfer display */
768 if (g_spath > -1) { /* Send pathnames */
772 if (g_rpath > -1) { /* Receive pathnames */
776 if (g_fncnv > -1) { /* Filename conversion */
781 makestr(&sndfilter,g_sfilter); /* Send filter */
782 makestr(&rcvfilter,g_rfilter); /* Receive filter */
783 #endif /* PIPESEND */
786 rmailf = rprintf = 0; /* MAIL and PRINT modifiers for SEND */
787 optbuf[0] = NUL; /* MAIL and PRINT options */
788 #endif /* NOFRILLS */
790 moving = 0; /* Reset delete-after-send indicator */
791 sndafter[0] = NUL; /* Reset SEND selection switches */
794 for (i = 0; i < NSNDEXCEPT; i++) {
816 ttgtpn() { /* Get typical port name */
818 Ideally this routine would be implemented in each of the cku?io.* modules,
819 but that requires changing the API definition.
826 "TAPI [ name ] or COM1"
830 "TXA0:, TTA0:, or LTA0:"
843 #else /* __FreeBSD__ */
846 #else /* __linux__ */
860 "/dev/term/00 or /dev/tty00"
867 #else /* CK_SCO32V4 */
879 #else /* datageneral */
891 #else /* MOTSV88R4 */
902 "/dev/cua, /dev/acu, /dev/tty0, etc"
904 "(sorry no example available)"
909 #endif /* MOTSV88R4 */
910 #endif /* SV68R3V6 */
913 #endif /* datageneral */
917 #endif /* CK_SCO32V4 */
918 #endif /* CK_SCOV5 */
919 #endif /* UNIXWARE */
924 #endif /* __linux__ */
925 #endif /* __FreeBSD__ */
934 /* C K _ E R R S T R -- Return message from most recent system error */
937 extern int ckrooterr;
944 /* Should have been declared in <string.h> */
945 _PROTOTYP( char * strerror, (int) );
946 #endif /* CK_ANSILIBS */
949 return("Off limits");
951 return(strerror(errno));
952 #else /* !USE_STRERROR */
954 extern char * ckvmserrstr(unsigned long);
957 return("Off limits");
959 return(ckvmserrstr(0L));
965 extern char *sys_errlist[];
966 #endif /* NDSYSERRLIST */
967 #else /* !__386BSD__ */
971 extern const char *const sys_errlist[];
972 #endif /* NDSYSERRLIST */
973 #endif /* __bsdi__ */
974 #endif /* __386BSD__ */
977 return("Off limits");
980 if (errno >= sys_nerr)
981 return("Error number out of range");
983 return((char *) sys_errlist[errno]);
988 extern char *sys_errlist[];
989 #endif /* NDSYSERRLIST */
992 return("Off limits");
995 if (errno >= sys_nerr)
996 return("Error number out of range");
998 return((char *) sys_errlist[errno]);
1001 #ifndef NDSYSERRLIST
1002 extern int sys_nerr;
1003 extern char *sys_errlist[];
1004 #endif /* NDSYSERRLIST */
1007 return("Off limits");
1010 if (errno >= sys_nerr)
1011 return("Error number out of range");
1013 return((char *) sys_errlist[errno]);
1016 #ifndef NDSYSERRLIST
1017 extern char *sys_errlist[];
1018 #endif /* NDSYSERRLIST */
1020 extern int_sys_nerr;
1025 return("Off limits");
1029 && errno <= _sys_nerr
1033 (char *) sys_errlist[errno]
1035 /* I don't know how to get a CLIB error string in OS/2 */
1047 #endif /* USE_STRERROR */
1052 Filename pattern recognition lists for automatic text/binary switching.
1053 These are somewhat passe after the addition of scanfile() (7.0).
1054 But with the addition of FTP [M]GET, they're back in style (8.0).
1056 Although, with FTP the lists need to be used in the reverse. With
1057 Kermit the list is used to imply the types of the local system. Whereas
1058 with FTP, the list must be used to imply the type of the remote system.
1059 Therefore, all platforms must now support all of the lists.
1061 char *txtpatterns[FTPATTERNS+1] = { NULL, NULL };
1062 char *binpatterns[FTPATTERNS+1] = { NULL, NULL };
1064 Default pattern lists for each platform...
1066 NOTE: In most cases we leave ".hlp", ".ini", and ".scr" alone; although they
1067 are traditionally text types, they are binary in Windows. So they are
1068 handled by the prevailing SET FILE TYPE, rather than automatically.
1069 Similarly for ".dat", ".inf", and so on. Also ".ps" since PostScript files
1070 are not always text. ".log" is omitted since logs can be text or binary,
1071 except in VMS they are usually text, etc etc.
1073 Later (Sep 2003): Add PostScript to binary patterns.
1075 static char *txtp[SYS_MAX][FTPATTERNS] = {
1080 "*.txt","*.c","*.h","*.r","*.w","*.cpp","*.cc","*.ksc","*.bwr","*.upd",
1081 "*.html","*.htm","*.mss","*.tex","*.nr","[Mm]akefile", "*.hex", "*.hqx",
1082 "*.for","*.f77","*.f","*.F","*.s","*.pas","*.java","*.el","*.lisp","*.sh",
1083 "*.m4","*.perl","*.pl","*.pod","*.pm","*.awk","*.sno","*.spt","*.sed",
1084 "*.ksc","*.TXT", "*read.me", "*READ.ME", ".*", "*/.*", "*.mem","*.mac",
1088 "*.txt","*.ksc","*.htm","*.html","*.bat","*.cmd","*.jav","*.asm", "*.hex",
1089 "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w",
1090 "*.java", "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile",
1091 "*.mem","*.mac","*.cc","*.pl","*.pod","*.pm","*.m4",NULL
1094 "*.com","*.txt","*.c", "*.for","*.pas","*.rno","*.rnh","*.mar","*.bli",
1095 "*.hlp","*.mss","*.doc","*.bwr","*.cld","*.hex","*.bas","*.ini","*.log",
1096 "*.mms","*.opt","*.ksc","*.perl","*.pl","*.pod","*.pm","*.sno","*.spt",
1100 "*.txt","*.ksc","*.htm","*.html","*.bat","*.cmd","*.jav","*.asm", "*.hex",
1101 "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w",
1102 "*.java", "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile",
1106 "*.txt","*.ksc","*.htm","*.bat","*.cmd","*.jav","*.asm", "*.hex",
1107 "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w",
1108 "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile", NULL
1111 "*.cmd","*.hlp","*.doc","*.ini","*.txt","*.mac","*.for","*.sai","*.bli",
1112 "*.pas","*.sno","*.spt","*.pcl","*.mss","*.rno","*.b36","*.tex","*.pub",
1113 "*.req","*.r36","*.mem","*.bwr","*.ccl","*.ctl","*.rnh","*.ksc",NULL
1116 "*.cmd","*.hlp","*.doc","*.ini","*.txt","*.mac","*.for","*.sai","*.bli",
1117 "*.pas","*.sno","*.spt","*.pcl","*.mss","*.rno","*.b36","*.tex","*.pub",
1118 "*.req","*.r36","*.mem","*.bwr","*.ccl","*.ctl","*.rnh","*.ksc",NULL
1121 "*.txt","*.ksc","*.htm","*.html","*.bat", "*.cmd","*.jav","*.asm","*.hex",
1122 "*.hqx","*.c", "*.h", "*.w", "*.java","*.bwr","*.upd","*.ttp","*.cm",
1123 "*.pl1","*.emacs", "read.me", "*.pl", "makefile", NULL
1126 "*.txt", "*.c", "*.h", "*.w", "*.er", "*.bwr", "*.upd", "read.me",
1127 "*.cli", "*.ksc", NULL
1130 "*.c","*.cpp","*.h","*.a","*akefile", /* program sources */
1131 "*.for","*.f77","*.f","*.F","*.s","*.pas","*.java","*.el","*.lisp",
1132 "*.sh","*.perl","*.awk","*.sno","*.spt","*.sed",
1133 "*.txt","*.w", /* general text */
1134 "*.ksc","*.bwr","*.upd",
1135 "*.html","*.htm","*.mss","*.tex","*.nr","*.hex", "*.hqx",
1136 "*.TXT", "*read.me", "*READ.ME", ".*", "*/.*",
1141 /* Note: .DOC added to (some) binary patterns June 1998... Microsoft wins. */
1143 static char *binp[SYS_MAX][FTPATTERNS] = {
1148 "*.gz","*.Z","*.tgz","*.gif", "*.tar","*.zip","*.o","*.so","*.a","*.out",
1149 "*.exe", "*.jpg", "*.jpeg", "*.tif","*.tiff", "*.pdf", "*.so.*", "*.class",
1150 "*.rpm", "*.bmp", "*.bz2", "*.BMP", "*.dll", "*.doc", "*.vxd", "*.dcx",
1151 "*.xl*", "*.lzh", "*.lhz", "*.au", "*.voc", "*.mpg", "*.mpeg","[wk]ermit",
1155 "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
1156 "*.class","*.cla","*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
1157 "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
1158 "*.pdf", "*.lzh", "*.vxd", "*.snd", "*.au", "* .voc", "*.mpg", "*.mpeg",
1162 "*.exe","*.obj","*.bak","*.bin","*.adf","*.stb","*.mai","*.sys","*.dmp",
1163 "*.ps", "*.dat","*.par", NULL
1166 "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
1167 "*.class", "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
1168 "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
1169 "*.pdf", "*.ps", "*.lzh", NULL
1172 "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
1173 "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
1174 "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
1175 "*.pdf", "*.ps", "*.lzh", NULL
1178 "*.exe","*.sav","*.bin","*.rim","*.rel","*.unv","*.lib","*.tap","*.dvi",
1182 "*.exe","*.sav","*.bin","*.rim","*.rel","*.unv","*.lib","*.tap","*.dvi",
1186 "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
1187 "*.class", "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
1188 "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
1189 "*.pdf", "*.ps", "*.lzh", "*.pm", NULL
1192 "*.ob", "*.pr", "*.dmp", "*.ps", NULL
1195 "*.gz","*.Z","*.z","*.tgz","*.lhz","*.tar", /* archivers */
1196 "*.zip","*.ar","*.zoo","*.rpm","*.lzh",
1197 /* object files, libraries, executables */
1198 "*.r","*.l","*.exe", "*.dll", "*.so.*", "*.class",
1200 "*.gif", "*.jpg", "*.jpeg", "*.tif","*.tiff", "*.pdf", "*.ps",
1201 "*.bmp", "*.bz2", "*.BMP","*.pcx",
1207 Set up default pattern lists so they can be freed and re-malloc'd.
1208 Each pattern list must terminated by a null element.
1213 for (i = 0; i < FTPATTERNS; i++) {
1214 txtpatterns[i] = NULL;
1215 binpatterns[i] = NULL;
1217 for (i = 0; i < FTPATTERNS; i++) {
1219 makestr(&(txtpatterns[i]),txtp[SYS_UNIX][i]);
1223 makestr(&(txtpatterns[i]),txtp[SYS_WIN32][i]);
1225 makestr(&(txtpatterns[i]),txtp[SYS_OS2][i]);
1229 makestr(&(txtpatterns[i]),txtp[SYS_VMS][i]);
1232 makestr(&(txtpatterns[i]),txtp[SYS_VOS][i]);
1235 makestr(&(txtpatterns[i]),txtp[SYS_DG][i]);
1236 #else /* datageneral */
1238 makestr(&(txtpatterns[i]),txtp[SYS_OSK][i]);
1240 makestr(&(txtpatterns[i]),txtp[SYS_UNK][i]);
1242 #endif /* datageneral */
1243 #endif /* STRATUS */
1250 for (i = 0; i < FTPATTERNS; i++) {
1252 makestr(&(binpatterns[i]),binp[SYS_UNIX][i]);
1256 makestr(&(binpatterns[i]),binp[SYS_WIN32][i]);
1258 makestr(&(binpatterns[i]),binp[SYS_OS2][i]);
1262 makestr(&(binpatterns[i]),binp[SYS_VMS][i]);
1265 makestr(&(binpatterns[i]),binp[SYS_VOS][i]);
1268 makestr(&(binpatterns[i]),binp[SYS_DG][i]);
1269 #else /* datageneral */
1271 makestr(&(binpatterns[i]),binp[SYS_OSK][i]);
1273 makestr(&(binpatterns[i]),binp[SYS_UNK][i]);
1275 #endif /* datageneral */
1276 #endif /* STRATUS */
1286 m a t c h n a m e -- Compare filename with text & binary name patterns.
1289 0 if name matches a text pattern but not a binary pattern.
1290 1 if name matches a binary pattern but not a text pattern.
1291 -1 if name matches no patterns.
1292 -2 if name matches a binary pattern and a text pattern.
1295 matchname(filename, local, os) char * filename; int local; int os; {
1296 int rc = -1; /* Return code */
1299 char tmpbuf[CKMAXPATH+1];
1300 #endif /* OS2ORUNIX */
1302 name = filename ? filename : ""; /* Copy of original arg */
1303 if (patterns && *name) { /* If PATTERNS ON... */
1307 if (ckmatch("*.~[1-9]*~",name,1,1)) { /* Name has backup suffix? */
1309 k = ckstrncpy(tmpbuf,name,CKMAXPATH+1); /* Yes, copy and strip */
1310 for (i = k - 3; i > 4; i--) {
1311 if (tmpbuf[i] == '~' && tmpbuf[i-1] == '.') {
1316 name = tmpbuf; /* And point to stripped copy */
1318 #endif /* OS2ORUNIX */
1319 zstrip(name,&p); /* Strip pathname too */
1323 if (txtpatterns[0]) { /* Search text patterns */
1324 for (i = 0; i < FTPATTERNS && txtpatterns[i]; i++) {
1325 if (ckmatch(txtpatterns[i],name,filecase,1)) {
1331 if (binpatterns[0]) { /* And search binary patterns */
1332 for (i = 0; i < FTPATTERNS && binpatterns[i]; i++) {
1333 if (ckmatch(binpatterns[i],name,filecase,1)) {
1334 rc = (rc > -1) ? -2 : 1;
1340 if (os >= 0 && os < SYS_MAX) {
1342 for (i = 0; i < FTPATTERNS && txtp[os][i]; i++) {
1343 if (ckmatch(txtp[os][i],name,filecase,1)) {
1350 for (i = 0; i < FTPATTERNS && binp[os][i]; i++) {
1351 if (ckmatch(binp[os][i],name,filecase,1)) {
1352 rc = (rc > -1) ? -2 : 1;
1360 debug(F111,"matchname",name,rc);
1363 #endif /* PATTERNS */
1368 #endif /* NOEVENMAX */
1369 #endif /* UNICODE */
1371 /* S C A N F I L E -- Analyze a file's contents */
1375 name: Pointer to name of existing file.
1376 flag: Pointer to int in which to return additional numeric data.
1379 -1 on failure (to open file or to read from it).
1380 Integer, 0..4, on success indicating file type:
1381 0 = 7-bit text (flag = -1)
1382 1 = UTF-8 text (flag = -1)
1383 2 = UCS-2 text (flag = 0: big-endian; flag = 1: little-endian)
1384 3 = 8-bit text (flag = 0: no C1 bytes; flag = 1: includes C1 bytes)
1385 4 = binary (flag = -1)
1387 If UNICODE is defined:
1389 1. If file begins with a valid BOM, it is believed. Otherwise we
1390 read the first 4K of the file (since it might be email with verbose
1391 headers) and analyze it:
1393 2. If file contains only valid UTF-8 sequences, we call it UTF-8;
1396 3. If the file contains lots of alternate 0 bytes, we call it UCS-2, and
1397 set the polarity according to whether the preponderance of them are in
1398 even or odd positions; otherwise:
1400 4. If EVENMAX is defined and the file contains lots of alternate bytes that
1401 are identical, even if they aren't zero, and the number of such bytes
1402 is at least four times the length of the maximum run of alternating
1403 identical bytes of the opposite polarity, we call it UCS-2; otherwise:
1405 5. If the file contained no bytes with their 8th bits on and no controls
1406 other than CR, LF, HT, and FF, we call it ASCII; otherwise:
1408 6. If it contains C0 control characters other than CR, LF, HT, and FF, we
1409 call it binary; otherwise:
1411 7. We call it 8-bit text, character set unknown (could be Latin-1 or
1414 Note that malformed UTF-8 is not diagnosed as UTF-8.
1416 If UNICODE is not defined:
1418 1. If the file contains C0 control characters other than CR, LF, HT, and
1419 FF, we call it binary; otherwise:
1421 2. If the file contains any 8-bit bytes, we call it 8-bit text; otherwise:
1423 3. We call it 7-bit text.
1425 In the non-Unicode case, UCS-2 is diagnosed as binary, but UTF-8 as
1428 There is no significant speed difference between the Unicode and
1432 scanfile(name,flag,nscanfile) char * name; int * flag, nscanfile; {
1433 FILE * fp; /* File pointer */
1434 unsigned char buf[SCANFILEBUF]; /* File data buffer for analysis */
1435 int x, val = -1, count = 0; /* Workers */
1436 int rc = -1; /* Return code */
1437 int pv = -1; /* Pattern-match value */
1438 int eof = 0; /* Flag for file EOF encountered */
1439 int bytes = 0; /* Total byte count */
1441 unsigned int c0, c1; /* First 2 file bytes (for BOM) */
1442 #endif /* UNICODE */
1443 extern int pipesend, filepeek;
1445 register int i; /* Loop control */
1446 int readsize = 0; /* How much to read */
1447 int eightbit = 0; /* Number of bytes with 8th bit on */
1448 int c0controls = 0; /* C0 non-text control-char counter */
1449 int c0noniso = 0; /* C0 non-ISO control-char counter */
1450 int c1controls = 0; /* C1 control-character counter */
1451 unsigned int c; /* Current character */
1452 int runmax = 0; /* Longest run of 0 bytes */
1453 int runzero = 0; /* Run of 0 bytes */
1454 int pctzero = 0; /* Percentage of 0 bytes */
1457 extern int eofmethod;
1458 #endif /* CK_CTRLZ */
1461 int notutf8 = 0; /* Nonzero if definitely not UTF-8 */
1462 int utf8state = 0; /* UTF-8 recognizer state */
1463 int oddzero = 0; /* Number of 0 bytes in odd postions */
1464 int evenzero = 0; /* and in even positions */
1465 int lfnul = 0; /* Number of <LF><NUL> sequences */
1466 int crlf = 0; /* Number of <CRLF> sequences */
1469 #endif /* UNICODE */
1473 int oddrun = 0, oddmax = 0, oddbyte = 0, oddmaxbyte = 0;
1474 int evenrun = 0, evenmax = 0, evenbyte = 0, evenmaxbyte = 0;
1475 #endif /* EVENMAX */
1476 #endif /* COMMENT */
1479 if (pipesend || calibrate || sndarray) /* Only for real files */
1482 debug(F111,"scanfile",name,nscanfile);
1485 pv = matchname(name,1,-1);
1489 rc = (pv == 1) ? FT_BIN : FT_TEXT;
1490 debug(F111,"scanfile !filepeek result",name,rc);
1493 #endif /* PATTERNS */
1496 /* We don't scan in VMS where text files have various record formats in */
1497 /* which record headers contain seemingly non-text bytes. So the best */
1498 /* we can do in VMS is tell whether the file is text or binary, period. */
1501 b = binary; /* Save current binary setting */
1502 if (zopeni(ZIFILE,name) > 0) { /* In VMS this sets binary */
1503 x = binary; /* Get result */
1504 zclose(ZIFILE); /* Close the file */
1505 binary = b; /* Restore previous binary setting */
1506 rc = x ? FT_BIN : FT_TEXT;
1513 eof = 0; /* End-of-file reached indicator */
1515 fp = fopen(name, "rb"); /* Open the file in binary mode */
1517 fp = fopen(name, "r");
1520 if (!fp) /* Failed? */
1523 while (1) { /* One or more gulps from file */
1524 if (eof) { /* EOF from last time? */
1525 debug(F111,"scanfile at EOF",name,bytes);
1526 if (runzero > runmax)
1530 if (nscanfile < 0) { /* Reading whole file */
1531 readsize = SCANFILEBUF;
1532 } else { /* Reading first nscanfilee bytes */
1533 readsize = nscanfile - bytes;
1536 if (readsize > SCANFILEBUF)
1537 readsize = SCANFILEBUF;
1539 debug(F101,"scanfile readsize","",readsize);
1540 count = fread(buf,1,readsize,fp); /* Read a buffer */
1541 if (count == EOF || count == 0) {
1542 debug(F111,"scanfile EOF",name,count);
1545 debug(F111,"scanfile buffer ok",name,count);
1547 if (bytes == 0 && count > 8) {
1548 /* PDF files can look like text in the beginning. */
1549 if (!ckstrcmp((char *)buf,"%PDF-1.",7,1)) {
1550 if (isdigit(buf[7])) {
1551 if (buf[8] == '\015' ||
1552 count > 9 && buf[8] == SP && buf[9] == '\015') {
1555 debug(F110,"scanfile PDF",buf,0);
1557 binary = 1; /* But they are binary. */
1561 } else if (!ckstrcmp((char *)buf,"%!PS-Ado",8,1)) {
1562 /* Ditto for PostScript */
1565 for (i = 8; i < count; i++) {
1571 debug(F110,"scanfile PostScript",buf,0);
1576 } else if (!ckstrcmp((char *)buf,") HP-PCL",8,1)) {
1577 /* HP PCL printer language */
1580 for (i = 8; i < count; i++) {
1586 debug(F110,"scanfile PCL",buf,0);
1591 #endif /* NOPCLSCAN */
1593 else if (buf[0] == '\033' && (buf[1] == 'E' || buf[1] == '%')) {
1594 /* Ditto for PJL Job printer header */
1597 for (i = 2; i < count; i++) {
1603 debug(F110,"scanfile PJL Job printer header",buf,0);
1607 #endif /* NOPJLSCAN */
1612 if (bytes == 0 && count > 1) {
1615 /* First look for BOM */
1617 c0 = (unsigned)((unsigned)buf[0]&0xFF); /* First file byte */
1618 c1 = (unsigned)((unsigned)buf[1]&0xFF); /* Second byte */
1620 if (c0 == 0xFE && c1 == 0xFF) { /* UCS-2 BE */
1623 debug(F111,"scanfile UCS2 BOM BE",ckitoa(val),rc);
1625 } else if (c0 == 0xFF && c1 == 0xFE) { /* UCS-2 LE */
1628 debug(F111,"scanfile UCS2 BOM LE",ckitoa(val),rc);
1630 } else if (count > 2) if (c0 == 0xEF && c1 == 0xBB &&
1631 (unsigned)((unsigned)buf[2]&0xFF) == 0xBF) {
1633 debug(F111,"scanfile UTF8 BOM",ckitoa(val),rc);
1636 if (incl_cnt) { /* Have BOM */
1641 #endif /* UNICODE */
1643 bytes += count; /* Count bytes read */
1644 eof = feof(fp); /* Flag for at EOF */
1646 for (i = 0; i < count; i++) { /* For each byte... */
1647 c = (unsigned)buf[i]; /* For ease of reference */
1648 if (!c) { /* Zero byte? */
1650 if (i&1) /* In odd position */
1653 evenzero++; /* In even position */
1654 #endif /* EVENMAX */
1656 } else { /* Not a zero byte */
1657 if (runzero > runmax)
1659 if (runmax > 2) /* That's all we need to be certain */
1660 break; /* it's a binary file. */
1667 /* This is to catch UCS-2 with a non-ASCII, non-Latin-1 repertoire */
1669 if (i > 1) { /* Look for runs of alternating chars */
1671 if (c == buf[i-2]) { /* In odd positions */
1676 oddmaxbyte = oddbyte;
1678 } else { /* and even positions */
1679 if (c == buf[i-2]) {
1684 evenmaxbyte = evenbyte;
1688 #endif /* EVENMAX */
1689 #endif /* COMMENT */
1691 if ((c & 0x80) == 0) { /* We have a 7-bit byte */
1693 if (i > 0 && c == 10) { /* Linefeed */
1694 if (buf[i-1] == 0) lfnul++; /* Preceded by NUL */
1695 else if (buf[i-1] == 13) crlf++; /* or by CR... */
1697 #endif /* UNICODE */
1698 if (c < ' ') { /* Check for CO controls */
1699 if (c != LF && c != CR && c != HT && c != FF) {
1701 if (c != ESC && c != SO && c != SI)
1704 if ((c == '\032') /* Ctrl-Z */
1706 && eof && (i >= count - 2)
1707 #endif /* COMMENT */
1712 if (eofmethod == XYEOF_Z && txtcz == 0) {
1713 if (c0controls == 0) /* All text prior to Ctrl-Z */
1716 #endif /* CK_CTRLZ */
1720 if (!notutf8 && utf8state) { /* In UTF-8 sequence? */
1722 debug(F000,"scanfile","7-bit byte in UTF8 sequence",c);
1723 notutf8++; /* Then it's not UTF-8 */
1726 #endif /* UNICODE */
1727 } else { /* We have an 8-bit byte */
1728 eightbit++; /* Count it */
1729 if (c >= 0x80 && c < 0xA0) /* Check for C1 controls */
1732 if (!notutf8) { /* If it might still be UTF8... */
1733 switch (utf8state) { /* Enter the UTF-8 state machine */
1734 case 0: /* First byte... */
1735 if ((c & 0xE0) == 0xC0) { /* Tells number of */
1736 utf8state = 1; /* subsequent bytes */
1737 } else if ((c & 0xF0) == 0xE0) {
1739 } else if ((c & 0xF8) == 0xF0) {
1745 case 1: /* Subsequent byte */
1748 if ((c & 0xC0) != 0x80) { /* Must start with 10 */
1749 debug(F000,"scanfile",
1750 "bad byte in UTF8 sequence",c);
1754 utf8state--; /* Good, one less in this sequence */
1756 default: /* Shouldn't happen */
1757 debug(F111,"scanfile","bad UTF8 state",utf8state);
1761 #endif /* UNICODE */
1765 fclose(fp); /* Close the file */
1766 debug(F101,"scanfile bytes","",bytes);
1768 if (bytes == 0) /* If nothing was read */
1769 return(-1); /* we're done. */
1772 /* In case we had a run that never broke... */
1776 oddmaxbyte = oddbyte;
1780 evenmaxbyte = evenbyte;
1782 #endif /* COMMENT */
1786 #endif /* EVENMAX */
1789 if (bytes > 100) /* Bytes is not 0 */
1790 pctzero = (evenzero + oddzero) / (bytes / 100);
1792 pctzero = ((evenzero + oddzero) * 100) / bytes;
1793 #endif /* UNICODE */
1796 if (deblog) { /* If debugging, dump statistics */
1797 debug(F101,"scanfile c0controls ","",c0controls);
1798 debug(F101,"scanfile c0noniso ","",c0noniso);
1799 debug(F101,"scanfile c1controls ","",c1controls);
1800 debug(F101,"scanfile eightbit ","",eightbit);
1802 debug(F101,"scanfile crlf ","",crlf);
1803 debug(F101,"scanfile lfnul ","",lfnul);
1804 debug(F101,"scanfile notutf8 ","",notutf8);
1805 debug(F101,"scanfile evenzero ","",evenzero);
1806 debug(F101,"scanfile oddzero ","",oddzero);
1807 debug(F101,"scanfile even/odd ","",(evenzero / (oddzero + 1)));
1808 debug(F101,"scanfile odd/even ","",(oddzero / (evenzero + 1)));
1809 debug(F101,"scanfile pctzero ","",pctzero);
1810 #endif /* UNICODE */
1813 debug(F101,"scanfile oddmax ","",oddmax);
1814 debug(F101,"scanfile oddmaxbyte ","",oddmaxbyte);
1815 debug(F101,"scanfile evenmax ","",evenmax);
1816 debug(F101,"scanfile evenmaxbyte","",evenmaxbyte);
1817 #endif /* EVENMAX */
1818 #endif /* COMMENT */
1819 debug(F101,"scanfile runmax ","",runmax);
1824 x = eightbit ? bytes / 20 : bytes / 4; /* For UCS-2... */
1826 if (runmax > 2) { /* File has run of more than 2 NULs */
1827 debug(F100,"scanfile BIN runmax","",0);
1828 rc = FT_BIN; /* so it can't be any kind of text. */
1831 } else if (rc == FT_UCS2 || (rc == FT_UTF8 && runmax == 0)) {
1832 goto xscanfile; /* File starts with a BOM */
1834 } else if (eightbit > 0 && !notutf8) { /* File has 8-bit data */
1835 if (runmax > 0) { /* and runs of NULs */
1836 debug(F100,"scanfile BIN (nnUTF8) runmax","",0);
1837 rc = FT_BIN; /* UTF-8 doesn't have NULs */
1838 } else { /* No NULs */
1839 debug(F100,"scanfile UTF8 (nnUTF8 + runmax == 0)","",0);
1840 rc = FT_UTF8; /* and not not UTF-8, so is UTF-8 */
1845 For UCS-2 detection, see if the text contains lines delimited by
1846 ASCII controls and containing spaces, ASCII digits, or other ASCII
1847 characters, thus forcing the presence of a certain percentage of zero bytes.
1848 For this purpose require 20% zero bytes, with at least six times as many
1849 in even (odd) positions as in odd (even) positions.
1851 if ((evenzero >= x && oddzero == 0) ||
1852 ((((evenzero / (oddzero + 1)) > 6) && (pctzero > 20)) &&
1856 debug(F100,"scanfile UCS2 noBOM BE (even/oddzero)","",0);
1859 } else if ((evenzero == 0 && oddzero >= x) ||
1860 ((((oddzero / (evenzero + 1)) > 6) && (pctzero > 20)) &&
1864 debug(F100,"scanfile UCS2 noBOM LE (even/oddzero)","",0);
1871 If the tests above fail, we still might have UCS-2 if there are significant
1872 runs of identical bytes in alternating positions, but only if it also has
1873 unusual C0 controls (otherwise we'd pick up hex files here). NOTE: We
1874 don't actually do this -- EVENMAX is not defined (see comments above at
1875 first occurrence of EVENMAX).
1877 } else if (c0noniso && evenmax > bytes / 4) {
1878 debug(F100,"scanfile UCS2 BE (evenmax)","",0);
1881 } else if (c0noniso && oddmax > bytes / 4) {
1882 debug(F100,"scanfile UCS2 LE (evenmax)","",0);
1885 #endif /* EVENMAX */
1886 #endif /* COMMENT */
1890 It seems to be UCS-2 but let's be more certain since there is no BOM...
1891 If the number of 7- and 8-bit characters is approximately equal, it might
1892 be a compressed file. In this case we decide based on the name.
1894 if (rc == FT_UCS2) {
1897 j = (c1controls * 100) / (c0controls + 1);
1898 debug(F101,"scanfile c1/c0 ","",j);
1899 k = (bytes * 100) / eightbit;
1900 debug(F101,"scanfile pct 8bit ","",k);
1901 if (k > 40 && k < 60 && j > 60) {
1902 if (ckmatch("{*.Z,*.gz,*.zip,*.ZIP}",name,1,1)) {
1903 debug(F110,"scanfile 8-bit BIN compressed",name,0);
1909 /* Small file - not enough evidence unless ... */
1912 if (oddzero != 0 && evenzero != 0) {
1913 debug(F100,"scanfile small UCS2 doubtful","",0);
1916 } else if (oddzero == 0 && evenzero == 0) {
1917 rc = eightbit ? FT_8BIT : FT_7BIT;
1920 goto xscanfile; /* Seems to be UCS-2 */
1923 /* If none of the above, it's probably not Unicode. */
1925 if (!eightbit) { /* It's 7-bit */
1926 if (c0controls) { /* This would be strange */
1927 if ((c0noniso > 0) && (txtcz == 0)) {
1928 debug(F100,"scanfile 7-bit BIN (c0coniso)","",0);
1931 debug(F100,"scanfile 7-bit ISO2022 TEXT (no c0noniso)","",0);
1934 } else { /* 7-bit text */
1935 debug(F100,"scanfile 7-bit TEXT (no c0controls)","",0);
1938 } else if (!c0noniso || txtcz) { /* 8-bit text */
1939 debug(F100,"scanfile 8-bit TEXT (no c0noniso)","",0);
1941 val = c1controls ? 1 : 0;
1942 } else { /* 8-bit binary */
1943 debug(F100,"scanfile 8-bit BIN (c0noniso)","",0);
1947 #else /* !UNICODE */
1950 debug(F100,"scanfile 8-bit BIN (c0noniso)","",0);
1952 } else if (eightbit) {
1953 debug(F100,"scanfile 8-bit TEXT (no c0noniso)","",0);
1955 val = c1controls ? 1 : 0;
1957 debug(F100,"scanfile 7-bit TEXT (no c0noniso)","",0);
1961 #endif /* UNICODE */
1964 if (flag) *flag = val;
1965 debug(F101,"scanfile result ","",rc);
1969 /* F I L E S E L E C T -- Select this file for sending */
1974 char *f, char *sa, char *sb, char *sna, char *snb,
1975 long minsiz, long maxsiz,
1976 int nbu, int nxlist,
1980 fileselect(f,sa,sb,sna,snb,minsiz,maxsiz,nbu,nxlist,xlist)
1981 char *f,*sa,*sb,*sna,*snb; long minsiz,maxsiz; int nbu,nxlist; char ** xlist;
1982 #endif /* CK_ANSIC */
1999 debug(F111,"fileselect NOLINKS zgetfs",f,zz);
2002 debug(F111,"fileselect NOLINKS zgfs_link",f,zgfs_link);
2008 #endif /* CKSYMLINK */
2010 debug(F110,"fileselect",f,0);
2011 if (*sa || *sb || *sna || *snb) {
2012 fdate = zfcdat(f); /* Date/time of this file */
2013 if (!fdate) fdate = "";
2015 debug(F111,"fileselect fdate",fdate,n);
2016 if (n != 17) /* Failed to get it */
2019 if (sa[0] && (strcmp(fdate,(char *)sa) <= 0)) {
2020 debug(F110,"fileselect sa",sa,0);
2021 /* tlog(F110,"Skipping (too old)",f,0); */
2025 if (sb[0] && (strcmp(fdate,(char *)sb) >= 0)) {
2026 debug(F110,"fileselect sb",sb,0);
2027 /* tlog(F110,"Skipping (too new)",f,0); */
2031 if (sna[0] && (strcmp(fdate,(char *)sna) > 0)) {
2032 debug(F110,"fileselect sna",sna,0);
2033 /* tlog(F110,"Skipping (too new)",f,0); */
2037 if (snb[0] && (strcmp(fdate,(char *)snb) < 0)) {
2038 debug(F110,"fileselect snb",snb,0);
2039 /* tlog(F110,"Skipping (too old)",f,0); */
2043 if (minsiz > -1L || maxsiz > -1L) { /* Smaller or larger */
2044 z = zchki(f); /* Get size */
2045 debug(F101,"fileselect filesize","",z);
2048 if ((minsiz > -1L) && (z >= minsiz)) {
2049 debug(F111,"fileselect minsiz skipping",f,minsiz);
2050 /* tlog(F111,"Skipping (too big)",f,z); */
2053 if ((maxsiz > -1L) && (z <= maxsiz)) {
2054 debug(F111,"fileselect maxsiz skipping",f,maxsiz);
2055 /* tlog(F110,"Skipping (too small)",f,0); */
2059 if (nbu) { /* Skipping backup files? */
2062 "*.~[0-9]*~" /* Not perfect but close enough. */
2064 "*.~*~" /* Less close. */
2065 #endif /* CKREGEX */
2067 debug(F110,"fileselect skipping backup",f,0);
2071 for (n = 0; xlist && n < nxlist; n++) {
2073 debug(F101,"fileselect xlist empty",0,n);
2076 if (ckmatch(xlist[n],f,filecase,1)) {
2077 debug(F111,"fileselect xlist",xlist[n],n);
2078 debug(F110,"fileselect skipping",f,0);
2082 if (xfiletype > -1) {
2083 n = scanfile(f,NULL,nscanfile);
2087 n = (n == FT_BIN) ? 1 : 0;
2092 debug(F110,"fileselect selecting",f,0);
2099 extern int WSASafeToCancel;
2101 #endif /* TCPSOCKET */
2105 extern int flow, autoflow, mdmtyp, cxtype, cxflow[];
2107 extern int dialcapas, dialfc;
2108 extern MDMINF * modemp[];
2113 debug(F101,"setflow autoflow","",autoflow);
2115 /* #ifdef COMMENT */
2116 /* WHY WAS THIS COMMENTED OUT? */
2117 if (!autoflow) /* Only if FLOW is AUTO */
2119 /* #endif */ /* COMMENT */
2121 debug(F101,"setflow local","",local);
2122 debug(F101,"setflow network","",network);
2123 debug(F101,"setflow cxtype","",cxtype);
2126 if (network && istncomport()) {
2127 flow = cxflow[CXT_MODEM];
2128 debug(F101,"setflow TN_COMPORT flow","",flow);
2131 #endif /* TN_COMPORT */
2133 if (network || !local || cxtype == CXT_DIRECT) {
2134 flow = cxflow[cxtype]; /* Set appropriate flow control */
2135 debug(F101,"setflow flow","",flow);
2138 if (cxtype != CXT_MODEM) /* Connection type should be modem */
2142 bits = dialcapas; /* Capability bits */
2143 if (!bits) { /* No bits? */
2144 p = modemp[mdmtyp]; /* Look in modem info structure */
2148 if (dialfc == FLO_AUTO) { /* If DIAL flow is AUTO */
2149 #ifdef CK_RTSCTS /* If we can do RTS/CTS flow control */
2150 if (bits & CKD_HW) /* and modem can do it too */
2151 flow = FLO_RTSC; /* then switch to RTS/CTS */
2152 else /* otherwise */
2153 flow = FLO_XONX; /* use Xon/Xoff. */
2157 flow = FLO_XONX; /* Use Xon/Xoff. */
2160 #endif /* CK_RTSCTS */
2163 debug(F101,"setflow modem flow","",flow);
2170 /* A U T O E X I T C H K -- Check for CONNECT-mode trigger string */
2172 Returns -1 if trigger not found, or else the trigger index, 0 or greater.
2173 (Replace with fancier and more efficient matcher later...)
2174 NOTE: to prevent unnecessary function call overhead, call this way:
2176 x = tt_trigger[0] ? autoexitchk(c) : -1;
2183 autoexitchk(c) CHAR c;
2184 #endif /* CK_ANSIC */
2186 extern CHAR * tt_trmatch[];
2187 extern char * tt_trigger[];
2189 for (i = 0; i < TRIGGERS; i++) {
2190 if (!tt_trigger[i]) { /* No more triggers in list */
2192 } else if (*tt_trigger[i]) {
2193 if (!tt_trmatch[i]) /* Just starting? */
2194 tt_trmatch[i] = (CHAR *)tt_trigger[i]; /* Set match pointer */
2195 if (c == *tt_trmatch[i]) { /* Compare this character */
2196 tt_trmatch[i]++; /* It matches */
2197 if (!*tt_trmatch[i]) { /* End of match string? */
2198 tt_trmatch[i] = (CHAR *) tt_trigger[i]; /* Yes, rewind, */
2199 debug(F101,"autoexitchk",tt_trigger[i],i); /* log, */
2200 return(i); /* and return success */
2202 } else /* No match */
2203 tt_trmatch[i] = (CHAR *) tt_trigger[i]; /* Rewind match string */
2204 } /* and go on the next match string */
2206 return(-1); /* No match found */
2208 #endif /* CK_TRIGGER */
2211 /* S H O M D M -- Show modem signals */
2216 Note use of "\r\n" to make sure this report prints right, even when
2217 called during CONNECT mode.
2223 "Modem signals unavailable in this version of Kermit\r\n");
2225 case -2: printf("No modem control for this device\r\n"); break;
2226 case -1: printf("Modem signals unavailable\r\n"); break;
2230 " Carrier Detect (CD): %s\r\n",(y & BM_DCD) ? "On": "Off");
2232 " Dataset Ready (DSR): %s\r\n",(y & BM_DSR) ? "On": "Off");
2235 " Clear To Send (CTS): %s\r\n",(y & BM_CTS) ? "On": "Off");
2239 " Ring Indicator (RI): %s\r\n",(y & BM_RNG) ? "On": "Off");
2242 " Data Terminal Ready (DTR): %s\r\n",
2246 (y & BM_DTR) ? "On": "Off"
2251 " Request To Send (RTS): %s\r\n",
2255 (y & BM_RTS) ? "On": "Off"
2259 #endif /* STRATUS */
2263 if (tttapi && !tapipass) {
2264 LPDEVCFG lpDevCfg = NULL;
2265 LPCOMMCONFIG lpCommConfig = NULL;
2266 LPMODEMSETTINGS lpModemSettings = NULL;
2269 if (cktapiGetModemSettings(&lpDevCfg,&lpModemSettings,
2270 &lpCommConfig,&lpDCB)) {
2272 cktapiDisplayModemSettings(lpDevCfg,lpModemSettings,
2273 lpCommConfig,lpDCB);
2276 #endif /* CK_TAPI */
2277 #endif /* BETADEBUG */
2280 #endif /* NOLOCAL */
2283 /* S D E B U -- Record spar results in debugging log */
2286 sdebu(len) int len; {
2287 debug(F111,"spar: data",(char *) rdatap,len);
2288 debug(F101," spsiz ","", spsiz);
2289 debug(F101," timint","",timint);
2290 debug(F101," npad ","", npad);
2291 debug(F101," padch ","", padch);
2292 debug(F101," seol ","", seol);
2293 debug(F101," ctlq ","", ctlq);
2294 debug(F101," ebq ","", ebq);
2295 debug(F101," ebqflg","",ebqflg);
2296 debug(F101," bctr ","", bctr);
2297 debug(F101," rptq ","", rptq);
2298 debug(F101," rptflg","",rptflg);
2299 debug(F101," lscapu","",lscapu);
2300 debug(F101," atcapu","",atcapu);
2301 debug(F101," lpcapu","",lpcapu);
2302 debug(F101," swcapu","",swcapu);
2303 debug(F101," wslotn","", wslotn);
2304 debug(F101," whatru","", whatru);
2306 /* R D E B U -- Debugging display of rpar() values */
2309 rdebu(d,len) CHAR *d; int len; {
2310 debug(F111,"rpar: data",d,len);
2311 debug(F101," rpsiz ","", xunchar(d[0]));
2312 debug(F101," rtimo ","", rtimo);
2313 debug(F101," mypadn","",mypadn);
2314 debug(F101," mypadc","",mypadc);
2315 debug(F101," eol ","", eol);
2316 debug(F101," ctlq ","", ctlq);
2317 debug(F101," sq ","", sq);
2318 debug(F101," ebq ","", ebq);
2319 debug(F101," ebqflg","",ebqflg);
2320 debug(F101," bctr ","", bctr);
2321 debug(F101," rptq ","", d[8]);
2322 debug(F101," rptflg","",rptflg);
2323 debug(F101," capas ","", capas);
2324 debug(F101," bits ","",d[capas]);
2325 debug(F101," lscapu","",lscapu);
2326 debug(F101," atcapu","",atcapu);
2327 debug(F101," lpcapu","",lpcapu);
2328 debug(F101," swcapu","",swcapu);
2329 debug(F101," wslotr","", wslotr);
2330 debug(F101," rpsiz(extended)","",rpsiz);
2334 /* C H K E R R -- Decide whether to exit upon a protocol error */
2338 if (backgrd && !server) fatal("Protocol error");
2340 #endif /* COMMENT */
2343 /* F A T A L -- Fatal error message */
2346 fatal(msg) char *msg; {
2348 static int initing = 0;
2350 debug(F111,"fatal",msg,initflg);
2352 if (!initflg) { /* If called from prescan */
2353 if (initing) /* or called from sysinit() */
2359 debug(F111,"fatal",msg,xitsta);
2360 tlog(F110,"Fatal:",msg,0L);
2362 if (strncmp(msg,"%CKERMIT",8))
2363 conol("%CKERMIT-E-FATAL, ");
2378 doexit(BAD_EXIT,xitsta | 1); /* Exit indicating failure */
2382 /* B L D L E N -- Make length-encoded copy of string */
2385 bldlen(str,dest) char *str, *dest; {
2387 len = (int)strlen(str);
2391 *dest = (char) tochar(len);
2392 strcpy(dest+1,str); /* Checked below in setgen() */
2397 /* S E T G E N -- Construct a generic command */
2399 Call with Generic command character followed by three string arguments.
2400 Trailing strings are allowed to be empty (""). Each string except the last
2401 non-empty string must be less than 95 characters long. The final nonempty
2402 string is allowed to be longer.
2406 setgen(char type, char * arg1, char * arg2, char * arg3)
2408 setgen(type,arg1,arg2,arg3) char type, *arg1, *arg2, *arg3;
2409 #endif /* CK_ANSIC */
2414 if (!(cmdstr = malloc(MAXSP + 1)))
2415 fatal("setgen: can't allocate memory");
2416 #endif /* DYNAMIC */
2421 if (!arg1) arg1 = "";
2422 if (!arg2) arg2 = "";
2423 if (!arg3) arg3 = "";
2424 if (((int)strlen(arg1)+(int)strlen(arg2)+(int)strlen(arg3)+4) < MAXSP) {
2426 upstr = bldlen(arg1,cp);
2428 upstr = bldlen(arg2,upstr);
2429 if (*arg3 != NUL) bldlen(arg3,upstr);
2433 debug(F110,"setgen",cmarg,0);
2441 static char *mgbufp = NULL;
2443 /* F N P A R S E -- */
2446 Argument is a character string containing one or more filespecs.
2447 This function breaks the string apart into an array of pointers, one
2448 to each filespec, and returns the number of filespecs. Used by server
2449 when it receives a GET command to allow it to process multiple file
2450 specifications in one transaction. Sets cmlist to point to a list of
2451 file pointers, exactly as if they were command line arguments.
2453 This version of fnparse treats spaces as filename separators. If your
2454 operating system allows spaces in filenames, you'll need a different
2457 This version of fnparse mallocs a string buffer to contain the names. It
2458 cannot assume that the string that is pointed to by the argument is safe.
2461 fnparse(string) char *string; {
2463 int r = 0, x; /* Return code */
2465 debug(F111,"fnparse",string,recursive);
2466 #endif /* RECURSIVE */
2468 if (mgbufp) free(mgbufp); /* Free this from last time. */
2469 mgbufp = malloc((int)strlen(string)+2);
2471 debug(F100,"fnparse malloc error","",0);
2476 ckstrncpy(fspec,string,fspeclen); /* Make copy for \v(filespec) */
2479 s = string; /* Input string */
2480 p = q = mgbufp; /* Point to the copy */
2481 r = 0; /* Initialize our return code */
2482 while (*s == SP || *s == HT) /* Skip leading spaces and tabs */
2484 for (x = strlen(s); /* Strip trailing spaces */
2485 (x > 1) && (s[x-1] == SP || s[x-1] == HT);
2488 while (1) { /* Loop through rest of string */
2489 if (*s == CMDQ) { /* Backslash (quote character)? */
2490 if ((x = xxesc(&s)) > -1) { /* Go interpret it. */
2491 *q++ = (char) x; /* Numeric backslash code, ok */
2492 } else { /* Just let it quote next char */
2493 s++; /* get past the backslash */
2494 *q++ = *s++; /* deposit next char */
2497 } else if (*s == SP || *s == NUL) { /* Unquoted space or NUL? */
2498 *q++ = NUL; /* End of output filename. */
2499 msfiles[r] = p; /* Add this filename to the list */
2500 debug(F111,"fnparse",msfiles[r],r);
2502 if (*s == NUL) break; /* End of string? */
2503 while (*s == SP) s++; /* Skip repeated spaces */
2504 p = q; /* Start of next name */
2506 } else *q++ = *s; /* Otherwise copy the character */
2507 s++; /* Next input character */
2509 debug(F101,"fnparse r","",r);
2510 msfiles[r] = ""; /* Put empty string at end of list */
2514 #endif /* NOMSEND */
2516 char * /* dbchr() for DEBUG SESSION */
2522 if (c & 0x80) { /* 8th bit on */
2526 if (c < SP) { /* Control character */
2528 *cp++ = (char) ctl(c);
2529 } else if (c == DEL) {
2532 } else { /* Printing character */
2535 *cp = '\0'; /* Terminate string */
2536 cp = s; /* Return pointer to it */
2540 /* C K H O S T -- Get name of local host (where C-Kermit is running) */
2543 Call with pointer to buffer to put hostname in, and length of buffer.
2544 Copies hostname into buffer on success, puts null string in buffer on
2555 #include <sys/utsname.h>
2560 #include <utsname.h>
2561 #endif /* BELLV10 */
2562 #endif /* SVORPOSIX*/
2565 extern char uidbuf[], * clienthost;
2566 #endif /* CKSYSLOG */
2569 ckhost(vvbuf,vvlen) char * vvbuf; int vvlen; {
2575 #endif /* NOSERVER */
2580 #else /* Everything else - rest of this routine */
2592 struct utsname hname;
2593 #endif /* APOLLOSR10 */
2594 #endif /* _386BSD */
2596 #endif /* SVORPOSIX */
2598 int ac0 = (char *) vvbuf, ac1 = -1, ac2 = 0;
2599 #endif /* datageneral */
2602 if (getenv("CK_NOPUSH")) { /* No shell access allowed */
2603 nopush = 1; /* on this host... */
2606 #endif /* NOSERVER */
2610 *vvbuf = NUL; /* How let's get our host name ... */
2612 #ifndef BELLV10 /* Does not have gethostname() */
2616 ckstrncpy(vvbuf,"Apollo",vvlen);
2619 if (gethostname(vvbuf,vvlen) < 0)
2623 if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
2627 if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
2629 if (uname(&hname) > -1) ckstrncpy(vvbuf,hname.nodename,vvlen);
2630 #endif /* TCPSOCKET */
2631 #else /* SVORPOSIX but not _386BSD or BSD44 */
2633 if (uname(&hname) > -1) ckstrncpy(vvbuf,hname.nodename,vvlen);
2635 if (uname(&hname) > -1) {
2639 #ifndef NOCKGETFQHOST
2640 if (!ckstrchr(p,'.'))
2641 p = (char *)ckgetfqhostname(p);
2642 #endif /* NOCKGETFQHOST */
2643 #endif /* TCPSOCKET */
2645 if (!*p) p = "(unknown)";
2646 ckstrncpy(vvbuf,p,vvlen);
2648 #endif /* __ia64__ */
2650 #endif /* _386BSD */
2652 #endif /* APOLLOSR10 */
2653 #else /* !SVORPOSIX */
2655 if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
2658 g = getenv("SYS$NODE");
2659 if (g) ckstrncpy(vvbuf,g,vvlen);
2660 x = (int)strlen(vvbuf);
2661 if (x > 1 && vvbuf[x-1] == ':' && vvbuf[x-2] == ':') vvbuf[x-2] = NUL;
2664 if (sys($HNAME,&ac0,&ac1,&ac2) == 0) /* successful */
2665 vvlen = ac2 + 1; /* enh - have to add one */
2667 #ifdef OS2 /* OS/2 */
2668 g = os2_gethostname();
2669 if (g) ckstrncpy(vvbuf,g,vvlen);
2673 if (gethostname(vvbuf, vvlen) < 0) *vvbuf = NUL;
2674 #endif /* TCPSOCKET */
2677 #endif /* datageneral */
2680 #endif /* SVORPOSIX */
2682 /* If TCP/IP is not installed, gethostname() fails, use uname() */
2683 if (gethostname(vvbuf,vvlen) < 0) {
2684 if (uname(&hname) > -1)
2685 ckstrncpy(vvbuf,hname.nodename,vvlen);
2690 #endif /* BELLV10 */
2691 if (*vvbuf == NUL) { /* If it's still empty */
2692 g = getenv("HOST"); /* try this */
2693 if (g) ckstrncpy(vvbuf,g,vvlen);
2695 vvbuf[vvlen-1] = NUL; /* Make sure result is terminated. */
2704 A S K M O R E -- Poor person's "more".
2705 Returns 0 if no more, 1 if more wanted.
2712 extern int timelimit;
2716 #endif /* IKSDCONF */
2718 extern int apcstatus, apcactive;
2727 if (inserver && !iksdcf)
2729 #endif /* IKSDCONF */
2731 if (apcactive == APC_LOCAL ||
2732 (apcactive == APC_REMOTE && (apcstatus & APC_NOINP)))
2746 concb((char)escape); /* Force CBREAK mode. */
2756 #endif /* NOSETBUF */
2765 cx = cmdgetc(timelimit);
2766 if (cx < -1 && timelimit) {
2767 printf("\n?IKS idle timeout - Goodbye.\n");
2768 doexit(GOOD_EXIT,0);
2769 } else if (cx == -1) { /* Connection lost */
2776 conbin((char)escape); /* Protect against Ctrl-Z */
2778 concb((char)escape);
2782 debug(F101,"askmore cmdgetc","",cx);
2784 debug(F100,"askmore EOF","",0);
2793 debug(F101,"askmore c","",c);
2800 case 'p': case 'P': case 'g': case 'G': /* Proceed or Go */
2802 /* fall thru on purpose */
2804 case SP: case 'y': case 'Y': case 012: case 015:
2806 write(1, "\015 \015", sizeof "\015 \015" - 1);
2808 printf("\015 \015");
2813 case 'n': case 'N': case 'q': case 'Q':
2825 printf("^%c...\n", (c + 0100));
2827 printf("^%c...\015\012", (c + 0100));
2831 /* Invalid answer */
2833 debug(F111,"askmore","invalid answer",c);
2834 printf("Y or space-bar for yes, N for no, G to show the rest\n");
2846 /* T R A P -- Terminal interrupt handler */
2853 #endif /* CK_ANSIC */
2855 extern int b_save, f_save;
2857 extern int timelimit;
2860 extern unsigned long startflags;
2863 #endif /* NOSETKEY */
2867 extern int i_active, instatus;
2872 extern int zchkod, zchkid;
2874 extern int unkmacro;
2882 signal(SIGINT, SIG_ACK);
2885 /* GEM is not reentrant, no i/o from interrupt level */
2886 cklongjmp(cmjbuf,1); /* Jump back to parser now! */
2892 debug(F101,"trap caught SIGINT","",sig);
2894 debug(F101,"trap caught signal","",sig);
2899 if ( sig == SIGBREAK && (startflags & 128) ) {
2900 debug(F101,"trap ignoring SIGBREAK","",sig);
2906 timelimit = 0; /* In case timed ASK interrupted */
2908 unkmacro = 0; /* Or ON_UNKNOWN_MACRO interrupted.. */
2911 zchkod = 0; /* Or file expansion interrupted... */
2915 if (what & W_CONNECT) { /* Are we in CONNECT mode? */
2917 The HP workstation Reset key sends some kind of ueber-SIGINT that can not
2918 be SIG_IGNored, so we wind up here somehow (even though this is *not* the
2919 current SIGINT handler). Just return.
2921 debug(F101,"trap: SIGINT caught during CONNECT","",sig);
2925 if (i_active) { /* INPUT command was active? */
2926 i_active = 0; /* Not any more... */
2927 instatus = INP_UI; /* INPUT status = User Interrupted */
2932 ftreset(); /* Restore global protocol settings */
2933 binary = b_save; /* Then restore these */
2939 zclose(ZIFILE); /* If we were transferring a file, */
2940 zclose(ZOFILE); /* close it. */
2942 cmdsquo(cmd_quoting); /* If command quoting was turned off */
2945 extern FILE * learnfp;
2946 extern int learning;
2953 #endif /* CKLEARN */
2956 delmac("_apc_commands",1);
2957 apcactive = APC_INACTIVE;
2964 if (ft_win) { /* If curses window open */
2965 debug(F100,"^C trap() curses","",0);
2966 xxscreen(SCR_CW,0,0L,""); /* Close it */
2967 conres(); /* Restore terminal */
2968 i = printf("^C..."); /* Echo ^C to standard output */
2971 i = printf("^C...\n"); /* Echo ^C to standard output */
2973 if (i < 1 && ferror(stdout)) { /* If there was an error */
2974 debug(F100,"^C trap() error","",0);
2975 fclose(stdout); /* close standard output */
2976 f = fopen(dftty, "w"); /* open the controlling terminal */
2977 if (f) stdout = f; /* and make it standard output */
2978 printf("^C...\n"); /* and echo the ^C again. */
2982 conres(); /* Set console back to normal mode */
2983 #endif /* STRATUS */
2985 if (ft_win) { /* If curses window open, */
2986 debug(F100,"^C trap() curses","",0);
2987 xxscreen(SCR_CW,0,0L,""); /* close it. */
2988 printf("^C..."); /* Echo ^C to standard output */
2997 connoi_mt(); /* Kill asynch task that listens to */
2999 conres(); /* the keyboard */
3000 #endif /* datageneral */
3003 /* This is stupid -- every version should have ttimoff()... */
3005 ttimoff(); /* Turn off any timer interrupts */
3008 ttimoff(); /* Turn off any timer interrupts */
3011 ttimoff(); /* Turn off any timer interrupts */
3015 os2gks = 1; /* Turn back on keycode mapping */
3016 #endif /* NOSETKEY */
3018 for (i = 0; i < VNUM; i++)
3020 #endif /* NOLOCAL */
3023 /* WSAIsBlocking() returns FALSE in Win95 during a blocking accept call */
3024 if ( WSASafeToCancel /* && WSAIsBlocking() */ ) {
3025 WSACancelBlockingCall();
3028 #endif /* TCPSOCKET */
3030 NCBCancelOutstanding();
3031 #endif /* CK_NETBIOS */
3032 ttimoff(); /* Turn off any timer interrupts */
3035 ttimoff(); /* Turn off any timer interrupts */
3038 #endif /* STRATUS */
3045 We are in an intercept routine but do not perform a F$RTE (done implicitly
3046 by rts). We have to decrement the sigmask as F$RTE does. Warning: longjump
3047 only restores the cpu registers, NOT the fpu registers. So don't use fpu at
3048 all or at least don't use common fpu (double or float) register variables.
3055 debug(F100,"trap about to longjmp","",0);
3057 cklongjmp(ckjaddr(cmjbuf),1);
3059 cklongjmp(cmjbuf,1);
3062 #else /* NOCCTRAP */
3063 /* No Ctrl-C trap, just exit. */
3064 #ifdef CK_CURSES /* Curses support? */
3065 xxscreen(SCR_CW,0,0L,""); /* Close curses window */
3066 #endif /* CK_CURSES */
3067 doexit(BAD_EXIT,what); /* Exit poorly */
3068 #endif /* NOCCTRAP */
3073 /* C K _ T I M E -- Returns pointer to current time. */
3077 static char tbuf[10];
3081 ztime(&p); /* "Thu Feb 8 12:00:00 1990" */
3082 if (!p) /* like asctime()! */
3085 for (x = 11; x < 19; x++) /* copy hh:mm:ss */
3086 tbuf[x - 11] = p[x]; /* to tbuf */
3087 tbuf[8] = NUL; /* terminate */
3089 return(tbuf); /* and return it */
3092 /* C C _ C L E A N -- Cleanup after terminal interrupt handler */
3097 zclose(ZIFILE); /* If we were transferring a file, */
3098 zclose(ZOFILE); /* close it. */
3099 printf("^C...\n"); /* Not VMS, no problem... */
3104 /* S T P T R A P -- Handle SIGTSTP (suspend) signals */
3110 stptrap(sig) int sig;
3111 #endif /* CK_ANSIC */
3115 int x; extern int cmflgs;
3116 debug(F101,"stptrap() caught signal","",sig);
3118 printf("\r\nsuspend disabled\r\n");
3120 if (what & W_COMMAND) { /* If we were parsing commands */
3121 prompt(xxstring); /* reissue the prompt and partial */
3122 if (!cmflgs) /* command (if any) */
3123 printf("%s",cmdbuf);
3127 conres(); /* Reset the console */
3129 /* Flush pending output first, in case we are continued */
3130 /* in the background, which could make us block */
3133 x = psuspend(xsuspend); /* Try to suspend. */
3136 printf("Job control not supported\r\n");
3137 conint(trap,stptrap); /* Rearm the trap. */
3138 debug(F100,"stptrap back from suspend","",0);
3140 case W_CONNECT: /* If suspended during CONNECT? */
3141 conbin((char)escape); /* put console back in binary mode */
3142 debug(F100,"stptrap W_CONNECT","",0);
3145 case W_COMMAND: /* Suspended in command mode */
3146 debug(F101,"stptrap W_COMMAND pflag","",pflag);
3147 concb((char)escape); /* Put back CBREAK tty mode */
3148 if (pflag) { /* If command parsing was */
3149 prompt(xxstring); /* reissue the prompt and partial */
3150 if (!cmflgs) /* command (if any) */
3151 printf("%s",cmdbuf);
3155 default: /* All other cases... */
3156 debug(F100,"stptrap default","",0);
3157 concb((char)escape); /* Put it back in CBREAK mode */
3168 /* T L O G -- Log a record in the transaction file */
3170 Call with a format and 3 arguments: two strings and a number:
3171 f - Format, a bit string in range 0-7, bit x is on, arg #x is printed.
3172 s1,s2 - String arguments 0 and 1.
3173 n - Long, argument 2.
3177 dotlog(int f, char *s1, char *s2, long n)
3179 dotlog(f,s1,s2,n) int f; long n; char *s1, *s2;
3180 #endif /* CK_ANSIC */
3182 static char s[TBUFL];
3184 char *sp = s; int x;
3188 if (!tralog) return; /* If no transaction log, don't */
3189 if (tlogfmt != 1) return;
3191 case F000: /* 0 (special) "s1 n s2" */
3192 if ((int)strlen(s1) + (int)strlen(s2) + 15 > TBUFL)
3193 sprintf(sp,"?T-Log string too long");
3195 sprintf(sp,"%s %ld %s",s1,n,s2);
3196 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3198 case F001: /* 1, " n" */
3199 sprintf(sp," %ld",n);
3200 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3202 case F010: /* 2, "[s2]" */
3203 x = (int)strlen(s2);
3204 if (s2[x] == '\n') s2[x] = '\0';
3206 sprintf(sp,"?String too long");
3207 else sprintf(sp,"[%s]",s2);
3208 if (zsoutl(ZTFILE,"") < 0) tralog = 0;
3210 case F011: /* 3, "[s2] n" */
3211 x = (int)strlen(s2);
3212 if (s2[x] == '\n') s2[x] = '\0';
3214 sprintf(sp,"?String too long");
3215 else sprintf(sp,"[%s] %ld",s2,n);
3216 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3218 case F100: /* 4, "s1" */
3219 if (zsoutl(ZTFILE,s1) < 0) tralog = 0;
3221 case F101: /* 5, "s1: n" */
3222 if ((int)strlen(s1) + 15 > TBUFL)
3223 sprintf(sp,"?String too long");
3224 else sprintf(sp,"%s: %ld",s1,n);
3225 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3227 case F110: /* 6, "s1 s2" */
3228 x = (int)strlen(s2);
3229 if (s2[x] == '\n') s2[x] = '\0';
3230 if ((int)strlen(s1) + x + 4 > TBUFL)
3231 sprintf(sp,"?String too long");
3233 sprintf(sp,"%s%s%s",s1,((*s2 == ':') ? "" : " "),s2);
3234 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3236 case F111: /* 7, "s1 s2: n" */
3237 x = (int)strlen(s2);
3238 if (s2[x] == '\n') s2[x] = '\0';
3239 if ((int)strlen(s1) + x + 15 > TBUFL)
3240 sprintf(sp,"?String too long");
3242 sprintf(sp,"%s%s%s: %ld",s1,((*s2 == ':') ? "" : " "),s2,n);
3243 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3246 sprintf(sp,"?Invalid format for tlog() - %ld",n);
3247 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3254 This is the transaction-log writer for BRIEF format.
3255 The idea is produce one record (line) per file. Each record
3256 has the following delimited fields:
3259 Action: SEND or RECV
3262 Transfer mode (text, binary, image, labeled, etc).
3263 Status: OK or FAILED
3264 Free-form comments in doublequotes
3265 The default separator is comma.
3266 If a field contains the separator, it is enclosed in doublequotes.
3270 doxlog(int x, char * fn, long fs, int fm, int status, char * msg)
3272 doxlog(x, fn, fs, fm, status, msg)
3273 int x; char * fn; long fs; int fm; int status; char * msg;
3274 #endif /* CK_ANSIC */
3278 char buf[CKMAXPATH+256], * bufp;
3281 int len, left, ftp = 0, k;
3283 if (!tralog) return; /* If no transaction log, don't */
3285 if (!fn) fn = ""; /* Protect against null pointers */
3290 sep[0] = (char) tlogsep;
3292 if (!sep[0]) sep[0] = ',';
3296 debug(F101,"XXX doxlog left 1","",left);
3298 p = zzndate(); /* Date */
3299 ckmakmsg(buf, left, p ? p : "00000000", sep, NULL, NULL);
3302 debug(F111,"XXX doxlog left 2",buf,left);
3305 ckstrncpy(bufp,p+11,left);
3308 debug(F111,"XXX doxlog left 3",buf,left);
3311 if (!(x & (W_SEND|W_RECV)))
3313 s = (x & W_SEND) ? "PUT" : "GET";
3316 s = (x & W_SEND) ? "SEND" : "RECV";
3319 ckmakmsg(bufp,left,sep,s,sep,NULL);
3322 debug(F111,"XXX doxlog left 4",buf,left);
3325 if (ckstrchr(fn,sep[0])) /* Filename */
3327 ckmakmsg(bufp,left,s,fn,s,sep);
3328 sprintf(tmpbuf,"%ld",fs); /* Size */
3329 ckstrncat(buf,tmpbuf,CKMAXPATH);
3330 ckstrncat(buf,sep,CKMAXPATH);
3331 debug(F110,"doxlog 4",buf,0);
3335 ckstrncpy(tmpbuf, (binary ? "binary" : "text"), TMPBUFSIZ);
3337 ckstrncpy(tmpbuf,gfmode(fm,0),TMPBUFSIZ);
3339 if (ckstrchr(tmpbuf,sep[0])) { /* Might contain spaces */
3340 ckstrncat(buf,"\"",CKMAXPATH);
3341 ckstrncat(buf,tmpbuf,CKMAXPATH);
3342 ckstrncat(buf,"\"",CKMAXPATH);
3344 ckstrncat(buf,tmpbuf,CKMAXPATH);
3345 ckstrncat(buf,sep,CKMAXPATH);
3346 debug(F110,"doxlog 5",buf,0);
3348 ckstrncat(buf, status ? "FAILED" : "OK",CKMAXPATH);
3350 left = CKMAXPATH+256 - len;
3351 if (left < 2) fatal("doxlog buffer overlow");
3353 debug(F111,"XXX doxlog left 5",buf,left);
3355 debug(F110,"doxlog buf 1", buf, len);
3357 if (status == 0 && left > 32) {
3361 debug(F101,"DOXLOG fpxfsecs","",(long)(fpxfsecs * 1000));
3363 cps = (long)((CKFLOAT) fs / fpxfsecs);
3364 sprintf(s,"%s\"%0.3fsec %ldcps\"",sep,fpxfsecs,cps);
3367 sprintf(s,"%s\"%ldsec %ldcps\"",sep,xfsecs,cps);
3368 #endif /* GFTIMER */
3369 } else if ((int)strlen(msg) + 4 < left) {
3370 sprintf(s,"%s\"%s\"",sep,msg);
3372 debug(F111,"XXX doxlog left 5",buf,left);
3374 debug(F110,"doxlog 5",buf,0);
3375 x = zsoutl(ZTFILE,buf);
3376 debug(F101,"doxlog zsoutl","",x);
3377 if (x < 0) tralog = 0;
3383 The rest of this file is for all implementations but the Macintosh.
3387 static int repaint = 0; /* Transfer display needs repainting */
3388 #endif /* CK_CURSES */
3391 /* C H K I N T -- Check for console interrupts */
3394 Used during file transfer in local mode only:
3395 . If user has not touched the keyboard, returns 0 with no side effects.
3396 . If user typed S or A (etc, see below) prints status message and returns 0.
3397 . If user typed X or F (etc, see below) returns 0 with cxseen set to 1.
3398 . If user typed Z or B (etc, see below) returns 0 with czseen set to 1.
3399 . If user typed E or C (etc, see below) returns -1.
3403 int ch, cn, ofd; long zz;
3406 if ((!local) || (quiet)) return(0); /* Only do this if local & not quiet */
3408 if (con_reads_mt) /* if conint_mt task is active */
3409 if (conint_avl) { /* and there's an interrupt pending */
3410 cn = 1; /* process it */
3412 conint_avl = 0; /* turn off flag so conint_mt can */
3413 } else /* proceed */
3415 else /* if conint_mt not active */
3416 if ((ch = coninc(2)) < 0) /* try to get char manually */
3417 return(0); /* I/O error, or no data */
3418 else /* if successful, set cn so we */
3419 cn = 1; /* know we got one */
3420 debug(F101,"chkint got keyboard character",ch,cn);
3421 #else /* !datageneral */
3424 extern int TlsIndex;
3425 struct _threadinfo * threadinfo;
3426 threadinfo = (struct _threadinfo *) TlsGetValue(TlsIndex);
3428 if (!WaitSem(threadinfo->DieSem,0))
3429 return -1; /* Cancel Immediately */
3433 cn = conchk(); /* Any input waiting? */
3434 debug(F101,"conchk","",cn);
3435 if (cn < 1) return(0);
3437 debug(F101,"coninc","",ch);
3438 if (ch < 0) return(0);
3439 #endif /* datageneral */
3443 case 'A': case 'a': case 0001: /* Status report */
3445 if (fdispla != XYFD_R && fdispla != XYFD_S && fdispla != XYFD_N)
3446 return(0); /* Only for serial, simple or none */
3447 ofd = fdispla; /* [MF] Save file display type */
3448 if (fdispla == XYFD_N)
3449 fdispla = XYFD_R; /* [MF] Pretend serial if no display */
3450 xxscreen(SCR_TN,0,0l,"Status report:");
3451 xxscreen(SCR_TN,0,0l," file type: ");
3454 case XYFT_L: xxscreen(SCR_TZ,0,0l,"labeled"); break;
3455 case XYFT_I: xxscreen(SCR_TZ,0,0l,"image"); break;
3456 case XYFT_U: xxscreen(SCR_TZ,0,0l,"binary undefined"); break;
3458 case XYFT_B: xxscreen(SCR_TZ,0,0l,"binary"); break;
3462 xxscreen(SCR_TZ,0,0l,"text");
3464 xxscreen(SCR_TU,0,0l,"text, ");
3465 if (tcharset == TC_TRANSP || xfrxla == 0) {
3466 xxscreen(SCR_TZ,0,0l,"transparent");
3468 if (what & W_SEND) {
3469 xxscreen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword);
3470 xxscreen(SCR_TU,0,0l," => ");
3471 xxscreen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword);
3473 xxscreen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword);
3474 xxscreen(SCR_TU,0,0l," => ");
3475 xxscreen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword);
3478 #endif /* NOCSETS */
3480 xxscreen(SCR_QE,0,filcnt," file number");
3481 if (fsize) xxscreen(SCR_QE,0,fsize," size");
3482 xxscreen(SCR_QE,0,ffc," characters so far");
3485 zz = what & W_SEND ? sendstart : what & W_RECV ? rs_len : 0;
3486 zz = ( (ffc + zz) * 100L ) / fsize;
3488 zz = ( ffc * 100L ) / fsize;
3489 #endif /* CK_RESEND */
3490 xxscreen(SCR_QE,0,zz, " percent done");
3492 if (bctu == 4) { /* Block check */
3493 xxscreen(SCR_TU,0,0L," block check: ");
3494 xxscreen(SCR_TZ,0,0L,"blank-free-2");
3495 } else xxscreen(SCR_QE,0,(long)bctu, " block check");
3496 xxscreen(SCR_QE,0,(long)rptflg," compression");
3497 xxscreen(SCR_QE,0,(long)ebqflg," 8th-bit prefixing");
3498 xxscreen(SCR_QE,0,(long)lscapu," locking shifts");
3500 xxscreen(SCR_QE,0, speed, " speed");
3503 xxscreen(SCR_QE,0,(long)spsiz, " packet length");
3504 else if (what & W_RECV || what & W_REMO)
3505 xxscreen(SCR_QE,0,(long)urpsiz," packet length");
3506 xxscreen(SCR_QE,0,(long)wslots, " window slots");
3507 fdispla = ofd; /* [MF] Restore file display type */
3510 case 'B': case 'b': case 0002: /* Cancel batch */
3511 case 'Z': case 'z': case 0032:
3514 xxscreen(SCR_ST,ST_MSG,0l,
3515 (((what & W_RECV) && (wslots > 1)) ?
3516 "Canceling batch, wait... " :
3517 "Canceling batch... ")
3521 case 'F': case 'f': case 0006: /* Cancel file */
3522 case 'X': case 'x': case 0030:
3525 xxscreen(SCR_ST,ST_MSG,0l,
3526 (((what & W_RECV) && (wslots > 1)) ?
3527 "Canceling file, wait... " :
3528 "Canceling file... ")
3532 case 'R': case 'r': case 0022: /* Resend packet */
3533 case 0015: case 0012:
3537 #endif /* STREAMING */
3538 xxscreen(SCR_ST,ST_MSG,0l,"Resending packet... ");
3544 case '\03': /* We're not trapping ^C's with */
3545 trap(0); /* signals, so we check here */
3546 #endif /* datageneral */
3548 case 'C': case 'c': /* Ctrl-C */
3551 #endif /* datageneral */
3553 case 'E': case 'e': /* Send error packet */
3559 case 0014: /* Ctrl-L to refresh screen */
3560 case 'L': case 'l': /* Also accept L (upper, lower) */
3561 case 0027: /* Ctrl-W synonym for VMS & Ingres */
3564 #endif /* CK_CURSES */
3567 case 't': /* Turn on debug-log timestamps */
3573 xxscreen(SCR_ST,ST_MSG,0l,
3574 "Debug timestamps On... ");
3577 xxscreen(SCR_ST,ST_MSG,0l,
3578 "Debug timestamps Off... ");
3587 debopn("debug.log",0);
3589 xxscreen(SCR_ST,ST_MSG,0l,"debug.log open... ");
3591 xxscreen(SCR_ST,ST_MSG,0l,"debug.log open FAILED... ");
3594 xxscreen(SCR_ST,ST_MSG,0l,"Debug log On... ");
3601 case 'd': /* Turn off debugging */
3604 xxscreen(SCR_ST,ST_MSG,0l,"Debug log Off... ");
3609 default: /* Anything else, print message */
3615 /* I N T M S G -- Issue message about terminal interrupts */
3622 #endif /* CK_ANSIC */
3626 #endif /* CK_NEED_SIG */
3628 if (!displa || quiet) /* Not if we're being quiet */
3630 if (server && (!srvdis || n > -1L)) /* Special for server */
3633 buf[0] = NUL; /* Keep compilers happy */
3634 #endif /* CK_NEED_SIG */
3637 conchk(); /* Clear out pending escape-signals */
3638 #endif /* SVORPOSIX */
3641 conres(); /* So Ctrl-C will work */
3643 if ((!server && n == 1L) || (server && n < 0L)) {
3649 "Type escape character (",
3654 xxscreen(SCR_TN,0,0l,buf);
3656 #endif /* CK_NEED_SIG */
3659 if (protocol == PROTO_K) {
3660 xxscreen(SCR_TN,0,0l,"X to cancel file, CR to resend current packet");
3661 xxscreen(SCR_TN,0,0l,"Z to cancel group, A for status report");
3662 xxscreen(SCR_TN,0,0l,"E to send Error packet, Ctrl-C to quit immediately: ");
3664 xxscreen(SCR_TN,0,0l,"Ctrl-C to cancel file transfer: ");
3667 xxscreen(SCR_TN,0,0l,"Transfer interruption disabled. ");
3670 else xxscreen(SCR_TU,0,0l," ");
3674 static int newdpy = 0; /* New display flag */
3675 static char fbuf[80]; /* Filename buffer */
3676 static char abuf[80]; /* As-name buffer */
3677 static char a2buf[80]; /* Second As-name buffer */
3678 static long oldffc = 0L;
3679 static long dots = 0L;
3680 static int hpos = 0;
3682 static VOID /* Initialize Serial or CRT display */
3687 newdpy = 0; /* Don't do this again */
3688 oldffc = 0L; /* Reset this */
3689 dots = 0L; /* and this.. */
3692 conoll(""); /* New line */
3693 if (what & W_SEND) s = "Sending: "; /* Action */
3694 else if (what & W_RECV) s = "Receiving: ";
3695 n = (int)strlen(s) + (int)strlen(fbuf);
3697 m = (int)strlen(abuf) + 4;
3698 if (n + m > cmd_cols) {
3707 m = (int)strlen(a2buf) + 4;
3708 if (n + m > cmd_cols) {
3717 *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
3719 if (fsize > -1L) { /* Size */
3720 sprintf(fbuf,"Size: %ld, Type: ",fsize); /* SAFE (80) */
3721 conol(fbuf); *fbuf = NUL;
3722 } else conol("Size: unknown, Type: ");
3723 if (binary) { /* Type */
3725 case XYFT_L: conol("labeled"); break;
3726 case XYFT_I: conol("image"); break;
3727 case XYFT_U: conol("binary undefined"); break;
3729 case XYFT_B: conol("binary"); break;
3736 if (tcharset == TC_TRANSP || xfrxla == 0) {
3737 conol("transparent");
3739 if (what & W_SEND) {
3740 conol(fcsinfo[fcharset].keyword);
3742 conol(tcsinfo[tcharset].keyword);
3744 conol(tcsinfo[tcharset].keyword);
3746 conol(fcsinfo[fcharset].keyword);
3749 #endif /* NOCSETS */
3753 conol(", STREAMING");
3754 #endif /* STREAMING */
3757 if (fdispla == XYFD_S) { /* CRT field headings */
3759 Define CK_CPS to show current transfer rate.
3760 Leave it undefined to show estimated time remaining.
3761 Estimated-time-remaining code from Andy Fyfe, not tested on
3767 conoll(" File Percent Packet");
3768 conoll(" Bytes Done CPS Length");
3770 conoll(" File Percent Secs Packet");
3771 conoll(" Bytes Done Left Length");
3780 c = completion code: 0 means transfer in progress, nonzero means it's done.
3781 Show the file transfer progress counter and perhaps verbose packet type.
3788 #endif /* CK_ANSIC */
3792 long et; /* Elapsed time, entire batch */
3793 #endif /* GFTIMER */
3794 long howfar; /* How far into file */
3795 long pd; /* Percent done, this file */
3796 long tp; /* Transfer rate, entire batch */
3797 long ps; /* Packet size, current packet */
3798 long mytfc; /* Local copy of byte counter */
3802 #endif /* GFTIMER */
3804 if (newdpy) /* Put up filenames, etc, */
3805 dpyinit(); /* if they're not there already. */
3807 howfar = ffc; /* How far */
3809 Calculate CPS rate even if not displaying on screen for use in file
3810 transfer statistics.
3813 tnow = gftimer(); /* Time since we started */
3814 ps = (what & W_RECV) ? rpktl : spktl; /* Packet size */
3816 if (what & W_SEND) /* In case we didn't start at */
3817 howfar += sendstart; /* the beginning... */
3818 else if (what & W_RECV)
3820 #endif /* CK_RESEND */
3821 pd = -1; /* Percent done. */
3822 if (c == NUL) { /* Still going, figure % done */
3823 if (fsize == 0L) return; /* Empty file, don't bother */
3824 pd = (fsize > 99L) ? (howfar / (fsize / 100L)) : 0L;
3825 if (pd > 100) pd = 100; /* Expansion */
3828 if (!cxseen && !discard && !czseen)
3829 pd = 100; /* File complete, so 100%. */
3831 mytfc = (pd < 100) ? tfc + ffc : tfc; /* CPS */
3832 tp = (long)((tnow > 0.0) ? (CKFLOAT) mytfc / tnow : 0);
3836 cps = tp; /* Set global variable */
3837 if (cps > peakcps && /* Peak transfer rate */
3838 ((what & W_SEND && spackets > wslots + 4) ||
3839 (!(what & W_SEND) && spackets > 10))) {
3843 #else /* Not GFTIMER */
3845 et = gtimer(); /* Elapsed time */
3846 ps = (what & W_RECV) ? rpktl : spktl; /* Packet length */
3848 if (what & W_SEND) /* And if we didn't start at */
3849 howfar += sendstart; /* the beginning... */
3850 else if (what & W_RECV)
3852 #endif /* CK_RESEND */
3853 pd = -1; /* Percent done. */
3854 if (c == NUL) { /* Still going, figure % done */
3855 if (fsize == 0L) return; /* Empty file, don't bother */
3856 pd = (fsize > 99L) ? (howfar / (fsize / 100L)) : 0L;
3857 if (pd > 100) pd = 100; /* Expansion */
3860 if (!cxseen && !discard && !czseen)
3861 pd = 100; /* File complete, so 100%. */
3866 fsecs = time (from gtimer) that this file started (set in sfile()).
3867 Rate so far is ffc / (et - fsecs), estimated time for remaining bytes
3868 is (fsize - ffc) / (ffc / (et - fsecs)).
3870 tp = (howfar > 0L) ? (fsize - howfar) * (et - fsecs) / howfar : 0L;
3874 mytfc = (pd < 100) ? tfc + ffc : tfc;
3875 tp = (et > 0) ? mytfc / et : 0; /* Transfer rate */
3876 if (c && (tp == 0)) /* Watch out for subsecond times */
3879 cps = tp; /* Set global variable */
3880 if (cps > peakcps && /* Peak transfer rate */
3881 ((what & W_SEND && spackets > wslots + 4) ||
3882 (!(what & W_SEND) && spackets > 10))) {
3887 #endif /* GFTIMER */
3889 if (fdispla == XYFD_S) { /* CRT display */
3891 /* These sprintfs should be safe until we have 32-digit numbers */
3894 sprintf(buffer, "%c%9ld%5ld%%%8ld%8ld ", CR, howfar, pd, tp, ps);
3896 sprintf(buffer, "%c%9ld %8ld%8ld ", CR, howfar, tp, ps);
3899 } else if (fdispla == XYFD_R) { /* SERIAL */
3901 if (howfar - oldffc < 1024) /* Update display every 1K */
3903 oldffc = howfar; /* Time for new display */
3904 k = (howfar / 1024L) - dots; /* How many K so far */
3905 for (i = 0L; i < k; i++) {
3906 if (hpos++ > (cmd_cols - 3)) { /* Time to wrap? */
3910 conoc('.'); /* Print a dot for this K */
3911 dots++; /* Count it */
3917 /* C K S C R E E N -- Screen display function */
3921 f - argument descriptor
3922 c - a character or small integer
3926 and global fdispla = SET FILE DISPLAY value:
3929 XYFD_R = SERIAL: Dots, etc, works on any terminal, even hardcopy.
3930 XYFD_S = CRT: Works on any CRT, writes over current line.
3931 XYFD_C = FULLSCREEN: Requires terminal-dependent screen control.
3932 XYFD_B = BRIEF: Like SERIAL but only filename & completion status.
3933 XYFD_G = GUI; Windows GUI, same behavior as FULLSCREEN
3937 ckscreen(int f, char c,long n,char *s)
3939 ckscreen(f,c,n,s) int f; char c; long n; char *s;
3940 #endif /* CK_ANSIC */
3943 int len; /* Length of string */
3947 _PROTOTYP( VOID conbgt, (int) );
3952 ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit? */
3954 if (!local && !ftp) /* In remote mode - don't do this */
3959 if (!fxd_inited) /* Initialize if necessary */
3964 obg = backgrd; /* Previous background status */
3965 conbgt(1); /* See if running in background */
3966 if (!backgrd && obg) { /* Just came into foreground? */
3967 concb((char)escape); /* Put console back in CBREAK mode */
3968 setint(); /* Restore interrupts */
3973 if ((f != SCR_WM) && (f != SCR_EM)) /* Always update warnings & errors */
3975 (backgrd && bgset) ||
3976 fdispla == XYFD_N ||
3982 if (f == SCR_FN) /* VMS - shorten the name */
3983 s = zrelname(s,zgtdir());
3986 if (dest == DEST_S) /* SET DESTINATION SCREEN */
3987 return; /* would interfere... */
3990 if (fdispla == XYFD_G) { /* If gui display selected */
3991 screeng(f,c,n,s); /* call the gui version */
3996 if (fdispla == XYFD_C) { /* If fullscreen display selected */
3997 screenc(f,c,n,s); /* call the fullscreen version */
4000 #endif /* CK_CURSES */
4002 len = (int)strlen(s); /* Length of string */
4004 switch (f) { /* Handle our function code */
4005 case SCR_FN: /* Filename */
4006 if (fdispla == XYFD_B) {
4009 printf(" %s %s", what & W_SEND ? "PUT" : "GET", s);
4012 printf(" %s %s", what & W_SEND ? "SEND" : "RECV", s);
4019 conoll(""); conol(s); conoc(SP); hpos = len + 1;
4021 ckstrncpy(fbuf,s,80);
4022 abuf[0] = a2buf[0] = NUL;
4023 newdpy = 1; /* New file so refresh display */
4027 case SCR_AN: /* As-name */
4028 if (fdispla == XYFD_B) {
4030 printf("(as %s) ",s);
4031 #endif /* COMMENT */
4035 if (hpos + len > 75) { conoll(""); hpos = 0; }
4036 conol("=> "); conol(s);
4037 if ((hpos += (len + 3)) > 78) { conoll(""); hpos = 0; }
4040 ckstrncpy(a2buf,s,80);
4042 ckstrncpy(abuf,s,80);
4047 case SCR_FS: /* File-size */
4048 if (fdispla == XYFD_B) {
4049 printf(" (%s) (%ld byte%s)",
4051 (binary ? "binary" : "text")
4055 , n, n == 1L ? "" : "s");
4062 sprintf(buf,", Size: %ld",n); conoll(buf); hpos = 0;
4066 case SCR_XD: /* X-packet data */
4067 if (fdispla == XYFD_B)
4070 conoll(""); conoll(s); hpos = 0;
4072 ckstrncpy(fbuf,s,80);
4073 abuf[0] = a2buf[0] = NUL;
4077 case SCR_ST: /* File status */
4079 case ST_OK: /* Transferred OK */
4080 showpkt('Z'); /* Update numbers one last time */
4081 if (fdispla == XYFD_B) {
4083 printf(": OK (%0.3f sec, %ld cps)\n",fpxfsecs,
4084 (long)((CKFLOAT)ffc / fpxfsecs));
4086 printf(": OK (%d sec, %ld cps)\n",xfsecs,ffc/xfsecs);
4087 #endif /* GFTIMER */
4090 if ((hpos += 5) > 78) conoll(""); /* Wrap screen line. */
4091 conoll(" [OK]"); hpos = 0; /* Print OK message. */
4092 if (fdispla == XYFD_S) { /* We didn't show Z packet when */
4093 conoc('Z'); /* it came, so show it now. */
4098 case ST_DISC: /* Discarded */
4099 if (fdispla == XYFD_B) {
4100 printf(": DISCARDED\n");
4103 if ((hpos += 12) > 78) conoll("");
4104 conoll(" [discarded]"); hpos = 0;
4107 case ST_INT: /* Interrupted */
4108 if (fdispla == XYFD_B) {
4109 printf(": INTERRUPTED\n");
4112 if ((hpos += 14) > 78) conoll("");
4113 conoll(" [interrupted]"); hpos = 0;
4117 if (fdispla == XYFD_B) {
4119 printf(": WOULD BE TRANSFERRED (New file)\n");
4120 else if (n == SKP_XUP)
4121 printf(": WOULD BE TRANSFERRED (Remote file older)\n");
4122 else if (n == SKP_SIM)
4123 printf(": WOULD BE TRANSFERRED\n");
4124 else if (n > 0 && n < nskreason)
4125 printf(": SKIPPED (%s)\n",skreason[n]);
4127 printf(": SKIPPED\n");
4129 } else if (fdispla == XYFD_S) {
4130 if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
4131 conoll(""); /* New line */
4132 if (what & W_SEND) conol("Would Send: "); /* Action */
4133 else if (what & W_RECV) conol("Would Receive: ");
4135 if (*abuf) conol(" => "); conol(abuf); /* Names */
4136 if (*a2buf) conol(" => "); conol(a2buf); /* Names */
4137 *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
4139 conoll(" [simulated]");
4142 if ((hpos += 10) > 78) conoll("");
4143 conol(" [simulated]"); hpos = 0;
4146 case ST_SKIP: /* Skipped */
4147 if (fdispla == XYFD_B) {
4149 printf(": WOULD BE TRANSFERRED (New file)\n");
4150 else if (n == SKP_XUP)
4151 printf(": WOULD BE TRANSFERRED (Remote file older)\n");
4152 else if (n == SKP_SIM)
4153 printf(": WOULD BE TRANSFERRED\n");
4154 else if (n > 0 && n < nskreason)
4155 printf(": SKIPPED (%s)\n",skreason[n]);
4157 printf(": SKIPPED\n");
4159 } else if (fdispla == XYFD_S) {
4160 if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
4161 conoll(""); /* New line */
4162 if (what & W_SEND) conol("Sending: "); /* Action */
4163 else if (what & W_RECV) conol("Receiving: ");
4165 if (*abuf) conol(" => "); conol(abuf); /* Names */
4166 if (*a2buf) conol(" => "); conol(a2buf); /* Names */
4167 *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
4169 conoll(" [skipped]");
4172 if ((hpos += 10) > 78) conoll("");
4173 conol(" "); conol(fbuf);
4174 conoll(" [skipped]"); hpos = 0;
4177 case ST_ERR: /* Error */
4178 if (fdispla == XYFD_B) {
4179 printf(": ERROR: %s\n",s);
4183 conol("Error: "); conoll(s); hpos = 0;
4186 case ST_MSG: /* Message */
4188 if (fdispla == XYFD_B) {
4190 printf(": MESSAGE: %s\n",s);
4200 case ST_REFU: /* Refused */
4201 if (fdispla == XYFD_B) {
4202 printf(": REFUSED\n");
4204 } else if (fdispla == XYFD_S) {
4205 if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
4206 conoll(""); /* New line */
4207 if (what & W_SEND) conol("Sending: "); /* Action */
4208 else if (what & W_RECV) conol("Receiving: ");
4210 if (*abuf) conol(" => "); conol(abuf); /* Names */
4211 if (*a2buf) conol(" => "); conol(a2buf); /* Names */
4212 *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
4215 conol("Refused: "); conoll(s);
4219 conol("Refused: "); conoll(s); hpos = 0;
4222 case ST_INC: /* Incomplete */
4223 if (fdispla == XYFD_B) {
4224 printf(": INCOMPLETE\n");
4227 if ((hpos += 12) > 78) conoll("");
4228 conoll(" [incomplete]"); hpos = 0;
4232 conoll("*** screen() called with bad status ***");
4238 case SCR_PN: /* Packet number */
4239 if (fdispla == XYFD_B) {
4242 ckmakmsg(buf,80,s,": ",ckltoa(n),NULL);
4243 conol(buf); hpos += (int)strlen(buf); return;
4246 case SCR_PT: /* Packet type or pseudotype */
4247 if (fdispla == XYFD_B)
4249 if (c == 'Y') return; /* Don't bother with ACKs */
4250 if (c == 'D') { /* In data transfer phase, */
4251 showpkt(NUL); /* show progress. */
4255 if (hpos++ > 77) { /* If near right margin, */
4256 conoll(""); /* Start new line */
4257 hpos = 0; /* and reset counter. */
4260 if (c == 'Z' && fdispla == XYFD_S)
4263 conoc(c); /* Display the packet type. */
4265 if (c == 'G') conoll(""); /* New line after G packets */
4269 case SCR_TC: /* Transaction complete */
4270 if (xfrbel) bleep(BP_NOTE);
4271 if (fdispla == XYFD_B) { /* Brief display... */
4274 fx = filcnt - filrej;
4275 printf(" SUMMARY: %ld file%s", fx, ((fx == 1L) ? "" : "s"));
4276 printf(", %ld byte%s", tfc, ((tfc == 1L) ? "" : "s"));
4278 printf(", %0.3f sec, %ld cps", fptsecs, tfcps);
4280 printf(", %ld sec, %ld cps", tsecs, tfcps);
4281 #endif /* GFTIMER */
4292 case SCR_EM: /* Error message */
4293 if (fdispla == XYFD_B) {
4294 printf(" ERROR: %s\n",s);
4297 conoll(""); conoc('?'); conoll(s); hpos = 0; return;
4299 case SCR_WM: /* Warning message */
4300 if (fdispla == XYFD_B) {
4301 printf(" WARNING: %s\n",s);
4304 conoll(""); conoll(s); hpos = 0; return;
4306 case SCR_TU: /* Undelimited text */
4307 if (fdispla == XYFD_B)
4309 if ((hpos += len) > 77) { conoll(""); hpos = len; }
4312 case SCR_TN: /* Text delimited at beginning */
4313 if (fdispla == XYFD_B)
4315 conoll(""); conol(s); hpos = len; return;
4317 case SCR_TZ: /* Text delimited at end */
4318 if (fdispla == XYFD_B)
4320 if ((hpos += len) > 77) { conoll(""); hpos = len; }
4323 case SCR_QE: /* Quantity equals */
4324 if (fdispla == XYFD_B)
4326 ckmakmsg(buf,80,s,": ",ckltoa(n),NULL);
4327 conoll(buf); hpos = 0; return;
4329 case SCR_CW: /* Close fullscreen window */
4330 return; /* No window to close */
4336 conoll("*** screen() called with bad object ***");
4341 #endif /* NODISPLAY */
4343 /* E R M S G -- Nonfatal error message */
4345 /* Should be used only for printing the message text from an Error packet. */
4348 ermsg(msg) char *msg; { /* Print error message */
4349 debug(F110,"ermsg",msg,0);
4351 xxscreen(SCR_EM,0,0L,msg);
4352 tlog(F110,"Protocol Error:",msg,0L);
4357 setseslog(x) int x; {
4360 KuiSetProperty(KUI_TERM_CAPTURE,x,0);
4365 doclean(fc) int fc; { /* General cleanup */
4368 #endif /* OS2ORUNIX */
4370 extern int exithangup;
4372 extern char filnam[];
4378 dostop(); /* Stop all command files and end macros */
4395 tlog(F100,"Transaction Log Closed","",0L);
4402 debug(F100,"doclean calling dologend","",0);
4403 dologend(); /* End current log record if any */
4405 if (dialog) { /* If connection log open */
4407 *diafil = '\0'; /* close it. */
4410 #endif /* COMMENT */
4414 zclose(ZRFILE); /* READ and WRITE files, if any. */
4417 zclose(ZIFILE); /* And other files too */
4418 x = chkfn(ZOFILE); /* Download in progress? */
4419 debug(F111,"doclean chkfn ZOFILE",filnam,x);
4420 debug(F111,"doclean keep","",keep);
4421 zclose(ZOFILE); /* Close output file */
4422 if (x > 0 && !keep) { /* If it was being downloaded */
4424 x = zdelet(filnam); /* Delete if INCOMPLETE = DISCARD */
4425 debug(F111,"doclean download filename",filnam,x);
4431 if (fc < 1) { /* RESETing, not EXITing */
4433 if (deblog) { /* Close the debug log. */
4445 debug(F101,"doclean exithangup","",exithangup);
4446 if (local && exithangup) { /* Close communication connection */
4451 debug(F101,"doclean ttchk()","",x);
4453 debug(F101,"doclean ttyfd","",ttyfd);
4454 #endif /* OS2ORUNIX */
4460 || haslock /* Make sure we get lockfile! */
4461 || (!network && ttyfd > -1)
4465 extern int wasclosed, whyclosed;
4466 debug(F100,"doclean hanging up and closing","",0);
4471 printf("Closing %s...",ttname);
4474 mdmhup(); /* Hangup the modem??? */
4476 ttclos(0); /* Close external line, if any */
4484 whyclosed = WC_CLOS;
4486 if (nmac) { /* Any macros defined? */
4488 k = mlook(mactab,"on_close",nmac); /* Look this up */
4489 if (k >= 0) { /* If found, */
4491 /* printf("ON_CLOSE DOCLEAN\n"); */
4492 *(mactab[k].kwd) = NUL; /* See comment below */
4493 if (dodo(k,ckitoa(whyclosed),0) > -1) /* set it up, */
4494 parser(1); /* and execute it */
4501 ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default tty */
4502 local = dfloc; /* And default remote/local status */
4505 else if (local) debug(F100,"doclean hangup/close skipped","",0);
4507 #endif /* NOLOCAL */
4510 ftpbye(); /* If FTP connection open, close it */
4515 ttclos(0); /* If IKSD, close socket */
4520 If a macro named "on_exit" is defined, execute it. Also remove it from the
4521 macro table, in case its definition includes an EXIT or QUIT command, which
4522 would cause much recursion and would prevent the program from ever actually
4525 if (nmac) { /* Any macros defined? */
4527 char * cmd = "on_exit"; /* MSVC 2.x compiler error */
4528 k = mlook(mactab,cmd,nmac); /* Look up "on_exit" */
4529 if (k >= 0) { /* If found, */
4531 /* This makes a mess if ON_EXIT itself executes macros */
4532 *(mactab[k].kwd) = NUL; /* poke its name from the table, */
4534 /* Replace the keyword with something that doesn't wreck the */
4535 /* order of the keyword table */
4536 ckstrncpy(mactab[k].kwd,"on_exxx",8);
4537 #endif /* COMMENT */
4538 if (dodo(k,"",0) > -1) /* set it up, */
4539 parser(1); /* and execute it */
4544 Put console terminal back to normal. This is done here because the
4545 ON_EXIT macro calls the parser, which meddles with console terminal modes.
4547 conres(); /* Restore console terminal. */
4550 /* Should be no need for this, and maybe it's screwing things up? */
4551 connoi(); /* Turn off console interrupt traps */
4552 #endif /* COMMENT */
4554 /* Delete the Startup File if we are supposed to. */
4557 extern int DeleteStartupFile;
4558 debug(F111,"doclean DeleteStartupFile",cmdfil,DeleteStartupFile);
4559 if (DeleteStartupFile) {
4560 int rc = zdelet(cmdfil);
4561 debug(F111,"doclean zdelet",cmdfil,rc);
4565 syscleanup(); /* System-dependent cleanup, last */
4568 /* D O E X I T -- Exit from the program. */
4571 First arg is general, system-independent symbol: GOOD_EXIT or BAD_EXIT.
4572 If second arg is -1, take 1st arg literally.
4573 If second arg is not -1, work it into the exit code.
4576 doexit(exitstat,code) int exitstat, code; {
4577 extern int x_logged, quitting;
4579 extern int display_demo;
4580 extern int SysInited;
4584 extern int krb4_autodel;
4587 extern int krb5_autodel;
4589 #endif /* CK_KERBEROS */
4593 static $DESCRIPTOR(symnam,"CKERMIT_STATUS");
4594 static struct dsc$descriptor_s symval;
4600 extern long lucalls, luhits, xxhits, luloop;
4602 #endif /* USE_LUCACHE */
4604 extern int cmdstats[];
4611 static int initing = 0;
4621 debug(F101,"lookup cache size","",lusize);
4622 debug(F101,"lookup calls ....","",lucalls);
4623 debug(F101,"lookup cache hits","",luhits);
4624 debug(F101,"lookup start hits","",xxhits);
4625 debug(F101,"lookup loop iterations","",luloop);
4626 #endif /* USE_LUCACHE */
4628 for (i = 0; i < 256; i++) {
4630 debug(F111,"CMSTATS",ckitoa(i),cmdstats[i]);
4633 debug(F101,"doexit exitstat","",exitstat);
4634 debug(F101,"doexit code","",code);
4635 debug(F101,"doexit xitsta","",xitsta);
4640 /* If we are automatically destroying Kerberos credentials on Exit */
4643 if (krb4_autodel == KRB_DEL_EX) {
4644 extern struct krb_op_data krb_op;
4646 krb_op.cache = NULL;
4647 ck_krb4_destroy(&krb_op);
4651 if (krb5_autodel == KRB_DEL_EX) {
4652 extern struct krb_op_data krb_op;
4653 extern char * krb5_d_cc;
4655 krb_op.cache = krb5_d_cc;
4656 ck_krb5_destroy(&krb_op);
4659 #endif /* CK_KERBEROS */
4666 extern struct cmdptr *cmdstk;
4668 extern struct cmdptr cmdstk[];
4669 #endif /* DCMDBUF */
4670 extern int tt_status[];
4673 /* If there is a demo screen to be displayed, display it */
4679 /* This is going to be hideous. If we have a status line */
4680 /* in the command window turn it off before we exit. */
4682 if ( tt_status[VCMD] && vmode == VCMD ) {
4683 domac("_clear_statusline","set command statusline off",
4684 cmdstk[cmdlvl].ccflgs);
4685 delmac("_clear_statusline",1);
4686 RequestScreenMutex(-1);
4687 VscrnIsDirty(vmode);
4688 ReleaseScreenMutex();
4689 while ( IsVscrnDirty(vmode) )
4691 RequestScreenMutex(-1);
4692 ReleaseScreenMutex();
4695 DialerSend(OPT_KERMIT_EXIT,exitstat);
4697 debug(F100,"doexit about to msleep","",0);
4704 #endif /* NOLOCAL */
4708 if (inserver && x_logged) {
4711 If a macro named "on_logout" is defined, execute it. Also remove it from the
4712 macro table, in case its definition includes an EXIT or QUIT command, which
4713 would cause much recursion and would prevent the program from ever actually
4716 if (nmac) { /* Any macros defined? */
4718 char * cmd = "on_logout"; /* MSVC 2.x compiler error */
4719 k = mlook(mactab,cmd,nmac); /* Look up "on_logout" */
4720 if (k >= 0) { /* If found, */
4721 *(mactab[k].kwd) = NUL; /* poke its name from the table, */
4722 if (dodo(k,"",0) > -1) /* set it up, */
4723 parser(1); /* and execute it */
4729 #endif /* CK_LOGIN */
4732 debug(F100,"doexit about to doclean","",0);
4733 doclean(1); /* Clean up most things */
4737 code = 0; /* Since we set two different items */
4738 sprintf(envstr,"%d", exitstat | code); /* SAFE */
4739 symval.dsc$w_length = (int)strlen(envstr);
4740 symval.dsc$a_pointer = envstr;
4741 symval.dsc$b_class = DSC$K_CLASS_S;
4742 symval.dsc$b_dtype = DSC$K_DTYPE_T;
4743 i = 2; /* Store in global table */
4744 #ifdef COMMENT /* Martin Zinser */
4745 LIB$SET_SYMBOL(&symnam, &symval, &i);
4747 lib$set_symbol(&symnam, &symval, &i);
4748 #endif /* COMMENT */
4749 if (exitstat == BAD_EXIT)
4750 exitstat = SS$_ABORT | STS$M_INHIB_MSG;
4751 if (exitstat == GOOD_EXIT)
4752 exitstat = SS$_NORMAL | STS$M_INHIB_MSG;
4754 if (code != -1) /* Take 1st arg literally */
4760 debug(F101,"doexit ikdbopen","",ikdbopen);
4761 if (ikdbopen && dbfp) { /* If IKSD database open */
4763 x = freeslot(mydbslot); /* Free our slot... */
4764 debug(F101,"doexit freeslot","",x);
4765 fclose(dbfp); /* and close it. */
4770 /* We have put this off till the very last moment... */
4773 if (deblog) { /* Close the debug log. */
4774 debug(F101,"C-Kermit EXIT status","",exitstat);
4782 _exit(exitstat); /* Exit from C-Kermit (no matter what) */
4784 exit(exitstat); /* Exit from C-Kermit */
4789 bgchk() { /* Check background status */
4790 if (bgset < 0) { /* They didn't type SET BACKGROUND */
4791 #ifdef VMS /* Set prompt flag based on */
4792 pflag = !batch; /* what we detected at startup. */
4796 } else { /* Otherwise SET BACKGROUND value */
4797 pflag = (bgset == 0 ? 1 : 0);
4801 /* Message flag on only if at top level, pflag is on, and QUIET is OFF */
4803 msgflg = (pflag == 0) ? 0 : !quiet;
4810 /* Set console interrupts */
4813 setint() { /* According to SET COMMAND INTERRUP */
4816 if (xsuspend) x |= 2;
4817 debug(F101,"setint","",x);
4819 switch (x) { /* Set the desired combination */
4820 case 0: connoi(); break; /* No interrupts */
4821 case 1: conint(trap,SIG_IGN); break;
4822 case 2: conint(SIG_IGN,stptrap); break;
4823 case 3: conint(trap,stptrap); break;
4825 bgchk(); /* Check background status */
4829 /* D E B U G -- Enter a record in the debugging log */
4832 Call with a format, two strings, and a number:
4833 f - Format, a bit string in range 0-7.
4834 If bit x is on, then argument number x is printed.
4835 s1 - String, argument number 1. If selected, printed as is.
4836 s2 - String, argument number 2. If selected, printed in brackets.
4837 n - Long int, argument 3. If selected, printed preceded by equals sign.
4839 f=0 is special: print s1,s2, and interpret n as a char.
4841 f=F011 (3) is also special; in this case s2 is interpeted as a counted
4842 string that might contain NULs. n is the length. If n is negative, this
4843 means the string has been truncated and ".." should be printed after the
4844 first n bytes. NUL and LF bytes are printed as "<NUL>" and "<LF>".
4847 deblog: nonzero if debug log open.
4848 debok: nonzero if ok to write entries.
4851 WARNING: Don't change DEBUFL without changing sprintf() formats below,
4856 WARNING: This routine is not thread-safe, especially when Kermit is
4857 executing on multiple CPUs -- as different threads write to the same
4858 static buffer, the debug statements are all interleaved. To be fixed
4861 static char *dbptr = (char *)0;
4865 dodebug(int f, char *s1, char *s2, long n)
4867 dodebug(f,s1,s2,n) int f; char *s1, *s2; long n;
4868 #endif /* CK_ANSIC */
4874 extern int SysInited;
4877 if (!deblog || !debok)
4882 if (!chkfn(ZDFILE)) /* Debug log not open, don't. */
4884 #endif /* COMMENT */
4885 if (!dbptr) { /* Allocate memory buffer */
4886 dbptr = malloc(DBUFL+4); /* This only happens once */
4893 This prevents infinite recursion in case we accidentally put a debug()
4894 call in this routine, or call another routine that contains debug() calls.
4895 From this point on, all returns from this return must be via goto xdebug,
4896 which sets deblog back to 1.
4900 if (RequestDebugMutex(30000))
4904 deblog = 0; /* Prevent infinite recursion */
4907 if (debtim) { /* Timestamp */
4908 char *tb, tsbuf[48];
4910 ckstrncpy(tsbuf,tb,32);
4912 sprintf(tsbuf+19,".%03ld ",ztmsec); /* SAFE */
4918 zsout(ZDFILE,tsbuf+11);
4920 if (!s1) s1="(NULL)";
4921 if (!s2) s2="(NULL)";
4928 This should work, but it doesn't.
4929 So instead we'll cope with overflow via sprintf formats.
4930 N.B.: UNFORTUNATELY, this means we have to put constants in the
4933 if (f != F011 && (!f || (f & 6))) { /* String argument(s) included? */
4934 x = (int) strlen(s1) + (int) strlen(s2) + 18;
4935 if (x > dbufl) { /* Longer than buffer? */
4936 if (dbptr) /* Yes, free previous buffer */
4938 dbptr = (char *) malloc(x + 2); /* Allocate a new one */
4940 zsoutl(ZDFILE,"DEBUG: Memory allocation failure");
4946 sprintf(dbptr,"DEBUG: Buffer expanded to %d\n", x + 18);
4947 zsoutl(ZDFILE,dbptr);
4951 #endif /* COMMENT */
4954 /* The aforementioned sprintf() formats were like this: */
4955 if (n > 31 && n < 127)
4956 sprintf(sp,"%.100s%.2000s:%c\n",s1,s2,(CHAR) n);
4957 else if (n < 32 || n == 127)
4958 sprintf(sp,"%.100s%.2000s:^%c\n",s1,s2,(CHAR) ((n+64) & 0x7F));
4959 else if (n > 127 && n < 160)
4960 sprintf(sp,"%.100s%.2000s:~^%c\n",s1,s2,(CHAR)((n-64) & 0x7F));
4961 else if (n > 159 && n < 256)
4962 sprintf(sp,"%.100s%.2000s:~%c\n",s1,s2,(CHAR) (n & 0x7F));
4963 else sprintf(sp,"%.100s%.2000s:%ld\n",s1,s2,n);
4965 But, naturally, it turns out these are not portable either, so now
4966 we do the stupidest possible thing.
4968 #endif /* COMMENT */
4971 /* Need to accept longer strings when debugging authenticated connections */
4973 if (len2 + 2 >= DBUFL) s2 = "(string too long)";
4974 } else if (f != F011 && f != F100) {
4975 if (len1 > 100) s1 = "(string too long)";
4976 if (len2 + 101 >= DBUFL) s2 = "(string too long)";
4980 if (len1 > 100) s1 = "(string too long)";
4981 if (len2 + 101 >= DBUFL) s2 = "(string too long)";
4983 #endif /* BIGBUFOK */
4987 switch (f) { /* Write log record according to format. */
4988 case F000: /* 0 = print both strings, and n as a char. */
4990 if ((n > 31 && n < 127) || (n > 159 && n < 256))
4991 sprintf(sp,"%s[%s]=%c\n",s1,s2,(CHAR) n);
4992 else if (n < 32 || n == 127)
4993 sprintf(sp,"%s[%s]=^%c\n",s1,s2,(CHAR) ((n+64) & 0x7F));
4994 else if (n > 127 && n < 160)
4995 sprintf(sp,"%s[%s]=~^%c\n",s1,s2,(CHAR)((n-64) & 0x7F));
4996 else sprintf(sp,"%s[%s]=0x%lX\n",s1,s2,n);
4998 if ((n > 31 && n < 127) || (n > 159 && n < 256))
4999 sprintf(sp,"%s=%c\n",s1,(CHAR) n);
5000 else if (n < 32 || n == 127)
5001 sprintf(sp,"%s=^%c\n",s1,(CHAR) ((n+64) & 0x7F));
5002 else if (n > 127 && n < 160)
5003 sprintf(sp,"%s=~^%c\n",s1,(CHAR)((n-64) & 0x7F));
5004 else sprintf(sp,"%s=0x%lX\n",s1,n);
5006 if (zsout(ZDFILE,dbptr) < 0) {
5011 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5012 cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5014 #endif /* CKSYSLOG */
5017 case F001: /* 1, "=n" */
5019 /* This was never used */
5020 sprintf(sp,"=%ld\n",n);
5022 /* Like F111, but shows number n in hex */
5030 NULL,NULL,NULL,NULL,NULL,NULL
5032 #endif /* COMMENT */
5033 if (zsout(ZDFILE,dbptr) < 0) {
5038 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5039 cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5041 #endif /* CKSYSLOG */
5045 This one was never used so (October 2000) we now use it like F011,
5046 except in this case we treat s2 as NUL terminated.
5051 This one treats n as the length of the string s2, which may contain NULs.
5052 It's good for logging NUL-bearing data in the debug log.
5055 int i, j, contd = 0;
5056 char * p = s2, *pbuf = NULL; /* p = source pointer */
5057 int m; /* pbuf = destination pointer */
5060 if (n < 0) { /* n = size of source */
5061 n = 0 - n; /* Negative means to add "..." */
5074 if (n == 0) /* 0 means do nothing */
5076 m = DBUFL - 8; /* Get size for interpreted part */
5077 if (n > m) /* Ensure requested size not too big */
5079 pbuf = dbptr; /* Construction pointer */
5081 pbuf[i++] = '['; /* Interpret the string into it */
5082 for (j = 0; j < n && i < m-4; p++,j++) { /* char by char... */
5091 } else if (*p == CR) {
5099 } else if (*p == HT) {
5122 if (i < m-2 && (*p || contd)) {
5128 if (zsout(ZDFILE,s1) < 0) {
5132 if (zsoutl(ZDFILE,pbuf) < 0) {
5137 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5138 cksyslog(SYSLG_DB,1,"debug",s1,pbuf);
5140 #endif /* CKSYSLOG */
5144 case F100: /* 4, "s1" */
5145 if (zsoutl(ZDFILE,s1) < 0) {
5150 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5151 cksyslog(SYSLG_DB,1,"debug",s1,NULL);
5153 #endif /* CKSYSLOG */
5155 case F101: /* 5, "s1=n" */
5156 sprintf(sp,"%s=%ld\n",s1,n);
5157 if (zsout(ZDFILE,dbptr) < 0) {
5162 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5163 cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5165 #endif /* CKSYSLOG */
5167 case F110: /* 6, "s1[s2]" */
5168 sprintf(sp,"%s[%s]\n",s1,s2);
5169 if (zsout(ZDFILE,dbptr) < 0) {
5174 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5175 cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5177 #endif /* CKSYSLOG */
5179 case F111: /* 7, "s1[s2]=n" */
5180 sprintf(sp,"%s[%s]=%ld\n",s1,s2,n);
5181 if (zsout(ZDFILE,dbptr) < 0) {
5186 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5187 cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5189 #endif /* CKSYSLOG */
5192 sprintf(sp,"\n?Invalid format for debug() - %d\n",f);
5193 if (zsout(ZDFILE,dbptr) < 0) {
5198 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5199 cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5201 #endif /* CKSYSLOG */
5204 xdebug: /* Common exit point */
5207 ReleaseDebugMutex();
5209 deblog = 1; /* Restore this */
5216 dohexdump(CHAR *msg, CHAR *st, int cnt)
5218 dohexdump(msg,st,cnt) CHAR *msg; CHAR *st; int cnt;
5219 #endif /* CK_ANSIC */
5221 int i = 0, j = 0, k = 0;
5224 extern int SysInited;
5227 if (!deblog) return(0); /* If no debug log, don't. */
5228 if (!dbptr) { /* Allocate memory buffer */
5229 dbptr = malloc(DBUFL+1); /* This only happens once */
5239 if (RequestDebugMutex(30000))
5243 deblog = 0; /* Prevent infinite recursion */
5254 NULL,NULL,NULL,NULL,NULL,NULL,NULL
5256 if (zsout(ZDFILE,dbptr) < 0) {
5269 zsout(ZDFILE,dbptr);
5270 if (zsout(ZDFILE,dbptr) < 0) {
5276 for (i = 0; i < cnt; i++) {
5278 for (j = 0 ; (j < 16); j++) {
5282 (j == 8 ? "| " : ""),
5288 (j == 8 ? "| " : "")
5290 ckstrncat(dbptr,tmp,DBUFL+1);
5292 ckstrncat(dbptr," ",DBUFL+1);
5293 for (k = 0; (k < 16) && ((i + k) < cnt); k++) {
5296 (k == 8 ? " " : ""),
5297 isprint(st[i + k]) ? st[i + k] : '.'
5299 ckstrncat(dbptr,tmp,DBUFL+1);
5301 ckstrncat(dbptr,"\n",DBUFL+1);
5303 if (zsout(ZDFILE,dbptr) < 0) {
5314 ReleaseDebugMutex();
5322 /* Session Log... */
5324 extern int slogts; /* Session Log timestamps */
5329 logchar(unsigned short c)
5335 #endif /* CK_ANSIC */
5337 /* logchar */ { /* Log character c to session log */
5343 if ((sessft != XYFT_T) ||
5361 #endif /* STRATUS */
5362 #endif /* datageneral */
5376 if (slogts) { /* Log is timestamped */
5377 if (tsstate == 0) { /* State = between-lines */
5378 char * p; /* zstime() pointer */
5379 char ts[48]; /* timestamp buffer */
5380 ztime(&p); /* Get asctime() string */
5381 ckstrncpy(ts,p,32); /* Make safe copy */
5382 if (ztmsec > -1L) { /* Add msecs if we have them */
5383 sprintf(&ts[19],".%03ld: ",ztmsec); /* SAFE */
5389 if (zsout(ZSFILE,&ts[11]) < 0)
5391 if (c != '\n') /* If this is not eol */
5392 tsstate = 1; /* go to in-a-line state. */
5393 } else if (c == '\n') { /* In a line */
5394 tsstate = 0; /* If eol go to between-lines state. */
5397 if (zchout(ZSFILE,(CHAR)(c & 0xFF)) < 0) /* Log the character */
5403 conoll("ERROR WRITING SESSION LOG, LOG CLOSED!");
5406 #endif /* NOLOCAL */
5410 logstr(s, len) char * s; int len; { /* Log string to session log */
5415 while (seslog && (n < len))
5417 #endif /* NOLOCAL */
5428 /* VOS has curses but no tgetent() */
5430 tgetent(s1, s2) char * s1, * s2; {
5433 #endif /* STRATUS */
5437 _PROTOTYP(int tgetent,(char *, char *));
5442 There are three different ways to do fullscreen on VMS.
5443 1. Use the real curses library, VAXCCURSE.
5444 2. Use do-it-yourself code.
5445 3. Use the Screen Manager, SMG$.
5447 Method 1 doesn't work quite right; you can't call endwin(), so once you've
5448 started curses mode, you can never leave.
5450 Method 2 doesn't optimize the screen, and so much more time is spent in
5451 screen writes. This actually causes file transfers to fail because the
5452 tty device input buffer can be overrun while the screen is being updated,
5453 especially on a slow MicroVAX that has small typeahead buffers.
5455 In the following #ifdef block, #define one of them and #undef the other 2.
5457 So now let's try method 3...
5460 #define CK_SMG /* Screen Manager */
5461 #undef MYCURSES /* Do-it-yourself */
5462 #undef VMSCURSE /* VAXCCURSE library */
5465 But just before New Years, 2000, the SMG library seemed to break on
5466 both VMS systems we have here (an Alpha with VMS 7.1 and a VAX with 5.5).
5467 So back to MYCURSES, which works fine.
5478 #endif /* CK_WREFRESH */
5479 #endif /* MYCURSES */
5481 /* S C R E E N C -- Screen display function, uses curses */
5483 /* Idea for curses display contributed by Chris Pratt of APV Baker, UK */
5485 /* Avoid conficts with curses.h */
5488 /* Same as ckcasc.h, but in a different radix... */
5495 #undef VOID /* This was defined in ckcdeb.h */
5496 #endif /* MYCURSES */
5498 #undef BS /* These were defined in ckcasc.h */
5503 #undef SP /* Used in ncurses */
5504 #define CHR_SP 32 /* Use this instead */
5506 #ifdef VMS /* VMS fullscreen display */
5507 #ifdef MYCURSES /* Do-it-yourself method */
5508 extern int isvt52; /* From CKVTIO.C */
5509 #define printw printf
5511 #ifdef VMSCURSE /* VMS curses library VAXCCURSE */
5513 /* Note: Screen manager doesn't need a header file */
5514 #endif /* VMSCURSE */
5515 #endif /* MYCURSES */
5517 #ifdef MYCURSES /* Do-it-yourself method */
5518 #define isvt52 0 /* Used by OS/2, VT-100/ANSI always */
5520 #define printw ckxprintf
5521 #else /* CKXPRINTF */
5523 #define printw Vscrnprintw
5525 #define printw printf
5527 #endif /* CKXPRINTF */
5528 #else /* Use real curses */
5529 #ifdef CK_NCURSES /* or ncurses... */
5530 #ifdef CKXPRINTF /* Our printf macro conflicts with */
5531 #undef printf /* use of "printf" in ncurses.h */
5532 #endif /* CKXPRINTF */
5533 #include <ncurses.h>
5535 #define printf ckxprintf
5536 #endif /* CKXPRINTF */
5537 #else /* Not ncurses */
5538 #ifdef CKXPRINTF /* Our printf macro conflicts with */
5539 #undef printf /* use of "printf" in curses.h */
5540 #endif /* CKXPRINTF */
5541 #ifdef M_XENIX /* SCO XENIX... */
5544 #endif /* M_TERMCAP */
5547 #endif /* M_TERMINFO */
5548 #endif /* M_XENIX */
5550 #undef NLS /* Avoid 'redeclaration of free'. */
5554 #define printf ckxprintf
5555 #endif /* CKXPRINTF */
5556 #endif /* CK_NCURSES */
5557 #endif /* MYCURSES */
5560 #endif /* CK_CURSES */
5562 /* F X D I N I T -- File Xfer Display Initialization */
5569 /* Can't use VOID because of curses.h */
5574 #endif /* CK_ANSIC */
5576 #endif /* MYCURSES */
5577 #endif /* CK_CURSES */
5580 static int notermcap = 1;
5582 static int notermcap = 0;
5583 #endif /* NOTERMCAP */
5591 #endif /* CKANSIC */
5593 fxdinit(xdispla) int xdispla; {
5600 debug(F101,"fxdinit xdispla","",xdispla);
5601 debug(F101,"fxdinit fxd_inited","",fxd_inited);
5605 /* No curses for IKSD */
5610 if (fxd_inited) /* Only do this once */
5615 if (xdispla == XYFD_R || xdispla == XYFD_S || xdispla == XYFD_B) {
5617 printf("%s\n",xfrmsg);
5618 makestr(&xfrmsg,NULL);
5624 /* Force BRIEF in Batch logs */
5625 if (batch && (xdispla == XYFD_C || xdispla == XYFD_S))
5628 if (xdispla == XYFD_C || xdispla == 9999) {
5633 Allocate tgetent() buffer. Make it big -- some termcaps can be huge;
5634 tgetent() merrily writes past the end of the buffer, causing core dumps
5637 trmbuf = (char *)malloc(TRMBUFL);
5640 debug(F101,"fxdinit malloc trmbuf","FAILED",TRMBUFL);
5644 debug(F111,"fxdinit malloc trmbuf","OK",TRMBUFL);
5645 debug(F001,"fxdinit trmbuf","",trmbuf);
5647 memset(trmbuf,'\0',(size_t)TRMBUFL);
5648 debug(F100,"fxdinit memset OK","",0);
5649 #endif /* COMMENT */
5651 #endif /* DYNAMIC */
5653 debug(F100,"fxdinit before getenv(TERM)","",0);
5655 debug(F110,"fxdinit after getenv(TERM)",s,0);
5658 debug(F110,"fxdinit before tgetent()",s,0);
5659 x = tgetent(trmbuf,s);
5660 debug(F111,"fxdinit tgetent",s,x);
5664 debug(F110,"fxdinit TERM null - no tgetent",s,0);
5666 if (x < 1 && !quiet && !backgrd
5671 printf("Warning: terminal type unknown: \"%s\"\n",s);
5673 /* Confusing - nobody knows what this means */
5674 printf("SCREEN command will use ANSI sequences.\n");
5675 #endif /* COMMENT */
5677 printf("Fullscreen file transfer display disabled.\n");
5684 #endif /* MYCURSES */
5687 #endif /* CK_CURSES */
5689 #endif /* STRATUS */
5691 #endif /* COHERENT */
5693 #endif /* NODISPLAY */
5698 Long section for Screen Manager starts here...
5703 #include <smgdef.h> /* use this on VAX C 2.4 */
5704 /* #include <smgmsg.h> */
5706 #include <smg$routines.h> /* Martin Zinser */
5707 #endif /* OLD_VMS */
5709 extern unsigned int vms_status; /* Used for system service return status */
5711 static long smg_pasteboard_id = -1; /* pasteboard identifier */
5712 static long smg_display_id = -1; /* display identifier */
5713 static int smg_open = 0; /* flag if smg current open */
5714 static int smg_inited = 0; /* flag if smg initialized */
5717 #define clrtoeol() SMG$ERASE_LINE(&smg_display_id, 0, 0)
5719 #define clear() SMG$ERASE_DISPLAY(&smg_display_id, 0, 0, 0, 0)
5721 #define touchwin(scr) SMG$REPAINT_SCREEN(&smg_pasteboard_id)
5723 #else /* Not COMMENT */
5725 #define clrtoeol() smg$erase_line(&smg_display_id, 0, 0)
5727 #define clear() smg$erase_display(&smg_display_id, 0, 0, 0, 0)
5729 #define touchwin(scr) smg$repaint_screen(&smg_pasteboard_id)
5730 #endif /* COMMENT */
5732 #define clearok(curscr,ok) /* Let wrefresh() do the work */
5734 #define wrefresh(cursrc) touchwin(scr)
5737 move(row, col) int row, col; {
5738 /* Change from 0-based for curses to 1-based for SMG */
5742 debug(F111,"VMS smg move",ckitoa(row),col);
5743 #ifdef COMMENT /* Martin Zinser */
5744 CHECK_ERR("move: smg$set_cursor_abs",
5745 SMG$SET_CURSOR_ABS(&smg_display_id, &row, &col));
5747 CHECK_ERR("move: smg$set_cursor_abs",
5748 smg$set_cursor_abs(&smg_display_id, &row, &col));
5749 #endif /* COMMENT */
5750 debug(F101,"VMS smg move vms_status","",vms_status);
5755 #endif /* VMS_V40 */
5758 #endif /* VMS_V42 */
5761 #endif /* VMS_V44 */
5765 int rows = 24, cols = 80;
5766 int row = 1, col = 1;
5768 debug(F101,"VMS initscr smg_pasteboard_id A","",smg_pasteboard_id);
5770 if (smg_pasteboard_id == -1) { /* Open the screen */
5771 #ifdef OLD_VMS /* Note: Routine calls lowercased 9/96 */
5772 CHECK_ERR("initscr: smg$create_pasteboard",
5773 smg$create_pasteboard(&smg_pasteboard_id, 0, 0, 0, 0));
5775 /* For VMS V5, not tested */
5776 CHECK_ERR("initscr: smg$create_pasteboard",
5777 smg$create_pasteboard(&smg_pasteboard_id, 0, 0, 0, 0, 0));
5778 #endif /* OLD_VMS */
5780 debug(F101,"VMS initscr smg_pasteboard_id B","",smg_pasteboard_id);
5781 if (smg_pasteboard_id == -1) {
5782 printf("?Error initializing fullscreen display\n");
5787 debug(F101,"VMS initscr smg_display_id","",smg_display_id);
5788 if (smg_display_id == -1) { /* Create a display window */
5790 #ifdef COMMENT /* Martin Zinser */
5791 CHECK_ERR("initscr: smg$create_virtual_display",
5792 SMG$CREATE_VIRTUAL_DISPLAY(&rows, &cols, &smg_display_id,
5795 /* Connect the display window to the screen */
5796 CHECK_ERR("initscr: smg$paste_virtual_display",
5797 SMG$PASTE_VIRTUAL_DISPLAY(&smg_display_id,&smg_pasteboard_id,
5800 CHECK_ERR("initscr: smg$create_virtual_display",
5801 smg$create_virtual_display(&rows, &cols, &smg_display_id,
5804 /* Connect the display window to the screen */
5805 CHECK_ERR("initscr: smg$paste_virtual_display",
5806 smg$paste_virtual_display(&smg_display_id,&smg_pasteboard_id,
5808 #endif /* COMMENT */
5810 debug(F101,"VMS initscr smg_open A","",smg_open);
5811 if (!smg_open) { /* Start a batch update */
5814 CHECK_ERR("initscr: smg$begin_pasteboard_update",
5815 SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id));
5817 CHECK_ERR("initscr: smg$begin_pasteboard_update",
5818 smg$begin_pasteboard_update(&smg_pasteboard_id));
5819 #endif /* COMMENT */
5820 debug(F101,"VMS initscr smg$begin_pasteboard_update","",vms_status);
5822 debug(F101,"VMS initscr smg_open B","",smg_open);
5829 debug(F101,"refresh smg_pasteboard_id","",smg_pasteboard_id);
5831 if (smg_open == 0 || smg_pasteboard_id == -1)
5834 #ifdef COMMENT /* Martin Zinser */
5835 CHECK_ERR("refresh: smg$end_pasteboard_update",
5836 SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id));
5837 CHECK_ERR("refresh: smg$begin_pasteboard_update",
5838 SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id));
5840 CHECK_ERR("refresh: smg$end_pasteboard_update",
5841 smg$end_pasteboard_update(&smg_pasteboard_id));
5842 CHECK_ERR("refresh: smg$begin_pasteboard_update",
5843 smg$begin_pasteboard_update(&smg_pasteboard_id));
5844 #endif /* COMMENT */
5855 CHECK_ERR("endwin: smg$end_pasteboard_update",
5856 SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id));
5858 CHECK_ERR("endwin: smg$end_pasteboard_update",
5859 smg$end_pasteboard_update(&smg_pasteboard_id));
5860 #endif /* COMMENT */
5866 These calls clear the screen.
5867 (convert routine calls to lowercase - Martin Zinser)
5869 CHECK_ERR("endwin: smg$delete_virtual_display",
5870 SMG$DELETE_VIRTUAL_DISPLAY(&smg_display_id));
5871 smg_display_id = -1;
5873 CHECK_ERR("endwin: smg$delete_pasteboard",
5874 SMG$DELETE_PASTEBOARD(&smg_pasteboard_id, 0));
5875 smg_pasteboard_id = -1;
5876 #endif /* COMMENT */
5880 /* DECC 6.2 screams bloody murder about printw ("not enough args") */
5881 /* but adding the following prototype only makes it holler louder. */
5883 /* "varargs" prototype for printw */
5884 _PROTOTYP(static int printw,(char *, ...));
5886 #endif /* COMMENT */
5890 _PROTOTYP(static void printw,(char *, ...));
5892 printw(char *str,...) {
5895 $DESCRIPTOR(text_dsc, 0);
5896 text_dsc.dsc$a_pointer=buf;
5900 text_dsc.dsc$w_length = vsprintf(buf, str, ap);
5902 CHECK_ERR("printw: smg$put_chars",
5903 smg$put_chars(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0));
5907 printw(str, a1, a2, a3, a4, a5, a6, a7, a8)
5909 long a1, a2, a3, a4, a5, a6, a7, a8;
5912 $DESCRIPTOR(text_dsc, 0);
5915 text_dsc.dsc$a_pointer=buf;
5916 text_dsc.dsc$w_length = sprintf(buf, str, a1, a2, a3, a4, a5, a6, a7, a8);
5917 CHECK_ERR("printw: smg$put_chars",
5918 smg$put_chars(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0));
5924 ck_curpos(row, col) {
5925 debug(F111,"VMS smg ck_curpos",ckitoa(row),col);
5926 if (!smg_inited || !smg_open) {
5929 debug(F101,"VMS smg curpos smg_open","",smg_open);
5932 debug(F111,"VMS smg ck_curpos",ckitoa(row-1),col-1);
5933 move(row - 1, col - 1); /* SMG is 0-based */
5941 debug(F101,"VMS smg ck_cls smg_inited","",smg_inited);
5942 if (!smg_inited || !smg_open) {
5945 debug(F101,"VMS smg ck_cls smg_open","",smg_open);
5956 debug(F101,"VMS smg ck_cleol smg_inited","",smg_inited);
5957 if (!smg_inited || !smg_open) {
5960 debug(F101,"VMS smg ck_cleol smg_open","",smg_open);
5972 Do-it-yourself curses implementation for VMS, OS/2 and other ANSI/VT-100's.
5973 Supports only the VT52 and VT1xx (and later VT2xx/3xx/4xx) terminals.
5974 By Terry Kennedy, St Peters College.
5976 First, some stuff we can just ignore:
5980 touchwin(x) int x; {
5997 * Now, some stuff we need to do:
6000 _PROTOTYP( int move, (int, int) );
6003 move(row, col) int row, col; {
6005 printf("\033Y%c%c", row + 037, col + 037);
6007 printf("\033[%d;%dH", row + 1, col + 1);
6042 ck_curpos(row, col) int row, col; {
6048 /* Windows NT and Windows 95 do not provide ANSI emulation */
6049 /* Therefore we might as well not use it for OS/2 either */
6052 move(row, col) int row, col; {
6054 SetCurPos(row, col);
6055 #endif /* ONETERMUPD */
6056 lgotoxy( VCMD, col+1, row+1);
6066 if (VscrnGetBufferSize(VCMD) > 0) {
6067 VscrnScroll(VCMD, UPWARD, 0,
6068 VscrnGetHeight(VCMD)-(1),
6069 VscrnGetHeight(VCMD)-(0), TRUE, CHR_SP);
6070 cleartermscreen(VCMD);
6075 WrtNCell(cell, cmd_rows * cmd_cols, 0, 0);
6076 #endif /* ONETERMUPD */
6088 GetCurPos(&row, &col );
6089 WrtNCell(cell, cmd_cols - col -1, row, col);
6090 #endif /* ONETERMUPD */
6091 clrtoeoln(VCMD,CHR_SP);
6097 ck_curpos(row, col) int row, col; {
6113 #endif /* MYCURSES */
6119 /* Termcap/Terminfo section */
6121 static char cur_cls[32] = { NUL, NUL };
6122 static char cur_cleol[32] = { NUL, NUL };
6123 static char cur_cm[64] = { NUL, NUL };
6124 static char tgsbuf[128] = { NUL, NUL };
6129 #endif /* CK_ANSIC */
6130 ck_termset(x) int x; {
6135 debug(F100,"tgetent is a macro","",0);
6136 #endif /* tgetent */
6138 debug(F100,"tgetstr is a macro","",0);
6139 #endif /* tgetstr */
6141 debug(F100,"tputs is a macro","",0);
6144 debug(F100,"tgoto is a macro","",0);
6147 /* tgetstr() gets a segmentation fault on OSF/1 */
6148 debug(F100,"ck_termset NOTERMCAP","",0);
6151 debug(F100,"ck_termset notermcap","",0);
6154 debug(F101,"ck_termset x","",x);
6159 debug(F110,"ck_termset calling tgetstr","cl",0);
6160 if (tgetstr("cl", &bp)) { /* Get clear-screen code */
6161 debug(F110,"ck_termset tgetstr cl",tgsbuf,"");
6162 if ((int)strlen(tgsbuf) < 32)
6163 ckstrncpy(cur_cls,tgsbuf,32);
6167 if (tgetstr("ce", &bp)) { /* Get clear-to-end-of-line code */
6168 debug(F110,"ck_termset tgetstr ce",tgsbuf,"");
6169 if ((int)strlen(tgsbuf) < 32)
6170 ckstrncpy(cur_cleol,tgsbuf,32);
6174 if (tgetstr("cm", &bp)) { /* Get cursor-movement code */
6175 debug(F110,"ck_termset tgetstr cm",tgsbuf,"");
6176 if ((int)strlen(tgsbuf) < 64)
6177 ckstrncpy(cur_cm,tgsbuf,64);
6181 #endif /* NOTERMCAP */
6186 #define TPUTSFNTYPE void
6188 #define TPUTSFNTYPE int
6189 #endif /* TPUTSISVOID */
6190 #endif /* TPUTSFNTYPE */
6192 #ifndef TPUTSARGTYPE
6194 #define TPUTSARGTYPE char
6197 #define TPUTSARGTYPE char
6199 #define TPUTSARGTYPE int
6202 #endif /* TPUTSARGTYPE */
6206 ck_outc(TPUTSARGTYPE x)
6208 ck_outc(x) TPUTSARGTYPE x;
6209 #endif /* CK_ANSIC */
6210 { /* To satisfy tputs() arg3 prototype */
6214 rc = (inserver) ? ttoc(c) : conoc(c);
6217 #endif /* TPUTSISVOID */
6221 ck_curpos(row, col) int row, col; {
6223 TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
6225 TPUTSFNTYPE (*fn)();
6226 #endif /* CK_ANSIC */
6229 if (!cur_cm[0]) { /* We don't have escape sequences */
6231 return(-1); /* Do nothing */
6233 /* Both C-Kermit's SCREEN command and ANSI/VT100 are 1-based */
6234 printf("\033[%d;%dH", row, col); /* Or default to ANSI */
6235 #endif /* COMMENT */
6238 /* termcap/terminfo is 0-based */
6240 #ifdef TPUTSARG1CONST
6242 #endif /* TPUTSARG1CONST */
6243 tgoto(cur_cm,col-1,row-1),1,fn);
6251 TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
6253 TPUTSFNTYPE (*fn)();
6254 #endif /* CK_ANSIC */
6257 if (!cur_cls[0]) { /* If we don't have escape sequences */
6259 return(-1); /* Do nothing */
6261 printf("\033[;H\033[2J"); /* Or default to ANSI */
6262 #endif /* COMMENT */
6265 debug(F111,"ck_cls 2",cur_cls,fxd_inited);
6266 tputs(cur_cls,cmd_rows,fn);
6274 TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
6276 TPUTSFNTYPE (*fn)();
6277 #endif /* CK_ANSIC */
6280 if (!cur_cleol[0]) { /* If we don't have escape sequences */
6282 return(-1); /* Do nothing */
6284 printf("\033[K"); /* Or use ANSI */
6285 #endif /* COMMENT */
6288 tputs(cur_cleol,1,fn);
6292 #endif /* CK_CURPOS */
6295 ck_termset(x) int x; {
6298 #endif /* NOTERMCAP */
6304 printf("\033[;H\033[2J");
6315 ck_curpos(row, col) int row, col; {
6316 printf("\033[%d;%dH", row, col);
6319 #endif /* CK_CURPOS */
6323 static int cinit = 0; /* Flag for curses init'd */
6324 static int cendw = 0; /* endwin() was called */
6327 #ifdef CK_ANSIC /* Because VOID used by curses.h */
6334 #endif /* MYCURSES */
6335 #endif /* CK_ANSIC */
6336 #ifdef CK_ANSIC /* Update % transfered and % bar */
6337 updpct(long old, long new)
6338 #else /* CK_ANSIC */
6339 updpct(old, new) long old, new;
6340 #endif /* CK_ANSIC */
6348 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_PCD, (long) new);
6359 move(CW_PCD, 26 + m);
6363 if ((m + 1) % 5 == 0)
6370 if (new % 2 != 0) printw("-");
6371 /* move(CW_PCD, 22+53); */
6374 printw("%c", '\333');
6378 printw("%c", '\261');
6381 #endif /* CK_PCT_BAR */
6383 #else /* !COMMENT */
6385 #define CHAR1 '\333' /* OS2 - CP437 */
6386 #define CHAR2 '\261'
6388 #define CHAR1 '/' /* Default */
6391 debug(F101,"updpct old","",old);
6392 debug(F101,"updpct new","",new);
6394 printw("%-3ld", new); /* (was) printw("%ld", new); */
6397 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) new );
6414 printw("%c", CHAR1);
6416 printw("%c", CHAR2);
6419 #endif /* CK_PCT_BAR */
6420 #endif /* COMMENT */
6423 static long old_tr = -1L; /* Time remaining previously */
6427 shoetl(long old_tr, long cps, long fsiz, long howfar)
6429 shoetl(old_tr, cps, fsiz, howfar) long old_tr, cps, fsiz, howfar;
6430 #endif /* CK_ANSIC */
6431 /* shoetl */ { /* Estimated time left in transfer */
6432 long tr; /* Time remaining, seconds */
6435 if (fsiz > 0L && cps > 0L)
6436 tr = (long)((CKFLOAT)(fsiz - howfar) / (CKFLOAT)cps);
6440 tr = (fsiz > 0L && cps > 0L) ?
6441 ((fsiz - howfar) / cps) :
6443 #endif /* GFTIMER */
6447 printw("%s",hhmmss(tr));
6450 KuiSetProperty(KUI_FILE_TRANSFER, (long)CW_TR, (long)hhmmss(tr));
6456 printw("(unknown)");
6459 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "(unknown)" );
6469 shocps(int pct, long fsiz, long howfar)
6471 shocps(pct, fsiz, howfar) int pct; long fsiz, howfar;
6472 #endif /* CK_ANSIC */
6475 static long oldffc = 0L;
6476 #endif /* CPS_WEIGHTED */
6481 #endif /* GFTIMER */
6484 xx = (gtv >= 0.0) ? gtv : 0.0; /* Floating-point version */
6486 if ((gtv - oldgtv) < (CKFLOAT) 1.0) /* Only do this once per second */
6490 xx = (gtv >= 0) ? gtv : 0; /* Whole-number version */
6492 if ((gtv - oldgtv) < 1)
6495 #endif /* GFTIMER */
6498 /* debug(F100,"SHOCPS: WEIGHTED","",0); */
6499 if (gtv != oldgtv) { /* The first packet is ignored */
6503 if (oldcps && oldgtv >
6508 #endif /* GFTIMER */
6509 ) { /* The first second is ignored */
6511 This version of shocps() produces a weighted average that some
6512 people like, but most people find it disconcerting and bombard us
6513 with questions and complaints about why the CPS figure fluctuates so
6514 wildly. So now you only get the weighted average if you build the
6515 program yourself with CPS_WEIGHTED defined.
6519 cps = (long)((((CKFLOAT)oldcps * 3.0) +
6520 (CKFLOAT)(ffc - oldffc) / (gtv-oldgtv) ) / 4.0);
6522 cps = ( (oldcps * 3) + (ffc - oldffc) / (gtv-oldgtv) ) / 4;
6523 #endif /* GFTIMER */
6525 /* And an alternate weighting scheme from Vincent Fatica... */
6527 ((1+pct/300)*oldffc/oldgtv+(1-pct/100)*(ffc-oldffc)/(gtv-oldgtv)))
6529 #endif /* CPS_VINCE */
6531 /* No weighted average since there is nothing to weigh */
6533 cps = (long)(gtv != 0.0 ?
6534 (CKFLOAT)(ffc - oldffc) / (gtv - oldgtv) :
6537 cps = gtv ? (ffc - oldffc) / (gtv - oldgtv) : (ffc - oldffc) ;
6538 #endif /* GFTIMER */
6543 debug(F101,"SHOCPS: pct ","",pct);
6544 debug(F101,"SHOCPS: gtv ","",gtv);
6545 debug(F101,"SHOCPS: oldgtv","",oldgtv);
6546 debug(F101,"SHOCPS: dgtv ","",(long)(gtv-oldgtv));
6547 debug(F101,"SHOCPS: ffc ","",ffc);
6548 debug(F101,"SHOCPS: oldffc","",oldffc);
6549 debug(F101,"SHOCPS: dffc ","",ffc-oldffc);
6550 debug(F101,"SHOCPS: cps ","",cps);
6553 #endif /* COMMENT */
6558 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
6564 #else /* !CPS_WEIGHTED */
6568 debug(F100,"SHOCPS: NOT WEIGHTED","",0);
6569 debug(F101,"SHOCPS: pct ","",pct);
6570 debug(F101,"SHOCPS: gtv ","",gtv);
6571 debug(F101,"SHOCPS: oldgtv ","",oldgtv);
6572 debug(F101,"SHOCPS: dgtv ","",(long)gtv - (long)oldgtv);
6573 debug(F101,"SHOCPS: ffc ","",ffc);
6574 debug(F101,"SHOCPS: oldffc ","",oldffc);
6575 debug(F101,"SHOCPS: dffc ","",ffc-oldffc);
6576 debug(F101,"SHOCPS: cps ","",cps);
6577 debug(F101,"SHOCPS: filcnt ","",filcnt);
6579 debug(F101,"SHOCPS: fpfsecs","",fpfsecs);
6580 #endif /* GFTIMER */
6582 debug(F101,"shocps gtv","",gtv);
6585 #endif /* COMMENT */
6586 /* debug(F101,"shocps fpfsecs","",fpfsecs); */
6587 secs = gtv - fpfsecs;
6588 /* debug(F101,"shocps secs","",(long)secs); */
6590 cps = (long)((CKFLOAT) ffc / secs);
6591 /* debug(F101,"shocps cps","",cps); */
6595 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
6601 #else /* Not GFTIMER */
6602 if ((secs = gtv - fsecs) > 0) {
6603 cps = (secs < 1L) ? ffc : ffc / secs;
6607 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
6613 #endif /* GFTIMER */
6614 #endif /* CPS_WEIGHTED */
6616 if (cps > peakcps && /* Peak transfer rate */
6617 ((what & W_SEND && spackets > wslots + 4) ||
6618 (!(what & W_SEND) && spackets > 10))) {
6621 old_tr = shoetl(old_tr, cps, fsiz, howfar);
6626 #ifdef CK_ANSIC /* Because VOID used by curses.h */
6633 #endif /* MYCURSES */
6634 #endif /* CK_ANSIC */
6635 scrft() { /* Display file type */
6641 ckstrncpy(xferstr,"LABELED",256);
6644 ckstrncpy(xferstr,"IMAGE",256);
6647 ckstrncpy(xferstr,"BINARY UNDEFINED",256);
6650 ckstrncpy(xferstr,"MACBINARY",256);
6653 ckstrncpy(xferstr,"TENEX",256);
6657 ckstrncpy(xferstr,"BINARY",256);
6661 if (what & W_SEND && sendstart > 0L) {
6662 if (sendmode == SM_PSEND) {
6663 ckstrncat(xferstr, " / partial", 256);
6664 } else if (sendmode == SM_RESEND) {
6665 ckstrncat(xferstr, " / resend", 256);
6667 } else if (what & W_RECV && rs_len > 0L) {
6668 ckstrncat(xferstr, " / resend", 256);
6670 #endif /* CK_RESEND */
6674 ckstrncpy(xferstr,"TEXT",256);
6679 ckstrncat(xferstr," (no translation)", 256);
6681 ckmakxmsg(&xferstr[4],252,
6683 fcsinfo[(what & W_SEND) ? ftp_csl : ftp_csx].keyword,
6685 fcsinfo[(what & W_SEND) ? ftp_csx : ftp_csl].keyword,
6687 NULL,NULL,NULL,NULL,NULL,NULL,NULL
6690 #endif /* NOUNICODE */
6692 if (tcharset == TC_TRANSP) {
6693 ckstrncat(xferstr, " (no translation)", 256);
6695 if (what & W_SEND) {
6696 sprintf( &xferstr[strlen(xferstr)], /* safe */
6698 fcsinfo[fcharset].keyword, /* built-in keywords */
6699 tcsinfo[tcharset].keyword /* lengths are controlled */
6702 sprintf( &xferstr[strlen(xferstr)], /* safe */
6704 tcsinfo[tcharset].keyword, /* built-in keywords */
6705 fcsinfo[fcharset].keyword); /* lengths controlled */
6708 #endif /* NOCSETS */
6711 printw("%s", xferstr);
6715 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TYP, (long) xferstr );
6722 static FILE *ck_stdout = NULL;
6723 static int ck_fd = -1;
6724 #endif /* CK_NEWTERM */
6726 static long pct = 0L, oldpct = 0L, oldrtt = -1L;
6727 static int oldtyp = 0, oldwin = -1, oldtry = -1, oldlen = -1, oldtim = -1;
6730 static char *netname[] = {
6732 "TCP/IP", /* 01 TCP (Sockets) */
6733 "TCP/IP", /* 02 TCP (Streams) */
6734 "X.25", /* 03 SunLink X.24 */
6735 "DECnet", /* 04 DECnet */
6736 "VAX PSI", /* 05 VAX PSI */
6737 "Named Pipes", /* 06 LAN Manager Named Pipe */
6738 "X.25", /* 07 Stratus VOS X.25 */
6739 "NetBIOS", /* 08 IBM NETBIOS */
6740 "SuperLAT", /* 07 Meridian SuperLAT */
6741 "File", /* 10 File */
6742 "Command", /* 11 Subprocess (pipe) */
6743 "DLL", /* 12 DLL does i/o */
6744 "X.25", /* 13 IBM AIXLink X.25 */
6745 "X.25", /* 14 HP-UX X.25 */
6746 "PTY", /* 15 Pseudoterminal */
6748 "<ERROR>", /* 17 In case new types are added */
6749 "<ERROR>", /* 18 but nobody remembers to update */
6750 "<ERROR>", /* 19 this table ... */
6753 static int nnetname = (sizeof(netname) / sizeof(char *));
6755 #endif /* NETCONN */
6759 screenc(int f, char c,long n,char *s)
6765 #endif /* MYCURSES */
6767 int f; /* argument descriptor */
6768 char c; /* a character or small integer */
6769 long n; /* a long integer */
6770 char *s; /* a string */
6771 #endif /* CK_ANSIC */
6774 extern int tls_active_flag, ssl_active_flag;
6777 extern int ttnproto;
6778 #endif /* RLOGCODE */
6780 static long fsiz = -1L; /* Copy of file size */
6781 static long fcnt = 0L; /* Number of files transferred */
6782 static long fbyt = 0L; /* Total file bytes of all files transferred */
6783 static long howfar = 0L; /* How much of current file has been xfer'd. */
6784 static int pctlbl = 0L; /* Percent done vs Bytes so far */
6790 int len; /* Length of string */
6791 int errors = 0; /* Error counter */
6794 debug(F101,"screenc cinit","",cinit);
6795 debug(F101,"screenc cendw","",cendw);
6797 if (!s) s = ""; /* Always do this. */
6799 ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit */
6800 net = network || ftp;
6801 xnet = ftp ? 1 : nettype; /* NET_TCPB == 1 */
6803 if (cinit == 0 || cendw > 0) { /* Handle borderline cases... */
6804 if (f == SCR_CW) { /* Close window, but it's not open */
6808 debug(F111,"screenc A",s,f);
6810 (f == SCR_PT && c == 'E')) { /* Fatal error before window open */
6811 conoll(""); conoc('?'); conoll(s); return; /* Regular display */
6814 if (cinit == 0) { /* Only call initscr() once */
6816 /* Check these now -- if they are defined but not numeric */
6817 /* they can crash curses */
6818 s = getenv("LINES");
6819 if (s) if (!rdigits(s)) {
6820 printf("?LINES variable not numeric: \"%s\".\n",s);
6821 printf("(Fullscreen display disabled)\n");
6825 s = getenv("COLUMNS");
6826 if (s) if (!rdigits(s)) {
6827 printf("?COLUMNS variable not numeric: \"%s\".\n",s);
6828 printf("(Fullscreen display disabled)\n");
6832 cendw = 1; /* New window needs repainting */
6834 if (!initscr()) { /* Oops, can't initialize window? */
6836 In fact, this doesn't happen. "man curses" says initscr() halts the
6837 entire program if it fails, which is true on the systems where I've
6838 tested it. It will fail if your terminal type is not known to it.
6839 That's why SET FILE DISPLAY FULLSCREEN calls tgetent() to make sure the
6840 terminal type is known before allowing a curses display.
6842 fprintf(stderr,"CURSES INITSCR ERROR\r\n");
6843 fdispla = XYFD_S; /* Fall back to CRT display */
6846 cinit++; /* Window initialized ok */
6847 debug(F100,"CURSES INITSCR OK","",0);
6849 #else /* Save some memory. */
6851 /* (From Andy Fyfe <andy@vlsi.cs.caltech.edu>)
6852 System V curses seems to reserve the right to alter the buffering
6853 on the output FILE* without restoring it. Fortunately System V
6854 curses provides newterm(), an alternative to initscr(), that
6855 allows us to specify explicitly the terminal type and input and
6856 output FILE pointers. Thus we duplicate stdout, and let curses
6857 have the copy. The original remains unaltered. Unfortunately,
6858 newterm() seems to be particular to System V.
6862 ck_fd = dup(fileno(stdout));
6863 ck_stdout = (ck_fd >= 0) ? (FILE *)fdopen(ck_fd, "w") : NULL;
6865 debug(F100,"screenc newterm...","",0);
6867 /* NOTE: It might be necessary to do this with stdin too! */
6868 /* This would have been the case in FreeBSD 4.1 but they fixed the */
6869 /* problem by restoring the buffering of stdin before the final release. */
6870 /* (But T.E. Dickey says stdin is not buffered?) */
6872 if (ck_stdout == NULL || newterm(s, ck_stdout, stdin) == 0) {
6874 "Fullscreen display not supported for terminal type: %s\r\n",s);
6875 fdispla = XYFD_S; /* Use CRT instead */
6878 debug(F100,"screenc newterm ok","",0);
6880 debug(F100,"screen calling initscr","",0);
6881 initscr(); /* Initialize curses. */
6882 debug(F100,"screen initscr ok","",0);
6883 #endif /* CK_NEWTERM */
6884 cinit++; /* Remember curses was initialized. */
6885 #endif /* COMMENT */
6887 ft_win = 1; /* Window is open */
6891 This totally repaints the screen, just what we want, but we can only
6892 do this with real curses, and then only if clearok() and wrefresh() are
6893 provided in the curses library.
6900 clearok(stdscr, 1); /* QNX doesn't have curscr */
6907 #else /* No CK_WREFRESH */
6909 Kermit's do-it-yourself method, works with all types of fullscreen
6910 support, but does not repaint all the fields. For example, the filename
6911 is lost, because it arrives at a certain time and never comes again, and
6912 Kermit presently does not save it anywhere. Making this method work for
6913 all fields would be a rather major recoding task, duplicating what curses
6914 already does, and would add a lot of complexity and storage space.
6917 #endif /* CK_WREFRESH */
6920 if (cendw) { /* endwin() was called previously */
6922 initscr(); /* (or should have been!) */
6929 In QNX, if we don't call initscr() here we core dump.
6930 I don't have any QNX curses documentation, but other curses manuals
6931 say that initscr() should be called only once per application, and
6932 experience shows that on other systems, calling initscr() here generally
6933 results in a core dump.
6935 debug(F100,"screenc re-calling initscr QNX","",0);
6941 But even so, second and subsequent curses displays are messed up.
6942 Calling touchwin, refresh, etc, doesn't make any difference.
6944 debug(F100,"screenc calling touchwin QNX","",0);
6946 debug(F100,"screenc calling refresh QNX","",0);
6948 #endif /* COMMENT */
6950 #else /* All others... */
6951 debug(F100,"screenc calling clear","",0);
6953 debug(F100,"screenc clear ok","",0);
6956 debug(F100,"screenc setup ok","",0);
6957 debug(F100,"screenc doing first move","",0);
6958 move(CW_BAN,0); /* Display the banner */
6959 debug(F110,"screenc myhost",myhost,0);
6961 debug(F110,"screenc myipaddr",myipaddr,0);
6962 #endif /* TCPSOCKET */
6964 debug(F100,"screenc calling first printw...","",0);
6965 /* Right here is where HP-UX 10.10 libxcurse.1 Rev 76.20 hangs... */
6966 #endif /* HPUX1010 */
6971 /* We need to perform this test because on non-TCP/IP */
6972 /* systems the call to getlocalipaddr() results in a */
6973 /* DNS Lookup which takes several minutes to time out */
6975 (xnet == NET_TCPA || xnet == NET_TCPB
6978 #endif /* SSHBUILTIN */
6983 if (myipaddr[0] && strcmp((char *)myhost,(char *)myipaddr))
6984 printw("%s, %s [%s]",versio,(char *)myhost,(char *)myipaddr);
6986 #endif /* TCPSOCKET */
6987 printw("%s, %s",versio,(char *)myhost);
6989 printw("%s",versio);
6992 debug(F100,"screenc first printw returns","",0);
6993 #endif /* HPUX1010 */
6995 printw("Current Directory: %s",zgtdir());
6998 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) zgtdir() );
7003 printw("Network Host: %s",
7005 ftp ? (ftp_host ? ftp_host : "(unknown)") :
7011 printw("Communication Device: %s",ttname);
7015 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_LIN, (long) ttname );
7021 printw("Network Type: ");
7024 printw("Communication Speed: ");
7026 move(CW_SPD,22); /* Serial speed or network type */
7031 if (xnet > nnetname)
7034 xname = netname[xnet];
7044 #endif /* SSHBUILTIN */
7045 #ifdef CK_ENCRYPTION
7046 || ck_tn_encrypting() && ck_tn_decrypting()
7047 #endif /* CK_ENCRYPTION */
7049 || tls_active_flag || ssl_active_flag
7053 #ifdef CK_ENCRYPTION
7054 || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
7055 #endif /* CK_ENCRYPTION */
7056 #endif /* CK_KERBEROS */
7057 #endif /* RLOGCODE */
7065 sprintf(buf,"%s (SECURE)",xname);
7066 KuiSetProperty(KUI_FILE_TRANSFER,
7072 printw("%s (SECURE)",xname);
7077 KuiSetProperty(KUI_FILE_TRANSFER,
7085 printw("(network)");
7088 KuiSetProperty(KUI_FILE_TRANSFER,
7094 #endif /* NETCONN */
7099 if (speed == 8880) {
7103 KuiSetProperty(KUI_FILE_TRANSFER,
7111 sprintf(speedbuf, "%ld", speed);
7112 printw("%s",speedbuf);
7115 KuiSetProperty(KUI_FILE_TRANSFER,
7126 KuiSetProperty(KUI_FILE_TRANSFER,
7135 printw("Parity: %s",ftp ? "none" : parnam((char)parity));
7138 KuiSetProperty(KUI_FILE_TRANSFER,
7140 (long) parnam((char)parity)
7145 if (/* rttflg && */ protocol == PROTO_K) {
7146 move(CW_TMO, 9); printw("RTT/Timeout:"); }
7147 #endif /* CK_TIMERS */
7148 move(CW_TYP,11); printw("File Type:");
7149 move(CW_SIZ,11); printw("File Size:");
7152 pctlbl = (what & W_SEND);
7153 printw("%s:", pctlbl ? "Percent Done" : "Bytes So Far");
7157 printw("%10s Protocol:", ftp ? "FTP" : ptab[protocol].p_name);
7158 #endif /* XYZ_INTERNAL */
7163 printw(" ...10...20...30...40...50...60...70...80...90..100");
7166 #endif /* CK_PCT_BAR */
7167 move(CW_TR, 1); printw("Estimated Time Left:");
7168 move(CW_CP, 2); printw("Transfer Rate, CPS:");
7169 move(CW_WS, 8); printw("Window Slots:%s",
7170 ((protocol == PROTO_K) && !ftp) ?
7173 move(CW_PT, 9); printw("Packet Type:");
7174 if (ftp || protocol != PROTO_K) {
7176 printw("%s", "N/A");
7177 move(CW_PC, 11); printw("I/O Count:");
7178 move(CW_PL, 10); printw("I/O Length:");
7180 move(CW_PC, 8); printw("Packet Count:");
7181 move(CW_PL, 7); printw("Packet Length:");
7184 move(CW_PR, 9); printw("Error Count:");
7186 move(CW_PR, 2); printw("Packet Retry Count:");
7189 move(CW_PB, 2); printw("Packet Block Check:");
7190 #endif /* COMMENT */
7191 move(CW_ERR,10); printw("Last Error:");
7192 move(CW_MSG, 8); printw("Last Message:");
7194 move(CW_MSG, 22); printw("%s",xfrmsg);
7195 makestr(&xfrmsg,NULL);
7199 printw("(Transfer interruption is disabled)");
7203 "<%s>X to cancel file, <%s>Z to cancel group, <%s><CR> to resend last packet",
7204 dbchr(escape), dbchr(escape), dbchr(escape)
7206 move(CW_INT + 1, 0);
7208 "<%s>E to send Error packet, ^C to quit immediately, <%s>L to refresh screen.",
7209 dbchr(escape), dbchr(escape)
7211 #else /* !CK_NEED_SIG */
7214 if (protocol == PROTO_K) {
7216 "X to cancel file, Z to cancel group, <Enter> to resend last packet,"
7220 #ifdef VMS /* In VMS avoid bottom line */
7222 "X: Cancel this file; E: Cancel transfer; ^C: Quit now; ^W: Refresh screen."
7226 "X to cancel file, Z to cancel group, <CR> to resend last packet,"
7232 move(CW_INT + 1, 0);
7233 if (protocol == PROTO_K) {
7235 "E to send Error packet, ^C to quit immediately, ^L to refresh screen."
7238 printw("^C to cancel file transfer.");
7241 #endif /* CK_NEED_SIG */
7246 debug(F101,"SCREENC switch","",f);
7247 debug(F000,"SCREENC c","",c);
7248 debug(F101,"SCREENC n","",n);
7250 len = strlen(s); /* Length of argument string */
7251 switch (f) { /* Handle our function code */
7252 case SCR_FN: /* Filename */
7253 oldpct = pct = 0L; /* Reset percents */
7255 gtv = (CKFLOAT) -1.0;
7256 /* oldgtv = (CKFLOAT) -1.0; */
7260 #endif /* GFTIMER */
7262 fsiz = -1L; /* Invalidate previous file size */
7263 move(CW_PCD,22); /* Erase percent done from last time */
7266 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) 0 );
7267 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_FFC, (long) 0 );
7271 move(CW_SIZ,22); /* Erase file size from last time */
7274 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) 0 );
7278 move(CW_ERR,22); /* And last error message */
7281 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) "" );
7287 if (protocol == PROTO_K && streamok) {
7290 printw(" Kermit STREAMING:");
7292 printw(" STREAMING:");
7293 #endif /* XYZ_INTERNAL */
7295 #endif /* STREAMING */
7296 #endif /* COMMENT */
7298 if (what & W_SEND) { /* If we're sending... */
7300 if (what & W_FTP) { /* FTP */
7306 switch (sendmode) { /* Kermit */
7309 printw("RESENDING:");
7319 #endif /* CK_RESEND */
7321 } else if (what & W_RECV) { /* If we're receiving... */
7323 if (what & W_FTP) { /* FTP */
7329 printw("RECEIVING:");
7332 } else if (what == (W_FTP|W_FT_DELE)) {
7334 printw("FTP DELETE:");
7336 } else { /* If we don't know... */
7337 move(CW_NAM,11); /* (should never see this) */
7338 printw("File Name:");
7340 move(CW_NAM,22); /* Display the filename */
7342 printw("%.55s..",s);
7344 } else printw("%s",s);
7347 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
7350 q = len; /* Remember name length for later */
7352 scrft(); /* Display file type (can change) */
7359 case SCR_AN: /* File as-name */
7360 if (q + len + 4 < 58) { /* Will fit */
7361 move(CW_NAM, 22 + q);
7365 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
7368 } else { /* Too long */
7369 move(CW_NAM, 22); /* Overwrite previous name */
7371 if (len + 4 > 57) { /* wg15 */
7372 printw(" => %.51s..",s); /* wg15 */
7373 len = 53; /* wg15 */
7374 } else printw(" => %s",s); /* wg15 */
7377 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
7381 q += len + 4; /* Remember horizontal position */
7389 case SCR_FS: /* File size */
7395 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) n );
7403 if (fsiz > -1L) { /* Put up percent label */
7406 printw("Percent Done:");
7411 if (fsiz > -1L) { /* Put up percent label */
7413 printw("Percent Done:");
7416 printw("Bytes So Far:");
7418 #endif /* COMMENT */
7420 scrft(); /* File type */
7427 case SCR_PT: /* Packet type or pseudotype */
7429 extern int sysindex;
7430 extern struct sysdata sysidlist[];
7431 /* Things that won't change after the 4th packet */
7433 printw("%s",parnam((char)parity));
7436 KuiSetProperty( KUI_FILE_TRANSFER,
7438 (long) parnam((char)parity)
7444 move(CW_PB, 22); /* Block check on this packet */
7450 #endif /* COMMENT */
7453 (ftp && (spackets == 1 || rpackets == 1)) ||
7462 ((protocol == PROTO_K) && (sysindex > -1))
7466 printw("Network Host: %s (%s)",
7468 ftp ? (ftp_host ? ftp_host : "") :
7474 sysidlist[sysindex].sid_name
7478 printw("Communication Device: %s (remote host is %s)",
7480 sysidlist[sysindex].sid_name
7488 if (/* rttflg && */ protocol == PROTO_K) {
7492 streaming && oldwin != -2
7495 #endif /* STREAMING */
7501 xx = (rttdelay + 500) / 1000;
7502 if (xx != oldrtt || rcvtimo != oldtim) {
7504 printw("%02ld / %02d", xx, rcvtimo);
7511 #endif /* CK_TIMERS */
7513 x = (what & W_RECV) ? /* Packet length */
7514 rpktl+(protocol==PROTO_K?1:0) :
7516 if (x != oldlen) { /* But only if it changed. */
7521 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PL, (long) x );
7527 move(CW_PC, 22); /* Packet count (always). */
7529 printw("%d", (what & W_RECV) ? rpackets : spackets);
7532 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PC, (long) spackets );
7537 if (protocol == PROTO_K && !ftp) { /* Window slots */
7544 sprintf(ws,"STREAMING");
7549 #endif /* STREAMING */
7550 if (wcur != oldwin) {
7551 sprintf(ws, "%d of %d", wcur < 1 ? 1 : wcur, wslotn);
7561 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_WS, (long) ws );
7566 errors = retrans + crunched + timeouts;
7567 if (errors != oldtry) { /* Retry count, if changed */
7569 printw("%d",errors);
7572 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PR, (long) errors );
7578 /* Sender's packet type */
7579 if (!ftp && (c != oldtyp && c != 'Y' && c != 'N')) {
7581 sprintf(type, "%c",c);
7586 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PT, (long) type );
7592 switch (c) { /* Now handle specific packet types */
7593 case 'S': /* Beginning of transfer */
7594 fcnt = fbyt = 0L; /* Clear counters */
7598 gtv = -1L; /* And old/new things... */
7599 #endif /* GFTIMER */
7603 case 'Z': /* or EOF */
7604 debug(F101,"screenc SCR_PT Z pktnum","",n);
7605 debug(F101,"screenc SCR_PT Z oldpct","",oldpct);
7606 debug(F101,"screenc SCR_PT Z pct","",pct);
7607 case 'D': /* Data packet */
7608 if (fsiz > 0L) { /* Show percent done if known */
7609 oldpct = pct; /* Remember previous percent */
7612 if (what & W_SEND) /* Account for PSEND or RESEND */
7613 howfar += sendstart;
7614 else if (what & W_RECV)
7616 #endif /* CK_RESEND */
7617 /* Percent done, to be displayed... */
7619 if (!discard && !cxseen && !czseen) pct = 100L;
7621 pct = (fsiz > 99L) ? (howfar / (fsiz / 100L)) : 0L;
7622 if (pct > 100L || /* Allow for expansion and */
7623 (oldpct == 99L && pct < 0L)) /* other boundary conditions */
7625 if (pct != oldpct) /* Only do this 100 times per file */
7626 updpct(oldpct, pct);
7633 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) howfar);
7636 cps = shocps((int) pct, fsiz, howfar);
7637 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
7640 case '%': /* Timeouts, retransmissions */
7641 cps = shocps((int) pct, fsiz, howfar);
7642 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
7644 errors = retrans + crunched + timeouts;
7645 if (errors != oldtry) { /* Error count, if changed */
7647 printw("%d",errors);
7651 KuiSetProperty(KUI_FILE_TRANSFER,
7652 (long) CW_PR, (long) errors
7664 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_ERR, (long) s);
7670 case 'E': /* Error packet */
7672 move(CW_ERR,22); /* Print its data field */
7677 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
7682 #endif /* COMMENT */
7683 fcnt = fbyt = 0L; /* So no bytes for this file */
7685 case 'Q': /* Crunched packet */
7686 cps = shocps((int) pct, fsiz, howfar);
7687 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
7689 printw("Damaged Packet");
7692 KuiSetProperty(KUI_FILE_TRANSFER,
7694 (long) "Damaged Packet"
7700 case 'q': /* Ctrl-C or connection lost */
7704 printw(*s ? s : "User interruption or connection lost");
7707 KuiSetProperty(KUI_FILE_TRANSFER,
7714 case 'T': /* Timeout */
7715 cps = shocps((int) pct, fsiz, howfar);
7716 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
7718 printw("Timeout %d sec",rcvtimo);
7721 KuiSetProperty(KUI_FILE_TRANSFER,
7728 errors = retrans + crunched + timeouts;
7729 if (errors != oldtry) { /* Error count, if changed */
7731 printw("%d",errors);
7734 KuiSetProperty(KUI_FILE_TRANSFER,
7735 (long) CW_PR, (long) errors
7743 default: /* Others, do nothing */
7752 case SCR_ST: /* File transfer status */
7753 debug(F101,"screenc SCR_ST c","",c);
7754 debug(F101,"screenc SCR_ST success","",success);
7755 debug(F101,"screenc SCR_ST cxseen","",cxseen);
7757 move(CW_PCD,22); /* Update percent done */
7758 if (c == ST_OK) { /* OK, print 100 % */
7765 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
7770 } else if (fsiz > 0L) /* Not OK, update final percent */
7772 The else part writes all over the screen -- howfar and/or fsiz have
7773 been reset as a consequence of the not-OKness of the transfer.
7776 updpct(oldpct, (howfar * 100L) / fsiz);
7779 if (c == ST_OK) { /* OK, print 100 % */
7780 move(CW_PCD,22); /* Update percent done */
7782 if (oldpct == 0) /* Switching from "bytes so far" */
7783 clrtoeol(); /* to "percent done"... */
7789 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
7795 #endif /* COMMENT */
7798 #endif /* COMMENT */
7801 /* No, leave it there so they can read it */
7802 move(CW_MSG,22); /* Remove any previous message */
7805 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_MSG, (long) "" );
7808 clrtoeol(); refresh();
7809 #endif /* COMMENT */
7814 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "" );
7817 clrtoeol(); refresh();
7819 switch (c) { /* Print new status message */
7820 case ST_OK: /* Transfer OK */
7821 fcnt++; /* Count this file */
7822 if (what == (W_FTP|W_FT_DELE)) {
7825 printw("Delete OK");
7830 printw("Transfer OK");
7834 KuiSetProperty(KUI_FILE_TRANSFER,
7836 (long) "Transfer OK"
7840 clrtoeol(); refresh();
7843 case ST_DISC: /* Discarded */
7845 printw("File discarded");
7848 KuiSetProperty(KUI_FILE_TRANSFER,
7850 (long) "File discarded"
7856 #endif /* COMMENT */
7857 clrtoeol(); refresh();
7860 case ST_INT: /* Interrupted */
7862 printw("Transfer interrupted");
7865 KuiSetProperty(KUI_FILE_TRANSFER,
7867 (long) "Transfer interrupted"
7873 #endif /* COMMENT */
7874 clrtoeol(); refresh();
7877 case ST_SKIP: /* Skipped */
7879 if (n > 0 && n < nskreason)
7880 printw("File skipped (%s)",skreason[n]);
7882 printw("File skipped");
7885 KuiSetProperty(KUI_FILE_TRANSFER,
7887 (long) "File skipped"
7893 #endif /* COMMENT */
7894 clrtoeol(); refresh();
7897 case ST_ERR: /* Error message */
7899 if (!s) s = (char *)epktmsg;
7903 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
7908 #endif /* COMMENT */
7909 clrtoeol(); refresh();
7912 case ST_REFU: /* Refused */
7916 sprintf( errbuf, "Refused, %s", s ) ;
7917 printw("%s", errbuf);
7920 KuiSetProperty(KUI_FILE_TRANSFER,(long) CW_ERR,(long) errbuf);
7927 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Refused");
7933 #endif /* COMMENT */
7934 clrtoeol(); refresh();
7939 printw("Incomplete");
7942 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Incomplete");
7947 #endif /* COMMENT */
7948 clrtoeol(); refresh();
7956 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_MSG,(long)s);
7959 clrtoeol(); refresh();
7962 default: /* Bad call */
7964 printw("*** screen() called with bad status ***");
7967 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR,
7968 (long) "*** screen() called with bad status ***" );
7971 clrtoeol(); refresh(); return;
7974 case SCR_TC: { /* Transaction complete */
7976 move(CW_CP,22); /* Overall transfer rate */
7979 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, tfcps);
7982 printw("%ld", tfcps);
7985 move(CW_MSG,22); /* Print statistics in message line */
7990 "SUCCESS. Files: %ld, Bytes: %ld, %ld CPS",
7995 printw("%s", msgbuf);
7998 KuiSetProperty(KUI_FILE_TRANSFER,
8008 printw(" Elapsed Time: %s",hhmmss((long)
8013 #endif /* GFTIMER */
8017 KuiSetProperty(KUI_FILE_TRANSFER,
8019 (long) hhmmss((long)
8024 #endif /* GFTIMER */
8029 move(23,0); clrtoeol(); /* Clear instructions lines */
8030 move(22,0); clrtoeol(); /* to make room for prompt. */
8034 oldgtv = (CKFLOAT) -1.0;
8037 #endif /* GFTIMER */
8040 debug(F100,"screenc endwin A","",0);
8044 Why and when was this call to conres() added? It makes no sense,
8045 and it breaks echoing on Solaris 8.
8049 #endif /* SOLARIS */
8050 #endif /* COMMENT */
8051 #endif /* VMSCURSE */
8054 pct = 100; oldpct = 0; /* Reset these for next time. */
8055 #endif /* COMMENT */
8056 oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
8059 if (xfrbel) bleep(BP_NOTE); /* Close window, then beep. */
8063 ft_win = 0; /* Window closed. */
8066 case SCR_EM: /* Error packet (fatal) */
8068 printw("FAILURE: %s",s);
8071 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
8074 if (xfrbel) bleep(BP_FAIL);
8077 #endif /* COMMENT */
8078 clrtoeol(); refresh(); return;
8080 case SCR_QE: /* Quantity equals */
8081 case SCR_TU: /* Undelimited text */
8082 case SCR_TN: /* Text delimited at start */
8083 case SCR_TZ: /* Text delimited at end */
8084 return; /* (ignored in fullscreen display) */
8086 case SCR_XD: /* X-packet data */
8092 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
8095 clrtoeol(); refresh(); return;
8097 case SCR_CW: /* Close Window */
8098 clrtoeol(); move(23,0); clrtoeol(); move(22,0); clrtoeol();
8101 pct = 100; oldpct = 0; /* Reset these for next time. */
8102 #endif /* COMMENT */
8103 oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
8107 debug(F100,"screenc endwin B","",0);
8109 #endif /* VMSCURSE */
8110 ft_win = 0; /* Flag that window is closed. */
8113 case SCR_CD: /* Display current directory */
8118 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) s );
8128 default: /* Bad call */
8132 KuiSetProperty(KUI_FILE_TRANSFER,
8134 (long) "*** screen() called with bad function code ***"
8138 printw("*** screen() called with bad function code ***");
8139 clrtoeol(); refresh(); return;
8142 #endif /* CK_CURSES */
8147 screeng(int f, char c,long n,char *s)
8151 int f; /* argument descriptor */
8152 char c; /* a character or small integer */
8153 long n; /* a long integer */
8154 char *s; /* a string */
8155 #endif /* CK_ANSIC */
8158 extern int tls_active_flag, ssl_active_flag;
8161 extern int ttnproto;
8162 #endif /* RLOGCODE */
8164 static long fsiz = -1L; /* Copy of file size */
8165 static long fcnt = 0L; /* Number of files transferred */
8166 static long fbyt = 0L; /* Total file bytes of all files transferred */
8167 static long howfar = 0L; /* How much of current file has been xfer'd. */
8168 static int pctlbl = 0L; /* Percent done vs Bytes so far */
8174 int len; /* Length of string */
8175 int errors = 0; /* Error counter */
8178 debug(F101,"screeng cinit","",cinit);
8179 debug(F101,"screeng cendw","",cendw);
8181 if (!s) s = ""; /* Always do this. */
8183 ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit */
8184 net = network || ftp;
8185 xnet = ftp ? 1 : nettype; /* NET_TCPB == 1 */
8187 if (cinit == 0 || cendw > 0) { /* Handle borderline cases... */
8188 if (f == SCR_CW) { /* Close window, but it's not open */
8192 debug(F111,"screeng A",s,f);
8194 (f == SCR_PT && c == 'E')) { /* Fatal error before window open */
8195 conoll(""); conoc('?'); conoll(s); return; /* Regular display */
8198 if (cinit == 0) { /* Only call initscr() once */
8199 /* Check these now -- if they are defined but not numeric */
8200 /* they can crash curses */
8201 cendw = 1; /* New window needs repainting */
8202 debug(F100,"screeng calling initscr","",0);
8203 initscr(); /* Initialize curses. */
8204 debug(F100,"screeng initscr ok","",0);
8205 cinit++; /* Remember curses was initialized. */
8207 ft_win = 1; /* Window is open */
8211 This totally repaints the screen, just what we want, but we can only
8212 do this with real curses, and then only if clearok() and wrefresh() are
8213 provided in the curses library.
8216 #else /* No CK_WREFRESH */
8218 Kermit's do-it-yourself method, works with all types of fullscreen
8219 support, but does not repaint all the fields. For example, the filename
8220 is lost, because it arrives at a certain time and never comes again, and
8221 Kermit presently does not save it anywhere. Making this method work for
8222 all fields would be a rather major recoding task, duplicating what curses
8223 already does, and would add a lot of complexity and storage space.
8226 #endif /* CK_WREFRESH */
8229 if (cendw) { /* endwin() was called previously */
8230 debug(F100,"screeng setup ok","",0);
8231 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) zgtdir() );
8232 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_LIN,
8235 ftp ? (ftp_host ? ftp_host : "(unknown)") :
8243 if (xnet > nnetname)
8246 xname = netname[xnet];
8256 #endif /* SSHBUILTIN */
8257 #ifdef CK_ENCRYPTION
8258 || ck_tn_encrypting() && ck_tn_decrypting()
8259 #endif /* CK_ENCRYPTION */
8261 || tls_active_flag || ssl_active_flag
8265 #ifdef CK_ENCRYPTION
8266 || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
8267 #endif /* CK_ENCRYPTION */
8268 #endif /* CK_KERBEROS */
8269 #endif /* RLOGCODE */
8275 sprintf(buf,"%s (SECURE)",xname);
8276 KuiSetProperty(KUI_FILE_TRANSFER,
8281 KuiSetProperty(KUI_FILE_TRANSFER,
8287 KuiSetProperty(KUI_FILE_TRANSFER,
8291 #endif /* NETCONN */
8296 if (speed == 8880) {
8297 KuiSetProperty(KUI_FILE_TRANSFER,
8303 sprintf(speedbuf, "%ld", speed);
8304 KuiSetProperty(KUI_FILE_TRANSFER,
8310 KuiSetProperty(KUI_FILE_TRANSFER,
8316 KuiSetProperty(KUI_FILE_TRANSFER,
8318 (long) parnam((char)parity)
8320 pctlbl = (what & W_SEND);
8323 debug(F101,"SCREENC switch","",f);
8324 debug(F000,"SCREENC c","",c);
8325 debug(F101,"SCREENC n","",n);
8327 len = strlen(s); /* Length of argument string */
8328 switch (f) { /* Handle our function code */
8329 case SCR_FN: /* Filename */
8330 oldpct = pct = 0L; /* Reset percents */
8332 gtv = (CKFLOAT) -1.0;
8333 /* oldgtv = (CKFLOAT) -1.0; */
8337 #endif /* GFTIMER */
8339 fsiz = -1L; /* Invalidate previous file size */
8340 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) 0 );
8341 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_FFC, (long) 0 );
8342 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) 0 );
8343 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) "" );
8345 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
8346 q = len; /* Remember name length for later */
8347 scrft(); /* Display file type (can change) */
8353 case SCR_AN: /* File as-name */
8354 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
8360 case SCR_FS: /* File size */
8363 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) n );
8365 if (fsiz > -1L) { /* Put up percent label */
8370 scrft(); /* File type */
8376 case SCR_PT: /* Packet type or pseudotype */
8378 extern int sysindex;
8379 extern struct sysdata sysidlist[];
8380 /* Things that won't change after the 4th packet */
8381 KuiSetProperty( KUI_FILE_TRANSFER,
8383 (long) parnam((char)parity)
8387 (ftp && (spackets == 1 || rpackets == 1)) ||
8395 ((protocol == PROTO_K) && (sysindex > -1))
8399 sprintf(msgbuf,"Network Host: %s (%s)",
8401 ftp ? (ftp_host ? ftp_host : "") :
8407 sysidlist[sysindex].sid_name
8411 "Communication Device: %s (remote host is %s)",
8413 sysidlist[sysindex].sid_name
8416 KuiSetProperty( KUI_FILE_TRANSFER,
8424 if (/* rttflg && */ protocol == PROTO_K) {
8428 streaming && oldwin != -2
8431 #endif /* STREAMING */
8434 sprintf(msgbuf,"00 / 00");
8435 KuiSetProperty( KUI_FILE_TRANSFER,
8440 xx = (rttdelay + 500) / 1000;
8441 if (xx != oldrtt || rcvtimo != oldtim) {
8443 sprintf(msgbuf,"%02ld / %02d", xx, rcvtimo);
8444 KuiSetProperty( KUI_FILE_TRANSFER,
8454 #endif /* CK_TIMERS */
8456 x = (what & W_RECV) ? /* Packet length */
8457 rpktl+(protocol==PROTO_K?1:0) :
8459 if (x != oldlen) { /* But only if it changed. */
8460 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PL, (long) x );
8463 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PC, (long) spackets );
8465 if (protocol == PROTO_K && !ftp) { /* Window slots */
8472 sprintf(ws,"STREAMING");
8477 #endif /* STREAMING */
8478 if (wcur != oldwin) {
8479 sprintf(ws, "%d of %d", wcur < 1 ? 1 : wcur, wslotn);
8484 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_WS, (long) ws );
8487 errors = retrans + crunched + timeouts;
8488 if (errors != oldtry) { /* Retry count, if changed */
8489 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PR, (long) errors );
8492 /* Sender's packet type */
8493 if (!ftp && (c != oldtyp && c != 'Y' && c != 'N')) {
8495 sprintf(type, "%c",c);
8496 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PT, (long) type );
8499 switch (c) { /* Now handle specific packet types */
8500 case 'S': /* Beginning of transfer */
8501 fcnt = fbyt = 0L; /* Clear counters */
8505 gtv = -1L; /* And old/new things... */
8506 #endif /* GFTIMER */
8510 case 'Z': /* or EOF */
8511 debug(F101,"screeng SCR_PT Z pktnum","",n);
8512 debug(F101,"screeng SCR_PT Z oldpct","",oldpct);
8513 debug(F101,"screeng SCR_PT Z pct","",pct);
8514 case 'D': /* Data packet */
8515 if (fsiz > 0L) { /* Show percent done if known */
8516 oldpct = pct; /* Remember previous percent */
8519 if (what & W_SEND) /* Account for PSEND or RESEND */
8520 howfar += sendstart;
8521 else if (what & W_RECV)
8523 #endif /* CK_RESEND */
8524 /* Percent done, to be displayed... */
8526 if (!discard && !cxseen && !czseen) pct = 100L;
8528 pct = (fsiz > 99L) ? (howfar / (fsiz / 100L)) : 0L;
8529 if (pct > 100L || /* Allow for expansion and */
8530 (oldpct == 99L && pct < 0L)) /* other boundary conditions */
8532 if (pct != oldpct) /* Only do this 100 times per file */
8533 updpct(oldpct, pct);
8535 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8537 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) howfar);
8538 cps = shocps((int) pct, fsiz, howfar);
8539 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8542 case '%': /* Timeouts, retransmissions */
8543 cps = shocps((int) pct, fsiz, howfar);
8544 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8546 errors = retrans + crunched + timeouts;
8547 if (errors != oldtry) { /* Error count, if changed */
8548 KuiSetProperty(KUI_FILE_TRANSFER,
8555 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_ERR, (long) s);
8559 case 'E': /* Error packet */
8561 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
8563 fcnt = fbyt = 0L; /* So no bytes for this file */
8565 case 'Q': /* Crunched packet */
8566 cps = shocps((int) pct, fsiz, howfar);
8567 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8568 KuiSetProperty(KUI_FILE_TRANSFER,
8570 (long) "Damaged Packet"
8573 case 'q': /* Ctrl-C or connection lost */
8575 if (!*s) s = "User interruption or connection lost";
8576 KuiSetProperty(KUI_FILE_TRANSFER,
8581 case 'T': /* Timeout */
8582 cps = shocps((int) pct, fsiz, howfar);
8583 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8584 KuiSetProperty(KUI_FILE_TRANSFER,
8588 errors = retrans + crunched + timeouts;
8589 if (errors != oldtry) { /* Error count, if changed */
8590 KuiSetProperty(KUI_FILE_TRANSFER,
8591 (long) CW_PR, (long) errors
8596 default: /* Others, do nothing */
8604 case SCR_ST: /* File transfer status */
8605 debug(F101,"screeng SCR_ST c","",c);
8606 debug(F101,"screeng SCR_ST success","",success);
8607 debug(F101,"screeng SCR_ST cxseen","",cxseen);
8609 if (c == ST_OK) { /* OK, print 100 % */
8613 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8616 } else if (fsiz > 0L) /* Not OK, update final percent */
8618 The else part writes all over the screen -- howfar and/or fsiz have
8619 been reset as a consequence of the not-OKness of the transfer.
8622 updpct(oldpct, (howfar * 100L) / fsiz);
8624 if (c == ST_OK) { /* OK, print 100 % */
8628 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8632 #endif /* COMMENT */
8634 #endif /* COMMENT */
8636 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "" );
8638 switch (c) { /* Print new status message */
8639 case ST_OK: /* Transfer OK */
8640 fcnt++; /* Count this file */
8641 if (what == (W_FTP|W_FT_DELE)) {
8642 KuiSetProperty(KUI_FILE_TRANSFER,
8648 KuiSetProperty(KUI_FILE_TRANSFER,
8650 (long) "Transfer OK"
8655 case ST_DISC: /* Discarded */
8656 KuiSetProperty(KUI_FILE_TRANSFER,
8658 (long) "File discarded"
8662 #endif /* COMMENT */
8665 case ST_INT: /* Interrupted */
8666 KuiSetProperty(KUI_FILE_TRANSFER,
8668 (long) "Transfer interrupted"
8672 #endif /* COMMENT */
8675 case ST_SKIP: { /* Skipped */
8677 if (n > 0 && n < nskreason)
8678 sprintf( errbuf, "File skipped, (%s)", skreason[n] ) ;
8680 sprintf( errbuf, "File skipped" ) ;
8681 KuiSetProperty(KUI_FILE_TRANSFER,
8687 #endif /* COMMENT */
8690 case ST_ERR: /* Error message */
8691 if (!s) s = (char *)epktmsg;
8692 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
8695 #endif /* COMMENT */
8698 case ST_REFU: /* Refused */
8701 sprintf( errbuf, "Refused, %s", s ) ;
8702 KuiSetProperty(KUI_FILE_TRANSFER,(long) CW_ERR,(long) errbuf);
8704 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Refused");
8708 #endif /* COMMENT */
8712 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Incomplete");
8715 #endif /* COMMENT */
8719 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_MSG,(long)s);
8722 default: /* Bad call */
8723 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR,
8724 (long) "*** screen() called with bad status ***" );
8728 case SCR_TC: { /* Transaction complete */
8730 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, tfcps);
8733 "SUCCESS. Files: %ld, Bytes: %ld, %ld CPS",
8738 KuiSetProperty(KUI_FILE_TRANSFER,
8743 KuiSetProperty(KUI_FILE_TRANSFER,
8745 (long) hhmmss((long)
8750 #endif /* GFTIMER */
8754 oldgtv = (CKFLOAT) -1.0;
8757 #endif /* GFTIMER */
8760 pct = 100; oldpct = 0; /* Reset these for next time. */
8761 #endif /* COMMENT */
8762 oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
8765 if (xfrbel) bleep(BP_NOTE); /* Close window, then beep. */
8766 ft_win = 0; /* Window closed. */
8769 case SCR_EM: /* Error packet (fatal) */
8770 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
8771 if (xfrbel) bleep(BP_FAIL);
8774 #endif /* COMMENT */
8777 case SCR_QE: /* Quantity equals */
8778 case SCR_TU: /* Undelimited text */
8779 case SCR_TN: /* Text delimited at start */
8780 case SCR_TZ: /* Text delimited at end */
8781 return; /* (ignored in fullscreen display) */
8783 case SCR_XD: /* X-packet data */
8785 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
8788 case SCR_CW: /* Close Window */
8790 pct = 100; oldpct = 0; /* Reset these for next time. */
8791 #endif /* COMMENT */
8792 oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
8795 ft_win = 0; /* Flag that window is closed. */
8798 case SCR_CD: /* Display current directory */
8799 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) s );
8805 default: /* Bad call */
8806 KuiSetProperty(KUI_FILE_TRANSFER,
8808 (long) "*** screen() called with bad function code ***"
8819 /* Dummies for when cursor control is not supported */
8821 ck_curpos(row, col) {
8834 #endif /* CK_CURPOS */
8839 struct iksdbfld dbfld[] = {
8840 /* Offset Length Type */
8841 { DB_FLAGS, dB_FLAGS, DBT_HEX }, /* 0 db_FLAGS Flags */
8842 { DB_ATYPE, dB_ATYPE, DBT_HEX }, /* 1 db_ATYPE Auth type */
8843 { DB_AMODE, dB_AMODE, DBT_HEX }, /* 3 db_AMODE Auth mode */
8844 { DB_STATE, dB_STATE, DBT_HEX }, /* 2 db_STATE State */
8845 { DB_MYPID, dB_MYPID, DBT_HEX }, /* 5 db_MYPID PID */
8846 { DB_SADDR, dB_SADDR, DBT_HEX }, /* 4 db_SADDR Server address */
8847 { DB_CADDR, dB_CADDR, DBT_HEX }, /* 6 db_CADDR Client address */
8848 { DB_START, dB_START, DBT_DAT }, /* 7 db_START Session start */
8849 { DB_LASTU, dB_LASTU, DBT_DAT }, /* 8 db_LASTU Last update */
8850 { DB_ULEN, dB_ULEN, DBT_HEX }, /* 9 db_ULEN Username length */
8851 { DB_DLEN, dB_DLEN, DBT_HEX }, /* 10 db_DLEN Directory name length */
8852 { DB_ILEN, dB_ILEN, DBT_HEX }, /* 11 db_ILEN Info length */
8853 { DB_PAD1, dB_PAD1, DBT_UND }, /* 12 db_PAD1 (Reserved) */
8854 { DB_USER, dB_USER, DBT_STR }, /* 13 db_USER Username */
8855 { DB_DIR, dB_DIR, DBT_STR }, /* 14 db_DIR Current Directory */
8856 { DB_INFO, dB_INFO, DBT_STR } /* 15 db_INFO State-specific info */
8859 static char lcknam[CKMAXPATH+1]; /* Lockfile pathname */
8860 static char tmplck[CKMAXPATH+1]; /* Temporary lockfile name */
8862 static char * updmode = /* Update mode for fopen() */
8874 /* D B I N I T -- Initialize the IKSD database... */
8878 extern int dbinited;
8880 debug(F110,"dbinit dbdir 1",dbdir,0);
8881 debug(F110,"dbinit dbfile 1",dbfile,0);
8889 p = getenv("SystemRoot");
8891 p = getenv("winbootdir");
8892 if (!p) p = getenv("windir");
8895 dbdir = malloc(strlen(p)+2);
8896 strcpy(dbdir,p); /* safe */
8903 if (*(p-1) != '/' ) {
8908 makestr(&dbdir,"C:/");
8913 makestr(&dbdir,IK_DBASEDIR);
8919 if (dbdir[x-1] != '/') {
8923 x += (int)strlen(IK_DBASEFIL);
8924 dbfile = (char *)malloc(x+1);
8925 sprintf(dbfile,"%s%s%s",dbdir,s,IK_DBASEFIL);
8927 debug(F110,"dbinit dbdir 2",dbdir,0);
8928 debug(F110,"dbinit dbfile 2",dbfile,0);
8929 mypid = getpid(); /* Get my pid */
8930 debug(F101,"dbinit mypid","",mypid);
8932 if (!myhexip[0]) { /* Set my hex IP address */
8934 extern unsigned long myxipaddr;
8935 if (getlocalipaddr() > -1) {
8937 sprintf(myhexip,"%08lx",myip); /* (Needs fixing for IPv6) */
8939 #endif /* TCPSOCKET */
8940 ckstrncpy(myhexip,"00000000",9);
8942 debug(F111,"dbinit myip",myhexip,myip);
8943 if (!peerhexip[0]) { /* Get peer's hex IP address */
8945 extern unsigned long peerxipaddr;
8947 peerip = peerxipaddr;
8948 sprintf(peerhexip,"%08lx",peerip); /* (Needs fixing for IPv6) */
8949 debug(F111,"dbinit peerip",peerhexip,peerip);
8951 debug(F101,"dbinit ckgetpeer failure","",errno);
8952 ckstrncpy(peerhexip,"00000000",9);
8955 ckstrncpy(peerhexip,"00000000",9);
8956 #endif /* TCPSOCKET */
8958 debug(F111,"dbinit peerip",peerhexip,peerip);
8959 debug(F101,"dbinit dbenabled","",dbenabled);
8960 if (dbenabled && inserver) {
8961 mydbslot = getslot();
8962 debug(F111,"dbinit getslot",ckitoa(ikdbopen),x);
8963 if (ikdbopen) dbinited = 1;
8968 /* U P D S L O T -- Update slot n */
8971 Opens the database if necessary, seeks to slot n, writes current record
8972 and adds current time to last-update field. n is the record sequence number
8973 (0, 1, 2, ...), not the seek pointer. Returns -1 on failure, 0 on success.
8976 updslot(n) int n; { /* Update our slot */
8980 debug(F111,"updslot","ikdbopen",ikdbopen);
8981 if (!ikdbopen) /* Not if not ok */
8983 if (!dbfp) { /* Open database if not open */
8984 dbfp = fopen(dbfile,updmode); /* In update no-truncate mode */
8986 debug(F110,"updslot fopen failed",dbfile,0);
8991 debug(F111,"updslot dbfile",dbfile,dbfp);
8992 position = n * DB_RECL;
8993 if (fseek(dbfp,position,0) < 0) { /* Seek to desired slot */
8994 debug(F111,"updslot fseek failed",dbfile,mydbseek);
8998 /* Update the update time */
8999 strncpy(&dbrec[dbfld[db_LASTU].off],
9003 if (fwrite(dbrec,1,DB_RECL,dbfp) < DB_RECL) { /* Write the record */
9004 debug(F110,"updslot fwrite failed",dbfile,0);
9007 } else { /* Flush the write */
9014 /* I N I T S L O T -- Initialize slot n with my info */
9017 initslot(n) int n; { /* Initialize slot */
9020 extern unsigned long peerxipaddr;
9021 #endif /* TCPSOCKET */
9023 debug(F101,"initslot","",n);
9026 memset(dbrec,32,DB_RECL);
9028 for (k = 0; k < DB_RECL; k++)
9030 #endif /* USE_MEMCPY */
9032 myflags = DBF_INUSE; /* Set in-use flag */
9033 mystate = W_NOTHING;
9037 k = dbfld[db_FLAGS].len; /* Length of flags field */
9038 strncpy(&dbrec[dbfld[db_FLAGS].off],ulongtohex(myflags,k),k);
9040 k = dbfld[db_ATYPE].len;
9041 strncpy(&dbrec[dbfld[db_ATYPE].off],ulongtohex(myatype,k),k);
9043 k = dbfld[db_AMODE].len;
9044 strncpy(&dbrec[dbfld[db_AMODE].off],ulongtohex(myamode,k),k);
9046 k = dbfld[db_STATE].len;
9047 strncpy(&dbrec[dbfld[db_STATE].off],ulongtohex(mystate,k),k);
9049 k = dbfld[db_SADDR].len;
9050 strncpy(&dbrec[dbfld[db_SADDR].off],ulongtohex(myip,k),k);
9054 k = dbfld[db_CADDR].len;
9055 strncpy(&dbrec[dbfld[db_CADDR].off],ulongtohex(peerxipaddr,k),k);
9057 k = dbfld[db_CADDR].len;
9058 strncpy(&dbrec[dbfld[db_CADDR].off],ulongtohex(0L,k),k);
9059 #endif /* TCPSOCKET */
9061 k = dbfld[db_MYPID].len;
9062 strncpy(&dbrec[dbfld[db_MYPID].off],ulongtohex(mypid,k),k);
9064 k = dbfld[db_START].len;
9065 strncpy(&dbrec[dbfld[db_START].off],ckdate(),k);
9067 k = dbfld[db_ULEN].len;
9068 strncpy(&dbrec[dbfld[db_ULEN].off],"0000",4);
9070 k = dbfld[db_DLEN].len;
9071 strncpy(&dbrec[dbfld[db_DLEN].off],"0000",4);
9073 k = dbfld[db_ILEN].len;
9074 strncpy(&dbrec[dbfld[db_ILEN].off],"0000",4);
9076 strncpy(&dbrec[dbfld[db_INFO].off],"INIT",4);
9081 slotstate(x,s1,s2,s3) int x; char *s1, *s2, *s3; {
9082 int k, l1, l2, l3, z;
9084 debug(F101,"slotstate ikdbopen","",ikdbopen);
9093 strncpy(&dbrec[DB_STATE],ulongtohex(mystate,4),4);
9094 k = dbfld[db_ILEN].len;
9095 z = l1 + l2 + l3 + 2;
9098 strncpy(&dbrec[DB_ILEN],ulongtohex((unsigned long)z,k),k);
9099 k = dbfld[db_INFO].len;
9100 z = dbfld[db_INFO].off;
9102 lset(&dbrec[z],s1,l1+1,32);
9106 lset(&dbrec[z],s2,l2+1,32);
9110 lset(&dbrec[z],s3,k,32);
9117 strncpy(buf,&dbrec[DB_INFO],127);
9119 for (i = 126; i > 0 && buf[i] == 32; i--) buf[i] = 0;
9120 debug(F111,"slotstate",buf,mystate);
9123 z = updslot(mydbslot);
9124 debug(F101,"slotstate updslot","",z);
9129 slotdir(s1,s2) char * s1, * s2; { /* Update current directory */
9137 k = dbfld[db_DLEN].len;
9138 strncpy(&dbrec[DB_DLEN],ulongtohex((unsigned long)(len1+len2),k),k);
9139 k = dbfld[db_DIR].len;
9141 lset(&dbrec[dbfld[db_DIR].off],s1,len1,32);
9142 lset(&dbrec[dbfld[db_DIR].off+len1],s2,k-len1,32);
9144 lset(&dbrec[dbfld[db_DIR].off],s2,k,32);
9146 return(updslot(mydbslot));
9149 /* F R E E S L O T -- Free slot n */
9152 freeslot(n) int n; {
9157 if (n == mydbslot) {
9158 dbflags = myflags & ~DBF_INUSE;
9159 dbflags &= ~DBF_LOGGED;
9161 k = dbfld[db_FLAGS].len;
9162 strncpy(&dbrec[dbfld[db_FLAGS].off],ulongtohex(dbflags,k),k);
9166 /* G E T S L O T -- Find a free database slot; returns slot number */
9169 getslot() { /* Find a free slot for us */
9170 FILE * rfp = NULL; /* Returns slot number (0, 1, ...) */
9171 char idstring[64]; /* PID string buffer (decimal) */
9172 char pidbuf[64], * s;
9173 int j, k, n, x, rc = -1;
9174 int lockfd, tries, haveslot = 0;
9176 /* char ipbuf[17]; */
9178 if (!myhexip[0]) /* Set my hex IP address if not set */
9179 ckstrncpy((char *)myhexip,"7F000001",33);
9180 sprintf(idstring,"%08lx:%010ld\n",myip,mypid);
9181 debug(F110,"getslot idstring", idstring, 0);
9183 /* Make temporary lockfile name IP.PID (hex.hex) */
9184 /* This should fit in 14 chars -- huge PIDs are usually not possible */
9185 /* on 14-char filename systems. */
9187 sprintf(tmplck,"%s%08lx.%lx",dbdir,myip,mypid);
9188 debug(F110,"getslot tempfile",tmplck,0);
9190 /* Make a temporary file */
9192 lockfd = creat(tmplck, 0600);
9194 debug(F111,"getslock temp lockfile create failure", tmplck, errno);
9197 /* Write my (decimal) PID into the temp file */
9199 write(lockfd,idstring,(int)strlen(idstring));
9200 if (close(lockfd) < 0) { /* Close lockfile */
9201 debug(F101,"getslot error closing temp lockfile", "", errno);
9204 sprintf(lcknam,"%s%s",dbdir,IK_LOCKFILE); /* Build lockfile name */
9205 debug(F110,"getslot lockfile",lcknam,0);
9207 rfp = fopen(lcknam,"r"); /* See if lockfile exists */
9208 if (rfp) { /* If so... */
9209 rset(pidbuf,"",64,0);
9210 x = fread(pidbuf,1,63,rfp); /* Read ID string from it */
9211 fclose(rfp); /* and close it quickly */
9212 debug(F110,"getslot lock exists",pidbuf,0);
9213 if (x > 0) { /* If we have a PID, check it */
9216 if (islower(*s)) *s = toupper(*s);
9219 debug(F110,"getslot lock IP",pidbuf,0);
9220 debug(F110,"gteslot my IP",myhexip,0);
9221 if (!strcmp(pidbuf,myhexip)) { /* Same IP address? */
9222 lockpid = atol(s+1); /* Yes, now get PID */
9223 debug(F101,"getslot lockpid","",lockpid);
9225 /* Check if PID lockpid on this computer is alive */
9226 x = zchkpid(lockpid);
9228 debug(F100,"getslot PID stale,removing lock","",0);
9237 debug(F111,"getslot lockfile open failure",lcknam,errno);
9240 /* Try IK_LCKTRIES (16) times to rename temp file to lockfile */
9242 for (tries = IK_LCKTRIES; tries > 0; tries--) {
9243 if (zrename(tmplck,lcknam) == 0)
9245 debug(F101,"getslot database locked by pid", "", dbpid);
9248 if (tries < 1) { /* Couldn't */
9249 debug(F110,"getslot create lock failure",lcknam,0);
9252 /* Have lock, open database */
9254 debug(F110,"getslot has lock",lcknam,0); /* Have lock */
9259 /* If database doesn't exist, create it. */
9261 debug(F110,"getslot dbfile",dbfile,0);
9262 if (zchki(dbfile) < 0) {
9263 debug(F110,"getslot creating new database",dbfile,0);
9264 x = creat(dbfile,0660);
9266 debug(F111,"getslot creat() failed", dbfile, errno);
9271 dbfp = fopen(dbfile,updmode); /* Open it in update mode */
9273 debug(F111,"getslot fopen failed",dbfile,errno);
9276 /* Now find a free (or new) slot... */
9278 dblastused = 0L; /* Seek pointer to last record inuse */
9279 mydbseek = 0L; /* Seek pointer for my record */
9281 /* Quickly read the whole database; n = record counter, i = seek pointer */
9283 for (n = 0, i = 0; !feof(dbfp); i += DB_RECL, n++) {
9284 x = fread(dbrec,1,DB_RECL,dbfp); /* Read a record */
9285 if (x < 1) /* EOF not caught by feof() */
9288 if (x != DB_RECL) { /* Watch out for trailing junk */
9289 debug(F101,"getslot bad size","",x); /* (Shouldn't happen...) */
9291 chsize(fileno(dbfp),i);
9293 ftruncate(fileno(dbfp),i);
9294 #endif /* COHERENT */
9299 #endif /* NOFTRUNCATE */
9300 debug(F101,"getslot record","",n);
9301 k = dbfld[db_FLAGS].off;
9302 j = dbfld[db_FLAGS].len;
9303 dbflags = hextoulong(&dbrec[k],j);
9304 debug(F001,"getslot dbflags","",dbflags);
9305 k = dbfld[db_MYPID].off;
9306 j = dbfld[db_MYPID].len;
9307 dbpid = hextoulong(&dbrec[k],j);
9308 debug(F001,"getslot dbpid","",dbpid);
9309 k = dbfld[db_SADDR].off;
9310 j = dbfld[db_SADDR].len;
9311 dbip = hextoulong(&dbrec[k],j);
9312 debug(F001,"getslot dbip","",dbip);
9314 if (dbflags & DBF_INUSE) { /* Remember last slot in use */
9315 x = 0; /* Make sure it's REALLY in use */
9316 if (dbpid == mypid && dbip == myip) { /* Check for PID == my PID */
9318 debug(F101,"getslot record pid","",dbpid);
9319 } else { /* Or for stale PID */
9321 debug(F101,"getslot zchkpid()","",x);
9323 if (!x) { /* Bogus record */
9325 debug(F101,"getslot stale record pid: freeslot()","",x);
9326 if (x > -1 && !haveslot)
9328 } else { /* It's really in use */
9332 if (!haveslot) { /* If I don't have a slot yet */
9333 if (!(dbflags & DBF_INUSE)) { /* Claim this one */
9334 debug(F101,"getslot free slot", "", n);
9337 mydbslot = n; /* But keep going... */
9341 /* Come here with i == seek pointer to first record after eof */
9343 if (!haveslot) { /* Found no free slot so add to end */
9344 debug(F101,"getslot new slot","",n);
9349 ikdbopen = 1; /* OK to make database entries */
9350 debug(F101,"getslot records","",n);
9351 debug(F101,"getslot dblastused","",dblastused);
9352 debug(F101,"getslot i","",i);
9354 /* Trim stale records from end */
9357 if (i > dblastused+DB_RECL) {
9358 debug(F101,"getslot truncating at","",dblastused+DB_RECL);
9360 x = chsize(fileno(dbfp),dblastused+DB_RECL);
9362 x = ftruncate(fileno(dbfp),dblastused+DB_RECL);
9363 #endif /* COHERENT */
9364 if (x < 0) /* (Not fatal) */
9365 debug(F101,"getslot ftruncate failed", "", errno);
9367 #endif /* NOFTRUNCATE */
9369 /* Initialize my record */
9371 if (initslot(mydbslot) < 0) {
9372 debug(F101,"getslot initslot() error","",n);
9376 debug(F101,"getslot OK","",mydbslot);
9377 rc = mydbslot; /* OK return code */
9379 xslot: /* Unlock the database and return */
9380 if (unlink(lcknam) < 0) {
9381 debug(F111,"getslot lockfile removal failed",lcknam,errno);