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, 2011,
13 Trustees of Columbia University in the City of New York.
14 All rights reserved. See the C-Kermit COPYING.TXT file or the
15 copyright text in the ckcmai.c module for disclaimer and permissions.
19 This module contains user interface functions needed by both the interactive
20 user interface and the command-line-only user interface, as well as the
21 screen-control routines (curses and equivalent).
51 #endif /* NOTERMCAP */
52 #endif /* NOHTERMCAP */
58 #endif /* NOHTERMCAP */
64 #endif /* NOTERMCAP */
68 _PROTOTYP(char * os2_gethostname, (void));
69 #define getpid _getpid
75 extern xx_strp xxstring;
80 _PROTOTYP( char * ckgetpeer, (VOID));
81 _PROTOTYP(int getlocalipaddr, (void));
82 _PROTOTYP(int istncomport, (void));
84 _PROTOTYP( char * ckgetfqhostname,(char *));
85 #endif /* NOCKGETFQHOST */
88 We should just pull in ckcnet.h here, but it causes a conflict with curses.h.
116 #endif /* SUPERLAT */
117 #endif /* TCPSOCKET */
119 #endif /* STRATUSX25 */
124 #endif /* CK_NETBIOS */
131 #endif /* MULTINET */
134 #endif /* DEC_TCPIP */
141 #endif /* TCPSOCKET */
152 #ifdef COMMENT /* Would you believe */
153 #undef COMMENT /* <os2.h> defines this ? */
157 #endif /* CK_NETBIOS */
160 extern ascreen commandscreen;
181 #endif /* CK_KERBEROS */
192 #include <lib$routines.h> /* Not for VAX C 2.3 */
202 /* fdopen() needs declaring because it's not declared in <stdio.h> */
203 _PROTOTYP( FILE * fdopen, (int, char *) );
204 #endif /* DCLFDOPEN */
207 /* popen() needs declaring because it's not declared in <stdio.h> */
208 _PROTOTYP( FILE * popen, (char *, char *) );
209 #endif /* DCLPOPEN */
211 int tt_crd = 0; /* Carriage return display */
212 int tt_lfd = 0; /* Linefeed display */
213 int interrupted = 0; /* Interrupted from keyboard flag */
214 int fxd_inited = 0; /* Fullscreen stuff initialized */
217 char debfil[CKMAXPATH+1]; /* Debugging log file name */
221 char trafil[CKMAXPATH+1]; /* Transaction log file name */
224 char sesfil[CKMAXPATH+1]; /* Session log file name */
227 char diafil[CKMAXPATH+1]; /* Connection log file name */
228 char cxlogbuf[CXLOGBUFL+1]; /* Connection log record buffer */
229 int cx_active = 0; /* Connection is active */
231 #endif /* CKLOGDIAL */
234 static char *cmdstr = NULL; /* Place to build generic command */
237 static char cmdstr[256];
239 static char cmdstr[4096];
244 char fspec[CMDBL+4]; /* Filename string for \v(filespec) */
245 int fspeclen = CMDBL;
247 char fspec[CKMAXPATH+4];
248 int fspeclen = CKMAXPATH;
251 char * rfspec = NULL; /* Received filespec: local */
252 char * prfspec = NULL; /* Preliminary rfspec */
253 char * sfspec = NULL; /* Sent filespec: local */
254 char * psfspec = NULL; /* Preliminary sfspec */
255 char * srfspec = NULL; /* Received filespec: remote */
256 char * psrfspec = NULL; /* Preliminary srfspec */
257 char * rrfspec = NULL; /* Sent filespec: remote */
258 char * prrfspec = NULL; /* Preliminary rrfspec */
260 int success = 1, /* Command success/failure flag */
261 cmdlvl = 0, /* Command level */
262 action = 0, /* Action selected on command line */
263 slogts = 0, /* Session-log timestamps on/off */
264 slognul = 0, /* Session-log null-terminated lines */
266 sessft = XYFT_T, /* Session log file type */
268 sessft = XYFT_B, /* (text for UNIX binary for others) */
270 pflag = 1, /* Print prompt */
271 msgflg = 1; /* Print informational messages */
273 extern int xaskmore, saveask; /* More-prompting */
276 extern int apcactive;
278 /* External variables */
280 extern int local, quiet, binary, network, what, parity, xitsta, escape,
281 tlevel, bgset, backgrd, xsuspend, cmdint, nettype, seslog, dfloc;
283 extern int cmd_rows, cmd_cols, xcmdsrc;
285 extern char cmdfil[];
291 #ifdef datageneral /* 2/12/92 ENH */
293 extern int con_reads_mt, conint_ch, conint_avl;
294 #endif /* datageneral */
298 extern char ttname[], *dftty, *cmarg, **cmlist, *versio, myhost[];
301 extern int fcharset, tcharset, xfrxla;
302 extern struct csinfo fcsinfo[], tcsinfo[];
306 extern unsigned char colorcmd;
311 int fdispla = XYFD_N;
313 #else /* NOXFER is not defined */
315 #ifdef OS2 /* File transfer display type */
316 int fdispla = XYFD_C; /* Curses (fullscreen) if we have it */
319 int fdispla = XYFD_C;
321 int fdispla = XYFD_S; /* Otherwise CRT */
322 #endif /* CK_CURSES */
325 extern struct ck_p ptab[];
326 extern int protocol, xfrbel, xfrint;
329 extern int streaming, streamok;
330 #endif /* STREAMING */
332 /* Used internally */
335 _PROTOTYP( VOID screeng, (int, char, long, char *) );
337 _PROTOTYP( VOID screenc, (int, char, CK_OFF_T, char *) );
342 static char xtrmbuf[TRMBUFL]; /* tgetent() buffer */
343 char * trmbuf = xtrmbuf;
345 char * trmbuf = NULL;
347 _PROTOTYP( static VOID dpyinit, (void) );
348 _PROTOTYP( static long shocps, (int, CK_OFF_T, CK_OFF_T) );
349 _PROTOTYP( static CK_OFF_T shoetl, (CK_OFF_T, long, CK_OFF_T, CK_OFF_T) );
350 #endif /* CK_CURSES */
352 static int ft_win = 0; /* Fullscreen file transfer display window is active */
354 /* Variables declared here */
356 static char * skreason[] = {
358 "Remote file not older", /* SKP_DAT */
359 "Identical modification times", /* SKP_EQU */
360 "Type", /* SKP_TYP */
361 "Size", /* SKP_SIZ */
362 "Name collision", /* SKP_NAM */
363 "Exception List", /* SKP_EXL */
364 "Dot file", /* SKP_DOT */
365 "Backup file", /* SKP_BKU */
366 "Recovery not needed", /* SKP_RES */
367 "Access denied", /* SKP_ACC */
368 "Not a regular file", /* SKP_NRF */
369 "Simulated", /* SKP_SIM */
370 "Simulated - Remote file older", /* SKP_XUP */
371 "Simulated - No remote file", /* SKP_XNX */
373 static int nskreason = (sizeof(skreason) / sizeof(char *));
376 gskreason(n) int n; {
377 return((n > 0 && n < nskreason) ? skreason[n] : "");
380 char pktfil[CKMAXPATH+1]; /* Packet log file name */
382 #ifndef NOMSEND /* Multiple SEND */
383 char *msfiles[MSENDMAX];
387 extern long rttdelay;
389 #endif /* CK_TIMERS */
394 extern CK_OFF_T sendstart, rs_len;
395 #endif /* CK_RESEND */
397 #ifdef CK_PCT_BAR /* File transfer thermometer */
398 int thermometer = 1; /* ON by default */
399 #endif /* CK_PCT_BAR */
402 CKFLOAT gtv = -1.0, oldgtv = -1.0;
407 long gtv = -1L, oldgtv = -1L;
410 extern int server, bctu, rptflg, ebqflg, spsiz, urpsiz, wmax, czseen, cxseen,
411 winlo, displa, timint, npad, ebq, bctr, rptq, atcapu, lpcapu,
412 swcapu, wslotn, wslotr, rtimo, mypadn, sq, capas, rpsiz, tsecs,
413 pktlog, lscapu, dest, srvdis, wslots, spackets, spktl, rpktl,
414 retrans, wcur, numerrs, fsecs, whatru, crunched, timeouts,
415 rpackets, fncnv, bye_active, discard, inserver, diractive, cdactive;
417 extern long filcnt, filrej, rptn, filcps, tfcps, cps, peakcps;
418 extern CK_OFF_T ffc, tfc, fsize;
422 extern CHAR *rdatap, padch, seol, ctlq, mypadc, eol, *epktmsg;
426 FILE * dbfp = NULL; /* File pointer to database file */
428 int dbenabled = 1; /* Flag for database is enabled */
429 extern int ikdbopen; /* Flag for database is open */
431 unsigned long mydbseek = 0L; /* Seek pointer to my record */
432 int mydbslot = 0; /* My slot number */
433 unsigned long myflags = 0L; /* My flags */
434 unsigned long myatype = 0L; /* My authorization type */
435 unsigned long myamode = 0L; /* My authorization mode */
436 unsigned long mystate = 0L; /* My state (SEND, RECEIVE, etc) */
437 unsigned long mypid = 0L; /* My PID */
438 unsigned long myip = 0L; /* My IP address */
439 unsigned long peerip = 0L; /* My peer's IP address */
441 unsigned long dbip = 0L; /* IP address in db record */
442 unsigned long dbpid = 0L; /* PID in db record */
443 unsigned long dbflags = 0L; /* Flags field in db record */
444 unsigned long dblastused = 0L; /* Last in-use record in db */
445 char dbrec[DB_RECL]; /* Database record buffer */
447 char * dbdir = NULL; /* Database directory */
448 char * dbfile = NULL; /* Database file full pathname */
449 char myhexip[33] = { NUL, NUL }; /* My IP address in hex */
450 char peerhexip[33] = { NUL, NUL }; /* Client's IP address in hex */
454 extern CKFLOAT fpfsecs, fptsecs, fpxfsecs;
462 extern char * ftp_host, ftp_srvtyp[];
463 extern int ftp_csx, ftp_csl, ftp_deb;
465 extern char myipaddr[];
466 #endif /* TCPSOCKET */
470 extern struct mtab *mactab; /* For ON_EXIT macro. */
474 extern char *cmdbuf; /* Command buffer */
476 extern char cmdbuf[]; /* Command buffer */
478 extern int cmd_quoting;
483 #include <setjmpex.h>
488 extern ckjmpbuf cmjbuf;
489 #endif /* NOCCTRAP */
491 extern int xfiletype, nscanfile;
494 shoesc(escape) int escape; {
495 extern char * ccntab[]; /* C0 control character name table */
496 extern int tt_escape;
497 if ((escape > 0 && escape < 32) || (escape == 127)) {
498 printf(" Escape character: Ctrl-%c (ASCII %d, %s): %s\r\n",
501 (escape == 127 ? "DEL" : ccntab[escape]),
502 tt_escape ? "enabled" : "disabled"
505 printf(" Escape character: Code %d",escape);
506 if (escape > 160 && escape < 256)
507 printf(" (%c)",escape);
508 printf(": %s\r\n", tt_escape ? "enabled" : "disabled");
514 /* P R E S E T -- Reset global protocol variables */
516 extern int recursive;
519 int patterns = SET_AUTO; /* Whether to use filename patterns */
520 extern int g_patterns; /* For saving and restoring */
522 int patterns = SET_OFF;
523 #endif /* PATTERNS */
527 extern int g_lf_opts, lf_opts;
528 #endif /* CK_LABELED */
529 extern int g_matchdot, g_usepipes, usepipes;
530 extern int g_binary, g_proto, g_displa, g_spath, g_rpath, g_fncnv;
531 extern int g_recursive;
532 extern int g_xfermode, xfermode;
533 extern int g_urpsiz, g_spsizf, g_spsiz;
534 extern int g_spsizr, g_spmax, g_wslotr, g_prefixing, g_fncact;
535 extern int g_fnspath, g_fnrpath, g_skipbup;
538 extern int zgfs_link;
539 #endif /* CKSYMLINK */
541 extern int g_pflg, pwflg, g_pcpt, pwcrypt;
542 extern char * g_pswd, pwbuf[];
546 extern int spsizf, spsizr, spmax, prefixing, fncact, fnspath, fnrpath;
547 extern int moving; /* SEND criteria */
548 extern char sndafter[], sndbefore[], *sndexcept[], *rcvexcept[];
549 extern CK_OFF_T sndlarger, sndsmaller, calibrate;
550 extern int rmailf, rprintf, skipbup;
551 extern char optbuf[];
554 extern char * g_sfilter, * g_rfilter;
555 extern char * sndfilter, * rcvfilter;
556 #endif /* PIPESEND */
557 extern char ** sndarray;
563 extern char * filefile;
564 extern int reliable, xreliable, c_save, ss_save, slostart, urclear;
565 extern int oopts, omode, oname, opath, kactive, autopath;
566 extern char * snd_move; /* Directory to move sent files to */
567 extern char * snd_rename; /* What to rename sent files to */
568 extern char * rcv_move;
569 extern char * rcv_rename;
570 extern char * g_snd_move;
571 extern char * g_snd_rename;
572 extern char * g_rcv_move;
573 extern char * g_rcv_rename;
577 extern char savdir[];
578 #endif /* CK_TMPDIR */
583 extern short s_ctlp[], ctlp[];
585 #endif /* CK_SPEED */
588 extern int fcs_save, tcs_save;
589 extern int g_xfrxla, xfrxla;
592 /* Restore / reset per-command file-transfer switches */
594 makestr(&snd_move,g_snd_move);
595 makestr(&rcv_move,g_rcv_move);
596 makestr(&snd_rename,g_snd_rename);
597 makestr(&rcv_rename,g_rcv_rename);
599 kactive = 0; /* Kermit protocol no longer active */
600 oopts = -1; /* O-Packet Options */
601 omode = -1; /* O-Packet Transfer Mode */
602 oname = -1; /* O-Packet Filename Options */
603 opath = -1; /* O-Packet Pathname Options */
606 rs_len = 0L; /* REGET position */
607 #endif /* CK_RESEND */
612 for (i = 0; i < 256; i++)
616 #endif /* CK_SPEED */
620 if (f_tmpdir) { /* If we changed to download dir */
621 zchdir((char *) savdir); /* Go back where we came from */
624 #endif /* CK_TMPDIR */
626 calibrate = 0L; /* Calibration run */
627 if (xreliable > -1) {
628 reliable = xreliable;
629 debug(F101,"ftreset reliable","",reliable);
633 if (autopath) { /* SET RECEIVE PATHNAMES AUTO */
637 if (filefile) { /* File list */
639 makestr(&filefile,NULL);
641 if (c_save > -1) { /* Block Check Type */
645 if (ss_save > -1) { /* Slow Start */
650 if (g_lf_opts > -1) {
651 lf_opts = g_lf_opts; /* Restore labeled transfer options */
654 #endif /* CK_LABELED */
657 if (tcs_save > -1) { /* Character sets */
669 setxlatype(tcharset,fcharset); /* Translation type */
675 ckstrncpy(pwbuf,g_pswd,PWBUFL);
676 makestr(&g_pswd,NULL);
689 if (g_binary > -1) { /* File type */
693 if (g_xfermode > -1) { /* Transfer mode */
694 xfermode = g_xfermode;
698 if (g_patterns > -1) { /* Filename patterns */
699 patterns = g_patterns;
702 #endif /* PATTERNS */
704 if (g_usepipes > -1) {
705 usepipes = g_usepipes;
708 if (g_matchdot > -1) {
709 matchdot = g_matchdot;
712 if (g_proto > -1) { /* Protocol */
718 debug(F101,"ftreset restoring urpsiz","",urpsiz);
723 debug(F101,"ftreset restoring spsizf","",spsizf);
728 debug(F101,"ftreset restoring spsiz","",spsiz);
733 debug(F101,"ftreset restoring spsizr","",spsizr);
744 if (g_prefixing > -1) {
745 prefixing = g_prefixing;
756 if (g_fnspath > -1) {
760 if (g_fnrpath > -1) {
764 if (g_skipbup > -1) {
768 nolinks = 2; /* /FOLLOWLINKS is never global */
769 recursive = 0; /* /RECURSIVE can never be global */
772 if (g_displa > -1) { /* File transfer display */
776 if (g_spath > -1) { /* Send pathnames */
780 if (g_rpath > -1) { /* Receive pathnames */
784 if (g_fncnv > -1) { /* Filename conversion */
789 makestr(&sndfilter,g_sfilter); /* Send filter */
790 makestr(&rcvfilter,g_rfilter); /* Receive filter */
791 #endif /* PIPESEND */
794 rmailf = rprintf = 0; /* MAIL and PRINT modifiers for SEND */
795 optbuf[0] = NUL; /* MAIL and PRINT options */
796 #endif /* NOFRILLS */
798 moving = 0; /* Reset delete-after-send indicator */
799 sndafter[0] = NUL; /* Reset SEND selection switches */
802 for (i = 0; i < NSNDEXCEPT; i++) {
810 sndlarger = (CK_OFF_T)-1;
811 sndsmaller = (CK_OFF_T)-1;
812 debug(F101,"present sndsmaller","",sndsmaller);
825 ttgtpn() { /* Get typical port name */
827 Ideally this routine would be implemented in each of the cku?io.* modules,
828 but that requires changing the API definition.
835 "TAPI [ name ] or COM1"
839 "TXA0:, TTA0:, or LTA0:"
852 #else /* __FreeBSD__ */
855 #else /* __linux__ */
869 "/dev/term/00 or /dev/tty00"
876 #else /* CK_SCO32V4 */
888 #else /* datageneral */
900 #else /* MOTSV88R4 */
911 "/dev/cua, /dev/acu, /dev/tty0, etc"
913 "(sorry no example available)"
918 #endif /* MOTSV88R4 */
919 #endif /* SV68R3V6 */
922 #endif /* datageneral */
926 #endif /* CK_SCO32V4 */
927 #endif /* CK_SCOV5 */
928 #endif /* UNIXWARE */
933 #endif /* __linux__ */
934 #endif /* __FreeBSD__ */
943 /* C K _ E R R S T R -- Return message from most recent system error */
946 extern int ckrooterr;
953 /* Should have been declared in <string.h> */
954 _PROTOTYP( char * strerror, (int) );
955 #endif /* CK_ANSILIBS */
958 return("Off limits");
960 return(strerror(errno));
961 #else /* !USE_STRERROR */
963 extern char * ckvmserrstr(unsigned long);
966 return("Off limits");
968 return(ckvmserrstr(0L));
974 extern char *sys_errlist[];
975 #endif /* NDSYSERRLIST */
976 #else /* !__386BSD__ */
980 extern const char *const sys_errlist[];
981 #endif /* NDSYSERRLIST */
982 #endif /* __bsdi__ */
983 #endif /* __386BSD__ */
986 return("Off limits");
989 if (errno >= sys_nerr)
990 return("Error number out of range");
992 return((char *) sys_errlist[errno]);
997 extern char *sys_errlist[];
998 #endif /* NDSYSERRLIST */
1001 return("Off limits");
1004 if (errno >= sys_nerr)
1005 return("Error number out of range");
1007 return((char *) sys_errlist[errno]);
1010 #ifndef NDSYSERRLIST
1011 extern int sys_nerr;
1012 extern char *sys_errlist[];
1013 #endif /* NDSYSERRLIST */
1016 return("Off limits");
1019 if (errno >= sys_nerr)
1020 return("Error number out of range");
1022 return((char *) sys_errlist[errno]);
1025 #ifndef NDSYSERRLIST
1026 extern char *sys_errlist[];
1027 #endif /* NDSYSERRLIST */
1029 extern int_sys_nerr;
1034 return("Off limits");
1038 && errno <= _sys_nerr
1042 (char *) sys_errlist[errno]
1044 /* I don't know how to get a CLIB error string in OS/2 */
1056 #endif /* USE_STRERROR */
1061 Filename pattern recognition lists for automatic text/binary switching.
1062 These are somewhat passe after the addition of scanfile() (7.0).
1063 But with the addition of FTP [M]GET, they're back in style (8.0).
1065 Although, with FTP the lists need to be used in the reverse. With
1066 Kermit the list is used to imply the types of the local system. Whereas
1067 with FTP, the list must be used to imply the type of the remote system.
1068 Therefore, all platforms must now support all of the lists.
1070 char *txtpatterns[FTPATTERNS+1] = { NULL, NULL };
1071 char *binpatterns[FTPATTERNS+1] = { NULL, NULL };
1073 Default pattern lists for each platform...
1075 NOTE: In most cases we leave ".hlp", ".ini", and ".scr" alone; although they
1076 are traditionally text types, they are binary in Windows. So they are
1077 handled by the prevailing SET FILE TYPE, rather than automatically.
1078 Similarly for ".dat", ".inf", and so on. Also ".ps" since PostScript files
1079 are not always text. ".log" is omitted since logs can be text or binary,
1080 except in VMS they are usually text, etc etc.
1082 Later (Sep 2003): Add PostScript to binary patterns.
1084 static char *txtp[SYS_MAX][FTPATTERNS] = {
1089 "*.txt","*.c","*.h","*.r","*.w","*.cpp","*.cc","*.ksc","*.bwr","*.upd",
1090 "*.html","*.htm","*.mss","*.tex","*.nr","[Mm]akefile", "*.hex", "*.hqx",
1091 "*.for","*.f77","*.f","*.F","*.s","*.pas","*.java","*.el","*.lisp","*.sh",
1092 "*.m4","*.perl","*.pl","*.pod","*.pm","*.awk","*.sno","*.spt","*.sed",
1093 "*.ksc","*.TXT", "*read.me", "*READ.ME", ".*", "*/.*", "*.mem","*.mac",
1097 "*.txt","*.ksc","*.htm","*.html","*.bat","*.cmd","*.jav","*.asm", "*.hex",
1098 "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w",
1099 "*.java", "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile",
1100 "*.mem","*.mac","*.cc","*.pl","*.pod","*.pm","*.m4",NULL
1103 "*.com","*.txt","*.c", "*.for","*.pas","*.rno","*.rnh","*.mar","*.bli",
1104 "*.hlp","*.mss","*.doc","*.bwr","*.cld","*.hex","*.bas","*.ini","*.log",
1105 "*.mms","*.opt","*.ksc","*.perl","*.pl","*.pod","*.pm","*.sno","*.spt",
1109 "*.txt","*.ksc","*.htm","*.html","*.bat","*.cmd","*.jav","*.asm", "*.hex",
1110 "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w",
1111 "*.java", "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile",
1115 "*.txt","*.ksc","*.htm","*.bat","*.cmd","*.jav","*.asm", "*.hex",
1116 "*.hqx", "*.c", "*.h", "*.cpp", "*.hpp", "*.cxx", "*.cxx", "*.w",
1117 "*.bwr", "*.upd", "*.mak", "read.me", "*.map", "makefile", NULL
1120 "*.cmd","*.hlp","*.doc","*.ini","*.txt","*.mac","*.for","*.sai","*.bli",
1121 "*.pas","*.sno","*.spt","*.pcl","*.mss","*.rno","*.b36","*.tex","*.pub",
1122 "*.req","*.r36","*.mem","*.bwr","*.ccl","*.ctl","*.rnh","*.ksc",NULL
1125 "*.cmd","*.hlp","*.doc","*.ini","*.txt","*.mac","*.for","*.sai","*.bli",
1126 "*.pas","*.sno","*.spt","*.pcl","*.mss","*.rno","*.b36","*.tex","*.pub",
1127 "*.req","*.r36","*.mem","*.bwr","*.ccl","*.ctl","*.rnh","*.ksc",NULL
1130 "*.txt","*.ksc","*.htm","*.html","*.bat", "*.cmd","*.jav","*.asm","*.hex",
1131 "*.hqx","*.c", "*.h", "*.w", "*.java","*.bwr","*.upd","*.ttp","*.cm",
1132 "*.pl1","*.emacs", "read.me", "*.pl", "makefile", NULL
1135 "*.txt", "*.c", "*.h", "*.w", "*.er", "*.bwr", "*.upd", "read.me",
1136 "*.cli", "*.ksc", NULL
1139 "*.c","*.cpp","*.h","*.a","*akefile", /* program sources */
1140 "*.for","*.f77","*.f","*.F","*.s","*.pas","*.java","*.el","*.lisp",
1141 "*.sh","*.perl","*.awk","*.sno","*.spt","*.sed",
1142 "*.txt","*.w", /* general text */
1143 "*.ksc","*.bwr","*.upd",
1144 "*.html","*.htm","*.mss","*.tex","*.nr","*.hex", "*.hqx",
1145 "*.TXT", "*read.me", "*READ.ME", ".*", "*/.*",
1150 /* Note: .DOC added to (some) binary patterns June 1998... Microsoft wins. */
1152 static char *binp[SYS_MAX][FTPATTERNS] = {
1157 "*.gz","*.Z","*.tgz","*.gif", "*.tar","*.zip","*.o","*.so","*.a","*.out",
1158 "*.exe", "*.jpg", "*.jpeg", "*.tif","*.tiff", "*.pdf", "*.so.*", "*.class",
1159 "*.rpm", "*.bmp", "*.bz2", "*.BMP", "*.dll", "*.doc", "*.vxd", "*.dcx",
1160 "*.xl*", "*.lzh", "*.lhz", "*.au", "*.voc", "*.mpg", "*.mpeg","[wk]ermit",
1164 "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
1165 "*.class","*.cla","*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
1166 "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
1167 "*.pdf", "*.lzh", "*.vxd", "*.snd", "*.au", "* .voc", "*.mpg", "*.mpeg",
1171 "*.exe","*.obj","*.bak","*.bin","*.adf","*.stb","*.mai","*.sys","*.dmp",
1172 "*.ps", "*.dat","*.par", NULL
1175 "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
1176 "*.class", "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
1177 "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
1178 "*.pdf", "*.ps", "*.lzh", NULL
1181 "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
1182 "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
1183 "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
1184 "*.pdf", "*.ps", "*.lzh", NULL
1187 "*.exe","*.sav","*.bin","*.rim","*.rel","*.unv","*.lib","*.tap","*.dvi",
1191 "*.exe","*.sav","*.bin","*.rim","*.rel","*.unv","*.lib","*.tap","*.dvi",
1195 "*.exe", "*.zip", "*.obj", "*.com", "*.gif", "*.jpg", "*.wav", "*.ram",
1196 "*.class", "*.cla", "*.dll", "*.drv", "*.ocx", "*.vbx", "*.lib", "*.ico",
1197 "*.bmp", "*.tif", "*.tar", "*.gz", "*.tgz", "*.xl*", "*.doc", "*.vxd",
1198 "*.pdf", "*.ps", "*.lzh", "*.pm", NULL
1201 "*.ob", "*.pr", "*.dmp", "*.ps", NULL
1204 "*.gz","*.Z","*.z","*.tgz","*.lhz","*.tar", /* archivers */
1205 "*.zip","*.ar","*.zoo","*.rpm","*.lzh",
1206 /* object files, libraries, executables */
1207 "*.r","*.l","*.exe", "*.dll", "*.so.*", "*.class",
1209 "*.gif", "*.jpg", "*.jpeg", "*.tif","*.tiff", "*.pdf", "*.ps",
1210 "*.bmp", "*.bz2", "*.BMP","*.pcx",
1216 Set up default pattern lists so they can be freed and re-malloc'd.
1217 Each pattern list must terminated by a null element.
1222 for (i = 0; i < FTPATTERNS; i++) {
1223 txtpatterns[i] = NULL;
1224 binpatterns[i] = NULL;
1226 for (i = 0; i < FTPATTERNS; i++) {
1228 makestr(&(txtpatterns[i]),txtp[SYS_UNIX][i]);
1232 makestr(&(txtpatterns[i]),txtp[SYS_WIN32][i]);
1234 makestr(&(txtpatterns[i]),txtp[SYS_OS2][i]);
1238 makestr(&(txtpatterns[i]),txtp[SYS_VMS][i]);
1241 makestr(&(txtpatterns[i]),txtp[SYS_VOS][i]);
1244 makestr(&(txtpatterns[i]),txtp[SYS_DG][i]);
1245 #else /* datageneral */
1247 makestr(&(txtpatterns[i]),txtp[SYS_OSK][i]);
1249 makestr(&(txtpatterns[i]),txtp[SYS_UNK][i]);
1251 #endif /* datageneral */
1252 #endif /* STRATUS */
1259 for (i = 0; i < FTPATTERNS; i++) {
1261 makestr(&(binpatterns[i]),binp[SYS_UNIX][i]);
1265 makestr(&(binpatterns[i]),binp[SYS_WIN32][i]);
1267 makestr(&(binpatterns[i]),binp[SYS_OS2][i]);
1271 makestr(&(binpatterns[i]),binp[SYS_VMS][i]);
1274 makestr(&(binpatterns[i]),binp[SYS_VOS][i]);
1277 makestr(&(binpatterns[i]),binp[SYS_DG][i]);
1278 #else /* datageneral */
1280 makestr(&(binpatterns[i]),binp[SYS_OSK][i]);
1282 makestr(&(binpatterns[i]),binp[SYS_UNK][i]);
1284 #endif /* datageneral */
1285 #endif /* STRATUS */
1295 m a t c h n a m e -- Compare filename with text & binary name patterns.
1298 0 if name matches a text pattern but not a binary pattern.
1299 1 if name matches a binary pattern but not a text pattern.
1300 -1 if name matches no patterns.
1301 -2 if name matches a binary pattern and a text pattern.
1304 matchname(filename, local, os) char * filename; int local; int os; {
1305 int rc = -1; /* Return code */
1308 char tmpbuf[CKMAXPATH+1];
1309 #endif /* OS2ORUNIX */
1311 name = filename ? filename : ""; /* Copy of original arg */
1312 if (patterns && *name) { /* If PATTERNS ON... */
1316 if (ckmatch("*.~[1-9]*~",name,1,1)) { /* Name has backup suffix? */
1318 k = ckstrncpy(tmpbuf,name,CKMAXPATH+1); /* Yes, copy and strip */
1319 for (i = k - 3; i > 4; i--) {
1320 if (tmpbuf[i] == '~' && tmpbuf[i-1] == '.') {
1325 name = tmpbuf; /* And point to stripped copy */
1327 #endif /* OS2ORUNIX */
1328 zstrip(name,&p); /* Strip pathname too */
1332 if (txtpatterns[0]) { /* Search text patterns */
1333 for (i = 0; i < FTPATTERNS && txtpatterns[i]; i++) {
1334 if (ckmatch(txtpatterns[i],name,filecase,1)) {
1340 if (binpatterns[0]) { /* And search binary patterns */
1341 for (i = 0; i < FTPATTERNS && binpatterns[i]; i++) {
1342 if (ckmatch(binpatterns[i],name,filecase,1)) {
1343 rc = (rc > -1) ? -2 : 1;
1349 if (os >= 0 && os < SYS_MAX) {
1351 for (i = 0; i < FTPATTERNS && txtp[os][i]; i++) {
1352 if (ckmatch(txtp[os][i],name,filecase,1)) {
1359 for (i = 0; i < FTPATTERNS && binp[os][i]; i++) {
1360 if (ckmatch(binp[os][i],name,filecase,1)) {
1361 rc = (rc > -1) ? -2 : 1;
1369 debug(F111,"matchname",name,rc);
1372 #endif /* PATTERNS */
1377 #endif /* NOEVENMAX */
1378 #endif /* UNICODE */
1380 /* S C A N F I L E -- Analyze a file's contents */
1384 name: Pointer to name of existing file.
1385 flag: Pointer to int in which to return additional numeric data.
1388 -1 on failure (to open file or to read from it).
1389 Integer, 0..4, on success indicating file type:
1390 0 = 7-bit text (flag = -1)
1391 1 = UTF-8 text (flag = -1)
1392 2 = UCS-2 text (flag = 0: big-endian; flag = 1: little-endian)
1393 3 = 8-bit text (flag = 0: no C1 bytes; flag = 1: includes C1 bytes)
1394 4 = Text (type unknown)
1395 5 = binary (flag = -1)
1397 If UNICODE is defined:
1399 1. If file begins with a valid BOM, it is believed. Otherwise we
1400 read the first 4K of the file (since it might be email with verbose
1401 headers) and analyze it:
1403 2. If file contains only valid UTF-8 sequences, we call it UTF-8;
1406 3. If the file contains lots of alternate 0 bytes, we call it UCS-2, and
1407 set the polarity according to whether the preponderance of them are in
1408 even or odd positions; otherwise:
1410 4. If EVENMAX is defined and the file contains lots of alternate bytes that
1411 are identical, even if they aren't zero, and the number of such bytes
1412 is at least four times the length of the maximum run of alternating
1413 identical bytes of the opposite polarity, we call it UCS-2; otherwise:
1415 5. If the file contained no bytes with their 8th bits on and no controls
1416 other than CR, LF, HT, and FF, we call it ASCII; otherwise:
1418 6. If it contains C0 control characters other than CR, LF, HT, and FF, we
1419 call it binary; otherwise:
1421 7. We call it 8-bit text, character set unknown (could be Latin-1 or
1424 Note that malformed UTF-8 is not diagnosed as UTF-8.
1426 If UNICODE is not defined:
1428 1. If the file contains C0 control characters other than CR, LF, HT, and
1429 FF, we call it binary; otherwise:
1431 2. If the file contains any 8-bit bytes, we call it 8-bit text; otherwise:
1433 3. We call it 7-bit text.
1435 In the non-Unicode case, UCS-2 is diagnosed as binary, but UTF-8 as
1438 There is no significant speed difference between the Unicode and
1442 scanfile(name,flag,nscanfile) char * name; int * flag, nscanfile; {
1443 FILE * fp; /* File pointer */
1444 unsigned char buf[SCANFILEBUF]; /* File data buffer for analysis */
1445 int x, val = -1, count = 0; /* Workers */
1446 int rc = -1; /* Return code */
1447 int pv = -1; /* Pattern-match value */
1448 int eof = 0; /* Flag for file EOF encountered */
1449 int bytes = 0; /* Total byte count */
1451 unsigned int c0, c1; /* First 2 file bytes (for BOM) */
1452 #endif /* UNICODE */
1453 extern int pipesend, filepeek;
1455 register int i; /* Loop control */
1456 int readsize = 0; /* How much to read */
1457 int eightbit = 0; /* Number of bytes with 8th bit on */
1458 int c0controls = 0; /* C0 non-text control-char counter */
1459 int c0noniso = 0; /* C0 non-ISO control-char counter */
1460 int c1controls = 0; /* C1 control-character counter */
1461 unsigned int c; /* Current character */
1462 int runmax = 0; /* Longest run of 0 bytes */
1463 int runzero = 0; /* Run of 0 bytes */
1464 int pctzero = 0; /* Percentage of 0 bytes */
1467 extern int eofmethod;
1468 #endif /* CK_CTRLZ */
1471 int notutf8 = 0; /* Nonzero if definitely not UTF-8 */
1472 int utf8state = 0; /* UTF-8 recognizer state */
1473 int oddzero = 0; /* Number of 0 bytes in odd postions */
1474 int evenzero = 0; /* and in even positions */
1475 int lfnul = 0; /* Number of <LF><NUL> sequences */
1476 int crlf = 0; /* Number of <CRLF> sequences */
1479 #endif /* UNICODE */
1483 int oddrun = 0, oddmax = 0, oddbyte = 0, oddmaxbyte = 0;
1484 int evenrun = 0, evenmax = 0, evenbyte = 0, evenmaxbyte = 0;
1485 #endif /* EVENMAX */
1486 #endif /* COMMENT */
1489 if (pipesend || calibrate || sndarray) /* Only for real files */
1492 debug(F111,"scanfile",name,nscanfile);
1495 pv = matchname(name,1,-1);
1499 rc = (pv == 1) ? FT_BIN : FT_TEXT;
1500 debug(F111,"scanfile !filepeek result",name,rc);
1503 #endif /* PATTERNS */
1506 /* We don't scan in VMS where text files have various record formats in */
1507 /* which record headers contain seemingly non-text bytes. So the best */
1508 /* we can do in VMS is tell whether the file is text or binary, period. */
1511 b = binary; /* Save current binary setting */
1512 if (zopeni(ZIFILE,name) > 0) { /* In VMS this sets binary */
1513 x = binary; /* Get result */
1514 zclose(ZIFILE); /* Close the file */
1515 binary = b; /* Restore previous binary setting */
1516 rc = x ? FT_BIN : FT_TEXT;
1523 eof = 0; /* End-of-file reached indicator */
1525 fp = fopen(name, "rb"); /* Open the file in binary mode */
1527 fp = fopen(name, "r");
1530 if (!fp) /* Failed? */
1533 while (1) { /* One or more gulps from file */
1534 if (eof) { /* EOF from last time? */
1535 debug(F111,"scanfile at EOF",name,bytes);
1536 if (runzero > runmax)
1540 if (nscanfile < 0) { /* Reading whole file */
1541 readsize = SCANFILEBUF;
1542 } else { /* Reading first nscanfilee bytes */
1543 readsize = nscanfile - bytes;
1546 if (readsize > SCANFILEBUF)
1547 readsize = SCANFILEBUF;
1549 debug(F101,"scanfile readsize","",readsize);
1550 count = fread(buf,1,readsize,fp); /* Read a buffer */
1551 if (count == EOF || count == 0) {
1552 debug(F111,"scanfile EOF",name,count);
1555 debug(F111,"scanfile buffer ok",name,count);
1557 if (bytes == 0 && count > 8) {
1558 /* PDF files can look like text in the beginning. */
1559 if (!ckstrcmp((char *)buf,"%PDF-1.",7,1)) {
1560 if (isdigit(buf[7])) {
1561 if (buf[8] == '\015' ||
1562 count > 9 && buf[8] == SP && buf[9] == '\015') {
1565 debug(F110,"scanfile PDF",buf,0);
1567 binary = 1; /* But they are binary. */
1571 } else if (!ckstrcmp((char *)buf,"%!PS-Ado",8,1)) {
1572 /* Ditto for PostScript */
1575 for (i = 8; i < count; i++) {
1581 debug(F110,"scanfile PostScript",buf,0);
1586 } else if (!ckstrcmp((char *)buf,") HP-PCL",8,1)) {
1587 /* HP PCL printer language */
1590 for (i = 8; i < count; i++) {
1596 debug(F110,"scanfile PCL",buf,0);
1601 #endif /* NOPCLSCAN */
1603 else if (buf[0] == '\033' && (buf[1] == 'E' || buf[1] == '%')) {
1604 /* Ditto for PJL Job printer header */
1607 for (i = 2; i < count; i++) {
1613 debug(F110,"scanfile PJL Job printer header",buf,0);
1617 #endif /* NOPJLSCAN */
1622 if (bytes == 0 && count > 1) {
1625 /* First look for BOM */
1627 c0 = (unsigned)((unsigned)buf[0]&0xFF); /* First file byte */
1628 c1 = (unsigned)((unsigned)buf[1]&0xFF); /* Second byte */
1630 if (c0 == 0xFE && c1 == 0xFF) { /* UCS-2 BE */
1633 debug(F111,"scanfile UCS2 BOM BE",ckitoa(val),rc);
1635 } else if (c0 == 0xFF && c1 == 0xFE) { /* UCS-2 LE */
1638 debug(F111,"scanfile UCS2 BOM LE",ckitoa(val),rc);
1640 } else if (count > 2) if (c0 == 0xEF && c1 == 0xBB &&
1641 (unsigned)((unsigned)buf[2]&0xFF) == 0xBF) {
1643 debug(F111,"scanfile UTF8 BOM",ckitoa(val),rc);
1646 if (incl_cnt) { /* Have BOM */
1651 #endif /* UNICODE */
1653 bytes += count; /* Count bytes read */
1654 eof = feof(fp); /* Flag for at EOF */
1656 for (i = 0; i < count; i++) { /* For each byte... */
1657 c = (unsigned)buf[i]; /* For ease of reference */
1658 if (!c) { /* Zero byte? */
1660 if (i&1) /* In odd position */
1663 evenzero++; /* In even position */
1664 #endif /* EVENMAX */
1666 } else { /* Not a zero byte */
1667 if (runzero > runmax)
1669 if (runmax > 2) /* That's all we need to be certain */
1670 break; /* it's a binary file. */
1677 /* This is to catch UCS-2 with a non-ASCII, non-Latin-1 repertoire */
1679 if (i > 1) { /* Look for runs of alternating chars */
1681 if (c == buf[i-2]) { /* In odd positions */
1686 oddmaxbyte = oddbyte;
1688 } else { /* and even positions */
1689 if (c == buf[i-2]) {
1694 evenmaxbyte = evenbyte;
1698 #endif /* EVENMAX */
1699 #endif /* COMMENT */
1701 if ((c & 0x80) == 0) { /* We have a 7-bit byte */
1703 if (i > 0 && c == 10) { /* Linefeed */
1704 if (buf[i-1] == 0) lfnul++; /* Preceded by NUL */
1705 else if (buf[i-1] == 13) crlf++; /* or by CR... */
1707 #endif /* UNICODE */
1708 if (c < ' ') { /* Check for CO controls */
1709 if (c != LF && c != CR && c != HT && c != FF) {
1711 if (c != ESC && c != SO && c != SI)
1714 if ((c == '\032') /* Ctrl-Z */
1716 && eof && (i >= count - 2)
1717 #endif /* COMMENT */
1722 if (eofmethod == XYEOF_Z && txtcz == 0) {
1723 if (c0controls == 0) /* All text prior to Ctrl-Z */
1726 #endif /* CK_CTRLZ */
1730 if (!notutf8 && utf8state) { /* In UTF-8 sequence? */
1732 debug(F000,"scanfile","7-bit byte in UTF8 sequence",c);
1733 notutf8++; /* Then it's not UTF-8 */
1736 #endif /* UNICODE */
1737 } else { /* We have an 8-bit byte */
1738 eightbit++; /* Count it */
1739 if (c >= 0x80 && c < 0xA0) /* Check for C1 controls */
1742 if (!notutf8) { /* If it might still be UTF8... */
1743 switch (utf8state) { /* Enter the UTF-8 state machine */
1744 case 0: /* First byte... */
1745 if ((c & 0xE0) == 0xC0) { /* Tells number of */
1746 utf8state = 1; /* subsequent bytes */
1747 } else if ((c & 0xF0) == 0xE0) {
1749 } else if ((c & 0xF8) == 0xF0) {
1755 case 1: /* Subsequent byte */
1758 if ((c & 0xC0) != 0x80) { /* Must start with 10 */
1759 debug(F000,"scanfile",
1760 "bad byte in UTF8 sequence",c);
1764 utf8state--; /* Good, one less in this sequence */
1766 default: /* Shouldn't happen */
1767 debug(F111,"scanfile","bad UTF8 state",utf8state);
1771 #endif /* UNICODE */
1775 fclose(fp); /* Close the file */
1776 debug(F101,"scanfile bytes","",bytes);
1778 if (bytes == 0) /* If nothing was read */
1779 return(-1); /* we're done. */
1782 /* In case we had a run that never broke... */
1786 oddmaxbyte = oddbyte;
1790 evenmaxbyte = evenbyte;
1792 #endif /* COMMENT */
1796 #endif /* EVENMAX */
1799 if (bytes > 100) /* Bytes is not 0 */
1800 pctzero = (evenzero + oddzero) / (bytes / 100);
1802 pctzero = ((evenzero + oddzero) * 100) / bytes;
1803 #endif /* UNICODE */
1806 if (deblog) { /* If debugging, dump statistics */
1807 debug(F101,"scanfile c0controls ","",c0controls);
1808 debug(F101,"scanfile c0noniso ","",c0noniso);
1809 debug(F101,"scanfile c1controls ","",c1controls);
1810 debug(F101,"scanfile eightbit ","",eightbit);
1812 debug(F101,"scanfile crlf ","",crlf);
1813 debug(F101,"scanfile lfnul ","",lfnul);
1814 debug(F101,"scanfile notutf8 ","",notutf8);
1815 debug(F101,"scanfile evenzero ","",evenzero);
1816 debug(F101,"scanfile oddzero ","",oddzero);
1817 debug(F101,"scanfile even/odd ","",(evenzero / (oddzero + 1)));
1818 debug(F101,"scanfile odd/even ","",(oddzero / (evenzero + 1)));
1819 debug(F101,"scanfile pctzero ","",pctzero);
1820 #endif /* UNICODE */
1823 debug(F101,"scanfile oddmax ","",oddmax);
1824 debug(F101,"scanfile oddmaxbyte ","",oddmaxbyte);
1825 debug(F101,"scanfile evenmax ","",evenmax);
1826 debug(F101,"scanfile evenmaxbyte","",evenmaxbyte);
1827 #endif /* EVENMAX */
1828 #endif /* COMMENT */
1829 debug(F101,"scanfile runmax ","",runmax);
1834 x = eightbit ? bytes / 20 : bytes / 4; /* For UCS-2... */
1836 if (runmax > 2) { /* File has run of more than 2 NULs */
1837 debug(F100,"scanfile BIN runmax","",0);
1838 rc = FT_BIN; /* so it can't be any kind of text. */
1841 } else if (rc == FT_UCS2 || (rc == FT_UTF8 && runmax == 0)) {
1842 goto xscanfile; /* File starts with a BOM */
1844 } else if (eightbit > 0 && !notutf8) { /* File has 8-bit data */
1845 if (runmax > 0) { /* and runs of NULs */
1846 debug(F100,"scanfile BIN (nnUTF8) runmax","",0);
1847 rc = FT_BIN; /* UTF-8 doesn't have NULs */
1848 } else { /* No NULs */
1849 debug(F100,"scanfile UTF8 (nnUTF8 + runmax == 0)","",0);
1850 rc = FT_UTF8; /* and not not UTF-8, so is UTF-8 */
1855 For UCS-2 detection, see if the text contains lines delimited by
1856 ASCII controls and containing spaces, ASCII digits, or other ASCII
1857 characters, thus forcing the presence of a certain percentage of zero bytes.
1858 For this purpose require 20% zero bytes, with at least six times as many
1859 in even (odd) positions as in odd (even) positions.
1861 if ((evenzero >= x && oddzero == 0) ||
1862 ((((evenzero / (oddzero + 1)) > 6) && (pctzero > 20)) &&
1866 debug(F100,"scanfile UCS2 noBOM BE (even/oddzero)","",0);
1869 } else if ((evenzero == 0 && oddzero >= x) ||
1870 ((((oddzero / (evenzero + 1)) > 6) && (pctzero > 20)) &&
1874 debug(F100,"scanfile UCS2 noBOM LE (even/oddzero)","",0);
1881 If the tests above fail, we still might have UCS-2 if there are significant
1882 runs of identical bytes in alternating positions, but only if it also has
1883 unusual C0 controls (otherwise we'd pick up hex files here). NOTE: We
1884 don't actually do this -- EVENMAX is not defined (see comments above at
1885 first occurrence of EVENMAX).
1887 } else if (c0noniso && evenmax > bytes / 4) {
1888 debug(F100,"scanfile UCS2 BE (evenmax)","",0);
1891 } else if (c0noniso && oddmax > bytes / 4) {
1892 debug(F100,"scanfile UCS2 LE (evenmax)","",0);
1895 #endif /* EVENMAX */
1896 #endif /* COMMENT */
1900 It seems to be UCS-2 but let's be more certain since there is no BOM...
1901 If the number of 7- and 8-bit characters is approximately equal, it might
1902 be a compressed file. In this case we decide based on the name.
1904 if (rc == FT_UCS2) {
1907 j = (c1controls * 100) / (c0controls + 1);
1908 debug(F101,"scanfile c1/c0 ","",j);
1909 k = (bytes * 100) / eightbit;
1910 debug(F101,"scanfile pct 8bit ","",k);
1911 if (k > 40 && k < 60 && j > 60) {
1912 if (ckmatch("{*.Z,*.gz,*.zip,*.ZIP}",name,1,1)) {
1913 debug(F110,"scanfile 8-bit BIN compressed",name,0);
1919 /* Small file - not enough evidence unless ... */
1922 if (oddzero != 0 && evenzero != 0) {
1923 debug(F100,"scanfile small UCS2 doubtful","",0);
1926 } else if (oddzero == 0 && evenzero == 0) {
1927 rc = eightbit ? FT_8BIT : FT_7BIT;
1930 goto xscanfile; /* Seems to be UCS-2 */
1933 /* If none of the above, it's probably not Unicode. */
1935 if (!eightbit) { /* It's 7-bit */
1936 if (c0controls) { /* This would be strange */
1937 if ((c0noniso > 0) && (txtcz == 0)) {
1938 debug(F100,"scanfile 7-bit BIN (c0coniso)","",0);
1941 debug(F100,"scanfile 7-bit ISO2022 TEXT (no c0noniso)","",0);
1944 } else { /* 7-bit text */
1945 debug(F100,"scanfile 7-bit TEXT (no c0controls)","",0);
1948 } else if (!c0noniso || txtcz) { /* 8-bit text */
1949 debug(F100,"scanfile 8-bit TEXT (no c0noniso)","",0);
1951 val = c1controls ? 1 : 0;
1952 } else { /* 8-bit binary */
1953 debug(F100,"scanfile 8-bit BIN (c0noniso)","",0);
1957 #else /* !UNICODE */
1960 debug(F100,"scanfile 8-bit BIN (c0noniso)","",0);
1962 } else if (eightbit) {
1963 debug(F100,"scanfile 8-bit TEXT (no c0noniso)","",0);
1965 val = c1controls ? 1 : 0;
1967 debug(F100,"scanfile 7-bit TEXT (no c0noniso)","",0);
1971 #endif /* UNICODE */
1974 if (flag) *flag = val;
1975 debug(F101,"scanfile result ","",rc);
1980 scanstring - like scan file but for a string.
1981 This is just a quick butchery of scanfile without thinking too much.
1984 scanstring(s) char * s; {
1985 int x, val = -1, count = 0; /* Workers */
1986 int rc = -1; /* Return code */
1987 int pv = -1; /* Pattern-match value */
1988 int bytes = 0; /* Total byte count */
1990 unsigned int c0, c1; /* First 2 file bytes (for BOM) */
1991 #endif /* UNICODE */
1992 extern int pipesend, filepeek;
1994 register int i; /* Loop control */
1995 int readsize = 0; /* How much to read */
1996 int eightbit = 0; /* Number of bytes with 8th bit on */
1997 int c0controls = 0; /* C0 non-text control-char counter */
1998 int c0noniso = 0; /* C0 non-ISO control-char counter */
1999 int c1controls = 0; /* C1 control-character counter */
2000 unsigned int c; /* Current character */
2001 int runmax = 0; /* Longest run of 0 bytes */
2002 int runzero = 0; /* Run of 0 bytes */
2003 int pctzero = 0; /* Percentage of 0 bytes */
2007 int notutf8 = 0; /* Nonzero if definitely not UTF-8 */
2008 int utf8state = 0; /* UTF-8 recognizer state */
2009 int oddzero = 0; /* Number of 0 bytes in odd postions */
2010 int evenzero = 0; /* and in even positions */
2011 int lfnul = 0; /* Number of <LF><NUL> sequences */
2012 int crlf = 0; /* Number of <CRLF> sequences */
2015 #endif /* UNICODE */
2022 if (bytes == 0 && count > 1) {
2025 /* First look for BOM */
2027 c0 = (unsigned)((unsigned)buf[0]&0xFF); /* First file byte */
2028 c1 = (unsigned)((unsigned)buf[1]&0xFF); /* Second byte */
2030 if (c0 == 0xFE && c1 == 0xFF) { /* UCS-2 BE */
2033 debug(F111,"scanstring UCS2 BOM BE",ckitoa(val),rc);
2035 } else if (c0 == 0xFF && c1 == 0xFE) { /* UCS-2 LE */
2038 debug(F111,"scanstring UCS2 BOM LE",ckitoa(val),rc);
2040 } else if (count > 2) if (c0 == 0xEF && c1 == 0xBB &&
2041 (unsigned)((unsigned)buf[2]&0xFF) == 0xBF) {
2043 debug(F111,"scanstring UTF8 BOM",ckitoa(val),rc);
2046 if (incl_cnt) { /* Have BOM */
2051 #endif /* UNICODE */
2053 bytes += count; /* Count bytes read */
2055 for (i = 0; i < count; i++) { /* For each byte... */
2056 c = (unsigned)buf[i]; /* For ease of reference */
2057 if (!c) { /* Zero byte? */
2058 goto xscanstring; /* Null terminated string */
2060 if ((c & 0x80) == 0) { /* We have a 7-bit byte */
2062 if (i > 0 && c == 10) { /* Linefeed */
2063 if (buf[i-1] == 0) lfnul++; /* Preceded by NUL */
2064 else if (buf[i-1] == 13) crlf++; /* or by CR... */
2066 #endif /* UNICODE */
2067 if (c < ' ') { /* Check for CO controls */
2068 if (c != LF && c != CR && c != HT && c != FF) {
2070 if (c != ESC && c != SO && c != SI)
2073 if ((c == '\032') /* Ctrl-Z */
2080 if (!notutf8 && utf8state) { /* In UTF-8 sequence? */
2082 debug(F000,"scanstring","7-bit byte in UTF8 sequence",c);
2083 notutf8++; /* Then it's not UTF-8 */
2086 #endif /* UNICODE */
2087 } else { /* We have an 8-bit byte */
2088 eightbit++; /* Count it */
2089 if (c >= 0x80 && c < 0xA0) /* Check for C1 controls */
2092 if (!notutf8) { /* If it might still be UTF8... */
2093 switch (utf8state) { /* Enter the UTF-8 state machine */
2094 case 0: /* First byte... */
2095 if ((c & 0xE0) == 0xC0) { /* Tells number of */
2096 utf8state = 1; /* subsequent bytes */
2097 } else if ((c & 0xF0) == 0xE0) {
2099 } else if ((c & 0xF8) == 0xF0) {
2105 case 1: /* Subsequent byte */
2108 if ((c & 0xC0) != 0x80) { /* Must start with 10 */
2109 debug(F000,"scanstring",
2110 "bad byte in UTF8 sequence",c);
2114 utf8state--; /* Good, one less in this sequence */
2116 default: /* Shouldn't happen */
2117 debug(F111,"scanstring","bad UTF8 state",utf8state);
2121 #endif /* UNICODE */
2124 if (bytes == 0) /* If nothing was read */
2125 return(-1); /* we're done. */
2128 if (bytes > 100) /* Bytes is not 0 */
2129 pctzero = (evenzero + oddzero) / (bytes / 100);
2131 pctzero = ((evenzero + oddzero) * 100) / bytes;
2132 #endif /* UNICODE */
2135 x = eightbit ? bytes / 20 : bytes / 4; /* For UCS-2... */
2137 if (runmax > 2) { /* File has run of more than 2 NULs */
2138 debug(F100,"scanstring BIN runmax","",0);
2139 rc = FT_BIN; /* so it can't be any kind of text. */
2142 } else if (rc == FT_UCS2 || (rc == FT_UTF8 && runmax == 0)) {
2143 goto xscanstring; /* File starts with a BOM */
2145 } else if (eightbit > 0 && !notutf8) { /* File has 8-bit data */
2146 if (runmax > 0) { /* and runs of NULs */
2147 debug(F100,"scanstring BIN (nnUTF8) runmax","",0);
2148 rc = FT_BIN; /* UTF-8 doesn't have NULs */
2149 } else { /* No NULs */
2150 debug(F100,"scanstring UTF8 (nnUTF8 + runmax == 0)","",0);
2151 rc = FT_UTF8; /* and not not UTF-8, so is UTF-8 */
2156 It seems to be UCS-2 but let's be more certain since there is no BOM...
2157 If the number of 7- and 8-bit characters is approximately equal, it might
2158 be a compressed file. In this case we decide based on the name.
2160 if (rc == FT_UCS2) {
2162 if (oddzero != 0 && evenzero != 0) {
2163 debug(F100,"scanstring small UCS2 doubtful","",0);
2166 } else if (oddzero == 0 && evenzero == 0) {
2167 rc = eightbit ? FT_8BIT : FT_7BIT;
2170 goto xscanstring; /* Seems to be UCS-2 */
2173 /* If none of the above, it's probably not Unicode. */
2175 if (!eightbit) { /* It's 7-bit */
2176 if (c0controls) { /* This would be strange */
2177 if ((c0noniso > 0) && (txtcz == 0)) {
2178 debug(F100,"scanstring 7-bit BIN (c0coniso)","",0);
2181 debug(F100,"scanstring 7-bit ISO2022 TEXT (no c0noniso)","",0);
2184 } else { /* 7-bit text */
2185 debug(F100,"scanstring 7-bit TEXT (no c0controls)","",0);
2188 } else if (!c0noniso || txtcz) { /* 8-bit text */
2189 debug(F100,"scanstring 8-bit TEXT (no c0noniso)","",0);
2191 val = c1controls ? 1 : 0;
2192 } else { /* 8-bit binary */
2193 debug(F100,"scanstring 8-bit BIN (c0noniso)","",0);
2197 #else /* !UNICODE */
2200 debug(F100,"scanstring 8-bit BIN (c0noniso)","",0);
2202 } else if (eightbit) {
2203 debug(F100,"scanstring 8-bit TEXT (no c0noniso)","",0);
2205 val = c1controls ? 1 : 0;
2207 debug(F100,"scanstring 7-bit TEXT (no c0noniso)","",0);
2211 #endif /* UNICODE */
2214 debug(F101,"scanstring result ","",rc);
2220 /* F I L E S E L E C T -- Select this file for sending */
2225 char *f, char *sa, char *sb, char *sna, char *snb,
2226 CK_OFF_T minsiz, CK_OFF_T maxsiz,
2227 int nbu, int nxlist,
2231 fileselect(f,sa,sb,sna,snb,minsiz,maxsiz,nbu,nxlist,xlist)
2232 char *f,*sa,*sb,*sna,*snb; CK_OFF_T minsiz,maxsiz;
2233 int nbu,nxlist; char ** xlist;
2234 #endif /* CK_ANSIC */
2240 debug(F111,"fileselect minsiz",ckfstoa(minsiz),minsiz);
2241 debug(F111,"fileselect maxsiz",ckfstoa(maxsiz),maxsiz);
2242 debug(F111,"fileselect (CK_OFF_T)-1",ckfstoa((CK_OFF_T)-1),(CK_OFF_T)-1);
2255 debug(F111,"fileselect NOLINKS zgetfs",f,zz);
2256 if (zz < (CK_OFF_T)0)
2258 debug(F111,"fileselect NOLINKS zgfs_link",f,zgfs_link);
2264 #endif /* CKSYMLINK */
2266 debug(F110,"fileselect",f,0);
2267 if (*sa || *sb || *sna || *snb) {
2268 fdate = zfcdat(f); /* Date/time of this file */
2269 if (!fdate) fdate = "";
2271 debug(F111,"fileselect fdate",fdate,n);
2272 if (n != 17) /* Failed to get it */
2275 if (sa[0] && (strcmp(fdate,(char *)sa) <= 0)) {
2276 debug(F110,"fileselect sa",sa,0);
2277 /* tlog(F110,"Skipping (too old)",f,0); */
2281 if (sb[0] && (strcmp(fdate,(char *)sb) >= 0)) {
2282 debug(F110,"fileselect sb",sb,0);
2283 /* tlog(F110,"Skipping (too new)",f,0); */
2287 if (sna[0] && (strcmp(fdate,(char *)sna) > 0)) {
2288 debug(F110,"fileselect sna",sna,0);
2289 /* tlog(F110,"Skipping (too new)",f,0); */
2293 if (snb[0] && (strcmp(fdate,(char *)snb) < 0)) {
2294 debug(F110,"fileselect snb",snb,0);
2295 /* tlog(F110,"Skipping (too old)",f,0); */
2299 /* Smaller or larger */
2300 if (minsiz > (CK_OFF_T)-1 || maxsiz > (CK_OFF_T)-1) {
2301 z = zchki(f); /* Get size */
2302 debug(F101,"fileselect filesize","",z);
2303 if (z < (CK_OFF_T)0)
2305 if ((minsiz > (CK_OFF_T)-1) && (z >= minsiz)) {
2306 debug(F111,"fileselect minsiz skipping",f,minsiz);
2307 /* tlog(F111,"Skipping (too big)",f,z); */
2310 if ((maxsiz > (CK_OFF_T)-1) && (z <= maxsiz)) {
2311 debug(F111,"fileselect maxsiz skipping",f,maxsiz);
2312 /* tlog(F110,"Skipping (too small)",f,0); */
2316 if (nbu) { /* Skipping backup files? */
2319 "*.~[0-9]*~" /* Not perfect but close enough. */
2321 "*.~*~" /* Less close. */
2322 #endif /* CKREGEX */
2324 debug(F110,"fileselect skipping backup",f,0);
2328 for (n = 0; xlist && n < nxlist; n++) {
2330 debug(F101,"fileselect xlist empty",0,n);
2333 if (ckmatch(xlist[n],f,filecase,1)) {
2334 debug(F111,"fileselect xlist",xlist[n],n);
2335 debug(F110,"fileselect skipping",f,0);
2339 if (xfiletype > -1) {
2340 n = scanfile(f,NULL,nscanfile);
2344 n = (n == FT_BIN) ? 1 : 0;
2349 debug(F110,"fileselect selecting",f,0);
2356 extern int WSASafeToCancel;
2358 #endif /* TCPSOCKET */
2362 extern int flow, autoflow, mdmtyp, cxtype, cxflow[];
2364 extern int dialcapas, dialfc;
2365 extern MDMINF * modemp[];
2370 debug(F101,"setflow autoflow","",autoflow);
2372 /* #ifdef COMMENT */
2373 /* WHY WAS THIS COMMENTED OUT? */
2374 if (!autoflow) /* Only if FLOW is AUTO */
2376 /* #endif */ /* COMMENT */
2378 debug(F101,"setflow local","",local);
2379 debug(F101,"setflow network","",network);
2380 debug(F101,"setflow cxtype","",cxtype);
2383 if (network && istncomport()) {
2384 flow = cxflow[CXT_MODEM];
2385 debug(F101,"setflow TN_COMPORT flow","",flow);
2388 #endif /* TN_COMPORT */
2390 if (network || !local || cxtype == CXT_DIRECT) {
2391 flow = cxflow[cxtype]; /* Set appropriate flow control */
2392 debug(F101,"setflow flow","",flow);
2395 if (cxtype != CXT_MODEM) /* Connection type should be modem */
2399 bits = dialcapas; /* Capability bits */
2400 if (!bits) { /* No bits? */
2401 p = modemp[mdmtyp]; /* Look in modem info structure */
2405 if (dialfc == FLO_AUTO) { /* If DIAL flow is AUTO */
2406 #ifdef CK_RTSCTS /* If we can do RTS/CTS flow control */
2407 if (bits & CKD_HW) /* and modem can do it too */
2408 flow = FLO_RTSC; /* then switch to RTS/CTS */
2409 else /* otherwise */
2410 flow = FLO_XONX; /* use Xon/Xoff. */
2414 flow = FLO_XONX; /* Use Xon/Xoff. */
2417 #endif /* CK_RTSCTS */
2420 debug(F101,"setflow modem flow","",flow);
2427 /* A U T O E X I T C H K -- Check for CONNECT-mode trigger string */
2429 Returns -1 if trigger not found, or else the trigger index, 0 or greater.
2430 (Replace with fancier and more efficient matcher later...)
2431 NOTE: to prevent unnecessary function call overhead, call this way:
2433 x = tt_trigger[0] ? autoexitchk(c) : -1;
2440 autoexitchk(c) CHAR c;
2441 #endif /* CK_ANSIC */
2443 extern CHAR * tt_trmatch[];
2444 extern char * tt_trigger[];
2446 for (i = 0; i < TRIGGERS; i++) {
2447 if (!tt_trigger[i]) { /* No more triggers in list */
2449 } else if (*tt_trigger[i]) {
2450 if (!tt_trmatch[i]) /* Just starting? */
2451 tt_trmatch[i] = (CHAR *)tt_trigger[i]; /* Set match pointer */
2452 if (c == *tt_trmatch[i]) { /* Compare this character */
2453 tt_trmatch[i]++; /* It matches */
2454 if (!*tt_trmatch[i]) { /* End of match string? */
2455 tt_trmatch[i] = (CHAR *) tt_trigger[i]; /* Yes, rewind, */
2456 debug(F101,"autoexitchk",tt_trigger[i],i); /* log, */
2457 return(i); /* and return success */
2459 } else /* No match */
2460 tt_trmatch[i] = (CHAR *) tt_trigger[i]; /* Rewind match string */
2461 } /* and go on the next match string */
2463 return(-1); /* No match found */
2465 #endif /* CK_TRIGGER */
2468 /* S H O M D M -- Show modem signals */
2473 Note use of "\r\n" to make sure this report prints right, even when
2474 called during CONNECT mode.
2480 "Modem signals unavailable in this version of Kermit\r\n");
2482 case -2: printf("No modem control for this device\r\n"); break;
2483 case -1: printf("Modem signals unavailable\r\n"); break;
2487 " Carrier Detect (CD): %s\r\n",(y & BM_DCD) ? "On": "Off");
2489 " Dataset Ready (DSR): %s\r\n",(y & BM_DSR) ? "On": "Off");
2492 " Clear To Send (CTS): %s\r\n",(y & BM_CTS) ? "On": "Off");
2496 " Ring Indicator (RI): %s\r\n",(y & BM_RNG) ? "On": "Off");
2499 " Data Terminal Ready (DTR): %s\r\n",
2503 (y & BM_DTR) ? "On": "Off"
2508 " Request To Send (RTS): %s\r\n",
2512 (y & BM_RTS) ? "On": "Off"
2516 #endif /* STRATUS */
2520 if (tttapi && !tapipass) {
2521 LPDEVCFG lpDevCfg = NULL;
2522 LPCOMMCONFIG lpCommConfig = NULL;
2523 LPMODEMSETTINGS lpModemSettings = NULL;
2526 if (cktapiGetModemSettings(&lpDevCfg,&lpModemSettings,
2527 &lpCommConfig,&lpDCB)) {
2529 cktapiDisplayModemSettings(lpDevCfg,lpModemSettings,
2530 lpCommConfig,lpDCB);
2533 #endif /* CK_TAPI */
2534 #endif /* BETADEBUG */
2537 #endif /* NOLOCAL */
2540 /* S D E B U -- Record spar results in debugging log */
2543 sdebu(len) int len; {
2544 debug(F111,"spar: data",(char *) rdatap,len);
2545 debug(F101," spsiz ","", spsiz);
2546 debug(F101," timint","",timint);
2547 debug(F101," npad ","", npad);
2548 debug(F101," padch ","", padch);
2549 debug(F101," seol ","", seol);
2550 debug(F101," ctlq ","", ctlq);
2551 debug(F101," ebq ","", ebq);
2552 debug(F101," ebqflg","",ebqflg);
2553 debug(F101," bctr ","", bctr);
2554 debug(F101," rptq ","", rptq);
2555 debug(F101," rptflg","",rptflg);
2556 debug(F101," lscapu","",lscapu);
2557 debug(F101," atcapu","",atcapu);
2558 debug(F101," lpcapu","",lpcapu);
2559 debug(F101," swcapu","",swcapu);
2560 debug(F101," wslotn","", wslotn);
2561 debug(F101," whatru","", whatru);
2563 /* R D E B U -- Debugging display of rpar() values */
2566 rdebu(d,len) CHAR *d; int len; {
2567 debug(F111,"rpar: data",d,len);
2568 debug(F101," rpsiz ","", xunchar(d[0]));
2569 debug(F101," rtimo ","", rtimo);
2570 debug(F101," mypadn","",mypadn);
2571 debug(F101," mypadc","",mypadc);
2572 debug(F101," eol ","", eol);
2573 debug(F101," ctlq ","", ctlq);
2574 debug(F101," sq ","", sq);
2575 debug(F101," ebq ","", ebq);
2576 debug(F101," ebqflg","",ebqflg);
2577 debug(F101," bctr ","", bctr);
2578 debug(F101," rptq ","", d[8]);
2579 debug(F101," rptflg","",rptflg);
2580 debug(F101," capas ","", capas);
2581 debug(F101," bits ","",d[capas]);
2582 debug(F101," lscapu","",lscapu);
2583 debug(F101," atcapu","",atcapu);
2584 debug(F101," lpcapu","",lpcapu);
2585 debug(F101," swcapu","",swcapu);
2586 debug(F101," wslotr","", wslotr);
2587 debug(F101," rpsiz(extended)","",rpsiz);
2591 /* C H K E R R -- Decide whether to exit upon a protocol error */
2595 if (backgrd && !server) fatal("Protocol error");
2597 #endif /* COMMENT */
2600 /* F A T A L -- Fatal error message */
2603 fatal(msg) char *msg; {
2605 static int initing = 0;
2607 debug(F111,"fatal",msg,initflg);
2609 if (!initflg) { /* If called from prescan */
2610 if (initing) /* or called from sysinit() */
2616 debug(F111,"fatal",msg,xitsta);
2617 tlog(F110,"Fatal:",msg,0L);
2619 if (strncmp(msg,"%CKERMIT",8))
2620 conol("%CKERMIT-E-FATAL, ");
2635 doexit(BAD_EXIT,xitsta | 1); /* Exit indicating failure */
2639 /* B L D L E N -- Make length-encoded copy of string */
2642 bldlen(str,dest) char *str, *dest; {
2644 len = (int)strlen(str);
2648 *dest = (char) tochar(len);
2649 strcpy(dest+1,str); /* Checked below in setgen() */
2654 /* S E T G E N -- Construct a generic command */
2656 Call with Generic command character followed by three string arguments.
2657 Trailing strings are allowed to be empty (""). Each string except the last
2658 non-empty string must be less than 95 characters long. The final nonempty
2659 string is allowed to be longer.
2663 setgen(char type, char * arg1, char * arg2, char * arg3)
2665 setgen(type,arg1,arg2,arg3) char type, *arg1, *arg2, *arg3;
2666 #endif /* CK_ANSIC */
2671 if (!(cmdstr = malloc(MAXSP + 1)))
2672 fatal("setgen: can't allocate memory");
2673 #endif /* DYNAMIC */
2678 if (!arg1) arg1 = "";
2679 if (!arg2) arg2 = "";
2680 if (!arg3) arg3 = "";
2681 if (((int)strlen(arg1)+(int)strlen(arg2)+(int)strlen(arg3)+4) < MAXSP) {
2683 upstr = bldlen(arg1,cp);
2685 upstr = bldlen(arg2,upstr);
2686 if (*arg3 != NUL) bldlen(arg3,upstr);
2690 debug(F110,"setgen",cmarg,0);
2698 static char *mgbufp = NULL;
2700 /* F N P A R S E -- */
2703 Argument is a character string containing one or more filespecs.
2704 This function breaks the string apart into an array of pointers, one
2705 to each filespec, and returns the number of filespecs. Used by server
2706 when it receives a GET command to allow it to process multiple file
2707 specifications in one transaction. Sets cmlist to point to a list of
2708 file pointers, exactly as if they were command line arguments.
2710 This version of fnparse treats spaces as filename separators. If your
2711 operating system allows spaces in filenames, you'll need a different
2714 This version of fnparse mallocs a string buffer to contain the names. It
2715 cannot assume that the string that is pointed to by the argument is safe.
2718 fnparse(string) char *string; {
2720 int r = 0, x; /* Return code */
2722 debug(F111,"fnparse",string,recursive);
2723 #endif /* RECURSIVE */
2725 if (mgbufp) free(mgbufp); /* Free this from last time. */
2726 mgbufp = malloc((int)strlen(string)+2);
2728 debug(F100,"fnparse malloc error","",0);
2733 ckstrncpy(fspec,string,fspeclen); /* Make copy for \v(filespec) */
2736 s = string; /* Input string */
2737 p = q = mgbufp; /* Point to the copy */
2738 r = 0; /* Initialize our return code */
2739 while (*s == SP || *s == HT) /* Skip leading spaces and tabs */
2741 for (x = strlen(s); /* Strip trailing spaces */
2742 (x > 1) && (s[x-1] == SP || s[x-1] == HT);
2745 while (1) { /* Loop through rest of string */
2746 if (*s == CMDQ) { /* Backslash (quote character)? */
2747 if ((x = xxesc(&s)) > -1) { /* Go interpret it. */
2748 *q++ = (char) x; /* Numeric backslash code, ok */
2749 } else { /* Just let it quote next char */
2750 s++; /* get past the backslash */
2751 *q++ = *s++; /* deposit next char */
2754 } else if (*s == SP || *s == NUL) { /* Unquoted space or NUL? */
2755 *q++ = NUL; /* End of output filename. */
2756 msfiles[r] = p; /* Add this filename to the list */
2757 debug(F111,"fnparse",msfiles[r],r);
2759 if (*s == NUL) break; /* End of string? */
2760 while (*s == SP) s++; /* Skip repeated spaces */
2761 p = q; /* Start of next name */
2763 } else *q++ = *s; /* Otherwise copy the character */
2764 s++; /* Next input character */
2766 debug(F101,"fnparse r","",r);
2767 msfiles[r] = ""; /* Put empty string at end of list */
2771 #endif /* NOMSEND */
2773 char * /* dbchr() for DEBUG SESSION */
2779 if (c & 0x80) { /* 8th bit on */
2783 if (c < SP) { /* Control character */
2785 *cp++ = (char) ctl(c);
2786 } else if (c == DEL) {
2789 } else { /* Printing character */
2792 *cp = '\0'; /* Terminate string */
2793 cp = s; /* Return pointer to it */
2797 /* C K H O S T -- Get name of local host (where C-Kermit is running) */
2800 Call with pointer to buffer to put hostname in, and length of buffer.
2801 Copies hostname into buffer on success, puts null string in buffer on
2812 #include <sys/utsname.h>
2817 #include <utsname.h>
2818 #endif /* BELLV10 */
2819 #endif /* SVORPOSIX*/
2822 extern char uidbuf[], * clienthost;
2823 #endif /* CKSYSLOG */
2826 ckhost(vvbuf,vvlen) char * vvbuf; int vvlen; {
2832 #endif /* NOSERVER */
2837 #else /* Everything else - rest of this routine */
2849 struct utsname hname;
2850 #endif /* APOLLOSR10 */
2851 #endif /* _386BSD */
2853 #endif /* SVORPOSIX */
2855 int ac0 = (char *) vvbuf, ac1 = -1, ac2 = 0;
2856 #endif /* datageneral */
2859 if (getenv("CK_NOPUSH")) { /* No shell access allowed */
2860 nopush = 1; /* on this host... */
2863 #endif /* NOSERVER */
2867 *vvbuf = NUL; /* How let's get our host name ... */
2869 #ifndef BELLV10 /* Does not have gethostname() */
2873 ckstrncpy(vvbuf,"Apollo",vvlen);
2876 if (gethostname(vvbuf,vvlen) < 0)
2880 if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
2884 if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
2886 if (uname(&hname) > -1) ckstrncpy(vvbuf,hname.nodename,vvlen);
2887 #endif /* TCPSOCKET */
2888 #else /* SVORPOSIX but not _386BSD or BSD44 */
2890 if (uname(&hname) > -1) ckstrncpy(vvbuf,hname.nodename,vvlen);
2892 if (uname(&hname) > -1) {
2896 #ifndef NOCKGETFQHOST
2897 if (!ckstrchr(p,'.'))
2898 p = (char *)ckgetfqhostname(p);
2899 #endif /* NOCKGETFQHOST */
2900 #endif /* TCPSOCKET */
2902 if (!*p) p = "(unknown)";
2903 ckstrncpy(vvbuf,p,vvlen);
2905 #endif /* __ia64__ */
2907 #endif /* _386BSD */
2909 #endif /* APOLLOSR10 */
2910 #else /* !SVORPOSIX */
2912 if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
2915 g = getenv("SYS$NODE");
2916 if (g) ckstrncpy(vvbuf,g,vvlen);
2917 x = (int)strlen(vvbuf);
2918 if (x > 1 && vvbuf[x-1] == ':' && vvbuf[x-2] == ':') vvbuf[x-2] = NUL;
2921 if (sys($HNAME,&ac0,&ac1,&ac2) == 0) /* successful */
2922 vvlen = ac2 + 1; /* enh - have to add one */
2924 #ifdef OS2 /* OS/2 */
2925 g = os2_gethostname();
2926 if (g) ckstrncpy(vvbuf,g,vvlen);
2930 if (gethostname(vvbuf, vvlen) < 0) *vvbuf = NUL;
2931 #endif /* TCPSOCKET */
2934 #endif /* datageneral */
2937 #endif /* SVORPOSIX */
2939 /* If TCP/IP is not installed, gethostname() fails, use uname() */
2940 if (gethostname(vvbuf,vvlen) < 0) {
2941 if (uname(&hname) > -1)
2942 ckstrncpy(vvbuf,hname.nodename,vvlen);
2947 #endif /* BELLV10 */
2948 if (*vvbuf == NUL) { /* If it's still empty */
2949 g = getenv("HOST"); /* try this */
2950 if (g) ckstrncpy(vvbuf,g,vvlen);
2952 vvbuf[vvlen-1] = NUL; /* Make sure result is terminated. */
2961 A S K M O R E -- Poor person's "more".
2962 Returns 0 if no more, 1 if more wanted.
2969 extern int timelimit;
2973 #endif /* IKSDCONF */
2975 extern int apcstatus, apcactive;
2984 if (inserver && !iksdcf)
2986 #endif /* IKSDCONF */
2988 if (apcactive == APC_LOCAL ||
2989 (apcactive == APC_REMOTE && (apcstatus & APC_NOINP)))
3003 concb((char)escape); /* Force CBREAK mode. */
3013 #endif /* NOSETBUF */
3022 cx = cmdgetc(timelimit);
3023 if (cx < -1 && timelimit) {
3024 printf("\n?IKS idle timeout - Goodbye.\n");
3025 doexit(GOOD_EXIT,0);
3026 } else if (cx == -1) { /* Connection lost */
3033 conbin((char)escape); /* Protect against Ctrl-Z */
3035 concb((char)escape);
3039 debug(F101,"askmore cmdgetc","",cx);
3041 debug(F100,"askmore EOF","",0);
3050 debug(F101,"askmore c","",c);
3057 case 'p': case 'P': case 'g': case 'G': /* Proceed or Go */
3059 /* fall thru on purpose */
3061 case SP: case 'y': case 'Y': case 012: case 015:
3063 write(1, "\015 \015", sizeof "\015 \015" - 1);
3065 printf("\015 \015");
3070 case 'n': case 'N': case 'q': case 'Q':
3082 printf("^%c...\n", (c + 0100));
3084 printf("^%c...\015\012", (c + 0100));
3088 /* Invalid answer */
3090 debug(F111,"askmore","invalid answer",c);
3091 printf("Y or space-bar for yes, N for no, G to show the rest\n");
3103 /* T R A P -- Terminal interrupt handler */
3110 #endif /* CK_ANSIC */
3112 extern int b_save, f_save;
3114 extern int timelimit;
3117 extern unsigned long startflags;
3120 #endif /* NOSETKEY */
3124 extern int i_active, instatus;
3129 extern int zchkod, zchkid;
3131 extern int unkmacro;
3139 signal(SIGINT, SIG_ACK);
3142 /* GEM is not reentrant, no i/o from interrupt level */
3143 cklongjmp(cmjbuf,1); /* Jump back to parser now! */
3148 debug(F100,"*********************","",0);
3150 debug(F101,"trap caught SIGINT","",sig);
3152 debug(F101,"trap caught signal","",sig);
3153 debug(F100,"*********************","",0);
3158 if ( sig == SIGBREAK && (startflags & 128) ) {
3159 debug(F101,"trap ignoring SIGBREAK","",sig);
3165 timelimit = 0; /* In case timed ASK interrupted */
3167 unkmacro = 0; /* Or ON_UNKNOWN_MACRO interrupted.. */
3170 zchkod = 0; /* Or file expansion interrupted... */
3174 if (what & W_CONNECT) { /* Are we in CONNECT mode? */
3176 The HP workstation Reset key sends some kind of ueber-SIGINT that can not
3177 be SIG_IGNored, so we wind up here somehow (even though this is *not* the
3178 current SIGINT handler). Just return.
3180 debug(F101,"trap: SIGINT caught during CONNECT","",sig);
3184 if (i_active) { /* INPUT command was active? */
3185 i_active = 0; /* Not any more... */
3186 instatus = INP_UI; /* INPUT status = User Interrupted */
3191 ftreset(); /* Restore global protocol settings */
3192 binary = b_save; /* Then restore these */
3198 zclose(ZIFILE); /* If we were transferring a file, */
3199 zclose(ZOFILE); /* close it. */
3201 cmdsquo(cmd_quoting); /* If command quoting was turned off */
3204 extern FILE * learnfp;
3205 extern int learning;
3212 #endif /* CKLEARN */
3215 delmac("_apc_commands",1);
3216 apcactive = APC_INACTIVE;
3223 if (ft_win) { /* If curses window open */
3224 debug(F100,"^C trap() curses","",0);
3225 xxscreen(SCR_CW,0,0L,""); /* Close it */
3226 conres(); /* Restore terminal */
3227 i = printf("^C..."); /* Echo ^C to standard output */
3230 i = printf("^C...\n"); /* Echo ^C to standard output */
3232 if (i < 1 && ferror(stdout)) { /* If there was an error */
3233 debug(F100,"^C trap() error","",0);
3234 fclose(stdout); /* close standard output */
3235 f = fopen(dftty, "w"); /* open the controlling terminal */
3236 if (f) stdout = f; /* and make it standard output */
3237 printf("^C...\n"); /* and echo the ^C again. */
3241 conres(); /* Set console back to normal mode */
3242 #endif /* STRATUS */
3244 if (ft_win) { /* If curses window open, */
3245 debug(F100,"^C trap() curses","",0);
3246 xxscreen(SCR_CW,0,0L,""); /* close it. */
3247 printf("^C..."); /* Echo ^C to standard output */
3256 connoi_mt(); /* Kill asynch task that listens to */
3258 conres(); /* the keyboard */
3259 #endif /* datageneral */
3262 /* This is stupid -- every version should have ttimoff()... */
3264 ttimoff(); /* Turn off any timer interrupts */
3267 ttimoff(); /* Turn off any timer interrupts */
3270 ttimoff(); /* Turn off any timer interrupts */
3274 os2gks = 1; /* Turn back on keycode mapping */
3275 #endif /* NOSETKEY */
3277 for (i = 0; i < VNUM; i++)
3279 #endif /* NOLOCAL */
3282 /* WSAIsBlocking() returns FALSE in Win95 during a blocking accept call */
3283 if ( WSASafeToCancel /* && WSAIsBlocking() */ ) {
3284 WSACancelBlockingCall();
3287 #endif /* TCPSOCKET */
3289 NCBCancelOutstanding();
3290 #endif /* CK_NETBIOS */
3291 ttimoff(); /* Turn off any timer interrupts */
3294 ttimoff(); /* Turn off any timer interrupts */
3297 #endif /* STRATUS */
3302 /* Clean up Ctrl-C out of REDIRECT or external protocol */
3304 extern PID_T pty_fork_pid;
3305 extern int pty_master_fd, pty_slave_fd;
3308 signal(SIGCHLD,SIG_IGN); /* We don't want this any more */
3310 debug(F101,"trap pty_master_fd","",pty_master_fd);
3311 if (pty_master_fd > 2) {
3312 x = close(pty_master_fd);
3313 debug(F101,"trap pty_master_fd close","",x);
3316 debug(F101,"trap pty_slave_fd","",pty_slave_fd);
3317 if (pty_slave_fd > 2) {
3318 x = close(pty_slave_fd);
3319 debug(F101,"trap pty_slave_fd close","",x);
3322 debug(F101,"trap pty_fork_pid","",pty_fork_pid);
3323 if (pty_fork_pid > 0) {
3324 x = kill(pty_fork_pid,0); /* See if the fork is really there */
3325 debug(F111,"trap pty_fork_pid kill 0 errno",ckitoa(x),errno);
3326 if (x == 0) { /* Seems to be active */
3327 x = kill(pty_fork_pid,SIGHUP); /* Ask it to clean up & exit */
3328 debug(F101,"trap pty_fork_pid kill SIGHUP","",x);
3331 x = kill(pty_fork_pid,0); /* Is it still there? */
3334 /* This module is not always exposed to <errno.h> */
3338 x = kill(pty_fork_pid,SIGKILL);
3339 debug(F101,"trap pty_fork_pid kill SIGKILL","",x);
3350 We are in an intercept routine but do not perform a F$RTE (done implicitly
3351 by rts). We have to decrement the sigmask as F$RTE does. Warning: longjump
3352 only restores the cpu registers, NOT the fpu registers. So don't use fpu at
3353 all or at least don't use common fpu (double or float) register variables.
3360 debug(F100,"trap about to longjmp","",0);
3362 cklongjmp(ckjaddr(cmjbuf),1);
3364 cklongjmp(cmjbuf,1);
3367 #else /* NOCCTRAP */
3368 /* No Ctrl-C trap, just exit. */
3369 #ifdef CK_CURSES /* Curses support? */
3370 xxscreen(SCR_CW,0,0L,""); /* Close curses window */
3371 #endif /* CK_CURSES */
3372 doexit(BAD_EXIT,what); /* Exit poorly */
3373 #endif /* NOCCTRAP */
3378 /* C K _ T I M E -- Returns pointer to current time. */
3382 static char tbuf[10];
3386 ztime(&p); /* "Thu Feb 8 12:00:00 1990" */
3387 if (!p) /* like asctime()! */
3390 for (x = 11; x < 19; x++) /* copy hh:mm:ss */
3391 tbuf[x - 11] = p[x]; /* to tbuf */
3392 tbuf[8] = NUL; /* terminate */
3394 return(tbuf); /* and return it */
3397 /* C C _ C L E A N -- Cleanup after terminal interrupt handler */
3402 zclose(ZIFILE); /* If we were transferring a file, */
3403 zclose(ZOFILE); /* close it. */
3404 printf("^C...\n"); /* Not VMS, no problem... */
3409 /* S T P T R A P -- Handle SIGTSTP (suspend) signals */
3415 stptrap(sig) int sig;
3416 #endif /* CK_ANSIC */
3420 int x; extern int cmflgs;
3421 debug(F101,"stptrap() caught signal","",sig);
3423 printf("\r\nsuspend disabled\r\n");
3425 if (what & W_COMMAND) { /* If we were parsing commands */
3426 prompt(xxstring); /* reissue the prompt and partial */
3427 if (!cmflgs) /* command (if any) */
3428 printf("%s",cmdbuf);
3432 conres(); /* Reset the console */
3434 /* Flush pending output first, in case we are continued */
3435 /* in the background, which could make us block */
3438 x = psuspend(xsuspend); /* Try to suspend. */
3441 printf("Job control not supported\r\n");
3442 conint(trap,stptrap); /* Rearm the trap. */
3443 debug(F100,"stptrap back from suspend","",0);
3445 case W_CONNECT: /* If suspended during CONNECT? */
3446 conbin((char)escape); /* put console back in binary mode */
3447 debug(F100,"stptrap W_CONNECT","",0);
3450 case W_COMMAND: /* Suspended in command mode */
3451 debug(F101,"stptrap W_COMMAND pflag","",pflag);
3452 concb((char)escape); /* Put back CBREAK tty mode */
3453 if (pflag) { /* If command parsing was */
3454 prompt(xxstring); /* reissue the prompt and partial */
3455 if (!cmflgs) /* command (if any) */
3456 printf("%s",cmdbuf);
3460 default: /* All other cases... */
3461 debug(F100,"stptrap default","",0);
3462 concb((char)escape); /* Put it back in CBREAK mode */
3473 /* T L O G -- Log a record in the transaction file */
3475 Call with a format and 3 arguments: two strings and a number:
3476 f - Format, a bit string in range 0-7, bit x is on, arg #x is printed.
3477 s1,s2 - String arguments 0 and 1.
3478 n - Long, argument 2.
3482 dotlog(int f, char *s1, char *s2, CK_OFF_T n)
3484 dotlog(f,s1,s2,n) int f; CK_OFF_T n; char *s1, *s2;
3485 #endif /* CK_ANSIC */
3487 static char s[TBUFL];
3489 char *sp = s; int x;
3493 if (!tralog) return; /* If no transaction log, don't */
3494 if (tlogfmt != 1) return;
3496 case F000: /* 0 (special) "s1 n s2" */
3497 if ((int)strlen(s1) + (int)strlen(s2) + 15 > TBUFL)
3498 sprintf(sp,"?T-Log string too long");
3500 sprintf(sp,"%s %s %s",s1,ckfstoa(n),s2);
3501 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3503 case F001: /* 1, " n" */
3504 sprintf(sp," %s",ckfstoa(n));
3505 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3507 case F010: /* 2, "[s2]" */
3508 x = (int)strlen(s2);
3509 if (s2[x] == '\n') s2[x] = '\0';
3511 sprintf(sp,"?String too long");
3512 else sprintf(sp,"[%s]",s2);
3513 if (zsoutl(ZTFILE,"") < 0) tralog = 0;
3515 case F011: /* 3, "[s2] n" */
3516 x = (int)strlen(s2);
3517 if (s2[x] == '\n') s2[x] = '\0';
3519 sprintf(sp,"?String too long");
3520 else sprintf(sp,"[%s] %s",s2,ckfstoa(n));
3521 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3523 case F100: /* 4, "s1" */
3524 if (zsoutl(ZTFILE,s1) < 0) tralog = 0;
3526 case F101: /* 5, "s1: n" */
3527 if ((int)strlen(s1) + 15 > TBUFL)
3528 sprintf(sp,"?String too long");
3529 else sprintf(sp,"%s: %s",s1,ckfstoa(n));
3530 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3532 case F110: /* 6, "s1 s2" */
3533 x = (int)strlen(s2);
3534 if (s2[x] == '\n') s2[x] = '\0';
3535 if ((int)strlen(s1) + x + 4 > TBUFL)
3536 sprintf(sp,"?String too long");
3538 sprintf(sp,"%s%s%s",s1,((*s2 == ':') ? "" : " "),s2);
3539 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3541 case F111: /* 7, "s1 s2: n" */
3542 x = (int)strlen(s2);
3543 if (s2[x] == '\n') s2[x] = '\0';
3544 if ((int)strlen(s1) + x + 15 > TBUFL)
3545 sprintf(sp,"?String too long");
3547 sprintf(sp,"%s%s%s: %s",s1,((*s2 == ':') ? "" : " "),s2,ckfstoa(n));
3548 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3551 sprintf(sp,"?Invalid format for tlog() - %d",f);
3552 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3559 This is the transaction-log writer for BRIEF format.
3560 The idea is produce one record (line) per file. Each record
3561 has the following delimited fields:
3564 Action: SEND or RECV
3567 Transfer mode (text, binary, image, labeled, etc).
3568 Status: OK or FAILED
3569 Free-form comments in doublequotes
3570 The default separator is comma.
3571 If a field contains the separator, it is enclosed in doublequotes.
3575 doxlog(int x, char * fn, CK_OFF_T fs, int fm, int status, char * msg)
3577 doxlog(x, fn, fs, fm, status, msg)
3578 int x; char * fn; CK_OFF_T fs; int fm; int status; char * msg;
3579 #endif /* CK_ANSIC */
3583 char buf[CKMAXPATH+256], * bufp;
3586 int len, left, ftp = 0, k;
3588 if (!tralog) return; /* If no transaction log, don't */
3590 if (!fn) fn = ""; /* Protect against null pointers */
3595 sep[0] = (char) tlogsep;
3597 if (!sep[0]) sep[0] = ',';
3601 debug(F101,"XXX doxlog left 1","",left);
3603 p = zzndate(); /* Date */
3604 ckmakmsg(buf, left, p ? p : "00000000", sep, NULL, NULL);
3607 debug(F111,"XXX doxlog left 2",buf,left);
3610 ckstrncpy(bufp,p+11,left);
3613 debug(F111,"XXX doxlog left 3",buf,left);
3616 if (!(x & (W_SEND|W_RECV)))
3618 s = (x & W_SEND) ? "PUT" : "GET";
3621 s = (x & W_SEND) ? "SEND" : "RECV";
3624 ckmakmsg(bufp,left,sep,s,sep,NULL);
3627 debug(F111,"XXX doxlog left 4",buf,left);
3630 if (ckstrchr(fn,sep[0])) /* Filename */
3632 ckmakmsg(bufp,left,s,fn,s,sep);
3633 sprintf(tmpbuf,"%s",ckfstoa(fs)); /* Size */
3634 ckstrncat(buf,tmpbuf,CKMAXPATH);
3635 ckstrncat(buf,sep,CKMAXPATH);
3636 debug(F110,"doxlog 4",buf,0);
3640 ckstrncpy(tmpbuf, (binary ? "binary" : "text"), TMPBUFSIZ);
3642 ckstrncpy(tmpbuf,gfmode(fm,0),TMPBUFSIZ);
3644 if (ckstrchr(tmpbuf,sep[0])) { /* Might contain spaces */
3645 ckstrncat(buf,"\"",CKMAXPATH);
3646 ckstrncat(buf,tmpbuf,CKMAXPATH);
3647 ckstrncat(buf,"\"",CKMAXPATH);
3649 ckstrncat(buf,tmpbuf,CKMAXPATH);
3650 ckstrncat(buf,sep,CKMAXPATH);
3651 debug(F110,"doxlog 5",buf,0);
3653 ckstrncat(buf, status ? "FAILED" : "OK",CKMAXPATH);
3655 left = CKMAXPATH+256 - len;
3656 if (left < 2) fatal("doxlog buffer overlow");
3658 debug(F111,"XXX doxlog left 5",buf,left);
3660 debug(F110,"doxlog buf 1", buf, len);
3662 if (status == 0 && left > 32) {
3665 debug(F101,"DOXLOG fpxfsecs","",(long)(fpxfsecs * 1000));
3666 if (fpxfsecs) cps = (long)((CKFLOAT) fs / fpxfsecs);
3667 sprintf(s,"%s\"%0.3fsec %ldcps\"",sep,fpxfsecs,cps);
3669 if (xfsecs) cps = fs / xfsecs;
3670 sprintf(s,"%s\"%ldsec %ldcps\"",sep,xfsecs,cps);
3671 #endif /* GFTIMER */
3672 } else if ((int)strlen(msg) + 4 < left) {
3673 sprintf(s,"%s\"%s\"",sep,msg);
3675 debug(F111,"XXX doxlog left 5",buf,left);
3677 debug(F110,"doxlog 5",buf,0);
3678 x = zsoutl(ZTFILE,buf);
3679 debug(F101,"doxlog zsoutl","",x);
3680 if (x < 0) tralog = 0;
3686 The rest of this file is for all implementations but the Macintosh.
3690 static int repaint = 0; /* Transfer display needs repainting */
3691 #endif /* CK_CURSES */
3694 /* C H K I N T -- Check for console interrupts */
3697 Used during file transfer in local mode only:
3698 . If user has not touched the keyboard, returns 0 with no side effects.
3699 . If user typed S or A (etc, see below) prints status message and returns 0.
3700 . If user typed X or F (etc, see below) returns 0 with cxseen set to 1.
3701 . If user typed Z or B (etc, see below) returns 0 with czseen set to 1.
3702 . If user typed E or C (etc, see below) returns -1.
3706 int ch, cn, ofd; long zz;
3709 if ((!local) || (quiet)) return(0); /* Only do this if local & not quiet */
3711 if (con_reads_mt) /* if conint_mt task is active */
3712 if (conint_avl) { /* and there's an interrupt pending */
3713 cn = 1; /* process it */
3715 conint_avl = 0; /* turn off flag so conint_mt can */
3716 } else /* proceed */
3718 else /* if conint_mt not active */
3719 if ((ch = coninc(2)) < 0) /* try to get char manually */
3720 return(0); /* I/O error, or no data */
3721 else /* if successful, set cn so we */
3722 cn = 1; /* know we got one */
3723 debug(F101,"chkint got keyboard character",ch,cn);
3724 #else /* !datageneral */
3727 extern int TlsIndex;
3728 struct _threadinfo * threadinfo;
3729 threadinfo = (struct _threadinfo *) TlsGetValue(TlsIndex);
3731 if (!WaitSem(threadinfo->DieSem,0))
3732 return -1; /* Cancel Immediately */
3736 cn = conchk(); /* Any input waiting? */
3737 debug(F101,"conchk","",cn);
3738 if (cn < 1) return(0);
3740 debug(F101,"coninc","",ch);
3741 if (ch < 0) return(0);
3742 #endif /* datageneral */
3746 case 'A': case 'a': case 0001: /* Status report */
3748 if (fdispla != XYFD_R && fdispla != XYFD_S && fdispla != XYFD_N)
3749 return(0); /* Only for serial, simple or none */
3750 ofd = fdispla; /* [MF] Save file display type */
3751 if (fdispla == XYFD_N)
3752 fdispla = XYFD_R; /* [MF] Pretend serial if no display */
3753 xxscreen(SCR_TN,0,0l,"Status report:");
3754 xxscreen(SCR_TN,0,0l," file type: ");
3757 case XYFT_L: xxscreen(SCR_TZ,0,0l,"labeled"); break;
3758 case XYFT_I: xxscreen(SCR_TZ,0,0l,"image"); break;
3759 case XYFT_U: xxscreen(SCR_TZ,0,0l,"binary undefined"); break;
3761 case XYFT_B: xxscreen(SCR_TZ,0,0l,"binary"); break;
3765 xxscreen(SCR_TZ,0,0l,"text");
3767 xxscreen(SCR_TU,0,0l,"text, ");
3768 if (tcharset == TC_TRANSP || xfrxla == 0) {
3769 xxscreen(SCR_TZ,0,0l,"transparent");
3771 if (what & W_SEND) {
3772 xxscreen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword);
3773 xxscreen(SCR_TU,0,0l," => ");
3774 xxscreen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword);
3776 xxscreen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword);
3777 xxscreen(SCR_TU,0,0l," => ");
3778 xxscreen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword);
3781 #endif /* NOCSETS */
3783 xxscreen(SCR_QE,0,filcnt," file number");
3784 if (fsize) xxscreen(SCR_QE,0,fsize," size");
3785 xxscreen(SCR_QE,0,ffc," characters so far");
3788 zz = what & W_SEND ? sendstart : what & W_RECV ? rs_len : 0;
3789 zz = ( (ffc + zz) * 100L ) / fsize;
3791 zz = ( ffc * 100L ) / fsize;
3792 #endif /* CK_RESEND */
3793 xxscreen(SCR_QE,0,zz, " percent done");
3795 if (bctu == 4) { /* Block check */
3796 xxscreen(SCR_TU,0,0L," block check: ");
3797 xxscreen(SCR_TZ,0,0L,"blank-free-2");
3798 } else xxscreen(SCR_QE,0,(long)bctu, " block check");
3799 xxscreen(SCR_QE,0,(long)rptflg," compression");
3800 xxscreen(SCR_QE,0,(long)ebqflg," 8th-bit prefixing");
3801 xxscreen(SCR_QE,0,(long)lscapu," locking shifts");
3803 xxscreen(SCR_QE,0, speed, " speed");
3806 xxscreen(SCR_QE,0,spsiz, " packet length");
3807 else if (what & W_RECV || what & W_REMO)
3808 xxscreen(SCR_QE,0,urpsiz," packet length");
3809 xxscreen(SCR_QE,0,wslots, " window slots");
3810 fdispla = ofd; /* [MF] Restore file display type */
3813 case 'B': case 'b': case 0002: /* Cancel batch */
3814 case 'Z': case 'z': case 0032:
3817 xxscreen(SCR_ST,ST_MSG,0l,
3818 (((what & W_RECV) && (wslots > 1)) ?
3819 "Canceling batch, wait... " :
3820 "Canceling batch... ")
3824 case 'F': case 'f': case 0006: /* Cancel file */
3825 case 'X': case 'x': case 0030:
3828 xxscreen(SCR_ST,ST_MSG,0l,
3829 (((what & W_RECV) && (wslots > 1)) ?
3830 "Canceling file, wait... " :
3831 "Canceling file... ")
3835 case 'R': case 'r': case 0022: /* Resend packet */
3836 case 0015: case 0012:
3840 #endif /* STREAMING */
3841 xxscreen(SCR_ST,ST_MSG,0l,"Resending packet... ");
3847 case '\03': /* We're not trapping ^C's with */
3848 trap(0); /* signals, so we check here */
3849 #endif /* datageneral */
3851 case 'C': case 'c': /* Ctrl-C */
3854 #endif /* datageneral */
3856 case 'E': case 'e': /* Send error packet */
3862 case 0014: /* Ctrl-L to refresh screen */
3863 case 'L': case 'l': /* Also accept L (upper, lower) */
3864 case 0027: /* Ctrl-W synonym for VMS & Ingres */
3867 #endif /* CK_CURSES */
3870 case 't': /* Turn on debug-log timestamps */
3876 xxscreen(SCR_ST,ST_MSG,0l,
3877 "Debug timestamps On... ");
3880 xxscreen(SCR_ST,ST_MSG,0l,
3881 "Debug timestamps Off... ");
3890 debopn("debug.log",0);
3892 xxscreen(SCR_ST,ST_MSG,0l,"debug.log open... ");
3894 xxscreen(SCR_ST,ST_MSG,0l,"debug.log open FAILED... ");
3897 xxscreen(SCR_ST,ST_MSG,0l,"Debug log On... ");
3904 case 'd': /* Turn off debugging */
3907 xxscreen(SCR_ST,ST_MSG,0l,"Debug log Off... ");
3912 default: /* Anything else, print message */
3918 /* I N T M S G -- Issue message about terminal interrupts */
3925 #endif /* CK_ANSIC */
3929 #endif /* CK_NEED_SIG */
3931 if (!displa || quiet) /* Not if we're being quiet */
3933 if (server && (!srvdis || n > -1L)) /* Special for server */
3936 buf[0] = NUL; /* Keep compilers happy */
3937 #endif /* CK_NEED_SIG */
3940 conchk(); /* Clear out pending escape-signals */
3941 #endif /* SVORPOSIX */
3944 conres(); /* So Ctrl-C will work */
3946 if ((!server && n == 1L) || (server && n < 0L)) {
3952 "Type escape character (",
3957 xxscreen(SCR_TN,0,0l,buf);
3959 #endif /* CK_NEED_SIG */
3962 if (protocol == PROTO_K) {
3963 xxscreen(SCR_TN,0,0l,"X to cancel file, CR to resend current packet");
3964 xxscreen(SCR_TN,0,0l,"Z to cancel group, A for status report");
3965 xxscreen(SCR_TN,0,0l,"E to send Error packet, Ctrl-C to quit immediately: ");
3967 xxscreen(SCR_TN,0,0l,"Ctrl-C to cancel file transfer: ");
3970 xxscreen(SCR_TN,0,0l,"Transfer interruption disabled. ");
3973 else xxscreen(SCR_TU,0,0l," ");
3977 static int newdpy = 0; /* New display flag */
3978 static char fbuf[80]; /* Filename buffer */
3979 static char abuf[80]; /* As-name buffer */
3980 static char a2buf[80]; /* Second As-name buffer */
3981 static CK_OFF_T oldffc = 0L;
3982 static CK_OFF_T dots = 0L;
3983 static int hpos = 0;
3985 static VOID /* Initialize Serial or CRT display */
3990 newdpy = 0; /* Don't do this again */
3991 oldffc = (CK_OFF_T)0; /* Reset this */
3992 dots = (CK_OFF_T)0; /* and this.. */
3995 conoll(""); /* New line */
3996 if (what & W_SEND) s = "Sending: "; /* Action */
3997 else if (what & W_RECV) s = "Receiving: ";
3998 n = (int)strlen(s) + (int)strlen(fbuf);
4000 m = (int)strlen(abuf) + 4;
4001 if (n + m > cmd_cols) {
4010 m = (int)strlen(a2buf) + 4;
4011 if (n + m > cmd_cols) {
4020 *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
4022 if (fsize > (CK_OFF_T)-1) { /* Size */
4023 sprintf(fbuf,"Size: %s, Type: ",ckfstoa(fsize)); /* SAFE (80) */
4024 conol(fbuf); *fbuf = NUL;
4025 } else conol("Size: unknown, Type: ");
4026 if (binary) { /* Type */
4028 case XYFT_L: conol("labeled"); break;
4029 case XYFT_I: conol("image"); break;
4030 case XYFT_U: conol("binary undefined"); break;
4032 case XYFT_B: conol("binary"); break;
4039 if (tcharset == TC_TRANSP || xfrxla == 0) {
4040 conol("transparent");
4042 if (what & W_SEND) {
4043 conol(fcsinfo[fcharset].keyword);
4045 conol(tcsinfo[tcharset].keyword);
4047 conol(tcsinfo[tcharset].keyword);
4049 conol(fcsinfo[fcharset].keyword);
4052 #endif /* NOCSETS */
4056 conol(", STREAMING");
4057 #endif /* STREAMING */
4060 if (fdispla == XYFD_S) { /* CRT field headings */
4062 Define CK_CPS to show current transfer rate.
4063 Leave it undefined to show estimated time remaining.
4064 Estimated-time-remaining code from Andy Fyfe, not tested on
4070 conoll(" File Percent Packet");
4071 conoll(" Bytes Done CPS Length");
4073 conoll(" File Percent Secs Packet");
4074 conoll(" Bytes Done Left Length");
4083 c = completion code: 0 means transfer in progress, nonzero means it's done.
4084 Show the file transfer progress counter and perhaps verbose packet type.
4091 #endif /* CK_ANSIC */
4095 long et; /* Elapsed time, entire batch */
4096 #endif /* GFTIMER */
4097 CK_OFF_T howfar; /* How far into file */
4098 long pd; /* Percent done, this file */
4099 long tp; /* Transfer rate, entire batch */
4100 long ps; /* Packet size, current packet */
4101 CK_OFF_T mytfc; /* Local copy of byte counter */
4105 #endif /* GFTIMER */
4107 if (newdpy) /* Put up filenames, etc, */
4108 dpyinit(); /* if they're not there already. */
4110 howfar = ffc; /* How far */
4112 Calculate CPS rate even if not displaying on screen for use in file
4113 transfer statistics.
4116 tnow = gftimer(); /* Time since we started */
4117 ps = (what & W_RECV) ? rpktl : spktl; /* Packet size */
4119 if (what & W_SEND) /* In case we didn't start at */
4120 howfar += sendstart; /* the beginning... */
4121 else if (what & W_RECV)
4123 #endif /* CK_RESEND */
4124 pd = -1; /* Percent done. */
4125 if (c == NUL) { /* Still going, figure % done */
4126 if (!fsize) return; /* Empty file, don't bother */
4127 pd = (fsize > 99) ? (howfar / (fsize / (CK_OFF_T)100)) : 0;
4128 if (pd > 100) pd = 100; /* Expansion */
4131 if (!cxseen && !discard && !czseen)
4132 pd = 100; /* File complete, so 100%. */
4134 mytfc = (pd < 100) ? tfc + ffc : tfc; /* CPS */
4135 tp = (long)((tnow > 0.0) ? (CKFLOAT) mytfc / tnow : 0);
4139 cps = tp; /* Set global variable */
4140 if (cps > peakcps && /* Peak transfer rate */
4141 ((what & W_SEND && spackets > wslots + 4) ||
4142 (!(what & W_SEND) && spackets > 10))) {
4146 #else /* Not GFTIMER */
4148 et = gtimer(); /* Elapsed time */
4149 ps = (what & W_RECV) ? rpktl : spktl; /* Packet length */
4151 if (what & W_SEND) /* And if we didn't start at */
4152 howfar += sendstart; /* the beginning... */
4153 else if (what & W_RECV)
4155 #endif /* CK_RESEND */
4156 pd = -1; /* Percent done. */
4157 if (c == NUL) { /* Still going, figure % done */
4158 if (fsize == 0L) return; /* Empty file, don't bother */
4159 pd = (fsize > 99) ? (howfar / (fsize / (CK_OFF_T)100)) : 0;
4160 if (pd > 100) pd = 100; /* Expansion */
4163 if (!cxseen && !discard && !czseen)
4164 pd = 100; /* File complete, so 100%. */
4169 fsecs = time (from gtimer) that this file started (set in sfile()).
4170 Rate so far is ffc / (et - fsecs), estimated time for remaining bytes
4171 is (fsize - ffc) / (ffc / (et - fsecs)).
4173 tp = (howfar > 0) ? (fsize - howfar) * (et - fsecs) / howfar : 0;
4177 mytfc = (pd < 100) ? tfc + ffc : tfc;
4178 tp = (et > 0) ? mytfc / et : 0; /* Transfer rate */
4179 if (c && (tp == 0)) /* Watch out for subsecond times */
4182 cps = tp; /* Set global variable */
4183 if (cps > peakcps && /* Peak transfer rate */
4184 ((what & W_SEND && spackets > wslots + 4) ||
4185 (!(what & W_SEND) && spackets > 10))) {
4190 #endif /* GFTIMER */
4192 if (fdispla == XYFD_S) { /* CRT display */
4194 /* These sprintfs should be safe until we have 32-digit numbers */
4197 sprintf(buffer, "%c%9s%5ld%%%8ld%8ld ", CR,ckfstoa(howfar),pd,tp,ps);
4199 sprintf(buffer, "%c%9s %8ld%8ld ", CR,ckfstoa(howfar),tp,ps);
4202 } else if (fdispla == XYFD_R) { /* SERIAL */
4204 if (howfar - oldffc < 1024) /* Update display every 1K */
4206 oldffc = howfar; /* Time for new display */
4207 k = (howfar / 1024L) - dots; /* How many K so far */
4208 for (i = 0L; i < k; i++) {
4209 if (hpos++ > (cmd_cols - 3)) { /* Time to wrap? */
4213 conoc('.'); /* Print a dot for this K */
4214 dots++; /* Count it */
4220 /* C K S C R E E N -- Screen display function */
4224 f - argument descriptor
4225 c - a character or small integer
4229 and global fdispla = SET FILE DISPLAY value:
4232 XYFD_R = SERIAL: Dots, etc, works on any terminal, even hardcopy.
4233 XYFD_S = CRT: Works on any CRT, writes over current line.
4234 XYFD_C = FULLSCREEN: Requires terminal-dependent screen control.
4235 XYFD_B = BRIEF: Like SERIAL but only filename & completion status.
4236 XYFD_G = GUI; Windows GUI, same behavior as FULLSCREEN
4240 ckscreen(int f, char c,CK_OFF_T n,char *s)
4242 ckscreen(f,c,n,s) int f; char c; CK_OFF_T n; char *s;
4243 #endif /* CK_ANSIC */
4246 int len; /* Length of string */
4250 _PROTOTYP( VOID conbgt, (int) );
4255 ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit? */
4257 if (!local && !ftp) /* In remote mode - don't do this */
4262 if (!fxd_inited) /* Initialize if necessary */
4267 obg = backgrd; /* Previous background status */
4268 conbgt(1); /* See if running in background */
4269 if (!backgrd && obg) { /* Just came into foreground? */
4270 concb((char)escape); /* Put console back in CBREAK mode */
4271 setint(); /* Restore interrupts */
4276 if ((f != SCR_WM) && (f != SCR_EM)) /* Always update warnings & errors */
4278 (backgrd && bgset) ||
4279 fdispla == XYFD_N ||
4285 if (f == SCR_FN) /* VMS - shorten the name */
4286 s = zrelname(s,zgtdir());
4289 if (dest == DEST_S) /* SET DESTINATION SCREEN */
4290 return; /* would interfere... */
4293 if (fdispla == XYFD_G) { /* If gui display selected */
4294 screeng(f,c,n,s); /* call the gui version */
4299 if (fdispla == XYFD_C) { /* If fullscreen display selected */
4300 screenc(f,c,n,s); /* call the fullscreen version */
4303 #endif /* CK_CURSES */
4305 len = (int)strlen(s); /* Length of string */
4307 switch (f) { /* Handle our function code */
4308 case SCR_FN: /* Filename */
4309 if (fdispla == XYFD_B) {
4312 printf(" %s %s", what & W_SEND ? "PUT" : "GET", s);
4315 printf(" %s %s", what & W_SEND ? "SEND" : "RECV", s);
4322 conoll(""); conol(s); conoc(SP); hpos = len + 1;
4324 ckstrncpy(fbuf,s,80);
4325 abuf[0] = a2buf[0] = NUL;
4326 newdpy = 1; /* New file so refresh display */
4330 case SCR_AN: /* As-name */
4331 if (fdispla == XYFD_B) {
4333 printf("(as %s) ",s);
4334 #endif /* COMMENT */
4338 if (hpos + len > 75) { conoll(""); hpos = 0; }
4339 conol("=> "); conol(s);
4340 if ((hpos += (len + 3)) > 78) { conoll(""); hpos = 0; }
4343 ckstrncpy(a2buf,s,80);
4345 ckstrncpy(abuf,s,80);
4350 case SCR_FS: /* File-size */
4351 if (fdispla == XYFD_B) {
4352 printf(" (%s) (%s byte%s)",
4354 (binary ? "binary" : "text")
4358 , ckfstoa(n), n == 1 ? "" : "s");
4365 sprintf(buf,", Size: %s",ckfstoa(n)); conoll(buf); hpos = 0;
4369 case SCR_XD: /* X-packet data */
4370 if (fdispla == XYFD_B)
4373 conoll(""); conoll(s); hpos = 0;
4375 ckstrncpy(fbuf,s,80);
4376 abuf[0] = a2buf[0] = NUL;
4380 case SCR_ST: /* File status */
4382 case ST_OK: /* Transferred OK */
4383 showpkt('Z'); /* Update numbers one last time */
4384 if (fdispla == XYFD_B) {
4387 printf(": OK (%0.3f sec, %ld cps)",fpxfsecs,
4388 (long)((CKFLOAT)ffc / fpxfsecs));
4391 printf(": OK (%d sec, %ld cps)",xfsecs,ffc/xfsecs);
4392 #endif /* GFTIMER */
4396 if ((hpos += 5) > 78) conoll(""); /* Wrap screen line. */
4397 conoll(" [OK]"); hpos = 0; /* Print OK message. */
4398 if (fdispla == XYFD_S) { /* We didn't show Z packet when */
4399 conoc('Z'); /* it came, so show it now. */
4404 case ST_DISC: /* Discarded */
4405 if (fdispla == XYFD_B) {
4406 printf(": DISCARDED\n");
4409 if ((hpos += 12) > 78) conoll("");
4410 conoll(" [discarded]"); hpos = 0;
4413 case ST_INT: /* Interrupted */
4414 if (fdispla == XYFD_B) {
4415 printf(": INTERRUPTED\n");
4418 if ((hpos += 14) > 78) conoll("");
4419 conoll(" [interrupted]"); hpos = 0;
4423 if (fdispla == XYFD_B) {
4425 printf(": WOULD BE TRANSFERRED (New file)\n");
4426 else if (n == SKP_XUP)
4427 printf(": WOULD BE TRANSFERRED (Remote file older)\n");
4428 else if (n == SKP_SIM)
4429 printf(": WOULD BE TRANSFERRED\n");
4430 else if (n > 0 && n < nskreason)
4431 printf(": SKIPPED (%s)\n",skreason[n]);
4433 printf(": SKIPPED\n");
4435 } else if (fdispla == XYFD_S) {
4436 if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
4437 conoll(""); /* New line */
4438 if (what & W_SEND) conol("Would Send: "); /* Action */
4439 else if (what & W_RECV) conol("Would Receive: ");
4441 if (*abuf) conol(" => "); conol(abuf); /* Names */
4442 if (*a2buf) conol(" => "); conol(a2buf); /* Names */
4443 *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
4445 conoll(" [simulated]");
4448 if ((hpos += 10) > 78) conoll("");
4449 conol(" [simulated]"); hpos = 0;
4452 case ST_SKIP: /* Skipped */
4453 if (fdispla == XYFD_B) {
4455 printf(": WOULD BE TRANSFERRED (New file)\n");
4456 else if (n == SKP_XUP)
4457 printf(": WOULD BE TRANSFERRED (Remote file older)\n");
4458 else if (n == SKP_SIM)
4459 printf(": WOULD BE TRANSFERRED\n");
4460 else if (n > 0 && n < nskreason)
4461 printf(": SKIPPED (%s)\n",skreason[n]);
4463 printf(": SKIPPED\n");
4465 } else if (fdispla == XYFD_S) {
4466 if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
4467 conoll(""); /* New line */
4468 if (what & W_SEND) conol("Sending: "); /* Action */
4469 else if (what & W_RECV) conol("Receiving: ");
4471 if (*abuf) conol(" => "); conol(abuf); /* Names */
4472 if (*a2buf) conol(" => "); conol(a2buf); /* Names */
4473 *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
4475 conoll(" [skipped]");
4478 if ((hpos += 10) > 78) conoll("");
4479 conol(" "); conol(fbuf);
4480 conoll(" [skipped]"); hpos = 0;
4483 case ST_ERR: /* Error */
4484 if (fdispla == XYFD_B) {
4485 printf(": ERROR: %s\n",s);
4489 conol("Error: "); conoll(s); hpos = 0;
4492 case ST_MSG: /* Message */
4494 if (fdispla == XYFD_B) {
4496 printf(": MESSAGE: %s\n",s);
4506 case ST_REFU: /* Refused */
4507 if (fdispla == XYFD_B) {
4508 printf(": REFUSED\n");
4510 } else if (fdispla == XYFD_S) {
4511 if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
4512 conoll(""); /* New line */
4513 if (what & W_SEND) conol("Sending: "); /* Action */
4514 else if (what & W_RECV) conol("Receiving: ");
4516 if (*abuf) conol(" => "); conol(abuf); /* Names */
4517 if (*a2buf) conol(" => "); conol(a2buf); /* Names */
4518 *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
4521 conol("Refused: "); conoll(s);
4525 conol("Refused: "); conoll(s); hpos = 0;
4528 case ST_INC: /* Incomplete */
4529 if (fdispla == XYFD_B) {
4530 printf(": INCOMPLETE\n");
4533 if ((hpos += 12) > 78) conoll("");
4534 conoll(" [incomplete]"); hpos = 0;
4538 conoll("*** screen() called with bad status ***");
4544 case SCR_PN: /* Packet number */
4545 if (fdispla == XYFD_B) {
4548 ckmakmsg(buf,80,s,": ",ckltoa(n),NULL);
4549 conol(buf); hpos += (int)strlen(buf); return;
4552 case SCR_PT: /* Packet type or pseudotype */
4553 if (fdispla == XYFD_B)
4555 if (c == 'Y') return; /* Don't bother with ACKs */
4556 if (c == 'D') { /* In data transfer phase, */
4557 showpkt(NUL); /* show progress. */
4561 if (hpos++ > 77) { /* If near right margin, */
4562 conoll(""); /* Start new line */
4563 hpos = 0; /* and reset counter. */
4566 if (c == 'Z' && fdispla == XYFD_S)
4569 conoc(c); /* Display the packet type. */
4571 if (c == 'G') conoll(""); /* New line after G packets */
4575 case SCR_TC: /* Transaction complete */
4576 if (xfrbel) bleep(BP_NOTE);
4577 if (fdispla == XYFD_B) { /* Brief display... */
4580 fx = filcnt - filrej;
4581 printf(" SUMMARY: %ld file%s", fx, ((fx == 1) ? "" : "s"));
4582 printf(", %s byte%s", ckfstoa(tfc), ((tfc == 1) ? "" : "s"));
4584 printf(", %0.3f sec, %ld cps", fptsecs, tfcps);
4586 printf(", %ld sec, %ld cps", tsecs, tfcps);
4587 #endif /* GFTIMER */
4598 case SCR_EM: /* Error message */
4599 if (fdispla == XYFD_B) {
4600 printf(" ERROR: %s\n",s);
4603 conoll(""); conoc('?'); conoll(s); hpos = 0; return;
4605 case SCR_WM: /* Warning message */
4606 if (fdispla == XYFD_B) {
4607 printf(" WARNING: %s\n",s);
4610 conoll(""); conoll(s); hpos = 0; return;
4612 case SCR_MS: /* Message from other Kermit */
4613 if (fdispla == XYFD_B) {
4614 printf(" MESSAGE: %s\n",s);
4617 conoll(""); conoll(s); hpos = 0; return;
4619 case SCR_TU: /* Undelimited text */
4620 if (fdispla == XYFD_B)
4622 if ((hpos += len) > 77) { conoll(""); hpos = len; }
4625 case SCR_TN: /* Text delimited at beginning */
4626 if (fdispla == XYFD_B)
4628 conoll(""); conol(s); hpos = len; return;
4630 case SCR_TZ: /* Text delimited at end */
4631 if (fdispla == XYFD_B)
4633 if ((hpos += len) > 77) { conoll(""); hpos = len; }
4636 case SCR_QE: /* Quantity equals */
4637 if (fdispla == XYFD_B)
4639 ckmakmsg(buf,80,s,": ",ckltoa(n),NULL);
4640 conoll(buf); hpos = 0; return;
4642 case SCR_CW: /* Close fullscreen window */
4643 return; /* No window to close */
4649 conoll("*** screen() called with bad object ***");
4654 #endif /* NODISPLAY */
4656 /* E R M S G -- Nonfatal error message */
4658 /* Should be used only for printing the message text from an Error packet. */
4661 ermsg(msg) char *msg; { /* Print error message */
4662 debug(F110,"ermsg",msg,0);
4664 xxscreen(SCR_EM,0,0L,msg);
4665 tlog(F110,"Protocol Error:",msg,0L);
4670 setseslog(x) int x; {
4673 KuiSetProperty(KUI_TERM_CAPTURE,x,0);
4678 doclean(fc) int fc; { /* General cleanup */
4681 #endif /* OS2ORUNIX */
4683 extern int exithangup;
4685 extern char filnam[];
4691 dostop(); /* Stop all command files and end macros */
4708 tlog(F100,"Transaction Log Closed","",0L);
4715 debug(F100,"doclean calling dologend","",0);
4716 dologend(); /* End current log record if any */
4718 if (dialog) { /* If connection log open */
4720 *diafil = '\0'; /* close it. */
4723 #endif /* COMMENT */
4727 zclose(ZRFILE); /* READ and WRITE files, if any. */
4730 zclose(ZIFILE); /* And other files too */
4731 x = chkfn(ZOFILE); /* Download in progress? */
4732 debug(F111,"doclean chkfn ZOFILE",filnam,x);
4733 debug(F111,"doclean keep","",keep);
4734 zclose(ZOFILE); /* Close output file */
4735 if (x > 0 && !keep) { /* If it was being downloaded */
4737 x = zdelet(filnam); /* Delete if INCOMPLETE = DISCARD */
4738 debug(F111,"doclean download filename",filnam,x);
4744 if (fc < 1) { /* RESETing, not EXITing */
4746 if (deblog) { /* Close the debug log. */
4758 debug(F101,"doclean exithangup","",exithangup);
4759 if (local && exithangup) { /* Close communication connection */
4764 debug(F101,"doclean ttchk()","",x);
4766 debug(F101,"doclean ttyfd","",ttyfd);
4767 #endif /* OS2ORUNIX */
4773 || haslock /* Make sure we get lockfile! */
4774 || (!network && ttyfd > -1)
4778 extern int wasclosed, whyclosed;
4779 debug(F100,"doclean hanging up and closing","",0);
4784 printf("Closing %s...",ttname);
4787 mdmhup(); /* Hangup the modem??? */
4789 ttclos(0); /* Close external line, if any */
4797 whyclosed = WC_CLOS;
4799 if (nmac) { /* Any macros defined? */
4801 k = mlook(mactab,"on_close",nmac); /* Look this up */
4802 if (k >= 0) { /* If found, */
4804 /* printf("ON_CLOSE DOCLEAN\n"); */
4805 *(mactab[k].kwd) = NUL; /* See comment below */
4806 if (dodo(k,ckitoa(whyclosed),0) > -1) /* set it up, */
4807 parser(1); /* and execute it */
4814 ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default tty */
4815 local = dfloc; /* And default remote/local status */
4818 else if (local) debug(F100,"doclean hangup/close skipped","",0);
4820 #endif /* NOLOCAL */
4823 ftpbye(); /* If FTP connection open, close it */
4828 ttclos(0); /* If IKSD, close socket */
4833 If a macro named "on_exit" is defined, execute it. Also remove it from the
4834 macro table, in case its definition includes an EXIT or QUIT command, which
4835 would cause much recursion and would prevent the program from ever actually
4838 if (nmac) { /* Any macros defined? */
4840 char * cmd = "on_exit"; /* MSVC 2.x compiler error */
4841 k = mlook(mactab,cmd,nmac); /* Look up "on_exit" */
4842 if (k >= 0) { /* If found, */
4844 /* This makes a mess if ON_EXIT itself executes macros */
4845 *(mactab[k].kwd) = NUL; /* poke its name from the table, */
4847 /* Replace the keyword with something that doesn't wreck the */
4848 /* order of the keyword table */
4849 ckstrncpy(mactab[k].kwd,"on_exxx",8);
4850 #endif /* COMMENT */
4851 if (dodo(k,"",0) > -1) /* set it up, */
4852 parser(1); /* and execute it */
4857 Put console terminal back to normal. This is done here because the
4858 ON_EXIT macro calls the parser, which meddles with console terminal modes.
4860 conres(); /* Restore console terminal. */
4863 /* Should be no need for this, and maybe it's screwing things up? */
4864 connoi(); /* Turn off console interrupt traps */
4865 #endif /* COMMENT */
4867 /* Delete the Startup File if we are supposed to. */
4870 extern int DeleteStartupFile;
4871 debug(F111,"doclean DeleteStartupFile",cmdfil,DeleteStartupFile);
4872 if (DeleteStartupFile) {
4873 int rc = zdelet(cmdfil);
4874 debug(F111,"doclean zdelet",cmdfil,rc);
4878 syscleanup(); /* System-dependent cleanup, last */
4881 /* D O E X I T -- Exit from the program. */
4884 First arg is general, system-independent symbol: GOOD_EXIT or BAD_EXIT.
4885 If second arg is -1, take 1st arg literally.
4886 If second arg is not -1, work it into the exit code.
4889 doexit(exitstat,code) int exitstat, code; {
4890 extern int x_logged, quitting;
4892 extern int display_demo;
4893 extern int SysInited;
4897 extern int krb4_autodel;
4900 extern int krb5_autodel;
4902 #endif /* CK_KERBEROS */
4906 static $DESCRIPTOR(symnam,"CKERMIT_STATUS");
4907 static struct dsc$descriptor_s symval;
4913 extern long lucalls, luhits, xxhits, luloop;
4915 #endif /* USE_LUCACHE */
4917 extern int cmdstats[];
4924 static int initing = 0;
4934 debug(F101,"lookup cache size","",lusize);
4935 debug(F101,"lookup calls ....","",lucalls);
4936 debug(F101,"lookup cache hits","",luhits);
4937 debug(F101,"lookup start hits","",xxhits);
4938 debug(F101,"lookup loop iterations","",luloop);
4939 #endif /* USE_LUCACHE */
4941 for (i = 0; i < 256; i++) {
4943 debug(F111,"CMSTATS",ckitoa(i),cmdstats[i]);
4946 debug(F101,"doexit exitstat","",exitstat);
4947 debug(F101,"doexit code","",code);
4948 debug(F101,"doexit xitsta","",xitsta);
4953 /* If we are automatically destroying Kerberos credentials on Exit */
4956 if (krb4_autodel == KRB_DEL_EX) {
4957 extern struct krb_op_data krb_op;
4959 krb_op.cache = NULL;
4960 ck_krb4_destroy(&krb_op);
4964 if (krb5_autodel == KRB_DEL_EX) {
4965 extern struct krb_op_data krb_op;
4966 extern char * krb5_d_cc;
4968 krb_op.cache = krb5_d_cc;
4969 ck_krb5_destroy(&krb_op);
4972 #endif /* CK_KERBEROS */
4979 extern struct cmdptr *cmdstk;
4981 extern struct cmdptr cmdstk[];
4982 #endif /* DCMDBUF */
4983 extern int tt_status[];
4986 /* If there is a demo screen to be displayed, display it */
4992 /* This is going to be hideous. If we have a status line */
4993 /* in the command window turn it off before we exit. */
4995 if ( tt_status[VCMD] && vmode == VCMD ) {
4996 domac("_clear_statusline","set command statusline off",
4997 cmdstk[cmdlvl].ccflgs);
4998 delmac("_clear_statusline",1);
4999 RequestScreenMutex(-1);
5000 VscrnIsDirty(vmode);
5001 ReleaseScreenMutex();
5002 while ( IsVscrnDirty(vmode) )
5004 RequestScreenMutex(-1);
5005 ReleaseScreenMutex();
5008 DialerSend(OPT_KERMIT_EXIT,exitstat);
5010 debug(F100,"doexit about to msleep","",0);
5017 #endif /* NOLOCAL */
5021 if (inserver && x_logged) {
5024 If a macro named "on_logout" is defined, execute it. Also remove it from the
5025 macro table, in case its definition includes an EXIT or QUIT command, which
5026 would cause much recursion and would prevent the program from ever actually
5029 if (nmac) { /* Any macros defined? */
5031 char * cmd = "on_logout"; /* MSVC 2.x compiler error */
5032 k = mlook(mactab,cmd,nmac); /* Look up "on_logout" */
5033 if (k >= 0) { /* If found, */
5034 *(mactab[k].kwd) = NUL; /* poke its name from the table, */
5035 if (dodo(k,"",0) > -1) /* set it up, */
5036 parser(1); /* and execute it */
5042 #endif /* CK_LOGIN */
5045 debug(F100,"doexit about to doclean","",0);
5046 doclean(1); /* Clean up most things */
5050 code = 0; /* Since we set two different items */
5051 sprintf(envstr,"%d", exitstat | code); /* SAFE */
5052 symval.dsc$w_length = (int)strlen(envstr);
5053 symval.dsc$a_pointer = envstr;
5054 symval.dsc$b_class = DSC$K_CLASS_S;
5055 symval.dsc$b_dtype = DSC$K_DTYPE_T;
5056 i = 2; /* Store in global table */
5057 #ifdef COMMENT /* Martin Zinser */
5058 LIB$SET_SYMBOL(&symnam, &symval, &i);
5060 lib$set_symbol(&symnam, &symval, &i);
5061 #endif /* COMMENT */
5062 if (exitstat == BAD_EXIT)
5063 exitstat = SS$_ABORT | STS$M_INHIB_MSG;
5064 if (exitstat == GOOD_EXIT)
5065 exitstat = SS$_NORMAL | STS$M_INHIB_MSG;
5067 if (code != -1) /* Take 1st arg literally */
5073 debug(F101,"doexit ikdbopen","",ikdbopen);
5074 if (ikdbopen && dbfp) { /* If IKSD database open */
5076 x = freeslot(mydbslot); /* Free our slot... */
5077 debug(F101,"doexit freeslot","",x);
5078 fclose(dbfp); /* and close it. */
5083 /* We have put this off till the very last moment... */
5086 if (deblog) { /* Close the debug log. */
5087 debug(F101,"C-Kermit EXIT status","",exitstat);
5095 _exit(exitstat); /* Exit from C-Kermit (no matter what) */
5097 exit(exitstat); /* Exit from C-Kermit */
5102 bgchk() { /* Check background status */
5103 if (bgset < 0) { /* They didn't type SET BACKGROUND */
5104 #ifdef VMS /* Set prompt flag based on */
5105 pflag = !batch; /* what we detected at startup. */
5109 } else { /* Otherwise SET BACKGROUND value */
5110 pflag = (bgset == 0 ? 1 : 0);
5114 /* Message flag on only if at top level, pflag is on, and QUIET is OFF */
5116 msgflg = (pflag == 0) ? 0 : !quiet;
5123 /* Set console interrupts */
5126 setint() { /* According to SET COMMAND INTERRUP */
5129 if (xsuspend) x |= 2;
5130 debug(F101,"setint","",x);
5132 switch (x) { /* Set the desired combination */
5133 case 0: connoi(); break; /* No interrupts */
5134 case 1: conint(trap,SIG_IGN); break;
5135 case 2: conint(SIG_IGN,stptrap); break;
5136 case 3: conint(trap,stptrap); break;
5138 bgchk(); /* Check background status */
5142 /* D E B U G -- Enter a record in the debugging log */
5145 Call with a format, two strings, and a number:
5146 f - Format, a bit string in range 0-7.
5147 If bit x is on, then argument number x is printed.
5148 s1 - String, argument number 1. If selected, printed as is.
5149 s2 - String, argument number 2. If selected, printed in brackets.
5150 n - Long int, argument 3. If selected, printed preceded by equals sign.
5152 f=0 is special: print s1,s2, and interpret n as a char.
5154 f=F011 (3) is also special; in this case s2 is interpeted as a counted
5155 string that might contain NULs. n is the length. If n is negative, this
5156 means the string has been truncated and ".." should be printed after the
5157 first n bytes. NUL and LF bytes are printed as "<NUL>" and "<LF>".
5160 deblog: nonzero if debug log open.
5161 debok: nonzero if ok to write entries.
5164 WARNING: Don't change DEBUFL without changing sprintf() formats below,
5169 WARNING: This routine is not thread-safe, especially when Kermit is
5170 executing on multiple CPUs -- as different threads write to the same
5171 static buffer, the debug statements are all interleaved. To be fixed
5174 static char *dbptr = (char *)0;
5178 dodebug(int f, char *s1, char *s2, CK_OFF_T n)
5180 dodebug(f,s1,s2,n) int f; char *s1, *s2; CK_OFF_T n;
5181 #endif /* CK_ANSIC */
5187 extern int SysInited;
5190 if (!deblog || !debok)
5195 if (!chkfn(ZDFILE)) /* Debug log not open, don't. */
5197 #endif /* COMMENT */
5198 if (!dbptr) { /* Allocate memory buffer */
5199 dbptr = malloc(DBUFL+4); /* This only happens once */
5206 This prevents infinite recursion in case we accidentally put a debug()
5207 call in this routine, or call another routine that contains debug() calls.
5208 From this point on, all returns from this return must be via goto xdebug,
5209 which sets deblog back to 1.
5213 if (RequestDebugMutex(30000))
5217 deblog = 0; /* Prevent infinite recursion */
5220 if (debtim) { /* Timestamp */
5221 char *tb, tsbuf[48];
5223 ckstrncpy(tsbuf,tb,32);
5225 sprintf(tsbuf+19,".%03ld ",ztmsec); /* SAFE */
5231 zsout(ZDFILE,tsbuf+11);
5233 if (!s1) s1="(NULL)";
5234 if (!s2) s2="(NULL)";
5241 This should work, but it doesn't.
5242 So instead we'll cope with overflow via sprintf formats.
5243 N.B.: UNFORTUNATELY, this means we have to put constants in the
5246 if (f != F011 && (!f || (f & 6))) { /* String argument(s) included? */
5247 x = (int) strlen(s1) + (int) strlen(s2) + 18;
5248 if (x > dbufl) { /* Longer than buffer? */
5249 if (dbptr) /* Yes, free previous buffer */
5251 dbptr = (char *) malloc(x + 2); /* Allocate a new one */
5253 zsoutl(ZDFILE,"DEBUG: Memory allocation failure");
5259 sprintf(dbptr,"DEBUG: Buffer expanded to %d\n", x + 18);
5260 zsoutl(ZDFILE,dbptr);
5264 #endif /* COMMENT */
5267 /* The aforementioned sprintf() formats were like this: */
5268 if (n > 31 && n < 127)
5269 sprintf(sp,"%.100s%.2000s:%c\n",s1,s2,(CHAR) n);
5270 else if (n < 32 || n == 127)
5271 sprintf(sp,"%.100s%.2000s:^%c\n",s1,s2,(CHAR) ((n+64) & 0x7F));
5272 else if (n > 127 && n < 160)
5273 sprintf(sp,"%.100s%.2000s:~^%c\n",s1,s2,(CHAR)((n-64) & 0x7F));
5274 else if (n > 159 && n < 256)
5275 sprintf(sp,"%.100s%.2000s:~%c\n",s1,s2,(CHAR) (n & 0x7F));
5276 else sprintf(sp,"%.100s%.2000s:%ld\n",s1,s2,n);
5278 But, naturally, it turns out these are not portable either, so now
5279 we do the stupidest possible thing.
5281 #endif /* COMMENT */
5284 /* Need to accept longer strings when debugging authenticated connections */
5286 if (len2 + 2 >= DBUFL) s2 = "(string too long)";
5287 } else if (f != F011 && f != F100) {
5288 if (len1 > 100) s1 = "(string too long)";
5289 if (len2 + 101 >= DBUFL) s2 = "(string too long)";
5293 if (len1 > 100) s1 = "(string too long)";
5294 if (len2 + 101 >= DBUFL) s2 = "(string too long)";
5296 #endif /* BIGBUFOK */
5300 switch (f) { /* Write log record according to format. */
5301 case F000: /* 0 = print both strings, and n as a char. */
5303 if ((n > 31 && n < 127) || (n > 159 && n < 256))
5304 sprintf(sp,"%s[%s]=%c\n",s1,s2,(CHAR) n);
5305 else if (n < 32 || n == 127)
5306 sprintf(sp,"%s[%s]=^%c\n",s1,s2,(CHAR) ((n+64) & 0x7F));
5307 else if (n > 127 && n < 160)
5308 sprintf(sp,"%s[%s]=~^%c\n",s1,s2,(CHAR)((n-64) & 0x7F));
5309 else sprintf(sp,"%s[%s]=0x%lX\n",s1,s2,(long)n);
5311 if ((n > 31 && n < 127) || (n > 159 && n < 256))
5312 sprintf(sp,"%s=%c\n",s1,(CHAR) n);
5313 else if (n < 32 || n == 127)
5314 sprintf(sp,"%s=^%c\n",s1,(CHAR) ((n+64) & 0x7F));
5315 else if (n > 127 && n < 160)
5316 sprintf(sp,"%s=~^%c\n",s1,(CHAR)((n-64) & 0x7F));
5317 else sprintf(sp,"%s=0x%lX\n",s1,(long)n);
5319 if (zsout(ZDFILE,dbptr) < 0) {
5324 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5325 cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5327 #endif /* CKSYSLOG */
5330 case F001: /* 1, "=n" */
5332 /* This was never used */
5333 sprintf(sp,"=%s\n",ckfstoa(n));
5335 /* Like F111, but shows number n in hex */
5343 NULL,NULL,NULL,NULL,NULL,NULL
5345 #endif /* COMMENT */
5346 if (zsout(ZDFILE,dbptr) < 0) {
5351 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5352 cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5354 #endif /* CKSYSLOG */
5358 This one was never used so (October 2000) we now use it like F011,
5359 except in this case we treat s2 as NUL terminated.
5364 This one treats n as the length of the string s2, which may contain NULs.
5365 It's good for logging NUL-bearing data in the debug log.
5368 int i, j, contd = 0;
5369 char * p = s2, *pbuf = NULL; /* p = source pointer */
5370 int m; /* pbuf = destination pointer */
5373 if (n < 0) { /* n = size of source */
5374 n = 0 - n; /* Negative means to add "..." */
5387 if (n == 0) /* 0 means do nothing */
5389 m = DBUFL - 8; /* Get size for interpreted part */
5390 if (n > m) /* Ensure requested size not too big */
5392 pbuf = dbptr; /* Construction pointer */
5394 pbuf[i++] = '['; /* Interpret the string into it */
5395 for (j = 0; j < n && i < m-4; p++,j++) { /* char by char... */
5404 } else if (*p == CR) {
5412 } else if (*p == HT) {
5435 if (i < m-2 && (*p || contd)) {
5441 if (zsout(ZDFILE,s1) < 0) {
5445 if (zsoutl(ZDFILE,pbuf) < 0) {
5450 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5451 cksyslog(SYSLG_DB,1,"debug",s1,pbuf);
5453 #endif /* CKSYSLOG */
5457 case F100: /* 4, "s1" */
5458 if (zsoutl(ZDFILE,s1) < 0) {
5463 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5464 cksyslog(SYSLG_DB,1,"debug",s1,NULL);
5466 #endif /* CKSYSLOG */
5468 case F101: /* 5, "s1=n" */
5469 sprintf(sp,"%s=%s\n",s1,ckfstoa(n));
5470 if (zsout(ZDFILE,dbptr) < 0) {
5475 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5476 cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5478 #endif /* CKSYSLOG */
5480 case F110: /* 6, "s1[s2]" */
5481 sprintf(sp,"%s[%s]\n",s1,s2);
5482 if (zsout(ZDFILE,dbptr) < 0) {
5487 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5488 cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5490 #endif /* CKSYSLOG */
5492 case F111: /* 7, "s1[s2]=n" */
5493 sprintf(sp,"%s[%s]=%s\n",s1,s2,ckfstoa(n));
5494 if (zsout(ZDFILE,dbptr) < 0) {
5499 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5500 cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5502 #endif /* CKSYSLOG */
5505 sprintf(sp,"\n?Invalid format for debug() - %d\n",f);
5506 if (zsout(ZDFILE,dbptr) < 0) {
5511 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5512 cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5514 #endif /* CKSYSLOG */
5517 xdebug: /* Common exit point */
5520 ReleaseDebugMutex();
5522 deblog = 1; /* Restore this */
5529 dohexdump(CHAR *msg, CHAR *st, int cnt)
5531 dohexdump(msg,st,cnt) CHAR *msg; CHAR *st; int cnt;
5532 #endif /* CK_ANSIC */
5534 int i = 0, j = 0, k = 0;
5537 extern int SysInited;
5540 if (!deblog) return(0); /* If no debug log, don't. */
5541 if (!dbptr) { /* Allocate memory buffer */
5542 dbptr = malloc(DBUFL+1); /* This only happens once */
5552 if (RequestDebugMutex(30000))
5556 deblog = 0; /* Prevent infinite recursion */
5567 NULL,NULL,NULL,NULL,NULL,NULL,NULL
5569 if (zsout(ZDFILE,dbptr) < 0) {
5582 zsout(ZDFILE,dbptr);
5583 if (zsout(ZDFILE,dbptr) < 0) {
5589 for (i = 0; i < cnt; i++) {
5591 for (j = 0 ; (j < 16); j++) {
5595 (j == 8 ? "| " : ""),
5601 (j == 8 ? "| " : "")
5603 ckstrncat(dbptr,tmp,DBUFL+1);
5605 ckstrncat(dbptr," ",DBUFL+1);
5606 for (k = 0; (k < 16) && ((i + k) < cnt); k++) {
5609 (k == 8 ? " " : ""),
5610 isprint(st[i + k]) ? st[i + k] : '.'
5612 ckstrncat(dbptr,tmp,DBUFL+1);
5614 ckstrncat(dbptr,"\n",DBUFL+1);
5616 if (zsout(ZDFILE,dbptr) < 0) {
5627 ReleaseDebugMutex();
5635 /* Session Log... */
5641 logchar(unsigned short c)
5647 #endif /* CK_ANSIC */
5649 /* logchar */ { /* Log character c to session log */
5656 if ((sessft != XYFT_T) || (
5673 #endif /* STRATUS */
5674 #endif /* datageneral */
5686 if (c == '\0' && !sessft) /* NUL in text mode */
5687 if (slognul) oktolog = 1; /* only if padding (2009/10/22) */
5690 if (slogts) { /* Log is timestamped */
5691 if (tsstate == 0) { /* State = between-lines */
5692 char * p; /* zstime() pointer */
5693 char ts[48]; /* timestamp buffer */
5694 ztime(&p); /* Get asctime() string */
5695 ckstrncpy(ts,p,32); /* Make safe copy */
5696 if (ztmsec > -1L) { /* Add msecs if we have them */
5697 sprintf(&ts[19],".%03ld: ",ztmsec); /* SAFE */
5703 if (zsout(ZSFILE,&ts[11]) < 0)
5707 if (c == '\n') /* At end of line? */
5708 tsstate = 0; /* yes */
5710 tsstate = 1; /* no */
5711 if (zchout(ZSFILE,(CHAR)(c & 0xFF)) < 0) /* Log the character */
5713 if (tsstate == 0 && slognul != 0) { /* Null-terminating lines? */
5714 if (zchout(ZSFILE,(CHAR)0) < 0) /* Add a NUL */
5721 conoll("ERROR WRITING SESSION LOG, LOG CLOSED!");
5724 #endif /* NOLOCAL */
5728 logstr(s, len) char * s; int len; { /* Log string to session log */
5733 while (seslog && (n < len))
5735 #endif /* NOLOCAL */
5746 /* VOS has curses but no tgetent() */
5748 tgetent(s1, s2) char * s1, * s2; {
5751 #endif /* STRATUS */
5755 _PROTOTYP(int tgetent,(char *, char *));
5760 There are three different ways to do fullscreen on VMS.
5761 1. Use the real curses library, VAXCCURSE.
5762 2. Use do-it-yourself code.
5763 3. Use the Screen Manager, SMG$.
5765 Method 1 doesn't work quite right; you can't call endwin(), so once you've
5766 started curses mode, you can never leave.
5768 Method 2 doesn't optimize the screen, and so much more time is spent in
5769 screen writes. This actually causes file transfers to fail because the
5770 tty device input buffer can be overrun while the screen is being updated,
5771 especially on a slow MicroVAX that has small typeahead buffers.
5773 In the following #ifdef block, #define one of them and #undef the other 2.
5775 So now let's try method 3...
5778 #define CK_SMG /* Screen Manager */
5779 #undef MYCURSES /* Do-it-yourself */
5780 #undef VMSCURSE /* VAXCCURSE library */
5783 But just before New Years, 2000, the SMG library seemed to break on
5784 both VMS systems we have here (an Alpha with VMS 7.1 and a VAX with 5.5).
5785 So back to MYCURSES, which works fine.
5796 #endif /* CK_WREFRESH */
5797 #endif /* MYCURSES */
5799 /* S C R E E N C -- Screen display function, uses curses */
5801 /* Idea for curses display contributed by Chris Pratt of APV Baker, UK */
5803 /* Avoid conficts with curses.h */
5806 /* Same as ckcasc.h, but in a different radix... */
5813 #undef VOID /* This was defined in ckcdeb.h */
5814 #endif /* MYCURSES */
5816 #undef BS /* These were defined in ckcasc.h */
5823 #undef SP /* Used in ncurses */
5824 #define CHR_SP 32 /* Use this instead */
5826 #ifdef VMS /* VMS fullscreen display */
5827 #ifdef MYCURSES /* Do-it-yourself method */
5828 extern int isvt52; /* From CKVTIO.C */
5829 #define printw printf
5831 #ifdef VMSCURSE /* VMS curses library VAXCCURSE */
5833 /* Note: Screen manager doesn't need a header file */
5834 #endif /* VMSCURSE */
5835 #endif /* MYCURSES */
5837 #ifdef MYCURSES /* Do-it-yourself method */
5838 #define isvt52 0 /* Used by OS/2, VT-100/ANSI always */
5840 #define printw ckxprintf
5841 #else /* CKXPRINTF */
5843 #define printw Vscrnprintw
5845 #define printw printf
5847 #endif /* CKXPRINTF */
5848 #else /* Use real curses */
5849 #ifdef CK_NCURSES /* or ncurses... */
5850 #ifdef CKXPRINTF /* Our printf macro conflicts with */
5851 #undef printf /* use of "printf" in ncurses.h */
5852 #endif /* CKXPRINTF */
5853 #include <ncurses.h>
5855 #define printf ckxprintf
5856 #endif /* CKXPRINTF */
5857 #else /* Not ncurses */
5858 #ifdef CKXPRINTF /* Our printf macro conflicts with */
5859 #undef printf /* use of "printf" in curses.h */
5860 #endif /* CKXPRINTF */
5861 #ifdef M_XENIX /* SCO XENIX... */
5864 #endif /* M_TERMCAP */
5867 #endif /* M_TERMINFO */
5868 #endif /* M_XENIX */
5870 #undef NLS /* Avoid 'redeclaration of free'. */
5874 #define printf ckxprintf
5875 #endif /* CKXPRINTF */
5876 #endif /* CK_NCURSES */
5877 #endif /* MYCURSES */
5881 _PROTOTYP(int tgetent,(char *, char *));
5882 _PROTOTYP(char *tgetstr,(char *, char **));
5883 _PROTOTYP(int tputs,(char *, int, int (*)()));
5884 _PROTOTYP(char *tgoto,(const char *, int, int));
5887 #endif /* CK_CURSES */
5889 /* F X D I N I T -- File Xfer Display Initialization */
5896 /* Can't use VOID because of curses.h */
5901 #endif /* CK_ANSIC */
5903 #endif /* MYCURSES */
5904 #endif /* CK_CURSES */
5907 static int notermcap = 1;
5909 static int notermcap = 0;
5910 #endif /* NOTERMCAP */
5914 fxdinit(xdispla) int xdispla; {
5921 debug(F101,"fxdinit xdispla","",xdispla);
5922 debug(F101,"fxdinit fxd_inited","",fxd_inited);
5926 /* No curses for IKSD */
5931 if (fxd_inited) /* Only do this once */
5936 if (xdispla == XYFD_R || xdispla == XYFD_S || xdispla == XYFD_B) {
5938 printf("%s\n",xfrmsg);
5939 makestr(&xfrmsg,NULL);
5945 /* Force BRIEF in Batch logs */
5946 if (batch && (xdispla == XYFD_C || xdispla == XYFD_S))
5949 if (xdispla == XYFD_C || xdispla == 9999) {
5954 Allocate tgetent() buffer. Make it big -- some termcaps can be huge;
5955 tgetent() merrily writes past the end of the buffer, causing core dumps
5958 trmbuf = (char *)malloc(TRMBUFL);
5961 debug(F101,"fxdinit malloc trmbuf","FAILED",TRMBUFL);
5966 debug(F111,"fxdinit malloc trmbuf","OK",TRMBUFL);
5967 debug(F001,"fxdinit trmbuf","",trmbuf);
5968 memset(trmbuf,'\0',(size_t)TRMBUFL);
5969 debug(F100,"fxdinit memset OK","",0);
5970 #endif /* COMMENT */
5972 #endif /* DYNAMIC */
5974 debug(F100,"fxdinit before getenv(TERM)","",0);
5976 debug(F110,"fxdinit after getenv(TERM)",s,0);
5979 debug(F110,"fxdinit before tgetent()",s,0);
5980 x = tgetent(trmbuf,s);
5981 debug(F111,"fxdinit tgetent",s,x);
5985 debug(F110,"fxdinit TERM null - no tgetent",s,0);
5987 if (x < 1 && !quiet && !backgrd
5992 printf("Warning: terminal type unknown: \"%s\"\n",s);
5994 /* Confusing - nobody knows what this means */
5995 printf("SCREEN command will use ANSI sequences.\n");
5996 #endif /* COMMENT */
5998 printf("Fullscreen file transfer display disabled.\n");
6005 #endif /* MYCURSES */
6008 #endif /* CK_CURSES */
6010 #endif /* STRATUS */
6012 #endif /* COHERENT */
6014 #endif /* NODISPLAY */
6019 Long section for Screen Manager starts here...
6024 #include <smgdef.h> /* use this on VAX C 2.4 */
6025 /* #include <smgmsg.h> */
6027 #include <smg$routines.h> /* Martin Zinser */
6028 #endif /* OLD_VMS */
6030 extern unsigned int vms_status; /* Used for system service return status */
6032 static long smg_pasteboard_id = -1; /* pasteboard identifier */
6033 static long smg_display_id = -1; /* display identifier */
6034 static int smg_open = 0; /* flag if smg current open */
6035 static int smg_inited = 0; /* flag if smg initialized */
6038 #define clrtoeol() SMG$ERASE_LINE(&smg_display_id, 0, 0)
6040 #define clear() SMG$ERASE_DISPLAY(&smg_display_id, 0, 0, 0, 0)
6042 #define touchwin(scr) SMG$REPAINT_SCREEN(&smg_pasteboard_id)
6044 #else /* Not COMMENT */
6046 #define clrtoeol() smg$erase_line(&smg_display_id, 0, 0)
6048 #define clear() smg$erase_display(&smg_display_id, 0, 0, 0, 0)
6050 #define touchwin(scr) smg$repaint_screen(&smg_pasteboard_id)
6051 #endif /* COMMENT */
6053 #define clearok(curscr,ok) /* Let wrefresh() do the work */
6055 #define wrefresh(cursrc) touchwin(scr)
6058 move(row, col) int row, col; {
6059 /* Change from 0-based for curses to 1-based for SMG */
6063 debug(F111,"VMS smg move",ckitoa(row),col);
6064 #ifdef COMMENT /* Martin Zinser */
6065 CHECK_ERR("move: smg$set_cursor_abs",
6066 SMG$SET_CURSOR_ABS(&smg_display_id, &row, &col));
6068 CHECK_ERR("move: smg$set_cursor_abs",
6069 smg$set_cursor_abs(&smg_display_id, &row, &col));
6070 #endif /* COMMENT */
6071 debug(F101,"VMS smg move vms_status","",vms_status);
6076 #endif /* VMS_V40 */
6079 #endif /* VMS_V42 */
6082 #endif /* VMS_V44 */
6086 int rows = 24, cols = 80;
6087 int row = 1, col = 1;
6089 debug(F101,"VMS initscr smg_pasteboard_id A","",smg_pasteboard_id);
6091 if (smg_pasteboard_id == -1) { /* Open the screen */
6092 #ifdef OLD_VMS /* Note: Routine calls lowercased 9/96 */
6093 CHECK_ERR("initscr: smg$create_pasteboard",
6094 smg$create_pasteboard(&smg_pasteboard_id, 0, 0, 0, 0));
6096 /* For VMS V5, not tested */
6097 CHECK_ERR("initscr: smg$create_pasteboard",
6098 smg$create_pasteboard(&smg_pasteboard_id, 0, 0, 0, 0, 0));
6099 #endif /* OLD_VMS */
6101 debug(F101,"VMS initscr smg_pasteboard_id B","",smg_pasteboard_id);
6102 if (smg_pasteboard_id == -1) {
6103 printf("?Error initializing fullscreen display\n");
6108 debug(F101,"VMS initscr smg_display_id","",smg_display_id);
6109 if (smg_display_id == -1) { /* Create a display window */
6111 #ifdef COMMENT /* Martin Zinser */
6112 CHECK_ERR("initscr: smg$create_virtual_display",
6113 SMG$CREATE_VIRTUAL_DISPLAY(&rows, &cols, &smg_display_id,
6116 /* Connect the display window to the screen */
6117 CHECK_ERR("initscr: smg$paste_virtual_display",
6118 SMG$PASTE_VIRTUAL_DISPLAY(&smg_display_id,&smg_pasteboard_id,
6121 CHECK_ERR("initscr: smg$create_virtual_display",
6122 smg$create_virtual_display(&rows, &cols, &smg_display_id,
6125 /* Connect the display window to the screen */
6126 CHECK_ERR("initscr: smg$paste_virtual_display",
6127 smg$paste_virtual_display(&smg_display_id,&smg_pasteboard_id,
6129 #endif /* COMMENT */
6131 debug(F101,"VMS initscr smg_open A","",smg_open);
6132 if (!smg_open) { /* Start a batch update */
6135 CHECK_ERR("initscr: smg$begin_pasteboard_update",
6136 SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id));
6138 CHECK_ERR("initscr: smg$begin_pasteboard_update",
6139 smg$begin_pasteboard_update(&smg_pasteboard_id));
6140 #endif /* COMMENT */
6141 debug(F101,"VMS initscr smg$begin_pasteboard_update","",vms_status);
6143 debug(F101,"VMS initscr smg_open B","",smg_open);
6150 debug(F101,"refresh smg_pasteboard_id","",smg_pasteboard_id);
6152 if (smg_open == 0 || smg_pasteboard_id == -1)
6155 #ifdef COMMENT /* Martin Zinser */
6156 CHECK_ERR("refresh: smg$end_pasteboard_update",
6157 SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id));
6158 CHECK_ERR("refresh: smg$begin_pasteboard_update",
6159 SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id));
6161 CHECK_ERR("refresh: smg$end_pasteboard_update",
6162 smg$end_pasteboard_update(&smg_pasteboard_id));
6163 CHECK_ERR("refresh: smg$begin_pasteboard_update",
6164 smg$begin_pasteboard_update(&smg_pasteboard_id));
6165 #endif /* COMMENT */
6176 CHECK_ERR("endwin: smg$end_pasteboard_update",
6177 SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id));
6179 CHECK_ERR("endwin: smg$end_pasteboard_update",
6180 smg$end_pasteboard_update(&smg_pasteboard_id));
6181 #endif /* COMMENT */
6187 These calls clear the screen.
6188 (convert routine calls to lowercase - Martin Zinser)
6190 CHECK_ERR("endwin: smg$delete_virtual_display",
6191 SMG$DELETE_VIRTUAL_DISPLAY(&smg_display_id));
6192 smg_display_id = -1;
6194 CHECK_ERR("endwin: smg$delete_pasteboard",
6195 SMG$DELETE_PASTEBOARD(&smg_pasteboard_id, 0));
6196 smg_pasteboard_id = -1;
6197 #endif /* COMMENT */
6201 /* DECC 6.2 screams bloody murder about printw ("not enough args") */
6202 /* but adding the following prototype only makes it holler louder. */
6204 /* "varargs" prototype for printw */
6205 _PROTOTYP(static int printw,(char *, ...));
6207 #endif /* COMMENT */
6211 _PROTOTYP(static void printw,(char *, ...));
6213 printw(char *str,...) {
6216 $DESCRIPTOR(text_dsc, 0);
6217 text_dsc.dsc$a_pointer=buf;
6221 text_dsc.dsc$w_length = vsprintf(buf, str, ap);
6223 CHECK_ERR("printw: smg$put_chars",
6224 smg$put_chars(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0));
6228 printw(str, a1, a2, a3, a4, a5, a6, a7, a8)
6230 long a1, a2, a3, a4, a5, a6, a7, a8;
6233 $DESCRIPTOR(text_dsc, 0);
6236 text_dsc.dsc$a_pointer=buf;
6237 text_dsc.dsc$w_length = sprintf(buf, str, a1, a2, a3, a4, a5, a6, a7, a8);
6238 CHECK_ERR("printw: smg$put_chars",
6239 smg$put_chars(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0));
6245 ck_curpos(row, col) {
6246 debug(F111,"VMS smg ck_curpos",ckitoa(row),col);
6247 if (!smg_inited || !smg_open) {
6250 debug(F101,"VMS smg curpos smg_open","",smg_open);
6253 debug(F111,"VMS smg ck_curpos",ckitoa(row-1),col-1);
6254 move(row - 1, col - 1); /* SMG is 0-based */
6262 debug(F101,"VMS smg ck_cls smg_inited","",smg_inited);
6263 if (!smg_inited || !smg_open) {
6266 debug(F101,"VMS smg ck_cls smg_open","",smg_open);
6277 debug(F101,"VMS smg ck_cleol smg_inited","",smg_inited);
6278 if (!smg_inited || !smg_open) {
6281 debug(F101,"VMS smg ck_cleol smg_open","",smg_open);
6293 Do-it-yourself curses implementation for VMS, OS/2 and other ANSI/VT-100's.
6294 Supports only the VT52 and VT1xx (and later VT2xx/3xx/4xx) terminals.
6295 By Terry Kennedy, St Peters College.
6297 First, some stuff we can just ignore:
6301 touchwin(x) int x; {
6318 * Now, some stuff we need to do:
6321 _PROTOTYP( int move, (int, int) );
6324 move(row, col) int row, col; {
6326 printf("\033Y%c%c", row + 037, col + 037);
6328 printf("\033[%d;%dH", row + 1, col + 1);
6363 ck_curpos(row, col) int row, col; {
6369 /* Windows NT and Windows 95 do not provide ANSI emulation */
6370 /* Therefore we might as well not use it for OS/2 either */
6373 move(row, col) int row, col; {
6375 SetCurPos(row, col);
6376 #endif /* ONETERMUPD */
6377 lgotoxy( VCMD, col+1, row+1);
6387 if (VscrnGetBufferSize(VCMD) > 0) {
6388 VscrnScroll(VCMD, UPWARD, 0,
6389 VscrnGetHeight(VCMD)-(1),
6390 VscrnGetHeight(VCMD)-(0), TRUE, CHR_SP);
6391 cleartermscreen(VCMD);
6396 WrtNCell(cell, cmd_rows * cmd_cols, 0, 0);
6397 #endif /* ONETERMUPD */
6409 GetCurPos(&row, &col );
6410 WrtNCell(cell, cmd_cols - col -1, row, col);
6411 #endif /* ONETERMUPD */
6412 clrtoeoln(VCMD,CHR_SP);
6418 ck_curpos(row, col) int row, col; {
6434 #endif /* MYCURSES */
6440 /* Termcap/Terminfo section */
6442 static char cur_cls[32] = { NUL, NUL };
6443 static char cur_cleol[32] = { NUL, NUL };
6444 static char cur_cm[64] = { NUL, NUL };
6445 static char tgsbuf[128] = { NUL, NUL };
6450 #endif /* CK_ANSIC */
6451 ck_termset(x) int x; {
6456 debug(F100,"tgetent is a macro","",0);
6457 #endif /* tgetent */
6459 debug(F100,"tgetstr is a macro","",0);
6460 #endif /* tgetstr */
6462 debug(F100,"tputs is a macro","",0);
6465 debug(F100,"tgoto is a macro","",0);
6468 /* tgetstr() gets a segmentation fault on OSF/1 */
6469 debug(F100,"ck_termset NOTERMCAP","",0);
6472 debug(F100,"ck_termset notermcap","",0);
6475 debug(F101,"ck_termset x","",x);
6480 debug(F110,"ck_termset calling tgetstr","cl",0);
6481 if (tgetstr("cl", &bp)) { /* Get clear-screen code */
6482 debug(F110,"ck_termset tgetstr cl",tgsbuf,"");
6483 if ((int)strlen(tgsbuf) < 32)
6484 ckstrncpy(cur_cls,tgsbuf,32);
6488 if (tgetstr("ce", &bp)) { /* Get clear-to-end-of-line code */
6489 debug(F110,"ck_termset tgetstr ce",tgsbuf,"");
6490 if ((int)strlen(tgsbuf) < 32)
6491 ckstrncpy(cur_cleol,tgsbuf,32);
6495 if (tgetstr("cm", &bp)) { /* Get cursor-movement code */
6496 debug(F110,"ck_termset tgetstr cm",tgsbuf,"");
6497 if ((int)strlen(tgsbuf) < 64)
6498 ckstrncpy(cur_cm,tgsbuf,64);
6502 #endif /* NOTERMCAP */
6507 #define TPUTSFNTYPE void
6509 #define TPUTSFNTYPE int
6510 #endif /* TPUTSISVOID */
6511 #endif /* TPUTSFNTYPE */
6513 #ifndef TPUTSARGTYPE
6515 #define TPUTSARGTYPE char
6518 #define TPUTSARGTYPE char
6520 #define TPUTSARGTYPE int
6523 #endif /* TPUTSARGTYPE */
6527 ck_outc(TPUTSARGTYPE x)
6529 ck_outc(x) TPUTSARGTYPE x;
6530 #endif /* CK_ANSIC */
6531 { /* To satisfy tputs() arg3 prototype */
6535 rc = (inserver) ? ttoc(c) : conoc(c);
6538 #endif /* TPUTSISVOID */
6542 ck_curpos(row, col) int row, col; {
6544 TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
6546 TPUTSFNTYPE (*fn)();
6547 #endif /* CK_ANSIC */
6550 if (!cur_cm[0]) { /* We don't have escape sequences */
6552 return(-1); /* Do nothing */
6554 /* Both C-Kermit's SCREEN command and ANSI/VT100 are 1-based */
6555 printf("\033[%d;%dH", row, col); /* Or default to ANSI */
6556 #endif /* COMMENT */
6559 /* termcap/terminfo is 0-based */
6561 #ifdef TPUTSARG1CONST
6563 #endif /* TPUTSARG1CONST */
6564 tgoto(cur_cm,col-1,row-1),1,fn);
6572 TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
6574 TPUTSFNTYPE (*fn)();
6575 #endif /* CK_ANSIC */
6578 if (!cur_cls[0]) { /* If we don't have escape sequences */
6580 return(-1); /* Do nothing */
6582 printf("\033[;H\033[2J"); /* Or default to ANSI */
6583 #endif /* COMMENT */
6586 debug(F111,"ck_cls 2",cur_cls,fxd_inited);
6587 tputs(cur_cls,cmd_rows,fn);
6595 TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
6597 TPUTSFNTYPE (*fn)();
6598 #endif /* CK_ANSIC */
6601 if (!cur_cleol[0]) { /* If we don't have escape sequences */
6603 return(-1); /* Do nothing */
6605 printf("\033[K"); /* Or use ANSI */
6606 #endif /* COMMENT */
6609 tputs(cur_cleol,1,fn);
6613 #endif /* CK_CURPOS */
6616 ck_termset(x) int x; {
6619 #endif /* NOTERMCAP */
6625 printf("\033[;H\033[2J");
6636 ck_curpos(row, col) int row, col; {
6637 printf("\033[%d;%dH", row, col);
6640 #endif /* CK_CURPOS */
6644 static int cinit = 0; /* Flag for curses init'd */
6645 static int cendw = 0; /* endwin() was called */
6648 #ifdef CK_ANSIC /* Because VOID used by curses.h */
6655 #endif /* MYCURSES */
6656 #endif /* CK_ANSIC */
6657 #ifdef CK_ANSIC /* Update % transfered and % bar */
6658 updpct(long old, long new)
6659 #else /* CK_ANSIC */
6660 updpct(old, new) long old, new;
6661 #endif /* CK_ANSIC */
6669 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_PCD, (long) new);
6680 move(CW_PCD, 26 + m);
6684 if ((m + 1) % 5 == 0)
6691 if (new % 2 != 0) printw("-");
6692 /* move(CW_PCD, 22+53); */
6695 printw("%c", '\333');
6699 printw("%c", '\261');
6702 #endif /* CK_PCT_BAR */
6704 #else /* !COMMENT */
6706 #define CHAR1 '\333' /* OS2 - CP437 */
6707 #define CHAR2 '\261'
6709 #define CHAR1 '/' /* Default */
6712 debug(F101,"updpct old","",old);
6713 debug(F101,"updpct new","",new);
6715 printw("%-3ld", new); /* (was) printw("%ld", new); */
6718 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) new );
6735 printw("%c", CHAR1);
6737 printw("%c", CHAR2);
6740 #endif /* CK_PCT_BAR */
6741 #endif /* COMMENT */
6744 static CK_OFF_T old_tr = (CK_OFF_T)-1; /* Time remaining previously */
6748 shoetl(CK_OFF_T old_tr, long cps, CK_OFF_T fsiz, CK_OFF_T howfar)
6750 shoetl(old_tr, cps, fsiz, howfar) long cps; CK_OFF_T old_tr, fsiz, howfar;
6751 #endif /* CK_ANSIC */
6752 /* shoetl */ { /* Estimated time left in transfer */
6753 CK_OFF_T tr; /* Time remaining, seconds */
6756 if (fsiz > 0L && cps > 0L)
6757 tr = (CK_OFF_T)((CKFLOAT)(fsiz - howfar) / (CKFLOAT)cps);
6761 tr = (fsiz > 0L && cps > 0L) ?
6762 ((fsiz - howfar) / cps) :
6764 #endif /* GFTIMER */
6766 if (tr > (CK_OFF_T)-1) {
6768 printw("%s",hhmmss(tr));
6771 KuiSetProperty(KUI_FILE_TRANSFER, (long)CW_TR, (long)hhmmss(tr));
6777 printw("(unknown)");
6780 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "(unknown)" );
6790 shocps(int pct, CK_OFF_T fsiz, CK_OFF_T howfar)
6792 shocps(pct, fsiz, howfar) int pct; CK_OFF_T fsiz, howfar;
6793 #endif /* CK_ANSIC */
6796 static CK_OFF_T oldffc = 0L;
6797 #endif /* CPS_WEIGHTED */
6802 #endif /* GFTIMER */
6805 xx = (gtv >= 0.0) ? gtv : 0.0; /* Floating-point version */
6807 if ((gtv - oldgtv) < (CKFLOAT) 1.0) /* Only do this once per second */
6811 xx = (gtv >= 0) ? gtv : 0; /* Whole-number version */
6813 if ((gtv - oldgtv) < 1)
6816 #endif /* GFTIMER */
6819 /* debug(F100,"SHOCPS: WEIGHTED","",0); */
6820 if (gtv != oldgtv) { /* The first packet is ignored */
6824 if (oldcps && oldgtv >
6829 #endif /* GFTIMER */
6830 ) { /* The first second is ignored */
6832 This version of shocps() produces a weighted average that some
6833 people like, but most people find it disconcerting and bombard us
6834 with questions and complaints about why the CPS figure fluctuates so
6835 wildly. So now you only get the weighted average if you build the
6836 program yourself with CPS_WEIGHTED defined.
6840 cps = (long)((((CKFLOAT)oldcps * 3.0) +
6841 (CKFLOAT)(ffc - oldffc) / (gtv-oldgtv) ) / 4.0);
6843 cps = ( (oldcps * 3) + (ffc - oldffc) / (gtv-oldgtv) ) / 4;
6844 #endif /* GFTIMER */
6846 /* And an alternate weighting scheme from Vincent Fatica... */
6848 ((1+pct/300)*oldffc/oldgtv+(1-pct/100)*(ffc-oldffc)/(gtv-oldgtv)))
6850 #endif /* CPS_VINCE */
6852 /* No weighted average since there is nothing to weigh */
6854 cps = (long)(gtv != 0.0 ?
6855 (CKFLOAT)(ffc - oldffc) / (gtv - oldgtv) :
6858 cps = gtv ? (ffc - oldffc) / (gtv - oldgtv) : (ffc - oldffc) ;
6859 #endif /* GFTIMER */
6864 debug(F101,"SHOCPS: pct ","",pct);
6865 debug(F101,"SHOCPS: gtv ","",gtv);
6866 debug(F101,"SHOCPS: oldgtv","",oldgtv);
6867 debug(F101,"SHOCPS: dgtv ","",(long)(gtv-oldgtv));
6868 debug(F101,"SHOCPS: ffc ","",ffc);
6869 debug(F101,"SHOCPS: oldffc","",oldffc);
6870 debug(F101,"SHOCPS: dffc ","",ffc-oldffc);
6871 debug(F101,"SHOCPS: cps ","",cps);
6874 #endif /* COMMENT */
6879 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
6885 #else /* !CPS_WEIGHTED */
6889 debug(F100,"SHOCPS: NOT WEIGHTED","",0);
6890 debug(F101,"SHOCPS: pct ","",pct);
6891 debug(F101,"SHOCPS: gtv ","",gtv);
6892 debug(F101,"SHOCPS: oldgtv ","",oldgtv);
6893 debug(F101,"SHOCPS: dgtv ","",(long)gtv - (long)oldgtv);
6894 debug(F101,"SHOCPS: ffc ","",ffc);
6895 debug(F101,"SHOCPS: oldffc ","",oldffc);
6896 debug(F101,"SHOCPS: dffc ","",ffc-oldffc);
6897 debug(F101,"SHOCPS: cps ","",cps);
6898 debug(F101,"SHOCPS: filcnt ","",filcnt);
6900 debug(F101,"SHOCPS: fpfsecs","",fpfsecs);
6901 #endif /* GFTIMER */
6903 debug(F101,"shocps gtv","",gtv);
6906 #endif /* COMMENT */
6907 /* debug(F101,"shocps fpfsecs","",fpfsecs); */
6908 secs = gtv - fpfsecs;
6909 /* debug(F101,"shocps secs","",(long)secs); */
6911 cps = (long)((CKFLOAT) ffc / secs);
6912 /* debug(F101,"shocps cps","",cps); */
6916 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
6922 #else /* Not GFTIMER */
6923 if ((secs = gtv - fsecs) > 0) {
6924 cps = (secs < 1L) ? ffc : ffc / secs;
6928 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
6934 #endif /* GFTIMER */
6935 #endif /* CPS_WEIGHTED */
6937 if (cps > peakcps && /* Peak transfer rate */
6938 ((what & W_SEND && spackets > wslots + 4) ||
6939 (!(what & W_SEND) && spackets > 10))) {
6942 old_tr = shoetl(old_tr, cps, fsiz, howfar);
6947 #ifdef CK_ANSIC /* Because VOID used by curses.h */
6954 #endif /* MYCURSES */
6955 #endif /* CK_ANSIC */
6956 scrft() { /* Display file type */
6959 debug(F101,"scrft binary","",binary);
6963 ckstrncpy(xferstr,"LABELED",256);
6966 ckstrncpy(xferstr,"IMAGE",256);
6969 ckstrncpy(xferstr,"BINARY UNDEFINED",256);
6972 ckstrncpy(xferstr,"MACBINARY",256);
6975 ckstrncpy(xferstr,"TENEX",256);
6979 ckstrncpy(xferstr,"BINARY",256);
6983 if (what & W_SEND && sendstart > 0L) {
6984 if (sendmode == SM_PSEND) {
6985 ckstrncat(xferstr, " / partial", 256);
6986 } else if (sendmode == SM_RESEND) {
6987 ckstrncat(xferstr, " / resend", 256);
6989 } else if (what & W_RECV && rs_len > 0L) {
6990 ckstrncat(xferstr, " / resend", 256);
6992 #endif /* CK_RESEND */
6996 ckstrncpy(xferstr,"TEXT",256);
7001 ckstrncat(xferstr," (no translation)", 256);
7003 ckmakxmsg(&xferstr[4],252,
7005 fcsinfo[(what & W_SEND) ? ftp_csl : ftp_csx].keyword,
7007 fcsinfo[(what & W_SEND) ? ftp_csx : ftp_csl].keyword,
7009 NULL,NULL,NULL,NULL,NULL,NULL,NULL
7012 #endif /* NOUNICODE */
7014 if (tcharset == TC_TRANSP) {
7015 ckstrncat(xferstr, " (no translation)", 256);
7017 if (what & W_SEND) {
7018 sprintf( &xferstr[strlen(xferstr)], /* safe */
7020 fcsinfo[fcharset].keyword, /* built-in keywords */
7021 tcsinfo[tcharset].keyword /* lengths are controlled */
7024 sprintf( &xferstr[strlen(xferstr)], /* safe */
7026 tcsinfo[tcharset].keyword, /* built-in keywords */
7027 fcsinfo[fcharset].keyword); /* lengths controlled */
7030 #endif /* NOCSETS */
7033 printw("%s", xferstr);
7037 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TYP, (long) xferstr );
7044 static FILE *ck_stdout = NULL;
7045 static int ck_fd = -1;
7046 #endif /* CK_NEWTERM */
7048 static long pct = 0L, oldpct = 0L, oldrtt = -1L;
7049 static int oldtyp = 0, oldwin = -1, oldtry = -1, oldlen = -1, oldtim = -1;
7052 static char *netname[] = {
7054 "TCP/IP", /* 01 TCP (Sockets) */
7055 "TCP/IP", /* 02 TCP (Streams) */
7056 "X.25", /* 03 SunLink X.24 */
7057 "DECnet", /* 04 DECnet */
7058 "VAX PSI", /* 05 VAX PSI */
7059 "Named Pipes", /* 06 LAN Manager Named Pipe */
7060 "X.25", /* 07 Stratus VOS X.25 */
7061 "NetBIOS", /* 08 IBM NETBIOS */
7062 "SuperLAT", /* 07 Meridian SuperLAT */
7063 "File", /* 10 File */
7064 "Command", /* 11 Subprocess (pipe) */
7065 "DLL", /* 12 DLL does i/o */
7066 "X.25", /* 13 IBM AIXLink X.25 */
7067 "X.25", /* 14 HP-UX X.25 */
7068 "PTY", /* 15 Pseudoterminal */
7070 "<ERROR>", /* 17 In case new types are added */
7071 "<ERROR>", /* 18 but nobody remembers to update */
7072 "<ERROR>", /* 19 this table ... */
7075 static int nnetname = (sizeof(netname) / sizeof(char *));
7077 #endif /* NETCONN */
7081 screenc(int f, char c,CK_OFF_T n,char *s)
7085 int f; /* argument descriptor */
7086 char c; /* a character or small integer */
7087 CK_OFF_T n; /* a long integer */
7088 char *s; /* a string */
7089 #endif /* CK_ANSIC */
7092 extern int tls_active_flag, ssl_active_flag;
7095 extern int ttnproto;
7096 #endif /* RLOGCODE */
7098 static long fcnt = 0L; /* Number of files transferred */
7099 static CK_OFF_T fsiz = (CK_OFF_T)-1; /* Copy of file size */
7100 static CK_OFF_T fbyt = 0L; /* Total file bytes of all files transferred */
7101 static CK_OFF_T howfar = 0L; /* How much of current file has been xfer'd */
7102 static int pctlbl = 0L; /* Percent done vs Bytes so far */
7108 int len; /* Length of string */
7109 int errors = 0; /* Error counter */
7112 debug(F101,"screenc cinit","",cinit);
7113 debug(F101,"screenc cendw","",cendw);
7115 if (!s) s = ""; /* Always do this. */
7117 ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit */
7118 net = network || ftp;
7119 xnet = ftp ? 1 : nettype; /* NET_TCPB == 1 */
7121 if (cinit == 0 || cendw > 0) { /* Handle borderline cases... */
7122 if (f == SCR_CW) { /* Close window, but it's not open */
7126 debug(F111,"screenc A",s,f);
7128 (f == SCR_PT && c == 'E')) { /* Fatal error before window open */
7129 conoll(""); conoc('?'); conoll(s); return; /* Regular display */
7132 if (cinit == 0) { /* Only call initscr() once */
7134 /* Check these now -- if they are defined but not numeric */
7135 /* they can crash curses */
7136 s = getenv("LINES");
7137 if (s) if (!rdigits(s)) {
7138 printf("?LINES variable not numeric: \"%s\".\n",s);
7139 printf("(Fullscreen display disabled)\n");
7143 s = getenv("COLUMNS");
7144 if (s) if (!rdigits(s)) {
7145 printf("?COLUMNS variable not numeric: \"%s\".\n",s);
7146 printf("(Fullscreen display disabled)\n");
7150 cendw = 1; /* New window needs repainting */
7152 if (!initscr()) { /* Oops, can't initialize window? */
7154 In fact, this doesn't happen. "man curses" says initscr() halts the
7155 entire program if it fails, which is true on the systems where I've
7156 tested it. It will fail if your terminal type is not known to it.
7157 That's why SET FILE DISPLAY FULLSCREEN calls tgetent() to make sure the
7158 terminal type is known before allowing a curses display.
7160 fprintf(stderr,"CURSES INITSCR ERROR\r\n");
7161 fdispla = XYFD_S; /* Fall back to CRT display */
7164 cinit++; /* Window initialized ok */
7165 debug(F100,"CURSES INITSCR OK","",0);
7167 #else /* Save some memory. */
7169 /* (From Andy Fyfe <andy@vlsi.cs.caltech.edu>)
7170 System V curses seems to reserve the right to alter the buffering
7171 on the output FILE* without restoring it. Fortunately System V
7172 curses provides newterm(), an alternative to initscr(), that
7173 allows us to specify explicitly the terminal type and input and
7174 output FILE pointers. Thus we duplicate stdout, and let curses
7175 have the copy. The original remains unaltered. Unfortunately,
7176 newterm() seems to be particular to System V.
7180 ck_fd = dup(fileno(stdout));
7181 ck_stdout = (ck_fd >= 0) ? (FILE *)fdopen(ck_fd, "w") : NULL;
7183 debug(F100,"screenc newterm...","",0);
7185 /* NOTE: It might be necessary to do this with stdin too! */
7186 /* This would have been the case in FreeBSD 4.1 but they fixed the */
7187 /* problem by restoring the buffering of stdin before the final release. */
7188 /* (But T.E. Dickey says stdin is not buffered?) */
7190 if (ck_stdout == NULL || newterm(s, ck_stdout, stdin) == 0) {
7192 "Fullscreen display not supported for terminal type: %s\r\n",s);
7193 fdispla = XYFD_S; /* Use CRT instead */
7196 debug(F100,"screenc newterm ok","",0);
7198 debug(F100,"screen calling initscr","",0);
7199 initscr(); /* Initialize curses. */
7200 debug(F100,"screen initscr ok","",0);
7201 #endif /* CK_NEWTERM */
7202 cinit++; /* Remember curses was initialized. */
7203 #endif /* COMMENT */
7205 ft_win = 1; /* Window is open */
7209 This totally repaints the screen, just what we want, but we can only
7210 do this with real curses, and then only if clearok() and wrefresh() are
7211 provided in the curses library.
7218 clearok(stdscr, 1); /* QNX doesn't have curscr */
7225 #else /* No CK_WREFRESH */
7227 Kermit's do-it-yourself method, works with all types of fullscreen
7228 support, but does not repaint all the fields. For example, the filename
7229 is lost, because it arrives at a certain time and never comes again, and
7230 Kermit presently does not save it anywhere. Making this method work for
7231 all fields would be a rather major recoding task, duplicating what curses
7232 already does, and would add a lot of complexity and storage space.
7235 #endif /* CK_WREFRESH */
7238 if (cendw) { /* endwin() was called previously */
7240 initscr(); /* (or should have been!) */
7247 In QNX, if we don't call initscr() here we core dump.
7248 I don't have any QNX curses documentation, but other curses manuals
7249 say that initscr() should be called only once per application, and
7250 experience shows that on other systems, calling initscr() here generally
7251 results in a core dump.
7253 debug(F100,"screenc re-calling initscr QNX","",0);
7259 But even so, second and subsequent curses displays are messed up.
7260 Calling touchwin, refresh, etc, doesn't make any difference.
7262 debug(F100,"screenc calling touchwin QNX","",0);
7264 debug(F100,"screenc calling refresh QNX","",0);
7266 #endif /* COMMENT */
7268 #else /* All others... */
7269 debug(F100,"screenc calling clear","",0);
7271 debug(F100,"screenc clear ok","",0);
7274 debug(F100,"screenc setup ok","",0);
7275 debug(F100,"screenc doing first move","",0);
7276 move(CW_BAN,0); /* Display the banner */
7277 debug(F110,"screenc myhost",myhost,0);
7279 debug(F110,"screenc myipaddr",myipaddr,0);
7280 #endif /* TCPSOCKET */
7282 debug(F100,"screenc calling first printw...","",0);
7283 /* Right here is where HP-UX 10.10 libxcurse.1 Rev 76.20 hangs... */
7284 #endif /* HPUX1010 */
7289 /* We need to perform this test because on non-TCP/IP */
7290 /* systems the call to getlocalipaddr() results in a */
7291 /* DNS Lookup which takes several minutes to time out */
7293 (xnet == NET_TCPA || xnet == NET_TCPB
7296 #endif /* SSHBUILTIN */
7301 if (myipaddr[0] && strcmp((char *)myhost,(char *)myipaddr))
7302 printw("%s, %s [%s]",versio,(char *)myhost,(char *)myipaddr);
7304 #endif /* TCPSOCKET */
7305 printw("%s, %s",versio,(char *)myhost);
7307 printw("%s",versio);
7310 debug(F100,"screenc first printw returns","",0);
7311 #endif /* HPUX1010 */
7313 printw("Current Directory: %s",zgtdir());
7316 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) zgtdir() );
7321 printw("Network Host: %s",
7323 ftp ? (ftp_host ? ftp_host : "(unknown)") :
7329 printw("Communication Device: %s",ttname);
7333 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_LIN, (long) ttname );
7339 printw("Network Type: ");
7342 printw("Communication Speed: ");
7344 move(CW_SPD,22); /* Serial speed or network type */
7349 if (xnet > nnetname)
7352 xname = netname[xnet];
7362 #endif /* SSHBUILTIN */
7363 #ifdef CK_ENCRYPTION
7364 || ck_tn_encrypting() && ck_tn_decrypting()
7365 #endif /* CK_ENCRYPTION */
7367 || tls_active_flag || ssl_active_flag
7371 #ifdef CK_ENCRYPTION
7372 || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
7373 #endif /* CK_ENCRYPTION */
7374 #endif /* CK_KERBEROS */
7375 #endif /* RLOGCODE */
7383 sprintf(buf,"%s (SECURE)",xname);
7384 KuiSetProperty(KUI_FILE_TRANSFER,
7390 printw("%s (SECURE)",xname);
7395 KuiSetProperty(KUI_FILE_TRANSFER,
7403 printw("(network)");
7406 KuiSetProperty(KUI_FILE_TRANSFER,
7412 #endif /* NETCONN */
7417 if (speed == 8880) {
7421 KuiSetProperty(KUI_FILE_TRANSFER,
7429 sprintf(speedbuf, "%ld", speed);
7430 printw("%s",speedbuf);
7433 KuiSetProperty(KUI_FILE_TRANSFER,
7444 KuiSetProperty(KUI_FILE_TRANSFER,
7453 printw("Parity: %s",ftp ? "none" : parnam((char)parity));
7456 KuiSetProperty(KUI_FILE_TRANSFER,
7458 (long) parnam((char)parity)
7463 if (/* rttflg && */ protocol == PROTO_K) {
7464 move(CW_TMO, 9); printw("RTT/Timeout:"); }
7465 #endif /* CK_TIMERS */
7466 move(CW_TYP,11); printw("File Type:");
7467 move(CW_SIZ,11); printw("File Size:");
7470 pctlbl = (what & W_SEND);
7471 printw("%s:", pctlbl ? "Percent Done" : "Bytes So Far");
7475 printw("%10s Protocol:", ftp ? "FTP" : ptab[protocol].p_name);
7476 #endif /* XYZ_INTERNAL */
7481 printw(" ...10...20...30...40...50...60...70...80...90..100");
7484 #endif /* CK_PCT_BAR */
7485 move(CW_TR, 1); printw("Estimated Time Left:");
7486 move(CW_CP, 2); printw("Transfer Rate, CPS:");
7487 move(CW_WS, 8); printw("Window Slots:%s",
7488 ((protocol == PROTO_K) && !ftp) ?
7491 move(CW_PT, 9); printw("Packet Type:");
7492 if (ftp || protocol != PROTO_K) {
7494 printw("%s", "N/A");
7495 move(CW_PC, 11); printw("I/O Count:");
7496 move(CW_PL, 10); printw("I/O Length:");
7498 move(CW_PC, 8); printw("Packet Count:");
7499 move(CW_PL, 7); printw("Packet Length:");
7502 move(CW_PR, 9); printw("Error Count:");
7504 move(CW_PR, 2); printw("Packet Retry Count:");
7507 move(CW_PB, 2); printw("Packet Block Check:");
7508 #endif /* COMMENT */
7509 move(CW_ERR,10); printw("Last Error:");
7510 move(CW_MSG, 8); printw("Last Message:");
7512 move(CW_MSG, 22); printw("%s",xfrmsg);
7513 makestr(&xfrmsg,NULL);
7517 printw("(Transfer interruption is disabled)");
7521 "<%s>X to cancel file, <%s>Z to cancel group, <%s><CR> to resend last packet",
7522 dbchr(escape), dbchr(escape), dbchr(escape)
7524 move(CW_INT + 1, 0);
7526 "<%s>E to send Error packet, ^C to quit immediately, <%s>L to refresh screen.",
7527 dbchr(escape), dbchr(escape)
7529 #else /* !CK_NEED_SIG */
7532 if (protocol == PROTO_K) {
7534 "X to cancel file, Z to cancel group, <Enter> to resend last packet,"
7538 #ifdef VMS /* In VMS avoid bottom line */
7540 "X: Cancel this file; E: Cancel transfer; ^C: Quit now; ^W: Refresh screen."
7544 "X to cancel file, Z to cancel group, <CR> to resend last packet,"
7550 move(CW_INT + 1, 0);
7551 if (protocol == PROTO_K) {
7553 "E to send Error packet, ^C to quit immediately, ^L to refresh screen."
7556 printw("^C to cancel file transfer.");
7559 #endif /* CK_NEED_SIG */
7564 debug(F101,"SCREENC switch","",f);
7565 debug(F000,"SCREENC c","",c);
7566 debug(F101,"SCREENC n","",n);
7568 len = strlen(s); /* Length of argument string */
7569 switch (f) { /* Handle our function code */
7570 case SCR_FN: /* Filename */
7571 oldpct = pct = 0L; /* Reset percents */
7573 gtv = (CKFLOAT) -1.0;
7574 /* oldgtv = (CKFLOAT) -1.0; */
7578 #endif /* GFTIMER */
7580 fsiz = (CK_OFF_T)-1; /* Invalidate previous file size */
7581 move(CW_PCD,22); /* Erase percent done from last time */
7584 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) 0 );
7585 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_FFC, (long) 0 );
7589 move(CW_SIZ,22); /* Erase file size from last time */
7592 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) 0 );
7596 move(CW_ERR,22); /* And last error message */
7599 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) "" );
7605 if (protocol == PROTO_K && streamok) {
7608 printw(" Kermit STREAMING:");
7610 printw(" STREAMING:");
7611 #endif /* XYZ_INTERNAL */
7613 #endif /* STREAMING */
7614 #endif /* COMMENT */
7616 if (what & W_SEND) { /* If we're sending... */
7618 if (what & W_FTP) { /* FTP */
7620 printw(" FTP PUT:");
7624 switch (sendmode) { /* Kermit */
7627 printw(" RESENDING:");
7631 printw(" SENDING:");
7636 printw(" SENDING:");
7637 #endif /* CK_RESEND */
7639 } else if (what & W_RECV) { /* If we're receiving... */
7641 if (what & W_FTP) { /* FTP */
7643 printw(" FTP GET:");
7647 printw(" RECEIVING:");
7650 } else if (what == (W_FTP|W_FT_DELE)) {
7652 printw("FTP DELETE:");
7654 } else { /* If we don't know... */
7655 move(CW_NAM,10); /* (should never see this) */
7656 printw(" File Name:");
7658 move(CW_NAM,22); /* Display the filename */
7660 printw("%.55s..",s);
7662 } else printw("%s",s);
7665 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
7668 q = len; /* Remember name length for later */
7670 scrft(); /* Display file type (can change) */
7677 case SCR_AN: /* File as-name */
7678 if (q + len + 4 < 58) { /* Will fit */
7679 move(CW_NAM, 22 + q);
7683 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
7686 } else { /* Too long */
7687 move(CW_NAM, 22); /* Overwrite previous name */
7689 if (len + 4 > 57) { /* wg15 */
7690 printw(" => %.51s..",s); /* wg15 */
7691 len = 53; /* wg15 */
7692 } else printw(" => %s",s); /* wg15 */
7695 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
7699 q += len + 4; /* Remember horizontal position */
7707 case SCR_FS: /* File size */
7710 if (fsiz > (CK_OFF_T)-1) {
7713 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) n );
7716 printw("%s",ckfstoa(n));
7719 printw("POSSIBLY EXCEEDS LOCAL FILE SIZE LIMIT");
7724 if (fsiz > (CK_OFF_T)-1) { /* Put up percent label */
7727 printw("Percent Done:");
7732 if (fsiz > (CK_OFF_T)-1) { /* Put up percent label */
7734 printw("Percent Done:");
7737 printw("Bytes So Far:");
7739 #endif /* COMMENT */
7741 scrft(); /* File type */
7748 case SCR_PT: /* Packet type or pseudotype */
7750 extern int sysindex;
7751 extern struct sysdata sysidlist[];
7752 /* Things that won't change after the 4th packet */
7754 printw("%s",parnam((char)parity));
7757 KuiSetProperty( KUI_FILE_TRANSFER,
7759 (long) parnam((char)parity)
7765 move(CW_PB, 22); /* Block check on this packet */
7771 #endif /* COMMENT */
7774 (ftp && (spackets == 1 || rpackets == 1)) ||
7783 ((protocol == PROTO_K) && (sysindex > -1))
7787 printw("Network Host: %s (%s)",
7789 ftp ? (ftp_host ? ftp_host : "") :
7795 sysidlist[sysindex].sid_name
7799 printw("Communication Device: %s (remote host is %s)",
7801 sysidlist[sysindex].sid_name
7809 if (/* rttflg && */ protocol == PROTO_K) {
7813 streaming && oldwin != -2
7816 #endif /* STREAMING */
7822 xx = (rttdelay + 500) / 1000;
7823 if (xx != oldrtt || rcvtimo != oldtim) {
7825 printw("%02ld / %02d", xx, rcvtimo);
7832 #endif /* CK_TIMERS */
7834 x = (what & W_RECV) ? /* Packet length */
7835 rpktl+(protocol==PROTO_K?1:0) :
7837 if (x != oldlen) { /* But only if it changed. */
7842 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PL, (long) x );
7848 move(CW_PC, 22); /* Packet count (always). */
7850 printw("%d", (what & W_RECV) ? rpackets : spackets);
7853 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PC, (long) spackets );
7858 if (protocol == PROTO_K && !ftp) { /* Window slots */
7865 sprintf(ws,"STREAMING");
7870 #endif /* STREAMING */
7871 if (wcur != oldwin) {
7872 sprintf(ws, "%d of %d", wcur < 1 ? 1 : wcur, wslotn);
7882 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_WS, (long) ws );
7887 errors = retrans + crunched + timeouts;
7888 if (errors != oldtry) { /* Retry count, if changed */
7890 printw("%d",errors);
7893 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PR, (long) errors );
7899 /* Sender's packet type */
7900 if (!ftp && (c != oldtyp && c != 'Y' && c != 'N')) {
7902 sprintf(type, "%c",c);
7907 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PT, (long) type );
7913 switch (c) { /* Now handle specific packet types */
7914 case 'S': /* Beginning of transfer */
7915 fcnt = fbyt = 0L; /* Clear counters */
7919 gtv = -1L; /* And old/new things... */
7920 #endif /* GFTIMER */
7924 case 'Z': /* or EOF */
7925 debug(F101,"screenc SCR_PT Z pktnum","",n);
7926 debug(F101,"screenc SCR_PT Z oldpct","",oldpct);
7927 debug(F101,"screenc SCR_PT Z pct","",pct);
7928 case 'D': /* Data packet */
7929 if (fsiz > 0L) { /* Show percent done if known */
7930 oldpct = pct; /* Remember previous percent */
7933 if (what & W_SEND) /* Account for PSEND or RESEND */
7934 howfar += sendstart;
7935 else if (what & W_RECV)
7937 #endif /* CK_RESEND */
7938 /* Percent done, to be displayed... */
7940 if (!discard && !cxseen && !czseen) pct = 100L;
7942 pct = (fsiz > 99L) ? (howfar / (fsiz / 100L)) : 0L;
7943 if (pct > 100L || /* Allow for expansion and */
7944 (oldpct == 99L && pct < 0L)) /* other boundary conditions */
7946 if (pct != oldpct) /* Only do this 100 times per file */
7947 updpct(oldpct, pct);
7950 printw("%s", ckfstoa(ffc));
7954 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) howfar);
7957 cps = shocps((int) pct, fsiz, howfar);
7958 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
7961 case '%': /* Timeouts, retransmissions */
7962 cps = shocps((int) pct, fsiz, howfar);
7963 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
7965 errors = retrans + crunched + timeouts;
7966 if (errors != oldtry) { /* Error count, if changed */
7968 printw("%d",errors);
7972 KuiSetProperty(KUI_FILE_TRANSFER,
7973 (long) CW_PR, (long) errors
7985 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_ERR, (long) s);
7991 case 'E': /* Error packet */
7993 move(CW_ERR,22); /* Print its data field */
7998 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
8003 #endif /* COMMENT */
8004 fcnt = fbyt = 0L; /* So no bytes for this file */
8006 case 'Q': /* Crunched packet */
8007 cps = shocps((int) pct, fsiz, howfar);
8008 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8010 printw("Damaged Packet");
8013 KuiSetProperty(KUI_FILE_TRANSFER,
8015 (long) "Damaged Packet"
8021 case 'q': /* Ctrl-C or connection lost */
8025 printw(*s ? s : "User interruption or connection lost");
8028 KuiSetProperty(KUI_FILE_TRANSFER,
8035 case 'T': /* Timeout */
8036 cps = shocps((int) pct, fsiz, howfar);
8037 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8039 printw("Timeout %d sec",rcvtimo);
8042 KuiSetProperty(KUI_FILE_TRANSFER,
8049 errors = retrans + crunched + timeouts;
8050 if (errors != oldtry) { /* Error count, if changed */
8052 printw("%d",errors);
8055 KuiSetProperty(KUI_FILE_TRANSFER,
8056 (long) CW_PR, (long) errors
8064 default: /* Others, do nothing */
8073 case SCR_ST: /* File transfer status */
8074 debug(F101,"screenc SCR_ST c","",c);
8075 debug(F101,"screenc SCR_ST success","",success);
8076 debug(F101,"screenc SCR_ST cxseen","",cxseen);
8078 move(CW_PCD,22); /* Update percent done */
8079 if (c == ST_OK) { /* OK, print 100 % */
8083 printw("%s", ckfstoa(ffc));
8086 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8091 } else if (fsiz > 0L) /* Not OK, update final percent */
8093 The else part writes all over the screen -- howfar and/or fsiz have
8094 been reset as a consequence of the not-OKness of the transfer.
8097 updpct(oldpct, (howfar * 100L) / fsiz);
8100 if (c == ST_OK) { /* OK, print 100 % */
8101 move(CW_PCD,22); /* Update percent done */
8103 if (oldpct == 0) /* Switching from "bytes so far" */
8104 clrtoeol(); /* to "percent done"... */
8107 printw("%s", ckfstoa(ffc));
8110 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8116 #endif /* COMMENT */
8119 #endif /* COMMENT */
8122 /* No, leave it there so they can read it */
8123 move(CW_MSG,22); /* Remove any previous message */
8126 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_MSG, (long) "" );
8129 clrtoeol(); refresh();
8130 #endif /* COMMENT */
8135 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "" );
8138 clrtoeol(); refresh();
8140 switch (c) { /* Print new status message */
8141 case ST_OK: /* Transfer OK */
8142 fcnt++; /* Count this file */
8143 if (what == (W_FTP|W_FT_DELE)) {
8146 printw("Delete OK");
8151 printw("Transfer OK");
8155 KuiSetProperty(KUI_FILE_TRANSFER,
8157 (long) "Transfer OK"
8161 clrtoeol(); refresh();
8164 case ST_DISC: /* Discarded */
8166 printw("File discarded");
8169 KuiSetProperty(KUI_FILE_TRANSFER,
8171 (long) "File discarded"
8177 #endif /* COMMENT */
8178 clrtoeol(); refresh();
8181 case ST_INT: /* Interrupted */
8183 printw("Transfer interrupted");
8186 KuiSetProperty(KUI_FILE_TRANSFER,
8188 (long) "Transfer interrupted"
8194 #endif /* COMMENT */
8195 clrtoeol(); refresh();
8198 case ST_SKIP: /* Skipped */
8200 if (n > 0 && n < nskreason)
8201 printw("File skipped (%s)",skreason[n]);
8203 printw("File skipped");
8206 KuiSetProperty(KUI_FILE_TRANSFER,
8208 (long) "File skipped"
8214 #endif /* COMMENT */
8215 clrtoeol(); refresh();
8218 case ST_ERR: /* Error message */
8220 if (!s) s = (char *)epktmsg;
8224 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
8229 #endif /* COMMENT */
8230 clrtoeol(); refresh();
8233 case ST_REFU: /* Refused */
8237 sprintf( errbuf, "Refused, %s", s ) ;
8238 printw("%s", errbuf);
8241 KuiSetProperty(KUI_FILE_TRANSFER,(long) CW_ERR,(long) errbuf);
8248 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Refused");
8254 #endif /* COMMENT */
8255 clrtoeol(); refresh();
8260 printw("Incomplete");
8263 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Incomplete");
8268 #endif /* COMMENT */
8269 clrtoeol(); refresh();
8277 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_MSG,(long)s);
8280 clrtoeol(); refresh();
8283 default: /* Bad call */
8285 printw("*** screen() called with bad status ***");
8288 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR,
8289 (long) "*** screen() called with bad status ***" );
8292 clrtoeol(); refresh(); return;
8295 case SCR_TC: { /* Transaction complete */
8297 move(CW_CP,22); /* Overall transfer rate */
8300 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, tfcps);
8303 printw("%s", ckfstoa(tfcps));
8306 move(CW_MSG,22); /* Print statistics in message line */
8311 "SUCCESS. Files: %ld, Bytes: %s, %ld CPS",
8316 printw("%s", msgbuf);
8319 KuiSetProperty(KUI_FILE_TRANSFER,
8329 printw(" Elapsed Time: %s",hhmmss((long)
8334 #endif /* GFTIMER */
8338 KuiSetProperty(KUI_FILE_TRANSFER,
8340 (long) hhmmss((long)
8345 #endif /* GFTIMER */
8350 move(23,0); clrtoeol(); /* Clear instructions lines */
8351 move(22,0); clrtoeol(); /* to make room for prompt. */
8355 oldgtv = (CKFLOAT) -1.0;
8358 #endif /* GFTIMER */
8361 debug(F100,"screenc endwin A","",0);
8365 Why and when was this call to conres() added? It makes no sense,
8366 and it breaks echoing on Solaris 8.
8370 #endif /* SOLARIS */
8371 #endif /* COMMENT */
8372 #endif /* VMSCURSE */
8375 pct = 100; oldpct = 0; /* Reset these for next time. */
8376 #endif /* COMMENT */
8377 oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
8380 if (xfrbel) bleep(BP_NOTE); /* Close window, then beep. */
8384 ft_win = 0; /* Window closed. */
8387 case SCR_EM: /* Error packet (fatal) */
8389 printw("FAILURE: %s",s);
8392 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
8395 if (xfrbel) bleep(BP_FAIL);
8398 #endif /* COMMENT */
8399 clrtoeol(); refresh(); return;
8401 case SCR_QE: /* Quantity equals */
8402 case SCR_TU: /* Undelimited text */
8403 case SCR_TN: /* Text delimited at start */
8404 case SCR_TZ: /* Text delimited at end */
8405 return; /* (ignored in fullscreen display) */
8407 case SCR_MS: /* Message from Kermit partner */
8410 clrtoeol(); refresh(); return;
8412 case SCR_XD: /* X-packet data */
8418 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
8421 clrtoeol(); refresh(); return;
8423 case SCR_CW: /* Close Window */
8424 clrtoeol(); move(23,0); clrtoeol(); move(22,0); clrtoeol();
8427 pct = 100; oldpct = 0; /* Reset these for next time. */
8428 #endif /* COMMENT */
8429 oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
8433 debug(F100,"screenc endwin B","",0);
8435 #endif /* VMSCURSE */
8436 ft_win = 0; /* Flag that window is closed. */
8439 case SCR_CD: /* Display current directory */
8444 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) s );
8454 default: /* Bad call */
8458 KuiSetProperty(KUI_FILE_TRANSFER,
8460 (long) "*** screen() called with bad function code ***"
8464 printw("*** screen() called with bad function code ***");
8465 clrtoeol(); refresh(); return;
8468 #endif /* CK_CURSES */
8473 screeng(int f, char c,long n,char *s)
8477 int f; /* argument descriptor */
8478 char c; /* a character or small integer */
8479 long n; /* a long integer */
8480 char *s; /* a string */
8481 #endif /* CK_ANSIC */
8484 extern int tls_active_flag, ssl_active_flag;
8487 extern int ttnproto;
8488 #endif /* RLOGCODE */
8490 static CK_OFF_T fsiz = (CK_OFF_T)-1; /* Copy of file size */
8491 static long fcnt = 0L; /* Number of files transferred */
8492 static long fbyt = 0L; /* Total file bytes of all files transferred */
8493 static CK_OFF_T howfar = (CK_OFF_T)0; /* How much of file xfer'd so far */
8494 static int pctlbl = 0L; /* Percent done vs Bytes so far */
8500 int len; /* Length of string */
8501 int errors = 0; /* Error counter */
8504 debug(F101,"screeng cinit","",cinit);
8505 debug(F101,"screeng cendw","",cendw);
8507 if (!s) s = ""; /* Always do this. */
8509 ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit */
8510 net = network || ftp;
8511 xnet = ftp ? 1 : nettype; /* NET_TCPB == 1 */
8513 if (cinit == 0 || cendw > 0) { /* Handle borderline cases... */
8514 if (f == SCR_CW) { /* Close window, but it's not open */
8518 debug(F111,"screeng A",s,f);
8520 (f == SCR_PT && c == 'E')) { /* Fatal error before window open */
8521 conoll(""); conoc('?'); conoll(s); return; /* Regular display */
8524 if (cinit == 0) { /* Only call initscr() once */
8525 /* Check these now -- if they are defined but not numeric */
8526 /* they can crash curses */
8527 cendw = 1; /* New window needs repainting */
8528 debug(F100,"screeng calling initscr","",0);
8529 initscr(); /* Initialize curses. */
8530 debug(F100,"screeng initscr ok","",0);
8531 cinit++; /* Remember curses was initialized. */
8533 ft_win = 1; /* Window is open */
8537 This totally repaints the screen, just what we want, but we can only
8538 do this with real curses, and then only if clearok() and wrefresh() are
8539 provided in the curses library.
8542 #else /* No CK_WREFRESH */
8544 Kermit's do-it-yourself method, works with all types of fullscreen
8545 support, but does not repaint all the fields. For example, the filename
8546 is lost, because it arrives at a certain time and never comes again, and
8547 Kermit presently does not save it anywhere. Making this method work for
8548 all fields would be a rather major recoding task, duplicating what curses
8549 already does, and would add a lot of complexity and storage space.
8552 #endif /* CK_WREFRESH */
8555 if (cendw) { /* endwin() was called previously */
8556 debug(F100,"screeng setup ok","",0);
8557 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) zgtdir() );
8558 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_LIN,
8561 ftp ? (ftp_host ? ftp_host : "(unknown)") :
8569 if (xnet > nnetname)
8572 xname = netname[xnet];
8582 #endif /* SSHBUILTIN */
8583 #ifdef CK_ENCRYPTION
8584 || ck_tn_encrypting() && ck_tn_decrypting()
8585 #endif /* CK_ENCRYPTION */
8587 || tls_active_flag || ssl_active_flag
8591 #ifdef CK_ENCRYPTION
8592 || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
8593 #endif /* CK_ENCRYPTION */
8594 #endif /* CK_KERBEROS */
8595 #endif /* RLOGCODE */
8601 sprintf(buf,"%s (SECURE)",xname);
8602 KuiSetProperty(KUI_FILE_TRANSFER,
8607 KuiSetProperty(KUI_FILE_TRANSFER,
8613 KuiSetProperty(KUI_FILE_TRANSFER,
8617 #endif /* NETCONN */
8622 if (speed == 8880) {
8623 KuiSetProperty(KUI_FILE_TRANSFER,
8629 sprintf(speedbuf, "%ld", speed);
8630 KuiSetProperty(KUI_FILE_TRANSFER,
8636 KuiSetProperty(KUI_FILE_TRANSFER,
8642 KuiSetProperty(KUI_FILE_TRANSFER,
8644 (long) parnam((char)parity)
8646 pctlbl = (what & W_SEND);
8649 debug(F101,"SCREENC switch","",f);
8650 debug(F000,"SCREENC c","",c);
8651 debug(F101,"SCREENC n","",n);
8653 len = strlen(s); /* Length of argument string */
8654 switch (f) { /* Handle our function code */
8655 case SCR_FN: /* Filename */
8656 oldpct = pct = 0L; /* Reset percents */
8658 gtv = (CKFLOAT) -1.0;
8659 /* oldgtv = (CKFLOAT) -1.0; */
8663 #endif /* GFTIMER */
8665 fsiz = (CK_OFF_T)-1L; /* Invalidate previous file size */
8666 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) 0 );
8667 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_FFC, (long) 0 );
8668 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) 0 );
8669 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) "" );
8671 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
8672 q = len; /* Remember name length for later */
8673 scrft(); /* Display file type (can change) */
8679 case SCR_AN: /* File as-name */
8680 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
8686 case SCR_FS: /* File size */
8688 if (fsiz > (CK_OFF_T)-1) {
8689 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) n );
8691 if (fsiz > (CK_OFF_T)-1) { /* Put up percent label */
8696 scrft(); /* File type */
8702 case SCR_PT: /* Packet type or pseudotype */
8704 extern int sysindex;
8705 extern struct sysdata sysidlist[];
8706 /* Things that won't change after the 4th packet */
8707 KuiSetProperty( KUI_FILE_TRANSFER,
8709 (long) parnam((char)parity)
8713 (ftp && (spackets == 1 || rpackets == 1)) ||
8721 ((protocol == PROTO_K) && (sysindex > -1))
8725 sprintf(msgbuf,"Network Host: %s (%s)",
8727 ftp ? (ftp_host ? ftp_host : "") :
8733 sysidlist[sysindex].sid_name
8737 "Communication Device: %s (remote host is %s)",
8739 sysidlist[sysindex].sid_name
8742 KuiSetProperty( KUI_FILE_TRANSFER,
8750 if (/* rttflg && */ protocol == PROTO_K) {
8754 streaming && oldwin != -2
8757 #endif /* STREAMING */
8760 sprintf(msgbuf,"00 / 00");
8761 KuiSetProperty( KUI_FILE_TRANSFER,
8766 xx = (rttdelay + 500) / 1000;
8767 if (xx != oldrtt || rcvtimo != oldtim) {
8769 sprintf(msgbuf,"%02ld / %02d", xx, rcvtimo);
8770 KuiSetProperty( KUI_FILE_TRANSFER,
8780 #endif /* CK_TIMERS */
8782 x = (what & W_RECV) ? /* Packet length */
8783 rpktl+(protocol==PROTO_K?1:0) :
8785 if (x != oldlen) { /* But only if it changed. */
8786 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PL, (long) x );
8789 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PC, (long) spackets );
8791 if (protocol == PROTO_K && !ftp) { /* Window slots */
8798 sprintf(ws,"STREAMING");
8803 #endif /* STREAMING */
8804 if (wcur != oldwin) {
8805 sprintf(ws, "%d of %d", wcur < 1 ? 1 : wcur, wslotn);
8810 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_WS, (long) ws );
8813 errors = retrans + crunched + timeouts;
8814 if (errors != oldtry) { /* Retry count, if changed */
8815 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PR, (long) errors );
8818 /* Sender's packet type */
8819 if (!ftp && (c != oldtyp && c != 'Y' && c != 'N')) {
8821 sprintf(type, "%c",c);
8822 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PT, (long) type );
8825 switch (c) { /* Now handle specific packet types */
8826 case 'S': /* Beginning of transfer */
8827 fcnt = fbyt = 0L; /* Clear counters */
8831 gtv = -1L; /* And old/new things... */
8832 #endif /* GFTIMER */
8836 case 'Z': /* or EOF */
8837 debug(F101,"screeng SCR_PT Z pktnum","",n);
8838 debug(F101,"screeng SCR_PT Z oldpct","",oldpct);
8839 debug(F101,"screeng SCR_PT Z pct","",pct);
8840 case 'D': /* Data packet */
8841 if (fsiz > 0L) { /* Show percent done if known */
8842 oldpct = pct; /* Remember previous percent */
8845 if (what & W_SEND) /* Account for PSEND or RESEND */
8846 howfar += sendstart;
8847 else if (what & W_RECV)
8849 #endif /* CK_RESEND */
8850 /* Percent done, to be displayed... */
8852 if (!discard && !cxseen && !czseen) pct = 100L;
8854 pct = (fsiz > 99L) ? (howfar / (fsiz / 100L)) : 0L;
8855 if (pct > 100L || /* Allow for expansion and */
8856 (oldpct == 99L && pct < 0L)) /* other boundary conditions */
8858 if (pct != oldpct) /* Only do this 100 times per file */
8859 updpct(oldpct, pct);
8861 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8863 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) howfar);
8864 cps = shocps((int) pct, fsiz, howfar);
8865 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8868 case '%': /* Timeouts, retransmissions */
8869 cps = shocps((int) pct, fsiz, howfar);
8870 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8872 errors = retrans + crunched + timeouts;
8873 if (errors != oldtry) { /* Error count, if changed */
8874 KuiSetProperty(KUI_FILE_TRANSFER,
8881 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_ERR, (long) s);
8885 case 'E': /* Error packet */
8887 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
8889 fcnt = fbyt = 0L; /* So no bytes for this file */
8891 case 'Q': /* Crunched packet */
8892 cps = shocps((int) pct, fsiz, howfar);
8893 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8894 KuiSetProperty(KUI_FILE_TRANSFER,
8896 (long) "Damaged Packet"
8899 case 'q': /* Ctrl-C or connection lost */
8901 if (!*s) s = "User interruption or connection lost";
8902 KuiSetProperty(KUI_FILE_TRANSFER,
8907 case 'T': /* Timeout */
8908 cps = shocps((int) pct, fsiz, howfar);
8909 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8910 KuiSetProperty(KUI_FILE_TRANSFER,
8914 errors = retrans + crunched + timeouts;
8915 if (errors != oldtry) { /* Error count, if changed */
8916 KuiSetProperty(KUI_FILE_TRANSFER,
8917 (long) CW_PR, (long) errors
8922 default: /* Others, do nothing */
8930 case SCR_ST: /* File transfer status */
8931 debug(F101,"screeng SCR_ST c","",c);
8932 debug(F101,"screeng SCR_ST success","",success);
8933 debug(F101,"screeng SCR_ST cxseen","",cxseen);
8935 if (c == ST_OK) { /* OK, print 100 % */
8939 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8942 } else if (fsiz > 0L) /* Not OK, update final percent */
8944 The else part writes all over the screen -- howfar and/or fsiz have
8945 been reset as a consequence of the not-OKness of the transfer.
8948 updpct(oldpct, (howfar * 100L) / fsiz);
8950 if (c == ST_OK) { /* OK, print 100 % */
8954 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8958 #endif /* COMMENT */
8960 #endif /* COMMENT */
8962 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "" );
8964 switch (c) { /* Print new status message */
8965 case ST_OK: /* Transfer OK */
8966 fcnt++; /* Count this file */
8967 if (what == (W_FTP|W_FT_DELE)) {
8968 KuiSetProperty(KUI_FILE_TRANSFER,
8974 KuiSetProperty(KUI_FILE_TRANSFER,
8976 (long) "Transfer OK"
8981 case ST_DISC: /* Discarded */
8982 KuiSetProperty(KUI_FILE_TRANSFER,
8984 (long) "File discarded"
8988 #endif /* COMMENT */
8991 case ST_INT: /* Interrupted */
8992 KuiSetProperty(KUI_FILE_TRANSFER,
8994 (long) "Transfer interrupted"
8998 #endif /* COMMENT */
9001 case ST_SKIP: { /* Skipped */
9003 if (n > 0 && n < nskreason)
9004 sprintf( errbuf, "File skipped, (%s)", skreason[n] ) ;
9006 sprintf( errbuf, "File skipped" ) ;
9007 KuiSetProperty(KUI_FILE_TRANSFER,
9013 #endif /* COMMENT */
9016 case ST_ERR: /* Error message */
9017 if (!s) s = (char *)epktmsg;
9018 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
9021 #endif /* COMMENT */
9024 case ST_REFU: /* Refused */
9027 sprintf( errbuf, "Refused, %s", s ) ;
9028 KuiSetProperty(KUI_FILE_TRANSFER,(long) CW_ERR,(long) errbuf);
9030 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Refused");
9034 #endif /* COMMENT */
9038 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Incomplete");
9041 #endif /* COMMENT */
9045 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_MSG,(long)s);
9048 default: /* Bad call */
9049 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR,
9050 (long) "*** screen() called with bad status ***" );
9054 case SCR_TC: { /* Transaction complete */
9056 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, tfcps);
9059 "SUCCESS. Files: %s, Bytes: %ld, %ld CPS",
9064 KuiSetProperty(KUI_FILE_TRANSFER,
9069 KuiSetProperty(KUI_FILE_TRANSFER,
9071 (long) hhmmss((long)
9076 #endif /* GFTIMER */
9080 oldgtv = (CKFLOAT) -1.0;
9083 #endif /* GFTIMER */
9086 pct = 100; oldpct = 0; /* Reset these for next time. */
9087 #endif /* COMMENT */
9088 oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
9091 if (xfrbel) bleep(BP_NOTE); /* Close window, then beep. */
9092 ft_win = 0; /* Window closed. */
9095 case SCR_EM: /* Error packet (fatal) */
9096 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
9097 if (xfrbel) bleep(BP_FAIL);
9100 #endif /* COMMENT */
9103 case SCR_QE: /* Quantity equals */
9104 case SCR_TU: /* Undelimited text */
9105 case SCR_TN: /* Text delimited at start */
9106 case SCR_TZ: /* Text delimited at end */
9107 return; /* (ignored in fullscreen display) */
9109 case SCR_XD: /* X-packet data */
9111 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
9114 case SCR_CW: /* Close Window */
9116 pct = 100; oldpct = 0; /* Reset these for next time. */
9117 #endif /* COMMENT */
9118 oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
9121 ft_win = 0; /* Flag that window is closed. */
9124 case SCR_CD: /* Display current directory */
9125 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) s );
9131 default: /* Bad call */
9132 KuiSetProperty(KUI_FILE_TRANSFER,
9134 (long) "*** screen() called with bad function code ***"
9145 /* Dummies for when cursor control is not supported */
9147 ck_curpos(row, col) {
9160 #endif /* CK_CURPOS */
9165 struct iksdbfld dbfld[] = {
9166 /* Offset Length Type */
9167 { DB_FLAGS, dB_FLAGS, DBT_HEX }, /* 0 db_FLAGS Flags */
9168 { DB_ATYPE, dB_ATYPE, DBT_HEX }, /* 1 db_ATYPE Auth type */
9169 { DB_AMODE, dB_AMODE, DBT_HEX }, /* 3 db_AMODE Auth mode */
9170 { DB_STATE, dB_STATE, DBT_HEX }, /* 2 db_STATE State */
9171 { DB_MYPID, dB_MYPID, DBT_HEX }, /* 5 db_MYPID PID */
9172 { DB_SADDR, dB_SADDR, DBT_HEX }, /* 4 db_SADDR Server address */
9173 { DB_CADDR, dB_CADDR, DBT_HEX }, /* 6 db_CADDR Client address */
9174 { DB_START, dB_START, DBT_DAT }, /* 7 db_START Session start */
9175 { DB_LASTU, dB_LASTU, DBT_DAT }, /* 8 db_LASTU Last update */
9176 { DB_ULEN, dB_ULEN, DBT_HEX }, /* 9 db_ULEN Username length */
9177 { DB_DLEN, dB_DLEN, DBT_HEX }, /* 10 db_DLEN Directory name length */
9178 { DB_ILEN, dB_ILEN, DBT_HEX }, /* 11 db_ILEN Info length */
9179 { DB_PAD1, dB_PAD1, DBT_UND }, /* 12 db_PAD1 (Reserved) */
9180 { DB_USER, dB_USER, DBT_STR }, /* 13 db_USER Username */
9181 { DB_DIR, dB_DIR, DBT_STR }, /* 14 db_DIR Current Directory */
9182 { DB_INFO, dB_INFO, DBT_STR } /* 15 db_INFO State-specific info */
9185 static char lcknam[CKMAXPATH+1]; /* Lockfile pathname */
9186 static char tmplck[CKMAXPATH+1]; /* Temporary lockfile name */
9188 static char * updmode = /* Update mode for fopen() */
9200 /* D B I N I T -- Initialize the IKSD database... */
9204 extern int dbinited;
9206 debug(F110,"dbinit dbdir 1",dbdir,0);
9207 debug(F110,"dbinit dbfile 1",dbfile,0);
9215 p = getenv("SystemRoot");
9217 p = getenv("winbootdir");
9218 if (!p) p = getenv("windir");
9221 dbdir = malloc(strlen(p)+2);
9222 strcpy(dbdir,p); /* safe */
9229 if (*(p-1) != '/' ) {
9234 makestr(&dbdir,"C:/");
9239 makestr(&dbdir,IK_DBASEDIR);
9245 if (dbdir[x-1] != '/') {
9249 x += (int)strlen(IK_DBASEFIL);
9250 dbfile = (char *)malloc(x+1);
9251 sprintf(dbfile,"%s%s%s",dbdir,s,IK_DBASEFIL);
9253 debug(F110,"dbinit dbdir 2",dbdir,0);
9254 debug(F110,"dbinit dbfile 2",dbfile,0);
9255 mypid = getpid(); /* Get my pid */
9256 debug(F101,"dbinit mypid","",mypid);
9258 if (!myhexip[0]) { /* Set my hex IP address */
9260 extern unsigned long myxipaddr;
9261 if (getlocalipaddr() > -1) {
9263 sprintf(myhexip,"%08lx",myip); /* (Needs fixing for IPv6) */
9265 #endif /* TCPSOCKET */
9266 ckstrncpy(myhexip,"00000000",9);
9268 debug(F111,"dbinit myip",myhexip,myip);
9269 if (!peerhexip[0]) { /* Get peer's hex IP address */
9271 extern unsigned long peerxipaddr;
9273 peerip = peerxipaddr;
9274 sprintf(peerhexip,"%08lx",peerip); /* (Needs fixing for IPv6) */
9275 debug(F111,"dbinit peerip",peerhexip,peerip);
9277 debug(F101,"dbinit ckgetpeer failure","",errno);
9278 ckstrncpy(peerhexip,"00000000",9);
9281 ckstrncpy(peerhexip,"00000000",9);
9282 #endif /* TCPSOCKET */
9284 debug(F111,"dbinit peerip",peerhexip,peerip);
9285 debug(F101,"dbinit dbenabled","",dbenabled);
9286 if (dbenabled && inserver) {
9287 mydbslot = getslot();
9288 debug(F111,"dbinit getslot",ckitoa(ikdbopen),x);
9289 if (ikdbopen) dbinited = 1;
9294 /* U P D S L O T -- Update slot n */
9297 Opens the database if necessary, seeks to slot n, writes current record
9298 and adds current time to last-update field. n is the record sequence number
9299 (0, 1, 2, ...), not the seek pointer. Returns -1 on failure, 0 on success.
9302 updslot(n) int n; { /* Update our slot */
9306 debug(F111,"updslot","ikdbopen",ikdbopen);
9307 if (!ikdbopen) /* Not if not ok */
9309 if (!dbfp) { /* Open database if not open */
9310 dbfp = fopen(dbfile,updmode); /* In update no-truncate mode */
9312 debug(F110,"updslot fopen failed",dbfile,0);
9317 /* debug(F111,"updslot dbfile",dbfile,dbfp); */
9318 position = n * DB_RECL;
9319 if (CKFSEEK(dbfp,position,0) < 0) { /* Seek to desired slot */
9320 debug(F111,"updslot fseek failed",dbfile,mydbseek);
9324 /* Update the update time */
9325 strncpy(&dbrec[dbfld[db_LASTU].off],
9329 if (fwrite(dbrec,1,DB_RECL,dbfp) < DB_RECL) { /* Write the record */
9330 debug(F110,"updslot fwrite failed",dbfile,0);
9333 } else { /* Flush the write */
9340 /* I N I T S L O T -- Initialize slot n with my info */
9343 initslot(n) int n; { /* Initialize slot */
9346 extern unsigned long peerxipaddr;
9347 #endif /* TCPSOCKET */
9349 debug(F101,"initslot","",n);
9352 memset(dbrec,32,DB_RECL);
9354 for (k = 0; k < DB_RECL; k++)
9356 #endif /* USE_MEMCPY */
9358 myflags = DBF_INUSE; /* Set in-use flag */
9359 mystate = W_NOTHING;
9363 k = dbfld[db_FLAGS].len; /* Length of flags field */
9364 strncpy(&dbrec[dbfld[db_FLAGS].off],ulongtohex(myflags,k),k);
9366 k = dbfld[db_ATYPE].len;
9367 strncpy(&dbrec[dbfld[db_ATYPE].off],ulongtohex(myatype,k),k);
9369 k = dbfld[db_AMODE].len;
9370 strncpy(&dbrec[dbfld[db_AMODE].off],ulongtohex(myamode,k),k);
9372 k = dbfld[db_STATE].len;
9373 strncpy(&dbrec[dbfld[db_STATE].off],ulongtohex(mystate,k),k);
9375 k = dbfld[db_SADDR].len;
9376 strncpy(&dbrec[dbfld[db_SADDR].off],ulongtohex(myip,k),k);
9380 k = dbfld[db_CADDR].len;
9381 strncpy(&dbrec[dbfld[db_CADDR].off],ulongtohex(peerxipaddr,k),k);
9383 k = dbfld[db_CADDR].len;
9384 strncpy(&dbrec[dbfld[db_CADDR].off],ulongtohex(0L,k),k);
9385 #endif /* TCPSOCKET */
9387 k = dbfld[db_MYPID].len;
9388 strncpy(&dbrec[dbfld[db_MYPID].off],ulongtohex(mypid,k),k);
9390 k = dbfld[db_START].len;
9391 strncpy(&dbrec[dbfld[db_START].off],ckdate(),k);
9393 k = dbfld[db_ULEN].len;
9394 strncpy(&dbrec[dbfld[db_ULEN].off],"0000",4);
9396 k = dbfld[db_DLEN].len;
9397 strncpy(&dbrec[dbfld[db_DLEN].off],"0000",4);
9399 k = dbfld[db_ILEN].len;
9400 strncpy(&dbrec[dbfld[db_ILEN].off],"0000",4);
9402 strncpy(&dbrec[dbfld[db_INFO].off],"INIT",4);
9407 slotstate(x,s1,s2,s3) int x; char *s1, *s2, *s3; {
9408 int k, l1, l2, l3, z;
9410 debug(F101,"slotstate ikdbopen","",ikdbopen);
9419 strncpy(&dbrec[DB_STATE],ulongtohex(mystate,4),4);
9420 k = dbfld[db_ILEN].len;
9421 z = l1 + l2 + l3 + 2;
9424 strncpy(&dbrec[DB_ILEN],ulongtohex((unsigned long)z,k),k);
9425 k = dbfld[db_INFO].len;
9426 z = dbfld[db_INFO].off;
9428 lset(&dbrec[z],s1,l1+1,32);
9432 lset(&dbrec[z],s2,l2+1,32);
9436 lset(&dbrec[z],s3,k,32);
9443 strncpy(buf,&dbrec[DB_INFO],127);
9445 for (i = 126; i > 0 && buf[i] == 32; i--) buf[i] = 0;
9446 debug(F111,"slotstate",buf,mystate);
9449 z = updslot(mydbslot);
9450 debug(F101,"slotstate updslot","",z);
9455 slotdir(s1,s2) char * s1, * s2; { /* Update current directory */
9463 k = dbfld[db_DLEN].len;
9464 strncpy(&dbrec[DB_DLEN],ulongtohex((unsigned long)(len1+len2),k),k);
9465 k = dbfld[db_DIR].len;
9467 lset(&dbrec[dbfld[db_DIR].off],s1,len1,32);
9468 lset(&dbrec[dbfld[db_DIR].off+len1],s2,k-len1,32);
9470 lset(&dbrec[dbfld[db_DIR].off],s2,k,32);
9472 return(updslot(mydbslot));
9475 /* F R E E S L O T -- Free slot n */
9478 freeslot(n) int n; {
9483 if (n == mydbslot) {
9484 dbflags = myflags & ~DBF_INUSE;
9485 dbflags &= ~DBF_LOGGED;
9487 k = dbfld[db_FLAGS].len;
9488 strncpy(&dbrec[dbfld[db_FLAGS].off],ulongtohex(dbflags,k),k);
9492 /* G E T S L O T -- Find a free database slot; returns slot number */
9495 #include <fcntl.h> /* For creat() */
9499 getslot() { /* Find a free slot for us */
9500 FILE * rfp = NULL; /* Returns slot number (0, 1, ...) */
9501 char idstring[64]; /* PID string buffer (decimal) */
9502 char pidbuf[64], * s;
9503 int j, k, n, x, rc = -1;
9504 int lockfd, tries, haveslot = 0;
9507 /* char ipbuf[17]; */
9509 if (!myhexip[0]) /* Set my hex IP address if not set */
9510 ckstrncpy((char *)myhexip,"7F000001",33);
9511 sprintf(idstring,"%08lx:%010ld\n",myip,mypid);
9512 debug(F110,"getslot idstring", idstring, 0);
9514 /* Make temporary lockfile name IP.PID (hex.hex) */
9515 /* This should fit in 14 chars -- huge PIDs are usually not possible */
9516 /* on 14-char filename systems. */
9518 sprintf(tmplck,"%s%08lx.%lx",dbdir,myip,mypid);
9519 debug(F110,"getslot tempfile",tmplck,0);
9521 /* Make a temporary file */
9523 lockfd = creat(tmplck, 0600); /* BUT THIS ISN'T PORTABLE */
9525 debug(F111,"getslock temp lockfile create failure", tmplck, errno);
9528 /* Write my (decimal) PID into the temp file */
9530 write(lockfd,idstring,(int)strlen(idstring));
9531 if (close(lockfd) < 0) { /* Close lockfile */
9532 debug(F101,"getslot error closing temp lockfile", "", errno);
9535 sprintf(lcknam,"%s%s",dbdir,IK_LOCKFILE); /* Build lockfile name */
9536 debug(F110,"getslot lockfile",lcknam,0);
9538 rfp = fopen(lcknam,"r"); /* See if lockfile exists */
9539 if (rfp) { /* If so... */
9540 rset(pidbuf,"",64,0);
9541 x = fread(pidbuf,1,63,rfp); /* Read ID string from it */
9542 fclose(rfp); /* and close it quickly */
9543 debug(F110,"getslot lock exists",pidbuf,0);
9544 if (x > 0) { /* If we have a PID, check it */
9547 if (islower(*s)) *s = toupper(*s);
9550 debug(F110,"getslot lock IP",pidbuf,0);
9551 debug(F110,"gteslot my IP",myhexip,0);
9552 if (!strcmp(pidbuf,myhexip)) { /* Same IP address? */
9553 lockpid = atol(s+1); /* Yes, now get PID */
9554 debug(F101,"getslot lockpid","",lockpid);
9556 /* Check if PID lockpid on this computer is alive */
9557 x = zchkpid(lockpid);
9559 debug(F100,"getslot PID stale,removing lock","",0);
9568 debug(F111,"getslot lockfile open failure",lcknam,errno);
9571 /* Try IK_LCKTRIES (16) times to rename temp file to lockfile */
9573 for (tries = IK_LCKTRIES; tries > 0; tries--) {
9574 if (zrename(tmplck,lcknam) == 0)
9576 debug(F101,"getslot database locked by pid", "", dbpid);
9579 if (tries < 1) { /* Couldn't */
9580 debug(F110,"getslot create lock failure",lcknam,0);
9583 /* Have lock, open database */
9585 debug(F110,"getslot has lock",lcknam,0); /* Have lock */
9590 /* If database doesn't exist, create it. */
9592 debug(F110,"getslot dbfile",dbfile,0);
9593 if (zchki(dbfile) < 0) {
9594 debug(F110,"getslot creating new database",dbfile,0);
9595 x = creat(dbfile,0660);
9597 debug(F111,"getslot creat() failed", dbfile, errno);
9602 dbfp = fopen(dbfile,updmode); /* Open it in update mode */
9604 debug(F111,"getslot fopen failed",dbfile,errno);
9607 /* Now find a free (or new) slot... */
9609 dblastused = 0L; /* Seek pointer to last record inuse */
9610 mydbseek = 0L; /* Seek pointer for my record */
9612 /* Quickly read the whole database; n = record counter, i = seek pointer */
9614 for (n = 0, i = 0; !feof(dbfp); i += DB_RECL, n++) {
9615 x = fread(dbrec,1,DB_RECL,dbfp); /* Read a record */
9616 if (x < 1) /* EOF not caught by feof() */
9619 if (x != DB_RECL) { /* Watch out for trailing junk */
9620 debug(F101,"getslot bad size","",x); /* (Shouldn't happen...) */
9622 chsize(fileno(dbfp),i);
9624 ftruncate(fileno(dbfp),(CK_OFF_T)i);
9625 #endif /* COHERENT */
9630 #endif /* NOFTRUNCATE */
9631 debug(F101,"getslot record","",n);
9632 k = dbfld[db_FLAGS].off;
9633 j = dbfld[db_FLAGS].len;
9634 dbflags = hextoulong(&dbrec[k],j);
9635 debug(F001,"getslot dbflags","",dbflags);
9636 k = dbfld[db_MYPID].off;
9637 j = dbfld[db_MYPID].len;
9638 dbpid = hextoulong(&dbrec[k],j);
9639 debug(F001,"getslot dbpid","",dbpid);
9640 k = dbfld[db_SADDR].off;
9641 j = dbfld[db_SADDR].len;
9642 dbip = hextoulong(&dbrec[k],j);
9643 debug(F001,"getslot dbip","",dbip);
9645 if (dbflags & DBF_INUSE) { /* Remember last slot in use */
9646 x = 0; /* Make sure it's REALLY in use */
9647 if (dbpid == mypid && dbip == myip) { /* Check for PID == my PID */
9649 debug(F101,"getslot record pid","",dbpid);
9650 } else { /* Or for stale PID */
9652 debug(F101,"getslot zchkpid()","",x);
9654 if (!x) { /* Bogus record */
9656 debug(F101,"getslot stale record pid: freeslot()","",x);
9657 if (x > -1 && !haveslot)
9659 } else { /* It's really in use */
9663 if (!haveslot) { /* If I don't have a slot yet */
9664 if (!(dbflags & DBF_INUSE)) { /* Claim this one */
9665 debug(F101,"getslot free slot", "", n);
9668 mydbslot = n; /* But keep going... */
9672 /* Come here with i == seek pointer to first record after eof */
9674 if (!haveslot) { /* Found no free slot so add to end */
9675 debug(F101,"getslot new slot","",n);
9680 ikdbopen = 1; /* OK to make database entries */
9681 debug(F101,"getslot records","",n);
9682 debug(F101,"getslot dblastused","",dblastused);
9683 debug(F101,"getslot i","",i);
9685 /* Trim stale records from end */
9688 if (i > dblastused+DB_RECL) {
9689 debug(F101,"getslot truncating at","",dblastused+DB_RECL);
9691 x = chsize(fileno(dbfp),dblastused+DB_RECL);
9693 x = ftruncate(fileno(dbfp),(CK_OFF_T)(dblastused+DB_RECL));
9694 #endif /* COHERENT */
9695 if (x < 0) /* (Not fatal) */
9696 debug(F101,"getslot ftruncate failed", "", errno);
9698 #endif /* NOFTRUNCATE */
9700 /* Initialize my record */
9702 if (initslot(mydbslot) < 0) {
9703 debug(F101,"getslot initslot() error","",n);
9707 debug(F101,"getslot OK","",mydbslot);
9708 rc = mydbslot; /* OK return code */
9710 xslot: /* Unlock the database and return */
9711 if (unlink(lcknam) < 0) {
9712 debug(F111,"getslot lockfile removal failed",lcknam,errno);