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[];
2365 extern long dialcapas;
2366 extern MDMINF * modemp[];
2371 debug(F101,"setflow autoflow","",autoflow);
2373 /* #ifdef COMMENT */
2374 /* WHY WAS THIS COMMENTED OUT? */
2375 if (!autoflow) /* Only if FLOW is AUTO */
2377 /* #endif */ /* COMMENT */
2379 debug(F101,"setflow local","",local);
2380 debug(F101,"setflow network","",network);
2381 debug(F101,"setflow cxtype","",cxtype);
2384 if (network && istncomport()) {
2385 flow = cxflow[CXT_MODEM];
2386 debug(F101,"setflow TN_COMPORT flow","",flow);
2389 #endif /* TN_COMPORT */
2391 if (network || !local || cxtype == CXT_DIRECT) {
2392 flow = cxflow[cxtype]; /* Set appropriate flow control */
2393 debug(F101,"setflow flow","",flow);
2396 if (cxtype != CXT_MODEM) /* Connection type should be modem */
2400 bits = dialcapas; /* Capability bits */
2401 if (!bits) { /* No bits? */
2402 p = modemp[mdmtyp]; /* Look in modem info structure */
2406 if (dialfc == FLO_AUTO) { /* If DIAL flow is AUTO */
2407 #ifdef CK_RTSCTS /* If we can do RTS/CTS flow control */
2408 if (bits & CKD_HW) /* and modem can do it too */
2409 flow = FLO_RTSC; /* then switch to RTS/CTS */
2410 else /* otherwise */
2411 flow = FLO_XONX; /* use Xon/Xoff. */
2415 flow = FLO_XONX; /* Use Xon/Xoff. */
2418 #endif /* CK_RTSCTS */
2421 debug(F101,"setflow modem flow","",flow);
2428 /* A U T O E X I T C H K -- Check for CONNECT-mode trigger string */
2430 Returns -1 if trigger not found, or else the trigger index, 0 or greater.
2431 (Replace with fancier and more efficient matcher later...)
2432 NOTE: to prevent unnecessary function call overhead, call this way:
2434 x = tt_trigger[0] ? autoexitchk(c) : -1;
2441 autoexitchk(c) CHAR c;
2442 #endif /* CK_ANSIC */
2444 extern CHAR * tt_trmatch[];
2445 extern char * tt_trigger[];
2447 for (i = 0; i < TRIGGERS; i++) {
2448 if (!tt_trigger[i]) { /* No more triggers in list */
2450 } else if (*tt_trigger[i]) {
2451 if (!tt_trmatch[i]) /* Just starting? */
2452 tt_trmatch[i] = (CHAR *)tt_trigger[i]; /* Set match pointer */
2453 if (c == *tt_trmatch[i]) { /* Compare this character */
2454 tt_trmatch[i]++; /* It matches */
2455 if (!*tt_trmatch[i]) { /* End of match string? */
2456 tt_trmatch[i] = (CHAR *) tt_trigger[i]; /* Yes, rewind, */
2457 debug(F101,"autoexitchk",tt_trigger[i],i); /* log, */
2458 return(i); /* and return success */
2460 } else /* No match */
2461 tt_trmatch[i] = (CHAR *) tt_trigger[i]; /* Rewind match string */
2462 } /* and go on the next match string */
2464 return(-1); /* No match found */
2466 #endif /* CK_TRIGGER */
2469 /* S H O M D M -- Show modem signals */
2474 Note use of "\r\n" to make sure this report prints right, even when
2475 called during CONNECT mode.
2481 "Modem signals unavailable in this version of Kermit\r\n");
2483 case -2: printf("No modem control for this device\r\n"); break;
2484 case -1: printf("Modem signals unavailable\r\n"); break;
2488 " Carrier Detect (CD): %s\r\n",(y & BM_DCD) ? "On": "Off");
2490 " Dataset Ready (DSR): %s\r\n",(y & BM_DSR) ? "On": "Off");
2493 " Clear To Send (CTS): %s\r\n",(y & BM_CTS) ? "On": "Off");
2497 " Ring Indicator (RI): %s\r\n",(y & BM_RNG) ? "On": "Off");
2500 " Data Terminal Ready (DTR): %s\r\n",
2504 (y & BM_DTR) ? "On": "Off"
2509 " Request To Send (RTS): %s\r\n",
2513 (y & BM_RTS) ? "On": "Off"
2517 #endif /* STRATUS */
2521 if (tttapi && !tapipass) {
2522 LPDEVCFG lpDevCfg = NULL;
2523 LPCOMMCONFIG lpCommConfig = NULL;
2524 LPMODEMSETTINGS lpModemSettings = NULL;
2527 if (cktapiGetModemSettings(&lpDevCfg,&lpModemSettings,
2528 &lpCommConfig,&lpDCB)) {
2530 cktapiDisplayModemSettings(lpDevCfg,lpModemSettings,
2531 lpCommConfig,lpDCB);
2534 #endif /* CK_TAPI */
2535 #endif /* BETADEBUG */
2538 #endif /* NOLOCAL */
2541 /* S D E B U -- Record spar results in debugging log */
2544 sdebu(len) int len; {
2545 debug(F111,"spar: data",(char *) rdatap,len);
2546 debug(F101," spsiz ","", spsiz);
2547 debug(F101," timint","",timint);
2548 debug(F101," npad ","", npad);
2549 debug(F101," padch ","", padch);
2550 debug(F101," seol ","", seol);
2551 debug(F101," ctlq ","", ctlq);
2552 debug(F101," ebq ","", ebq);
2553 debug(F101," ebqflg","",ebqflg);
2554 debug(F101," bctr ","", bctr);
2555 debug(F101," rptq ","", rptq);
2556 debug(F101," rptflg","",rptflg);
2557 debug(F101," lscapu","",lscapu);
2558 debug(F101," atcapu","",atcapu);
2559 debug(F101," lpcapu","",lpcapu);
2560 debug(F101," swcapu","",swcapu);
2561 debug(F101," wslotn","", wslotn);
2562 debug(F101," whatru","", whatru);
2564 /* R D E B U -- Debugging display of rpar() values */
2567 rdebu(d,len) CHAR *d; int len; {
2568 debug(F111,"rpar: data",d,len);
2569 debug(F101," rpsiz ","", xunchar(d[0]));
2570 debug(F101," rtimo ","", rtimo);
2571 debug(F101," mypadn","",mypadn);
2572 debug(F101," mypadc","",mypadc);
2573 debug(F101," eol ","", eol);
2574 debug(F101," ctlq ","", ctlq);
2575 debug(F101," sq ","", sq);
2576 debug(F101," ebq ","", ebq);
2577 debug(F101," ebqflg","",ebqflg);
2578 debug(F101," bctr ","", bctr);
2579 debug(F101," rptq ","", d[8]);
2580 debug(F101," rptflg","",rptflg);
2581 debug(F101," capas ","", capas);
2582 debug(F101," bits ","",d[capas]);
2583 debug(F101," lscapu","",lscapu);
2584 debug(F101," atcapu","",atcapu);
2585 debug(F101," lpcapu","",lpcapu);
2586 debug(F101," swcapu","",swcapu);
2587 debug(F101," wslotr","", wslotr);
2588 debug(F101," rpsiz(extended)","",rpsiz);
2592 /* C H K E R R -- Decide whether to exit upon a protocol error */
2596 if (backgrd && !server) fatal("Protocol error");
2598 #endif /* COMMENT */
2601 /* F A T A L -- Fatal error message */
2604 fatal(msg) char *msg; {
2606 static int initing = 0;
2608 debug(F111,"fatal",msg,initflg);
2610 if (!initflg) { /* If called from prescan */
2611 if (initing) /* or called from sysinit() */
2617 debug(F111,"fatal",msg,xitsta);
2618 tlog(F110,"Fatal:",msg,0L);
2620 if (strncmp(msg,"%CKERMIT",8))
2621 conol("%CKERMIT-E-FATAL, ");
2636 doexit(BAD_EXIT,xitsta | 1); /* Exit indicating failure */
2640 /* B L D L E N -- Make length-encoded copy of string */
2643 bldlen(str,dest) char *str, *dest; {
2645 len = (int)strlen(str);
2649 *dest = (char) tochar(len);
2650 strcpy(dest+1,str); /* Checked below in setgen() */
2655 /* S E T G E N -- Construct a generic command */
2657 Call with Generic command character followed by three string arguments.
2658 Trailing strings are allowed to be empty (""). Each string except the last
2659 non-empty string must be less than 95 characters long. The final nonempty
2660 string is allowed to be longer.
2664 setgen(char type, char * arg1, char * arg2, char * arg3)
2666 setgen(type,arg1,arg2,arg3) char type, *arg1, *arg2, *arg3;
2667 #endif /* CK_ANSIC */
2672 if (!(cmdstr = malloc(MAXSP + 1)))
2673 fatal("setgen: can't allocate memory");
2674 #endif /* DYNAMIC */
2679 if (!arg1) arg1 = "";
2680 if (!arg2) arg2 = "";
2681 if (!arg3) arg3 = "";
2682 if (((int)strlen(arg1)+(int)strlen(arg2)+(int)strlen(arg3)+4) < MAXSP) {
2684 upstr = bldlen(arg1,cp);
2686 upstr = bldlen(arg2,upstr);
2687 if (*arg3 != NUL) bldlen(arg3,upstr);
2691 debug(F110,"setgen",cmarg,0);
2699 static char *mgbufp = NULL;
2701 /* F N P A R S E -- */
2704 Argument is a character string containing one or more filespecs.
2705 This function breaks the string apart into an array of pointers, one
2706 to each filespec, and returns the number of filespecs. Used by server
2707 when it receives a GET command to allow it to process multiple file
2708 specifications in one transaction. Sets cmlist to point to a list of
2709 file pointers, exactly as if they were command line arguments.
2711 This version of fnparse treats spaces as filename separators. If your
2712 operating system allows spaces in filenames, you'll need a different
2715 This version of fnparse mallocs a string buffer to contain the names. It
2716 cannot assume that the string that is pointed to by the argument is safe.
2719 fnparse(string) char *string; {
2721 int r = 0, x; /* Return code */
2723 debug(F111,"fnparse",string,recursive);
2724 #endif /* RECURSIVE */
2726 if (mgbufp) free(mgbufp); /* Free this from last time. */
2727 mgbufp = malloc((int)strlen(string)+2);
2729 debug(F100,"fnparse malloc error","",0);
2734 ckstrncpy(fspec,string,fspeclen); /* Make copy for \v(filespec) */
2737 s = string; /* Input string */
2738 p = q = mgbufp; /* Point to the copy */
2739 r = 0; /* Initialize our return code */
2740 while (*s == SP || *s == HT) /* Skip leading spaces and tabs */
2742 for (x = strlen(s); /* Strip trailing spaces */
2743 (x > 1) && (s[x-1] == SP || s[x-1] == HT);
2746 while (1) { /* Loop through rest of string */
2747 if (*s == CMDQ) { /* Backslash (quote character)? */
2748 if ((x = xxesc(&s)) > -1) { /* Go interpret it. */
2749 *q++ = (char) x; /* Numeric backslash code, ok */
2750 } else { /* Just let it quote next char */
2751 s++; /* get past the backslash */
2752 *q++ = *s++; /* deposit next char */
2755 } else if (*s == SP || *s == NUL) { /* Unquoted space or NUL? */
2756 *q++ = NUL; /* End of output filename. */
2757 msfiles[r] = p; /* Add this filename to the list */
2758 debug(F111,"fnparse",msfiles[r],r);
2760 if (*s == NUL) break; /* End of string? */
2761 while (*s == SP) s++; /* Skip repeated spaces */
2762 p = q; /* Start of next name */
2764 } else *q++ = *s; /* Otherwise copy the character */
2765 s++; /* Next input character */
2767 debug(F101,"fnparse r","",r);
2768 msfiles[r] = ""; /* Put empty string at end of list */
2772 #endif /* NOMSEND */
2774 char * /* dbchr() for DEBUG SESSION */
2780 if (c & 0x80) { /* 8th bit on */
2784 if (c < SP) { /* Control character */
2786 *cp++ = (char) ctl(c);
2787 } else if (c == DEL) {
2790 } else { /* Printing character */
2793 *cp = '\0'; /* Terminate string */
2794 cp = s; /* Return pointer to it */
2798 /* C K H O S T -- Get name of local host (where C-Kermit is running) */
2801 Call with pointer to buffer to put hostname in, and length of buffer.
2802 Copies hostname into buffer on success, puts null string in buffer on
2813 #include <sys/utsname.h>
2818 #include <utsname.h>
2819 #endif /* BELLV10 */
2820 #endif /* SVORPOSIX*/
2823 extern char uidbuf[], * clienthost;
2824 #endif /* CKSYSLOG */
2827 ckhost(vvbuf,vvlen) char * vvbuf; int vvlen; {
2833 #endif /* NOSERVER */
2838 #else /* Everything else - rest of this routine */
2850 struct utsname hname;
2851 #endif /* APOLLOSR10 */
2852 #endif /* _386BSD */
2854 #endif /* SVORPOSIX */
2856 int ac0 = (char *) vvbuf, ac1 = -1, ac2 = 0;
2857 #endif /* datageneral */
2860 if (getenv("CK_NOPUSH")) { /* No shell access allowed */
2861 nopush = 1; /* on this host... */
2864 #endif /* NOSERVER */
2868 *vvbuf = NUL; /* How let's get our host name ... */
2870 #ifndef BELLV10 /* Does not have gethostname() */
2874 ckstrncpy(vvbuf,"Apollo",vvlen);
2877 if (gethostname(vvbuf,vvlen) < 0)
2881 if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
2885 if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
2887 if (uname(&hname) > -1) ckstrncpy(vvbuf,hname.nodename,vvlen);
2888 #endif /* TCPSOCKET */
2889 #else /* SVORPOSIX but not _386BSD or BSD44 */
2891 if (uname(&hname) > -1) ckstrncpy(vvbuf,hname.nodename,vvlen);
2893 if (uname(&hname) > -1) {
2897 #ifndef NOCKGETFQHOST
2898 if (!ckstrchr(p,'.'))
2899 p = (char *)ckgetfqhostname(p);
2900 #endif /* NOCKGETFQHOST */
2901 #endif /* TCPSOCKET */
2903 if (!*p) p = "(unknown)";
2904 ckstrncpy(vvbuf,p,vvlen);
2906 #endif /* __ia64__ */
2908 #endif /* _386BSD */
2910 #endif /* APOLLOSR10 */
2911 #else /* !SVORPOSIX */
2913 if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL;
2916 g = getenv("SYS$NODE");
2917 if (g) ckstrncpy(vvbuf,g,vvlen);
2918 x = (int)strlen(vvbuf);
2919 if (x > 1 && vvbuf[x-1] == ':' && vvbuf[x-2] == ':') vvbuf[x-2] = NUL;
2922 if (sys($HNAME,&ac0,&ac1,&ac2) == 0) /* successful */
2923 vvlen = ac2 + 1; /* enh - have to add one */
2925 #ifdef OS2 /* OS/2 */
2926 g = os2_gethostname();
2927 if (g) ckstrncpy(vvbuf,g,vvlen);
2931 if (gethostname(vvbuf, vvlen) < 0) *vvbuf = NUL;
2932 #endif /* TCPSOCKET */
2935 #endif /* datageneral */
2938 #endif /* SVORPOSIX */
2940 /* If TCP/IP is not installed, gethostname() fails, use uname() */
2941 if (gethostname(vvbuf,vvlen) < 0) {
2942 if (uname(&hname) > -1)
2943 ckstrncpy(vvbuf,hname.nodename,vvlen);
2948 #endif /* BELLV10 */
2949 if (*vvbuf == NUL) { /* If it's still empty */
2950 g = getenv("HOST"); /* try this */
2951 if (g) ckstrncpy(vvbuf,g,vvlen);
2953 vvbuf[vvlen-1] = NUL; /* Make sure result is terminated. */
2962 A S K M O R E -- Poor person's "more".
2963 Returns 0 if no more, 1 if more wanted.
2970 extern int timelimit;
2974 #endif /* IKSDCONF */
2976 extern int apcstatus, apcactive;
2985 if (inserver && !iksdcf)
2987 #endif /* IKSDCONF */
2989 if (apcactive == APC_LOCAL ||
2990 (apcactive == APC_REMOTE && (apcstatus & APC_NOINP)))
3004 concb((char)escape); /* Force CBREAK mode. */
3014 #endif /* NOSETBUF */
3023 cx = cmdgetc(timelimit);
3024 if (cx < -1 && timelimit) {
3025 printf("\n?IKS idle timeout - Goodbye.\n");
3026 doexit(GOOD_EXIT,0);
3027 } else if (cx == -1) { /* Connection lost */
3034 conbin((char)escape); /* Protect against Ctrl-Z */
3036 concb((char)escape);
3040 debug(F101,"askmore cmdgetc","",cx);
3042 debug(F100,"askmore EOF","",0);
3051 debug(F101,"askmore c","",c);
3058 case 'p': case 'P': case 'g': case 'G': /* Proceed or Go */
3060 /* fall thru on purpose */
3062 case SP: case 'y': case 'Y': case 012: case 015:
3064 write(1, "\015 \015", sizeof "\015 \015" - 1);
3066 printf("\015 \015");
3071 case 'n': case 'N': case 'q': case 'Q':
3083 printf("^%c...\n", (c + 0100));
3085 printf("^%c...\015\012", (c + 0100));
3089 /* Invalid answer */
3091 debug(F111,"askmore","invalid answer",c);
3092 printf("Y or space-bar for yes, N for no, G to show the rest\n");
3104 /* T R A P -- Terminal interrupt handler */
3111 #endif /* CK_ANSIC */
3113 extern int b_save, f_save;
3115 extern int timelimit;
3118 extern unsigned long startflags;
3121 #endif /* NOSETKEY */
3125 extern int i_active, instatus;
3130 extern int zchkod, zchkid;
3132 extern int unkmacro;
3140 signal(SIGINT, SIG_ACK);
3143 /* GEM is not reentrant, no i/o from interrupt level */
3144 cklongjmp(cmjbuf,1); /* Jump back to parser now! */
3149 debug(F100,"*********************","",0);
3151 debug(F101,"trap caught SIGINT","",sig);
3153 debug(F101,"trap caught signal","",sig);
3154 debug(F100,"*********************","",0);
3159 if ( sig == SIGBREAK && (startflags & 128) ) {
3160 debug(F101,"trap ignoring SIGBREAK","",sig);
3166 timelimit = 0; /* In case timed ASK interrupted */
3168 unkmacro = 0; /* Or ON_UNKNOWN_MACRO interrupted.. */
3171 zchkod = 0; /* Or file expansion interrupted... */
3175 if (what & W_CONNECT) { /* Are we in CONNECT mode? */
3177 The HP workstation Reset key sends some kind of ueber-SIGINT that can not
3178 be SIG_IGNored, so we wind up here somehow (even though this is *not* the
3179 current SIGINT handler). Just return.
3181 debug(F101,"trap: SIGINT caught during CONNECT","",sig);
3185 if (i_active) { /* INPUT command was active? */
3186 i_active = 0; /* Not any more... */
3187 instatus = INP_UI; /* INPUT status = User Interrupted */
3192 ftreset(); /* Restore global protocol settings */
3193 binary = b_save; /* Then restore these */
3199 zclose(ZIFILE); /* If we were transferring a file, */
3200 zclose(ZOFILE); /* close it. */
3202 cmdsquo(cmd_quoting); /* If command quoting was turned off */
3205 extern FILE * learnfp;
3206 extern int learning;
3213 #endif /* CKLEARN */
3216 delmac("_apc_commands",1);
3217 apcactive = APC_INACTIVE;
3224 if (ft_win) { /* If curses window open */
3225 debug(F100,"^C trap() curses","",0);
3226 xxscreen(SCR_CW,0,0L,""); /* Close it */
3227 conres(); /* Restore terminal */
3228 i = printf("^C..."); /* Echo ^C to standard output */
3231 i = printf("^C...\n"); /* Echo ^C to standard output */
3233 if (i < 1 && ferror(stdout)) { /* If there was an error */
3234 debug(F100,"^C trap() error","",0);
3235 fclose(stdout); /* close standard output */
3236 f = fopen(dftty, "w"); /* open the controlling terminal */
3237 if (f) stdout = f; /* and make it standard output */
3238 printf("^C...\n"); /* and echo the ^C again. */
3242 conres(); /* Set console back to normal mode */
3243 #endif /* STRATUS */
3245 if (ft_win) { /* If curses window open, */
3246 debug(F100,"^C trap() curses","",0);
3247 xxscreen(SCR_CW,0,0L,""); /* close it. */
3248 printf("^C..."); /* Echo ^C to standard output */
3257 connoi_mt(); /* Kill asynch task that listens to */
3259 conres(); /* the keyboard */
3260 #endif /* datageneral */
3263 /* This is stupid -- every version should have ttimoff()... */
3265 ttimoff(); /* Turn off any timer interrupts */
3268 ttimoff(); /* Turn off any timer interrupts */
3271 ttimoff(); /* Turn off any timer interrupts */
3275 os2gks = 1; /* Turn back on keycode mapping */
3276 #endif /* NOSETKEY */
3278 for (i = 0; i < VNUM; i++)
3280 #endif /* NOLOCAL */
3283 /* WSAIsBlocking() returns FALSE in Win95 during a blocking accept call */
3284 if ( WSASafeToCancel /* && WSAIsBlocking() */ ) {
3285 WSACancelBlockingCall();
3288 #endif /* TCPSOCKET */
3290 NCBCancelOutstanding();
3291 #endif /* CK_NETBIOS */
3292 ttimoff(); /* Turn off any timer interrupts */
3295 ttimoff(); /* Turn off any timer interrupts */
3298 #endif /* STRATUS */
3303 /* Clean up Ctrl-C out of REDIRECT or external protocol */
3305 extern PID_T pty_fork_pid;
3306 extern int pty_master_fd, pty_slave_fd;
3309 signal(SIGCHLD,SIG_IGN); /* We don't want this any more */
3311 debug(F101,"trap pty_master_fd","",pty_master_fd);
3312 if (pty_master_fd > 2) {
3313 x = close(pty_master_fd);
3314 debug(F101,"trap pty_master_fd close","",x);
3317 debug(F101,"trap pty_slave_fd","",pty_slave_fd);
3318 if (pty_slave_fd > 2) {
3319 x = close(pty_slave_fd);
3320 debug(F101,"trap pty_slave_fd close","",x);
3323 debug(F101,"trap pty_fork_pid","",pty_fork_pid);
3324 if (pty_fork_pid > 0) {
3325 x = kill(pty_fork_pid,0); /* See if the fork is really there */
3326 debug(F111,"trap pty_fork_pid kill 0 errno",ckitoa(x),errno);
3327 if (x == 0) { /* Seems to be active */
3328 x = kill(pty_fork_pid,SIGHUP); /* Ask it to clean up & exit */
3329 debug(F101,"trap pty_fork_pid kill SIGHUP","",x);
3332 x = kill(pty_fork_pid,0); /* Is it still there? */
3335 /* This module is not always exposed to <errno.h> */
3339 x = kill(pty_fork_pid,SIGKILL);
3340 debug(F101,"trap pty_fork_pid kill SIGKILL","",x);
3351 We are in an intercept routine but do not perform a F$RTE (done implicitly
3352 by rts). We have to decrement the sigmask as F$RTE does. Warning: longjump
3353 only restores the cpu registers, NOT the fpu registers. So don't use fpu at
3354 all or at least don't use common fpu (double or float) register variables.
3361 debug(F100,"trap about to longjmp","",0);
3363 cklongjmp(ckjaddr(cmjbuf),1);
3365 cklongjmp(cmjbuf,1);
3368 #else /* NOCCTRAP */
3369 /* No Ctrl-C trap, just exit. */
3370 #ifdef CK_CURSES /* Curses support? */
3371 xxscreen(SCR_CW,0,0L,""); /* Close curses window */
3372 #endif /* CK_CURSES */
3373 doexit(BAD_EXIT,what); /* Exit poorly */
3374 #endif /* NOCCTRAP */
3379 /* C K _ T I M E -- Returns pointer to current time. */
3383 static char tbuf[10];
3387 ztime(&p); /* "Thu Feb 8 12:00:00 1990" */
3388 if (!p) /* like asctime()! */
3391 for (x = 11; x < 19; x++) /* copy hh:mm:ss */
3392 tbuf[x - 11] = p[x]; /* to tbuf */
3393 tbuf[8] = NUL; /* terminate */
3395 return(tbuf); /* and return it */
3398 /* C C _ C L E A N -- Cleanup after terminal interrupt handler */
3403 zclose(ZIFILE); /* If we were transferring a file, */
3404 zclose(ZOFILE); /* close it. */
3405 printf("^C...\n"); /* Not VMS, no problem... */
3410 /* S T P T R A P -- Handle SIGTSTP (suspend) signals */
3416 stptrap(sig) int sig;
3417 #endif /* CK_ANSIC */
3421 int x; extern int cmflgs;
3422 debug(F101,"stptrap() caught signal","",sig);
3424 printf("\r\nsuspend disabled\r\n");
3426 if (what & W_COMMAND) { /* If we were parsing commands */
3427 prompt(xxstring); /* reissue the prompt and partial */
3428 if (!cmflgs) /* command (if any) */
3429 printf("%s",cmdbuf);
3433 conres(); /* Reset the console */
3435 /* Flush pending output first, in case we are continued */
3436 /* in the background, which could make us block */
3439 x = psuspend(xsuspend); /* Try to suspend. */
3442 printf("Job control not supported\r\n");
3443 conint(trap,stptrap); /* Rearm the trap. */
3444 debug(F100,"stptrap back from suspend","",0);
3446 case W_CONNECT: /* If suspended during CONNECT? */
3447 conbin((char)escape); /* put console back in binary mode */
3448 debug(F100,"stptrap W_CONNECT","",0);
3451 case W_COMMAND: /* Suspended in command mode */
3452 debug(F101,"stptrap W_COMMAND pflag","",pflag);
3453 concb((char)escape); /* Put back CBREAK tty mode */
3454 if (pflag) { /* If command parsing was */
3455 prompt(xxstring); /* reissue the prompt and partial */
3456 if (!cmflgs) /* command (if any) */
3457 printf("%s",cmdbuf);
3461 default: /* All other cases... */
3462 debug(F100,"stptrap default","",0);
3463 concb((char)escape); /* Put it back in CBREAK mode */
3474 /* T L O G -- Log a record in the transaction file */
3476 Call with a format and 3 arguments: two strings and a number:
3477 f - Format, a bit string in range 0-7, bit x is on, arg #x is printed.
3478 s1,s2 - String arguments 0 and 1.
3479 n - Long, argument 2.
3483 dotlog(int f, char *s1, char *s2, CK_OFF_T n)
3485 dotlog(f,s1,s2,n) int f; CK_OFF_T n; char *s1, *s2;
3486 #endif /* CK_ANSIC */
3488 static char s[TBUFL];
3490 char *sp = s; int x;
3494 if (!tralog) return; /* If no transaction log, don't */
3495 if (tlogfmt != 1) return;
3497 case F000: /* 0 (special) "s1 n s2" */
3498 if ((int)strlen(s1) + (int)strlen(s2) + 15 > TBUFL)
3499 sprintf(sp,"?T-Log string too long");
3501 sprintf(sp,"%s %s %s",s1,ckfstoa(n),s2);
3502 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3504 case F001: /* 1, " n" */
3505 sprintf(sp," %s",ckfstoa(n));
3506 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3508 case F010: /* 2, "[s2]" */
3509 x = (int)strlen(s2);
3510 if (s2[x] == '\n') s2[x] = '\0';
3512 sprintf(sp,"?String too long");
3513 else sprintf(sp,"[%s]",s2);
3514 if (zsoutl(ZTFILE,"") < 0) tralog = 0;
3516 case F011: /* 3, "[s2] n" */
3517 x = (int)strlen(s2);
3518 if (s2[x] == '\n') s2[x] = '\0';
3520 sprintf(sp,"?String too long");
3521 else sprintf(sp,"[%s] %s",s2,ckfstoa(n));
3522 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3524 case F100: /* 4, "s1" */
3525 if (zsoutl(ZTFILE,s1) < 0) tralog = 0;
3527 case F101: /* 5, "s1: n" */
3528 if ((int)strlen(s1) + 15 > TBUFL)
3529 sprintf(sp,"?String too long");
3530 else sprintf(sp,"%s: %s",s1,ckfstoa(n));
3531 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3533 case F110: /* 6, "s1 s2" */
3534 x = (int)strlen(s2);
3535 if (s2[x] == '\n') s2[x] = '\0';
3536 if ((int)strlen(s1) + x + 4 > TBUFL)
3537 sprintf(sp,"?String too long");
3539 sprintf(sp,"%s%s%s",s1,((*s2 == ':') ? "" : " "),s2);
3540 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3542 case F111: /* 7, "s1 s2: n" */
3543 x = (int)strlen(s2);
3544 if (s2[x] == '\n') s2[x] = '\0';
3545 if ((int)strlen(s1) + x + 15 > TBUFL)
3546 sprintf(sp,"?String too long");
3548 sprintf(sp,"%s%s%s: %s",s1,((*s2 == ':') ? "" : " "),s2,ckfstoa(n));
3549 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3552 sprintf(sp,"?Invalid format for tlog() - %d",f);
3553 if (zsoutl(ZTFILE,s) < 0) tralog = 0;
3560 This is the transaction-log writer for BRIEF format.
3561 The idea is produce one record (line) per file. Each record
3562 has the following delimited fields:
3565 Action: SEND or RECV
3568 Transfer mode (text, binary, image, labeled, etc).
3569 Status: OK or FAILED
3570 Free-form comments in doublequotes
3571 The default separator is comma.
3572 If a field contains the separator, it is enclosed in doublequotes.
3576 doxlog(int x, char * fn, CK_OFF_T fs, int fm, int status, char * msg)
3578 doxlog(x, fn, fs, fm, status, msg)
3579 int x; char * fn; CK_OFF_T fs; int fm; int status; char * msg;
3580 #endif /* CK_ANSIC */
3584 char buf[CKMAXPATH+256], * bufp;
3587 int len, left, ftp = 0, k;
3589 if (!tralog) return; /* If no transaction log, don't */
3591 if (!fn) fn = ""; /* Protect against null pointers */
3596 sep[0] = (char) tlogsep;
3598 if (!sep[0]) sep[0] = ',';
3602 debug(F101,"XXX doxlog left 1","",left);
3604 p = zzndate(); /* Date */
3605 ckmakmsg(buf, left, p ? p : "00000000", sep, NULL, NULL);
3608 debug(F111,"XXX doxlog left 2",buf,left);
3611 ckstrncpy(bufp,p+11,left);
3614 debug(F111,"XXX doxlog left 3",buf,left);
3617 if (!(x & (W_SEND|W_RECV)))
3619 s = (x & W_SEND) ? "PUT" : "GET";
3622 s = (x & W_SEND) ? "SEND" : "RECV";
3625 ckmakmsg(bufp,left,sep,s,sep,NULL);
3628 debug(F111,"XXX doxlog left 4",buf,left);
3631 if (ckstrchr(fn,sep[0])) /* Filename */
3633 ckmakmsg(bufp,left,s,fn,s,sep);
3634 sprintf(tmpbuf,"%s",ckfstoa(fs)); /* Size */
3635 ckstrncat(buf,tmpbuf,CKMAXPATH);
3636 ckstrncat(buf,sep,CKMAXPATH);
3637 debug(F110,"doxlog 4",buf,0);
3641 ckstrncpy(tmpbuf, (binary ? "binary" : "text"), TMPBUFSIZ);
3643 ckstrncpy(tmpbuf,gfmode(fm,0),TMPBUFSIZ);
3645 if (ckstrchr(tmpbuf,sep[0])) { /* Might contain spaces */
3646 ckstrncat(buf,"\"",CKMAXPATH);
3647 ckstrncat(buf,tmpbuf,CKMAXPATH);
3648 ckstrncat(buf,"\"",CKMAXPATH);
3650 ckstrncat(buf,tmpbuf,CKMAXPATH);
3651 ckstrncat(buf,sep,CKMAXPATH);
3652 debug(F110,"doxlog 5",buf,0);
3654 ckstrncat(buf, status ? "FAILED" : "OK",CKMAXPATH);
3656 left = CKMAXPATH+256 - len;
3657 if (left < 2) fatal("doxlog buffer overlow");
3659 debug(F111,"XXX doxlog left 5",buf,left);
3661 debug(F110,"doxlog buf 1", buf, len);
3663 if (status == 0 && left > 32) {
3666 debug(F101,"DOXLOG fpxfsecs","",(long)(fpxfsecs * 1000));
3667 if (fpxfsecs) cps = (long)((CKFLOAT) fs / fpxfsecs);
3668 sprintf(s,"%s\"%0.3fsec %ldcps\"",sep,fpxfsecs,cps);
3670 if (xfsecs) cps = fs / xfsecs;
3671 sprintf(s,"%s\"%ldsec %ldcps\"",sep,xfsecs,cps);
3672 #endif /* GFTIMER */
3673 } else if ((int)strlen(msg) + 4 < left) {
3674 sprintf(s,"%s\"%s\"",sep,msg);
3676 debug(F111,"XXX doxlog left 5",buf,left);
3678 debug(F110,"doxlog 5",buf,0);
3679 x = zsoutl(ZTFILE,buf);
3680 debug(F101,"doxlog zsoutl","",x);
3681 if (x < 0) tralog = 0;
3687 The rest of this file is for all implementations but the Macintosh.
3691 static int repaint = 0; /* Transfer display needs repainting */
3692 #endif /* CK_CURSES */
3695 /* C H K I N T -- Check for console interrupts */
3698 Used during file transfer in local mode only:
3699 . If user has not touched the keyboard, returns 0 with no side effects.
3700 . If user typed S or A (etc, see below) prints status message and returns 0.
3701 . If user typed X or F (etc, see below) returns 0 with cxseen set to 1.
3702 . If user typed Z or B (etc, see below) returns 0 with czseen set to 1.
3703 . If user typed E or C (etc, see below) returns -1.
3707 int ch, cn, ofd; long zz;
3710 if ((!local) || (quiet)) return(0); /* Only do this if local & not quiet */
3712 if (con_reads_mt) /* if conint_mt task is active */
3713 if (conint_avl) { /* and there's an interrupt pending */
3714 cn = 1; /* process it */
3716 conint_avl = 0; /* turn off flag so conint_mt can */
3717 } else /* proceed */
3719 else /* if conint_mt not active */
3720 if ((ch = coninc(2)) < 0) /* try to get char manually */
3721 return(0); /* I/O error, or no data */
3722 else /* if successful, set cn so we */
3723 cn = 1; /* know we got one */
3724 debug(F101,"chkint got keyboard character",ch,cn);
3725 #else /* !datageneral */
3728 extern int TlsIndex;
3729 struct _threadinfo * threadinfo;
3730 threadinfo = (struct _threadinfo *) TlsGetValue(TlsIndex);
3732 if (!WaitSem(threadinfo->DieSem,0))
3733 return -1; /* Cancel Immediately */
3737 cn = conchk(); /* Any input waiting? */
3738 debug(F101,"conchk","",cn);
3739 if (cn < 1) return(0);
3741 debug(F101,"coninc","",ch);
3742 if (ch < 0) return(0);
3743 #endif /* datageneral */
3747 case 'A': case 'a': case 0001: /* Status report */
3749 if (fdispla != XYFD_R && fdispla != XYFD_S && fdispla != XYFD_N)
3750 return(0); /* Only for serial, simple or none */
3751 ofd = fdispla; /* [MF] Save file display type */
3752 if (fdispla == XYFD_N)
3753 fdispla = XYFD_R; /* [MF] Pretend serial if no display */
3754 xxscreen(SCR_TN,0,0l,"Status report:");
3755 xxscreen(SCR_TN,0,0l," file type: ");
3758 case XYFT_L: xxscreen(SCR_TZ,0,0l,"labeled"); break;
3759 case XYFT_I: xxscreen(SCR_TZ,0,0l,"image"); break;
3760 case XYFT_U: xxscreen(SCR_TZ,0,0l,"binary undefined"); break;
3762 case XYFT_B: xxscreen(SCR_TZ,0,0l,"binary"); break;
3766 xxscreen(SCR_TZ,0,0l,"text");
3768 xxscreen(SCR_TU,0,0l,"text, ");
3769 if (tcharset == TC_TRANSP || xfrxla == 0) {
3770 xxscreen(SCR_TZ,0,0l,"transparent");
3772 if (what & W_SEND) {
3773 xxscreen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword);
3774 xxscreen(SCR_TU,0,0l," => ");
3775 xxscreen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword);
3777 xxscreen(SCR_TZ,0,0l,fcsinfo[fcharset].keyword);
3778 xxscreen(SCR_TU,0,0l," => ");
3779 xxscreen(SCR_TZ,0,0l,tcsinfo[tcharset].keyword);
3782 #endif /* NOCSETS */
3784 xxscreen(SCR_QE,0,filcnt," file number");
3785 if (fsize) xxscreen(SCR_QE,0,fsize," size");
3786 xxscreen(SCR_QE,0,ffc," characters so far");
3789 zz = what & W_SEND ? sendstart : what & W_RECV ? rs_len : 0;
3790 zz = ( (ffc + zz) * 100L ) / fsize;
3792 zz = ( ffc * 100L ) / fsize;
3793 #endif /* CK_RESEND */
3794 xxscreen(SCR_QE,0,zz, " percent done");
3796 if (bctu == 4) { /* Block check */
3797 xxscreen(SCR_TU,0,0L," block check: ");
3798 xxscreen(SCR_TZ,0,0L,"blank-free-2");
3799 } else xxscreen(SCR_QE,0,(long)bctu, " block check");
3800 xxscreen(SCR_QE,0,(long)rptflg," compression");
3801 xxscreen(SCR_QE,0,(long)ebqflg," 8th-bit prefixing");
3802 xxscreen(SCR_QE,0,(long)lscapu," locking shifts");
3804 xxscreen(SCR_QE,0, speed, " speed");
3807 xxscreen(SCR_QE,0,spsiz, " packet length");
3808 else if (what & W_RECV || what & W_REMO)
3809 xxscreen(SCR_QE,0,urpsiz," packet length");
3810 xxscreen(SCR_QE,0,wslots, " window slots");
3811 fdispla = ofd; /* [MF] Restore file display type */
3814 case 'B': case 'b': case 0002: /* Cancel batch */
3815 case 'Z': case 'z': case 0032:
3818 xxscreen(SCR_ST,ST_MSG,0l,
3819 (((what & W_RECV) && (wslots > 1)) ?
3820 "Canceling batch, wait... " :
3821 "Canceling batch... ")
3825 case 'F': case 'f': case 0006: /* Cancel file */
3826 case 'X': case 'x': case 0030:
3829 xxscreen(SCR_ST,ST_MSG,0l,
3830 (((what & W_RECV) && (wslots > 1)) ?
3831 "Canceling file, wait... " :
3832 "Canceling file... ")
3836 case 'R': case 'r': case 0022: /* Resend packet */
3837 case 0015: case 0012:
3841 #endif /* STREAMING */
3842 xxscreen(SCR_ST,ST_MSG,0l,"Resending packet... ");
3848 case '\03': /* We're not trapping ^C's with */
3849 trap(0); /* signals, so we check here */
3850 #endif /* datageneral */
3852 case 'C': case 'c': /* Ctrl-C */
3855 #endif /* datageneral */
3857 case 'E': case 'e': /* Send error packet */
3863 case 0014: /* Ctrl-L to refresh screen */
3864 case 'L': case 'l': /* Also accept L (upper, lower) */
3865 case 0027: /* Ctrl-W synonym for VMS & Ingres */
3868 #endif /* CK_CURSES */
3871 case 't': /* Turn on debug-log timestamps */
3877 xxscreen(SCR_ST,ST_MSG,0l,
3878 "Debug timestamps On... ");
3881 xxscreen(SCR_ST,ST_MSG,0l,
3882 "Debug timestamps Off... ");
3891 debopn("debug.log",0);
3893 xxscreen(SCR_ST,ST_MSG,0l,"debug.log open... ");
3895 xxscreen(SCR_ST,ST_MSG,0l,"debug.log open FAILED... ");
3898 xxscreen(SCR_ST,ST_MSG,0l,"Debug log On... ");
3905 case 'd': /* Turn off debugging */
3908 xxscreen(SCR_ST,ST_MSG,0l,"Debug log Off... ");
3913 default: /* Anything else, print message */
3919 /* I N T M S G -- Issue message about terminal interrupts */
3926 #endif /* CK_ANSIC */
3930 #endif /* CK_NEED_SIG */
3932 if (!displa || quiet) /* Not if we're being quiet */
3934 if (server && (!srvdis || n > -1L)) /* Special for server */
3937 buf[0] = NUL; /* Keep compilers happy */
3938 #endif /* CK_NEED_SIG */
3941 conchk(); /* Clear out pending escape-signals */
3942 #endif /* SVORPOSIX */
3945 conres(); /* So Ctrl-C will work */
3947 if ((!server && n == 1L) || (server && n < 0L)) {
3953 "Type escape character (",
3958 xxscreen(SCR_TN,0,0l,buf);
3960 #endif /* CK_NEED_SIG */
3963 if (protocol == PROTO_K) {
3964 xxscreen(SCR_TN,0,0l,"X to cancel file, CR to resend current packet");
3965 xxscreen(SCR_TN,0,0l,"Z to cancel group, A for status report");
3966 xxscreen(SCR_TN,0,0l,"E to send Error packet, Ctrl-C to quit immediately: ");
3968 xxscreen(SCR_TN,0,0l,"Ctrl-C to cancel file transfer: ");
3971 xxscreen(SCR_TN,0,0l,"Transfer interruption disabled. ");
3974 else xxscreen(SCR_TU,0,0l," ");
3978 static int newdpy = 0; /* New display flag */
3979 static char fbuf[80]; /* Filename buffer */
3980 static char abuf[80]; /* As-name buffer */
3981 static char a2buf[80]; /* Second As-name buffer */
3982 static CK_OFF_T oldffc = 0L;
3983 static CK_OFF_T dots = 0L;
3984 static int hpos = 0;
3986 static VOID /* Initialize Serial or CRT display */
3991 newdpy = 0; /* Don't do this again */
3992 oldffc = (CK_OFF_T)0; /* Reset this */
3993 dots = (CK_OFF_T)0; /* and this.. */
3996 conoll(""); /* New line */
3997 if (what & W_SEND) s = "Sending: "; /* Action */
3998 else if (what & W_RECV) s = "Receiving: ";
3999 n = (int)strlen(s) + (int)strlen(fbuf);
4001 m = (int)strlen(abuf) + 4;
4002 if (n + m > cmd_cols) {
4011 m = (int)strlen(a2buf) + 4;
4012 if (n + m > cmd_cols) {
4021 *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
4023 if (fsize > (CK_OFF_T)-1) { /* Size */
4024 sprintf(fbuf,"Size: %s, Type: ",ckfstoa(fsize)); /* SAFE (80) */
4025 conol(fbuf); *fbuf = NUL;
4026 } else conol("Size: unknown, Type: ");
4027 if (binary) { /* Type */
4029 case XYFT_L: conol("labeled"); break;
4030 case XYFT_I: conol("image"); break;
4031 case XYFT_U: conol("binary undefined"); break;
4033 case XYFT_B: conol("binary"); break;
4040 if (tcharset == TC_TRANSP || xfrxla == 0) {
4041 conol("transparent");
4043 if (what & W_SEND) {
4044 conol(fcsinfo[fcharset].keyword);
4046 conol(tcsinfo[tcharset].keyword);
4048 conol(tcsinfo[tcharset].keyword);
4050 conol(fcsinfo[fcharset].keyword);
4053 #endif /* NOCSETS */
4057 conol(", STREAMING");
4058 #endif /* STREAMING */
4061 if (fdispla == XYFD_S) { /* CRT field headings */
4063 Define CK_CPS to show current transfer rate.
4064 Leave it undefined to show estimated time remaining.
4065 Estimated-time-remaining code from Andy Fyfe, not tested on
4071 conoll(" File Percent Packet");
4072 conoll(" Bytes Done CPS Length");
4074 conoll(" File Percent Secs Packet");
4075 conoll(" Bytes Done Left Length");
4084 c = completion code: 0 means transfer in progress, nonzero means it's done.
4085 Show the file transfer progress counter and perhaps verbose packet type.
4092 #endif /* CK_ANSIC */
4096 long et; /* Elapsed time, entire batch */
4097 #endif /* GFTIMER */
4098 CK_OFF_T howfar; /* How far into file */
4099 long pd; /* Percent done, this file */
4100 long tp; /* Transfer rate, entire batch */
4101 long ps; /* Packet size, current packet */
4102 CK_OFF_T mytfc; /* Local copy of byte counter */
4106 #endif /* GFTIMER */
4108 if (newdpy) /* Put up filenames, etc, */
4109 dpyinit(); /* if they're not there already. */
4111 howfar = ffc; /* How far */
4113 Calculate CPS rate even if not displaying on screen for use in file
4114 transfer statistics.
4117 tnow = gftimer(); /* Time since we started */
4118 ps = (what & W_RECV) ? rpktl : spktl; /* Packet size */
4120 if (what & W_SEND) /* In case we didn't start at */
4121 howfar += sendstart; /* the beginning... */
4122 else if (what & W_RECV)
4124 #endif /* CK_RESEND */
4125 pd = -1; /* Percent done. */
4126 if (c == NUL) { /* Still going, figure % done */
4127 if (!fsize) return; /* Empty file, don't bother */
4128 pd = (fsize > 99) ? (howfar / (fsize / (CK_OFF_T)100)) : 0;
4129 if (pd > 100) pd = 100; /* Expansion */
4132 if (!cxseen && !discard && !czseen)
4133 pd = 100; /* File complete, so 100%. */
4135 mytfc = (pd < 100) ? tfc + ffc : tfc; /* CPS */
4136 tp = (long)((tnow > 0.0) ? (CKFLOAT) mytfc / tnow : 0);
4140 cps = tp; /* Set global variable */
4141 if (cps > peakcps && /* Peak transfer rate */
4142 ((what & W_SEND && spackets > wslots + 4) ||
4143 (!(what & W_SEND) && spackets > 10))) {
4147 #else /* Not GFTIMER */
4149 et = gtimer(); /* Elapsed time */
4150 ps = (what & W_RECV) ? rpktl : spktl; /* Packet length */
4152 if (what & W_SEND) /* And if we didn't start at */
4153 howfar += sendstart; /* the beginning... */
4154 else if (what & W_RECV)
4156 #endif /* CK_RESEND */
4157 pd = -1; /* Percent done. */
4158 if (c == NUL) { /* Still going, figure % done */
4159 if (fsize == 0L) return; /* Empty file, don't bother */
4160 pd = (fsize > 99) ? (howfar / (fsize / (CK_OFF_T)100)) : 0;
4161 if (pd > 100) pd = 100; /* Expansion */
4164 if (!cxseen && !discard && !czseen)
4165 pd = 100; /* File complete, so 100%. */
4170 fsecs = time (from gtimer) that this file started (set in sfile()).
4171 Rate so far is ffc / (et - fsecs), estimated time for remaining bytes
4172 is (fsize - ffc) / (ffc / (et - fsecs)).
4174 tp = (howfar > 0) ? (fsize - howfar) * (et - fsecs) / howfar : 0;
4178 mytfc = (pd < 100) ? tfc + ffc : tfc;
4179 tp = (et > 0) ? mytfc / et : 0; /* Transfer rate */
4180 if (c && (tp == 0)) /* Watch out for subsecond times */
4183 cps = tp; /* Set global variable */
4184 if (cps > peakcps && /* Peak transfer rate */
4185 ((what & W_SEND && spackets > wslots + 4) ||
4186 (!(what & W_SEND) && spackets > 10))) {
4191 #endif /* GFTIMER */
4193 if (fdispla == XYFD_S) { /* CRT display */
4195 /* These sprintfs should be safe until we have 32-digit numbers */
4198 sprintf(buffer, "%c%9s%5ld%%%8ld%8ld ", CR,ckfstoa(howfar),pd,tp,ps);
4200 sprintf(buffer, "%c%9s %8ld%8ld ", CR,ckfstoa(howfar),tp,ps);
4203 } else if (fdispla == XYFD_R) { /* SERIAL */
4205 if (howfar - oldffc < 1024) /* Update display every 1K */
4207 oldffc = howfar; /* Time for new display */
4208 k = (howfar / 1024L) - dots; /* How many K so far */
4209 for (i = 0L; i < k; i++) {
4210 if (hpos++ > (cmd_cols - 3)) { /* Time to wrap? */
4214 conoc('.'); /* Print a dot for this K */
4215 dots++; /* Count it */
4221 /* C K S C R E E N -- Screen display function */
4225 f - argument descriptor
4226 c - a character or small integer
4230 and global fdispla = SET FILE DISPLAY value:
4233 XYFD_R = SERIAL: Dots, etc, works on any terminal, even hardcopy.
4234 XYFD_S = CRT: Works on any CRT, writes over current line.
4235 XYFD_C = FULLSCREEN: Requires terminal-dependent screen control.
4236 XYFD_B = BRIEF: Like SERIAL but only filename & completion status.
4237 XYFD_G = GUI; Windows GUI, same behavior as FULLSCREEN
4241 ckscreen(int f, char c,CK_OFF_T n,char *s)
4243 ckscreen(f,c,n,s) int f; char c; CK_OFF_T n; char *s;
4244 #endif /* CK_ANSIC */
4247 int len; /* Length of string */
4251 _PROTOTYP( VOID conbgt, (int) );
4256 ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit? */
4258 if (!local && !ftp) /* In remote mode - don't do this */
4263 if (!fxd_inited) /* Initialize if necessary */
4268 obg = backgrd; /* Previous background status */
4269 conbgt(1); /* See if running in background */
4270 if (!backgrd && obg) { /* Just came into foreground? */
4271 concb((char)escape); /* Put console back in CBREAK mode */
4272 setint(); /* Restore interrupts */
4277 if ((f != SCR_WM) && (f != SCR_EM)) /* Always update warnings & errors */
4279 (backgrd && bgset) ||
4280 fdispla == XYFD_N ||
4286 if (f == SCR_FN) /* VMS - shorten the name */
4287 s = zrelname(s,zgtdir());
4290 if (dest == DEST_S) /* SET DESTINATION SCREEN */
4291 return; /* would interfere... */
4294 if (fdispla == XYFD_G) { /* If gui display selected */
4295 screeng(f,c,n,s); /* call the gui version */
4300 if (fdispla == XYFD_C) { /* If fullscreen display selected */
4301 screenc(f,c,n,s); /* call the fullscreen version */
4304 #endif /* CK_CURSES */
4306 len = (int)strlen(s); /* Length of string */
4308 switch (f) { /* Handle our function code */
4309 case SCR_FN: /* Filename */
4310 if (fdispla == XYFD_B) {
4313 printf(" %s %s", what & W_SEND ? "PUT" : "GET", s);
4316 printf(" %s %s", what & W_SEND ? "SEND" : "RECV", s);
4323 conoll(""); conol(s); conoc(SP); hpos = len + 1;
4325 ckstrncpy(fbuf,s,80);
4326 abuf[0] = a2buf[0] = NUL;
4327 newdpy = 1; /* New file so refresh display */
4331 case SCR_AN: /* As-name */
4332 if (fdispla == XYFD_B) {
4334 printf("(as %s) ",s);
4335 #endif /* COMMENT */
4339 if (hpos + len > 75) { conoll(""); hpos = 0; }
4340 conol("=> "); conol(s);
4341 if ((hpos += (len + 3)) > 78) { conoll(""); hpos = 0; }
4344 ckstrncpy(a2buf,s,80);
4346 ckstrncpy(abuf,s,80);
4351 case SCR_FS: /* File-size */
4352 if (fdispla == XYFD_B) {
4353 printf(" (%s) (%s byte%s)",
4355 (binary ? "binary" : "text")
4359 , ckfstoa(n), n == 1 ? "" : "s");
4366 sprintf(buf,", Size: %s",ckfstoa(n)); conoll(buf); hpos = 0;
4370 case SCR_XD: /* X-packet data */
4371 if (fdispla == XYFD_B)
4374 conoll(""); conoll(s); hpos = 0;
4376 ckstrncpy(fbuf,s,80);
4377 abuf[0] = a2buf[0] = NUL;
4381 case SCR_ST: /* File status */
4383 case ST_OK: /* Transferred OK */
4384 showpkt('Z'); /* Update numbers one last time */
4385 if (fdispla == XYFD_B) {
4388 printf(": OK (%0.3f sec, %ld cps)",fpxfsecs,
4389 (long)((CKFLOAT)ffc / fpxfsecs));
4392 printf(": OK (%d sec, %ld cps)",xfsecs,ffc/xfsecs);
4393 #endif /* GFTIMER */
4397 if ((hpos += 5) > 78) conoll(""); /* Wrap screen line. */
4398 conoll(" [OK]"); hpos = 0; /* Print OK message. */
4399 if (fdispla == XYFD_S) { /* We didn't show Z packet when */
4400 conoc('Z'); /* it came, so show it now. */
4405 case ST_DISC: /* Discarded */
4406 if (fdispla == XYFD_B) {
4407 printf(": DISCARDED\n");
4410 if ((hpos += 12) > 78) conoll("");
4411 conoll(" [discarded]"); hpos = 0;
4414 case ST_INT: /* Interrupted */
4415 if (fdispla == XYFD_B) {
4416 printf(": INTERRUPTED\n");
4419 if ((hpos += 14) > 78) conoll("");
4420 conoll(" [interrupted]"); hpos = 0;
4424 if (fdispla == XYFD_B) {
4426 printf(": WOULD BE TRANSFERRED (New file)\n");
4427 else if (n == SKP_XUP)
4428 printf(": WOULD BE TRANSFERRED (Remote file older)\n");
4429 else if (n == SKP_SIM)
4430 printf(": WOULD BE TRANSFERRED\n");
4431 else if (n > 0 && n < nskreason)
4432 printf(": SKIPPED (%s)\n",skreason[n]);
4434 printf(": SKIPPED\n");
4436 } else if (fdispla == XYFD_S) {
4437 if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
4438 conoll(""); /* New line */
4439 if (what & W_SEND) conol("Would Send: "); /* Action */
4440 else if (what & W_RECV) conol("Would Receive: ");
4442 if (*abuf) conol(" => "); conol(abuf); /* Names */
4443 if (*a2buf) conol(" => "); conol(a2buf); /* Names */
4444 *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
4446 conoll(" [simulated]");
4449 if ((hpos += 10) > 78) conoll("");
4450 conol(" [simulated]"); hpos = 0;
4453 case ST_SKIP: /* Skipped */
4454 if (fdispla == XYFD_B) {
4456 printf(": WOULD BE TRANSFERRED (New file)\n");
4457 else if (n == SKP_XUP)
4458 printf(": WOULD BE TRANSFERRED (Remote file older)\n");
4459 else if (n == SKP_SIM)
4460 printf(": WOULD BE TRANSFERRED\n");
4461 else if (n > 0 && n < nskreason)
4462 printf(": SKIPPED (%s)\n",skreason[n]);
4464 printf(": SKIPPED\n");
4466 } else if (fdispla == XYFD_S) {
4467 if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
4468 conoll(""); /* New line */
4469 if (what & W_SEND) conol("Sending: "); /* Action */
4470 else if (what & W_RECV) conol("Receiving: ");
4472 if (*abuf) conol(" => "); conol(abuf); /* Names */
4473 if (*a2buf) conol(" => "); conol(a2buf); /* Names */
4474 *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
4476 conoll(" [skipped]");
4479 if ((hpos += 10) > 78) conoll("");
4480 conol(" "); conol(fbuf);
4481 conoll(" [skipped]"); hpos = 0;
4484 case ST_ERR: /* Error */
4485 if (fdispla == XYFD_B) {
4486 printf(": ERROR: %s\n",s);
4490 conol("Error: "); conoll(s); hpos = 0;
4493 case ST_MSG: /* Message */
4495 if (fdispla == XYFD_B) {
4497 printf(": MESSAGE: %s\n",s);
4507 case ST_REFU: /* Refused */
4508 if (fdispla == XYFD_B) {
4509 printf(": REFUSED\n");
4511 } else if (fdispla == XYFD_S) {
4512 if (fdispla == XYFD_S && fbuf[0]) { /* CRT display */
4513 conoll(""); /* New line */
4514 if (what & W_SEND) conol("Sending: "); /* Action */
4515 else if (what & W_RECV) conol("Receiving: ");
4517 if (*abuf) conol(" => "); conol(abuf); /* Names */
4518 if (*a2buf) conol(" => "); conol(a2buf); /* Names */
4519 *fbuf = NUL; *abuf = NUL; *a2buf = NUL;
4522 conol("Refused: "); conoll(s);
4526 conol("Refused: "); conoll(s); hpos = 0;
4529 case ST_INC: /* Incomplete */
4530 if (fdispla == XYFD_B) {
4531 printf(": INCOMPLETE\n");
4534 if ((hpos += 12) > 78) conoll("");
4535 conoll(" [incomplete]"); hpos = 0;
4539 conoll("*** screen() called with bad status ***");
4545 case SCR_PN: /* Packet number */
4546 if (fdispla == XYFD_B) {
4549 ckmakmsg(buf,80,s,": ",ckltoa(n),NULL);
4550 conol(buf); hpos += (int)strlen(buf); return;
4553 case SCR_PT: /* Packet type or pseudotype */
4554 if (fdispla == XYFD_B)
4556 if (c == 'Y') return; /* Don't bother with ACKs */
4557 if (c == 'D') { /* In data transfer phase, */
4558 showpkt(NUL); /* show progress. */
4562 if (hpos++ > 77) { /* If near right margin, */
4563 conoll(""); /* Start new line */
4564 hpos = 0; /* and reset counter. */
4567 if (c == 'Z' && fdispla == XYFD_S)
4570 conoc(c); /* Display the packet type. */
4572 if (c == 'G') conoll(""); /* New line after G packets */
4576 case SCR_TC: /* Transaction complete */
4577 if (xfrbel) bleep(BP_NOTE);
4578 if (fdispla == XYFD_B) { /* Brief display... */
4581 fx = filcnt - filrej;
4582 printf(" SUMMARY: %ld file%s", fx, ((fx == 1) ? "" : "s"));
4583 printf(", %s byte%s", ckfstoa(tfc), ((tfc == 1) ? "" : "s"));
4585 printf(", %0.3f sec, %ld cps", fptsecs, tfcps);
4587 printf(", %ld sec, %ld cps", tsecs, tfcps);
4588 #endif /* GFTIMER */
4599 case SCR_EM: /* Error message */
4600 if (fdispla == XYFD_B) {
4601 printf(" ERROR: %s\n",s);
4604 conoll(""); conoc('?'); conoll(s); hpos = 0; return;
4606 case SCR_WM: /* Warning message */
4607 if (fdispla == XYFD_B) {
4608 printf(" WARNING: %s\n",s);
4611 conoll(""); conoll(s); hpos = 0; return;
4613 case SCR_MS: /* Message from other Kermit */
4614 if (fdispla == XYFD_B) {
4615 printf(" MESSAGE: %s\n",s);
4618 conoll(""); conoll(s); hpos = 0; return;
4620 case SCR_TU: /* Undelimited text */
4621 if (fdispla == XYFD_B)
4623 if ((hpos += len) > 77) { conoll(""); hpos = len; }
4626 case SCR_TN: /* Text delimited at beginning */
4627 if (fdispla == XYFD_B)
4629 conoll(""); conol(s); hpos = len; return;
4631 case SCR_TZ: /* Text delimited at end */
4632 if (fdispla == XYFD_B)
4634 if ((hpos += len) > 77) { conoll(""); hpos = len; }
4637 case SCR_QE: /* Quantity equals */
4638 if (fdispla == XYFD_B)
4640 ckmakmsg(buf,80,s,": ",ckltoa(n),NULL);
4641 conoll(buf); hpos = 0; return;
4643 case SCR_CW: /* Close fullscreen window */
4644 return; /* No window to close */
4650 conoll("*** screen() called with bad object ***");
4655 #endif /* NODISPLAY */
4657 /* E R M S G -- Nonfatal error message */
4659 /* Should be used only for printing the message text from an Error packet. */
4662 ermsg(msg) char *msg; { /* Print error message */
4663 debug(F110,"ermsg",msg,0);
4665 xxscreen(SCR_EM,0,0L,msg);
4666 tlog(F110,"Protocol Error:",msg,0L);
4671 setseslog(x) int x; {
4674 KuiSetProperty(KUI_TERM_CAPTURE,x,0);
4679 doclean(fc) int fc; { /* General cleanup */
4682 #endif /* OS2ORUNIX */
4684 extern int exithangup;
4686 extern char filnam[];
4692 dostop(); /* Stop all command files and end macros */
4709 tlog(F100,"Transaction Log Closed","",0L);
4716 debug(F100,"doclean calling dologend","",0);
4717 dologend(); /* End current log record if any */
4719 if (dialog) { /* If connection log open */
4721 *diafil = '\0'; /* close it. */
4724 #endif /* COMMENT */
4728 zclose(ZRFILE); /* READ and WRITE files, if any. */
4731 zclose(ZIFILE); /* And other files too */
4732 x = chkfn(ZOFILE); /* Download in progress? */
4733 debug(F111,"doclean chkfn ZOFILE",filnam,x);
4734 debug(F111,"doclean keep","",keep);
4735 zclose(ZOFILE); /* Close output file */
4736 if (x > 0 && !keep) { /* If it was being downloaded */
4738 x = zdelet(filnam); /* Delete if INCOMPLETE = DISCARD */
4739 debug(F111,"doclean download filename",filnam,x);
4745 if (fc < 1) { /* RESETing, not EXITing */
4747 if (deblog) { /* Close the debug log. */
4759 debug(F101,"doclean exithangup","",exithangup);
4760 if (local && exithangup) { /* Close communication connection */
4765 debug(F101,"doclean ttchk()","",x);
4767 debug(F101,"doclean ttyfd","",ttyfd);
4768 #endif /* OS2ORUNIX */
4774 || haslock /* Make sure we get lockfile! */
4775 || (!network && ttyfd > -1)
4779 extern int wasclosed, whyclosed;
4780 debug(F100,"doclean hanging up and closing","",0);
4785 printf("Closing %s...",ttname);
4788 mdmhup(); /* Hangup the modem??? */
4790 ttclos(0); /* Close external line, if any */
4798 whyclosed = WC_CLOS;
4800 if (nmac) { /* Any macros defined? */
4802 k = mlook(mactab,"on_close",nmac); /* Look this up */
4803 if (k >= 0) { /* If found, */
4805 /* printf("ON_CLOSE DOCLEAN\n"); */
4806 *(mactab[k].kwd) = NUL; /* See comment below */
4807 if (dodo(k,ckitoa(whyclosed),0) > -1) /* set it up, */
4808 parser(1); /* and execute it */
4815 ckstrncpy(ttname,dftty,TTNAMLEN); /* Restore default tty */
4816 local = dfloc; /* And default remote/local status */
4819 else if (local) debug(F100,"doclean hangup/close skipped","",0);
4821 #endif /* NOLOCAL */
4824 ftpbye(); /* If FTP connection open, close it */
4829 ttclos(0); /* If IKSD, close socket */
4834 If a macro named "on_exit" is defined, execute it. Also remove it from the
4835 macro table, in case its definition includes an EXIT or QUIT command, which
4836 would cause much recursion and would prevent the program from ever actually
4839 if (nmac) { /* Any macros defined? */
4841 char * cmd = "on_exit"; /* MSVC 2.x compiler error */
4842 k = mlook(mactab,cmd,nmac); /* Look up "on_exit" */
4843 if (k >= 0) { /* If found, */
4845 /* This makes a mess if ON_EXIT itself executes macros */
4846 *(mactab[k].kwd) = NUL; /* poke its name from the table, */
4848 /* Replace the keyword with something that doesn't wreck the */
4849 /* order of the keyword table */
4850 ckstrncpy(mactab[k].kwd,"on_exxx",8);
4851 #endif /* COMMENT */
4852 if (dodo(k,"",0) > -1) /* set it up, */
4853 parser(1); /* and execute it */
4858 Put console terminal back to normal. This is done here because the
4859 ON_EXIT macro calls the parser, which meddles with console terminal modes.
4861 conres(); /* Restore console terminal. */
4864 /* Should be no need for this, and maybe it's screwing things up? */
4865 connoi(); /* Turn off console interrupt traps */
4866 #endif /* COMMENT */
4868 /* Delete the Startup File if we are supposed to. */
4871 extern int DeleteStartupFile;
4872 debug(F111,"doclean DeleteStartupFile",cmdfil,DeleteStartupFile);
4873 if (DeleteStartupFile) {
4874 int rc = zdelet(cmdfil);
4875 debug(F111,"doclean zdelet",cmdfil,rc);
4879 syscleanup(); /* System-dependent cleanup, last */
4882 /* D O E X I T -- Exit from the program. */
4885 First arg is general, system-independent symbol: GOOD_EXIT or BAD_EXIT.
4886 If second arg is -1, take 1st arg literally.
4887 If second arg is not -1, work it into the exit code.
4890 doexit(exitstat,code) int exitstat, code; {
4891 extern int x_logged, quitting;
4893 extern int display_demo;
4894 extern int SysInited;
4898 extern int krb4_autodel;
4901 extern int krb5_autodel;
4903 #endif /* CK_KERBEROS */
4907 static $DESCRIPTOR(symnam,"CKERMIT_STATUS");
4908 static struct dsc$descriptor_s symval;
4914 extern long lucalls, luhits, xxhits, luloop;
4916 #endif /* USE_LUCACHE */
4918 extern int cmdstats[];
4925 static int initing = 0;
4935 debug(F101,"lookup cache size","",lusize);
4936 debug(F101,"lookup calls ....","",lucalls);
4937 debug(F101,"lookup cache hits","",luhits);
4938 debug(F101,"lookup start hits","",xxhits);
4939 debug(F101,"lookup loop iterations","",luloop);
4940 #endif /* USE_LUCACHE */
4942 for (i = 0; i < 256; i++) {
4944 debug(F111,"CMSTATS",ckitoa(i),cmdstats[i]);
4947 debug(F101,"doexit exitstat","",exitstat);
4948 debug(F101,"doexit code","",code);
4949 debug(F101,"doexit xitsta","",xitsta);
4954 /* If we are automatically destroying Kerberos credentials on Exit */
4957 if (krb4_autodel == KRB_DEL_EX) {
4958 extern struct krb_op_data krb_op;
4960 krb_op.cache = NULL;
4961 ck_krb4_destroy(&krb_op);
4965 if (krb5_autodel == KRB_DEL_EX) {
4966 extern struct krb_op_data krb_op;
4967 extern char * krb5_d_cc;
4969 krb_op.cache = krb5_d_cc;
4970 ck_krb5_destroy(&krb_op);
4973 #endif /* CK_KERBEROS */
4980 extern struct cmdptr *cmdstk;
4982 extern struct cmdptr cmdstk[];
4983 #endif /* DCMDBUF */
4984 extern int tt_status[];
4987 /* If there is a demo screen to be displayed, display it */
4993 /* This is going to be hideous. If we have a status line */
4994 /* in the command window turn it off before we exit. */
4996 if ( tt_status[VCMD] && vmode == VCMD ) {
4997 domac("_clear_statusline","set command statusline off",
4998 cmdstk[cmdlvl].ccflgs);
4999 delmac("_clear_statusline",1);
5000 RequestScreenMutex(-1);
5001 VscrnIsDirty(vmode);
5002 ReleaseScreenMutex();
5003 while ( IsVscrnDirty(vmode) )
5005 RequestScreenMutex(-1);
5006 ReleaseScreenMutex();
5009 DialerSend(OPT_KERMIT_EXIT,exitstat);
5011 debug(F100,"doexit about to msleep","",0);
5018 #endif /* NOLOCAL */
5022 if (inserver && x_logged) {
5025 If a macro named "on_logout" is defined, execute it. Also remove it from the
5026 macro table, in case its definition includes an EXIT or QUIT command, which
5027 would cause much recursion and would prevent the program from ever actually
5030 if (nmac) { /* Any macros defined? */
5032 char * cmd = "on_logout"; /* MSVC 2.x compiler error */
5033 k = mlook(mactab,cmd,nmac); /* Look up "on_logout" */
5034 if (k >= 0) { /* If found, */
5035 *(mactab[k].kwd) = NUL; /* poke its name from the table, */
5036 if (dodo(k,"",0) > -1) /* set it up, */
5037 parser(1); /* and execute it */
5043 #endif /* CK_LOGIN */
5046 debug(F100,"doexit about to doclean","",0);
5047 doclean(1); /* Clean up most things */
5051 code = 0; /* Since we set two different items */
5052 sprintf(envstr,"%d", exitstat | code); /* SAFE */
5053 symval.dsc$w_length = (int)strlen(envstr);
5054 symval.dsc$a_pointer = envstr;
5055 symval.dsc$b_class = DSC$K_CLASS_S;
5056 symval.dsc$b_dtype = DSC$K_DTYPE_T;
5057 i = 2; /* Store in global table */
5058 #ifdef COMMENT /* Martin Zinser */
5059 LIB$SET_SYMBOL(&symnam, &symval, &i);
5061 lib$set_symbol(&symnam, &symval, &i);
5062 #endif /* COMMENT */
5063 if (exitstat == BAD_EXIT)
5064 exitstat = SS$_ABORT | STS$M_INHIB_MSG;
5065 if (exitstat == GOOD_EXIT)
5066 exitstat = SS$_NORMAL | STS$M_INHIB_MSG;
5068 if (code != -1) /* Take 1st arg literally */
5074 debug(F101,"doexit ikdbopen","",ikdbopen);
5075 if (ikdbopen && dbfp) { /* If IKSD database open */
5077 x = freeslot(mydbslot); /* Free our slot... */
5078 debug(F101,"doexit freeslot","",x);
5079 fclose(dbfp); /* and close it. */
5084 /* We have put this off till the very last moment... */
5087 if (deblog) { /* Close the debug log. */
5088 debug(F101,"C-Kermit EXIT status","",exitstat);
5096 _exit(exitstat); /* Exit from C-Kermit (no matter what) */
5098 exit(exitstat); /* Exit from C-Kermit */
5103 bgchk() { /* Check background status */
5104 if (bgset < 0) { /* They didn't type SET BACKGROUND */
5105 #ifdef VMS /* Set prompt flag based on */
5106 pflag = !batch; /* what we detected at startup. */
5110 } else { /* Otherwise SET BACKGROUND value */
5111 pflag = (bgset == 0 ? 1 : 0);
5115 /* Message flag on only if at top level, pflag is on, and QUIET is OFF */
5117 msgflg = (pflag == 0) ? 0 : !quiet;
5124 /* Set console interrupts */
5127 setint() { /* According to SET COMMAND INTERRUP */
5130 if (xsuspend) x |= 2;
5131 debug(F101,"setint","",x);
5133 switch (x) { /* Set the desired combination */
5134 case 0: connoi(); break; /* No interrupts */
5135 case 1: conint(trap,SIG_IGN); break;
5136 case 2: conint(SIG_IGN,stptrap); break;
5137 case 3: conint(trap,stptrap); break;
5139 bgchk(); /* Check background status */
5143 /* D E B U G -- Enter a record in the debugging log */
5146 Call with a format, two strings, and a number:
5147 f - Format, a bit string in range 0-7.
5148 If bit x is on, then argument number x is printed.
5149 s1 - String, argument number 1. If selected, printed as is.
5150 s2 - String, argument number 2. If selected, printed in brackets.
5151 n - Long int, argument 3. If selected, printed preceded by equals sign.
5153 f=0 is special: print s1,s2, and interpret n as a char.
5155 f=F011 (3) is also special; in this case s2 is interpeted as a counted
5156 string that might contain NULs. n is the length. If n is negative, this
5157 means the string has been truncated and ".." should be printed after the
5158 first n bytes. NUL and LF bytes are printed as "<NUL>" and "<LF>".
5161 deblog: nonzero if debug log open.
5162 debok: nonzero if ok to write entries.
5165 WARNING: Don't change DEBUFL without changing sprintf() formats below,
5170 WARNING: This routine is not thread-safe, especially when Kermit is
5171 executing on multiple CPUs -- as different threads write to the same
5172 static buffer, the debug statements are all interleaved. To be fixed
5175 static char *dbptr = (char *)0;
5179 dodebug(int f, char *s1, char *s2, CK_OFF_T n)
5181 dodebug(f,s1,s2,n) int f; char *s1, *s2; CK_OFF_T n;
5182 #endif /* CK_ANSIC */
5188 extern int SysInited;
5191 if (!deblog || !debok)
5196 if (!chkfn(ZDFILE)) /* Debug log not open, don't. */
5198 #endif /* COMMENT */
5199 if (!dbptr) { /* Allocate memory buffer */
5200 dbptr = malloc(DBUFL+4); /* This only happens once */
5207 This prevents infinite recursion in case we accidentally put a debug()
5208 call in this routine, or call another routine that contains debug() calls.
5209 From this point on, all returns from this return must be via goto xdebug,
5210 which sets deblog back to 1.
5214 if (RequestDebugMutex(30000))
5218 deblog = 0; /* Prevent infinite recursion */
5221 if (debtim) { /* Timestamp */
5222 char *tb, tsbuf[48];
5224 ckstrncpy(tsbuf,tb,32);
5226 sprintf(tsbuf+19,".%03ld ",ztmsec); /* SAFE */
5232 zsout(ZDFILE,tsbuf+11);
5234 if (!s1) s1="(NULL)";
5235 if (!s2) s2="(NULL)";
5242 This should work, but it doesn't.
5243 So instead we'll cope with overflow via sprintf formats.
5244 N.B.: UNFORTUNATELY, this means we have to put constants in the
5247 if (f != F011 && (!f || (f & 6))) { /* String argument(s) included? */
5248 x = (int) strlen(s1) + (int) strlen(s2) + 18;
5249 if (x > dbufl) { /* Longer than buffer? */
5250 if (dbptr) /* Yes, free previous buffer */
5252 dbptr = (char *) malloc(x + 2); /* Allocate a new one */
5254 zsoutl(ZDFILE,"DEBUG: Memory allocation failure");
5260 sprintf(dbptr,"DEBUG: Buffer expanded to %d\n", x + 18);
5261 zsoutl(ZDFILE,dbptr);
5265 #endif /* COMMENT */
5268 /* The aforementioned sprintf() formats were like this: */
5269 if (n > 31 && n < 127)
5270 sprintf(sp,"%.100s%.2000s:%c\n",s1,s2,(CHAR) n);
5271 else if (n < 32 || n == 127)
5272 sprintf(sp,"%.100s%.2000s:^%c\n",s1,s2,(CHAR) ((n+64) & 0x7F));
5273 else if (n > 127 && n < 160)
5274 sprintf(sp,"%.100s%.2000s:~^%c\n",s1,s2,(CHAR)((n-64) & 0x7F));
5275 else if (n > 159 && n < 256)
5276 sprintf(sp,"%.100s%.2000s:~%c\n",s1,s2,(CHAR) (n & 0x7F));
5277 else sprintf(sp,"%.100s%.2000s:%ld\n",s1,s2,n);
5279 But, naturally, it turns out these are not portable either, so now
5280 we do the stupidest possible thing.
5282 #endif /* COMMENT */
5285 /* Need to accept longer strings when debugging authenticated connections */
5287 if (len2 + 2 >= DBUFL) s2 = "(string too long)";
5288 } else if (f != F011 && f != F100) {
5289 if (len1 > 100) s1 = "(string too long)";
5290 if (len2 + 101 >= DBUFL) s2 = "(string too long)";
5294 if (len1 > 100) s1 = "(string too long)";
5295 if (len2 + 101 >= DBUFL) s2 = "(string too long)";
5297 #endif /* BIGBUFOK */
5301 switch (f) { /* Write log record according to format. */
5302 case F000: /* 0 = print both strings, and n as a char. */
5304 if ((n > 31 && n < 127) || (n > 159 && n < 256))
5305 sprintf(sp,"%s[%s]=%c\n",s1,s2,(CHAR) n);
5306 else if (n < 32 || n == 127)
5307 sprintf(sp,"%s[%s]=^%c\n",s1,s2,(CHAR) ((n+64) & 0x7F));
5308 else if (n > 127 && n < 160)
5309 sprintf(sp,"%s[%s]=~^%c\n",s1,s2,(CHAR)((n-64) & 0x7F));
5310 else sprintf(sp,"%s[%s]=0x%lX\n",s1,s2,(long)n);
5312 if ((n > 31 && n < 127) || (n > 159 && n < 256))
5313 sprintf(sp,"%s=%c\n",s1,(CHAR) n);
5314 else if (n < 32 || n == 127)
5315 sprintf(sp,"%s=^%c\n",s1,(CHAR) ((n+64) & 0x7F));
5316 else if (n > 127 && n < 160)
5317 sprintf(sp,"%s=~^%c\n",s1,(CHAR)((n-64) & 0x7F));
5318 else sprintf(sp,"%s=0x%lX\n",s1,(long)n);
5320 if (zsout(ZDFILE,dbptr) < 0) {
5325 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5326 cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5328 #endif /* CKSYSLOG */
5331 case F001: /* 1, "=n" */
5333 /* This was never used */
5334 sprintf(sp,"=%s\n",ckfstoa(n));
5336 /* Like F111, but shows number n in hex */
5344 NULL,NULL,NULL,NULL,NULL,NULL
5346 #endif /* COMMENT */
5347 if (zsout(ZDFILE,dbptr) < 0) {
5352 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5353 cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5355 #endif /* CKSYSLOG */
5359 This one was never used so (October 2000) we now use it like F011,
5360 except in this case we treat s2 as NUL terminated.
5365 This one treats n as the length of the string s2, which may contain NULs.
5366 It's good for logging NUL-bearing data in the debug log.
5369 int i, j, contd = 0;
5370 char * p = s2, *pbuf = NULL; /* p = source pointer */
5371 int m; /* pbuf = destination pointer */
5374 if (n < 0) { /* n = size of source */
5375 n = 0 - n; /* Negative means to add "..." */
5388 if (n == 0) /* 0 means do nothing */
5390 m = DBUFL - 8; /* Get size for interpreted part */
5391 if (n > m) /* Ensure requested size not too big */
5393 pbuf = dbptr; /* Construction pointer */
5395 pbuf[i++] = '['; /* Interpret the string into it */
5396 for (j = 0; j < n && i < m-4; p++,j++) { /* char by char... */
5405 } else if (*p == CR) {
5413 } else if (*p == HT) {
5436 if (i < m-2 && (*p || contd)) {
5442 if (zsout(ZDFILE,s1) < 0) {
5446 if (zsoutl(ZDFILE,pbuf) < 0) {
5451 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5452 cksyslog(SYSLG_DB,1,"debug",s1,pbuf);
5454 #endif /* CKSYSLOG */
5458 case F100: /* 4, "s1" */
5459 if (zsoutl(ZDFILE,s1) < 0) {
5464 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5465 cksyslog(SYSLG_DB,1,"debug",s1,NULL);
5467 #endif /* CKSYSLOG */
5469 case F101: /* 5, "s1=n" */
5470 sprintf(sp,"%s=%s\n",s1,ckfstoa(n));
5471 if (zsout(ZDFILE,dbptr) < 0) {
5476 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5477 cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5479 #endif /* CKSYSLOG */
5481 case F110: /* 6, "s1[s2]" */
5482 sprintf(sp,"%s[%s]\n",s1,s2);
5483 if (zsout(ZDFILE,dbptr) < 0) {
5488 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5489 cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5491 #endif /* CKSYSLOG */
5493 case F111: /* 7, "s1[s2]=n" */
5494 sprintf(sp,"%s[%s]=%s\n",s1,s2,ckfstoa(n));
5495 if (zsout(ZDFILE,dbptr) < 0) {
5500 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5501 cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5503 #endif /* CKSYSLOG */
5506 sprintf(sp,"\n?Invalid format for debug() - %d\n",f);
5507 if (zsout(ZDFILE,dbptr) < 0) {
5512 if (ckxsyslog >= SYSLG_DB && ckxlogging) {
5513 cksyslog(SYSLG_DB,1,"debug",dbptr,NULL);
5515 #endif /* CKSYSLOG */
5518 xdebug: /* Common exit point */
5521 ReleaseDebugMutex();
5523 deblog = 1; /* Restore this */
5530 dohexdump(CHAR *msg, CHAR *st, int cnt)
5532 dohexdump(msg,st,cnt) CHAR *msg; CHAR *st; int cnt;
5533 #endif /* CK_ANSIC */
5535 int i = 0, j = 0, k = 0;
5538 extern int SysInited;
5541 if (!deblog) return(0); /* If no debug log, don't. */
5542 if (!dbptr) { /* Allocate memory buffer */
5543 dbptr = malloc(DBUFL+1); /* This only happens once */
5553 if (RequestDebugMutex(30000))
5557 deblog = 0; /* Prevent infinite recursion */
5568 NULL,NULL,NULL,NULL,NULL,NULL,NULL
5570 if (zsout(ZDFILE,dbptr) < 0) {
5583 zsout(ZDFILE,dbptr);
5584 if (zsout(ZDFILE,dbptr) < 0) {
5590 for (i = 0; i < cnt; i++) {
5592 for (j = 0 ; (j < 16); j++) {
5596 (j == 8 ? "| " : ""),
5602 (j == 8 ? "| " : "")
5604 ckstrncat(dbptr,tmp,DBUFL+1);
5606 ckstrncat(dbptr," ",DBUFL+1);
5607 for (k = 0; (k < 16) && ((i + k) < cnt); k++) {
5610 (k == 8 ? " " : ""),
5611 isprint(st[i + k]) ? st[i + k] : '.'
5613 ckstrncat(dbptr,tmp,DBUFL+1);
5615 ckstrncat(dbptr,"\n",DBUFL+1);
5617 if (zsout(ZDFILE,dbptr) < 0) {
5628 ReleaseDebugMutex();
5636 /* Session Log... */
5642 logchar(unsigned short c)
5648 #endif /* CK_ANSIC */
5650 /* logchar */ { /* Log character c to session log */
5657 if ((sessft != XYFT_T) || (
5674 #endif /* STRATUS */
5675 #endif /* datageneral */
5687 if (c == '\0' && !sessft) /* NUL in text mode */
5688 if (slognul) oktolog = 1; /* only if padding (2009/10/22) */
5691 if (slogts) { /* Log is timestamped */
5692 if (tsstate == 0) { /* State = between-lines */
5693 char * p; /* zstime() pointer */
5694 char ts[48]; /* timestamp buffer */
5695 ztime(&p); /* Get asctime() string */
5696 ckstrncpy(ts,p,32); /* Make safe copy */
5697 if (ztmsec > -1L) { /* Add msecs if we have them */
5698 sprintf(&ts[19],".%03ld: ",ztmsec); /* SAFE */
5704 if (zsout(ZSFILE,&ts[11]) < 0)
5708 if (c == '\n') /* At end of line? */
5709 tsstate = 0; /* yes */
5711 tsstate = 1; /* no */
5712 if (zchout(ZSFILE,(CHAR)(c & 0xFF)) < 0) /* Log the character */
5714 if (tsstate == 0 && slognul != 0) { /* Null-terminating lines? */
5715 if (zchout(ZSFILE,(CHAR)0) < 0) /* Add a NUL */
5722 conoll("ERROR WRITING SESSION LOG, LOG CLOSED!");
5725 #endif /* NOLOCAL */
5729 logstr(s, len) char * s; int len; { /* Log string to session log */
5734 while (seslog && (n < len))
5736 #endif /* NOLOCAL */
5747 /* VOS has curses but no tgetent() */
5749 tgetent(s1, s2) char * s1, * s2; {
5752 #endif /* STRATUS */
5756 _PROTOTYP(int tgetent,(char *, char *));
5761 There are three different ways to do fullscreen on VMS.
5762 1. Use the real curses library, VAXCCURSE.
5763 2. Use do-it-yourself code.
5764 3. Use the Screen Manager, SMG$.
5766 Method 1 doesn't work quite right; you can't call endwin(), so once you've
5767 started curses mode, you can never leave.
5769 Method 2 doesn't optimize the screen, and so much more time is spent in
5770 screen writes. This actually causes file transfers to fail because the
5771 tty device input buffer can be overrun while the screen is being updated,
5772 especially on a slow MicroVAX that has small typeahead buffers.
5774 In the following #ifdef block, #define one of them and #undef the other 2.
5776 So now let's try method 3...
5779 #define CK_SMG /* Screen Manager */
5780 #undef MYCURSES /* Do-it-yourself */
5781 #undef VMSCURSE /* VAXCCURSE library */
5784 But just before New Years, 2000, the SMG library seemed to break on
5785 both VMS systems we have here (an Alpha with VMS 7.1 and a VAX with 5.5).
5786 So back to MYCURSES, which works fine.
5797 #endif /* CK_WREFRESH */
5798 #endif /* MYCURSES */
5800 /* S C R E E N C -- Screen display function, uses curses */
5802 /* Idea for curses display contributed by Chris Pratt of APV Baker, UK */
5804 /* Avoid conficts with curses.h */
5807 /* Same as ckcasc.h, but in a different radix... */
5814 #undef VOID /* This was defined in ckcdeb.h */
5815 #endif /* MYCURSES */
5817 #undef BS /* These were defined in ckcasc.h */
5824 #undef SP /* Used in ncurses */
5825 #define CHR_SP 32 /* Use this instead */
5827 #ifdef VMS /* VMS fullscreen display */
5828 #ifdef MYCURSES /* Do-it-yourself method */
5829 extern int isvt52; /* From CKVTIO.C */
5830 #define printw printf
5832 #ifdef VMSCURSE /* VMS curses library VAXCCURSE */
5834 /* Note: Screen manager doesn't need a header file */
5835 #endif /* VMSCURSE */
5836 #endif /* MYCURSES */
5838 #ifdef MYCURSES /* Do-it-yourself method */
5839 #define isvt52 0 /* Used by OS/2, VT-100/ANSI always */
5841 #define printw ckxprintf
5842 #else /* CKXPRINTF */
5844 #define printw Vscrnprintw
5846 #define printw printf
5848 #endif /* CKXPRINTF */
5849 #else /* Use real curses */
5850 #ifdef CK_NCURSES /* or ncurses... */
5851 #ifdef CKXPRINTF /* Our printf macro conflicts with */
5852 #undef printf /* use of "printf" in ncurses.h */
5853 #endif /* CKXPRINTF */
5854 #include <ncurses.h>
5856 #define printf ckxprintf
5857 #endif /* CKXPRINTF */
5858 #else /* Not ncurses */
5859 #ifdef CKXPRINTF /* Our printf macro conflicts with */
5860 #undef printf /* use of "printf" in curses.h */
5861 #endif /* CKXPRINTF */
5862 #ifdef M_XENIX /* SCO XENIX... */
5865 #endif /* M_TERMCAP */
5868 #endif /* M_TERMINFO */
5869 #endif /* M_XENIX */
5871 #undef NLS /* Avoid 'redeclaration of free'. */
5875 #define printf ckxprintf
5876 #endif /* CKXPRINTF */
5877 #endif /* CK_NCURSES */
5878 #endif /* MYCURSES */
5882 _PROTOTYP(int tgetent,(char *, char *));
5883 _PROTOTYP(char *tgetstr,(char *, char **));
5884 _PROTOTYP(int tputs,(char *, int, int (*)()));
5885 _PROTOTYP(char *tgoto,(const char *, int, int));
5888 #endif /* CK_CURSES */
5890 /* F X D I N I T -- File Xfer Display Initialization */
5897 /* Can't use VOID because of curses.h */
5902 #endif /* CK_ANSIC */
5904 #endif /* MYCURSES */
5905 #endif /* CK_CURSES */
5908 static int notermcap = 1;
5910 static int notermcap = 0;
5911 #endif /* NOTERMCAP */
5915 fxdinit(xdispla) int xdispla; {
5922 debug(F101,"fxdinit xdispla","",xdispla);
5923 debug(F101,"fxdinit fxd_inited","",fxd_inited);
5927 /* No curses for IKSD */
5932 if (fxd_inited) /* Only do this once */
5937 if (xdispla == XYFD_R || xdispla == XYFD_S || xdispla == XYFD_B) {
5939 printf("%s\n",xfrmsg);
5940 makestr(&xfrmsg,NULL);
5946 /* Force BRIEF in Batch logs */
5947 if (batch && (xdispla == XYFD_C || xdispla == XYFD_S))
5950 if (xdispla == XYFD_C || xdispla == 9999) {
5955 Allocate tgetent() buffer. Make it big -- some termcaps can be huge;
5956 tgetent() merrily writes past the end of the buffer, causing core dumps
5959 trmbuf = (char *)malloc(TRMBUFL);
5962 debug(F101,"fxdinit malloc trmbuf","FAILED",TRMBUFL);
5967 debug(F111,"fxdinit malloc trmbuf","OK",TRMBUFL);
5968 debug(F001,"fxdinit trmbuf","",trmbuf);
5969 memset(trmbuf,'\0',(size_t)TRMBUFL);
5970 debug(F100,"fxdinit memset OK","",0);
5971 #endif /* COMMENT */
5973 #endif /* DYNAMIC */
5975 debug(F100,"fxdinit before getenv(TERM)","",0);
5977 debug(F110,"fxdinit after getenv(TERM)",s,0);
5980 debug(F110,"fxdinit before tgetent()",s,0);
5981 x = tgetent(trmbuf,s);
5982 debug(F111,"fxdinit tgetent",s,x);
5986 debug(F110,"fxdinit TERM null - no tgetent",s,0);
5988 if (x < 1 && !quiet && !backgrd
5993 printf("Warning: terminal type unknown: \"%s\"\n",s);
5995 /* Confusing - nobody knows what this means */
5996 printf("SCREEN command will use ANSI sequences.\n");
5997 #endif /* COMMENT */
5999 printf("Fullscreen file transfer display disabled.\n");
6006 #endif /* MYCURSES */
6009 #endif /* CK_CURSES */
6011 #endif /* STRATUS */
6013 #endif /* COHERENT */
6015 #endif /* NODISPLAY */
6020 Long section for Screen Manager starts here...
6025 #include <smgdef.h> /* use this on VAX C 2.4 */
6026 /* #include <smgmsg.h> */
6028 #include <smg$routines.h> /* Martin Zinser */
6029 #endif /* OLD_VMS */
6031 extern unsigned int vms_status; /* Used for system service return status */
6033 static long smg_pasteboard_id = -1; /* pasteboard identifier */
6034 static long smg_display_id = -1; /* display identifier */
6035 static int smg_open = 0; /* flag if smg current open */
6036 static int smg_inited = 0; /* flag if smg initialized */
6039 #define clrtoeol() SMG$ERASE_LINE(&smg_display_id, 0, 0)
6041 #define clear() SMG$ERASE_DISPLAY(&smg_display_id, 0, 0, 0, 0)
6043 #define touchwin(scr) SMG$REPAINT_SCREEN(&smg_pasteboard_id)
6045 #else /* Not COMMENT */
6047 #define clrtoeol() smg$erase_line(&smg_display_id, 0, 0)
6049 #define clear() smg$erase_display(&smg_display_id, 0, 0, 0, 0)
6051 #define touchwin(scr) smg$repaint_screen(&smg_pasteboard_id)
6052 #endif /* COMMENT */
6054 #define clearok(curscr,ok) /* Let wrefresh() do the work */
6056 #define wrefresh(cursrc) touchwin(scr)
6059 move(row, col) int row, col; {
6060 /* Change from 0-based for curses to 1-based for SMG */
6064 debug(F111,"VMS smg move",ckitoa(row),col);
6065 #ifdef COMMENT /* Martin Zinser */
6066 CHECK_ERR("move: smg$set_cursor_abs",
6067 SMG$SET_CURSOR_ABS(&smg_display_id, &row, &col));
6069 CHECK_ERR("move: smg$set_cursor_abs",
6070 smg$set_cursor_abs(&smg_display_id, &row, &col));
6071 #endif /* COMMENT */
6072 debug(F101,"VMS smg move vms_status","",vms_status);
6077 #endif /* VMS_V40 */
6080 #endif /* VMS_V42 */
6083 #endif /* VMS_V44 */
6087 int rows = 24, cols = 80;
6088 int row = 1, col = 1;
6090 debug(F101,"VMS initscr smg_pasteboard_id A","",smg_pasteboard_id);
6092 if (smg_pasteboard_id == -1) { /* Open the screen */
6093 #ifdef OLD_VMS /* Note: Routine calls lowercased 9/96 */
6094 CHECK_ERR("initscr: smg$create_pasteboard",
6095 smg$create_pasteboard(&smg_pasteboard_id, 0, 0, 0, 0));
6097 /* For VMS V5, not tested */
6098 CHECK_ERR("initscr: smg$create_pasteboard",
6099 smg$create_pasteboard(&smg_pasteboard_id, 0, 0, 0, 0, 0));
6100 #endif /* OLD_VMS */
6102 debug(F101,"VMS initscr smg_pasteboard_id B","",smg_pasteboard_id);
6103 if (smg_pasteboard_id == -1) {
6104 printf("?Error initializing fullscreen display\n");
6109 debug(F101,"VMS initscr smg_display_id","",smg_display_id);
6110 if (smg_display_id == -1) { /* Create a display window */
6112 #ifdef COMMENT /* Martin Zinser */
6113 CHECK_ERR("initscr: smg$create_virtual_display",
6114 SMG$CREATE_VIRTUAL_DISPLAY(&rows, &cols, &smg_display_id,
6117 /* Connect the display window to the screen */
6118 CHECK_ERR("initscr: smg$paste_virtual_display",
6119 SMG$PASTE_VIRTUAL_DISPLAY(&smg_display_id,&smg_pasteboard_id,
6122 CHECK_ERR("initscr: smg$create_virtual_display",
6123 smg$create_virtual_display(&rows, &cols, &smg_display_id,
6126 /* Connect the display window to the screen */
6127 CHECK_ERR("initscr: smg$paste_virtual_display",
6128 smg$paste_virtual_display(&smg_display_id,&smg_pasteboard_id,
6130 #endif /* COMMENT */
6132 debug(F101,"VMS initscr smg_open A","",smg_open);
6133 if (!smg_open) { /* Start a batch update */
6136 CHECK_ERR("initscr: smg$begin_pasteboard_update",
6137 SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id));
6139 CHECK_ERR("initscr: smg$begin_pasteboard_update",
6140 smg$begin_pasteboard_update(&smg_pasteboard_id));
6141 #endif /* COMMENT */
6142 debug(F101,"VMS initscr smg$begin_pasteboard_update","",vms_status);
6144 debug(F101,"VMS initscr smg_open B","",smg_open);
6151 debug(F101,"refresh smg_pasteboard_id","",smg_pasteboard_id);
6153 if (smg_open == 0 || smg_pasteboard_id == -1)
6156 #ifdef COMMENT /* Martin Zinser */
6157 CHECK_ERR("refresh: smg$end_pasteboard_update",
6158 SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id));
6159 CHECK_ERR("refresh: smg$begin_pasteboard_update",
6160 SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id));
6162 CHECK_ERR("refresh: smg$end_pasteboard_update",
6163 smg$end_pasteboard_update(&smg_pasteboard_id));
6164 CHECK_ERR("refresh: smg$begin_pasteboard_update",
6165 smg$begin_pasteboard_update(&smg_pasteboard_id));
6166 #endif /* COMMENT */
6177 CHECK_ERR("endwin: smg$end_pasteboard_update",
6178 SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id));
6180 CHECK_ERR("endwin: smg$end_pasteboard_update",
6181 smg$end_pasteboard_update(&smg_pasteboard_id));
6182 #endif /* COMMENT */
6188 These calls clear the screen.
6189 (convert routine calls to lowercase - Martin Zinser)
6191 CHECK_ERR("endwin: smg$delete_virtual_display",
6192 SMG$DELETE_VIRTUAL_DISPLAY(&smg_display_id));
6193 smg_display_id = -1;
6195 CHECK_ERR("endwin: smg$delete_pasteboard",
6196 SMG$DELETE_PASTEBOARD(&smg_pasteboard_id, 0));
6197 smg_pasteboard_id = -1;
6198 #endif /* COMMENT */
6202 /* DECC 6.2 screams bloody murder about printw ("not enough args") */
6203 /* but adding the following prototype only makes it holler louder. */
6205 /* "varargs" prototype for printw */
6206 _PROTOTYP(static int printw,(char *, ...));
6208 #endif /* COMMENT */
6212 _PROTOTYP(static void printw,(char *, ...));
6214 printw(char *str,...) {
6217 $DESCRIPTOR(text_dsc, 0);
6218 text_dsc.dsc$a_pointer=buf;
6222 text_dsc.dsc$w_length = vsprintf(buf, str, ap);
6224 CHECK_ERR("printw: smg$put_chars",
6225 smg$put_chars(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0));
6229 printw(str, a1, a2, a3, a4, a5, a6, a7, a8)
6231 long a1, a2, a3, a4, a5, a6, a7, a8;
6234 $DESCRIPTOR(text_dsc, 0);
6237 text_dsc.dsc$a_pointer=buf;
6238 text_dsc.dsc$w_length = sprintf(buf, str, a1, a2, a3, a4, a5, a6, a7, a8);
6239 CHECK_ERR("printw: smg$put_chars",
6240 smg$put_chars(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0));
6246 ck_curpos(row, col) {
6247 debug(F111,"VMS smg ck_curpos",ckitoa(row),col);
6248 if (!smg_inited || !smg_open) {
6251 debug(F101,"VMS smg curpos smg_open","",smg_open);
6254 debug(F111,"VMS smg ck_curpos",ckitoa(row-1),col-1);
6255 move(row - 1, col - 1); /* SMG is 0-based */
6263 debug(F101,"VMS smg ck_cls smg_inited","",smg_inited);
6264 if (!smg_inited || !smg_open) {
6267 debug(F101,"VMS smg ck_cls smg_open","",smg_open);
6278 debug(F101,"VMS smg ck_cleol smg_inited","",smg_inited);
6279 if (!smg_inited || !smg_open) {
6282 debug(F101,"VMS smg ck_cleol smg_open","",smg_open);
6294 Do-it-yourself curses implementation for VMS, OS/2 and other ANSI/VT-100's.
6295 Supports only the VT52 and VT1xx (and later VT2xx/3xx/4xx) terminals.
6296 By Terry Kennedy, St Peters College.
6298 First, some stuff we can just ignore:
6302 touchwin(x) int x; {
6319 * Now, some stuff we need to do:
6322 _PROTOTYP( int move, (int, int) );
6325 move(row, col) int row, col; {
6327 printf("\033Y%c%c", row + 037, col + 037);
6329 printf("\033[%d;%dH", row + 1, col + 1);
6364 ck_curpos(row, col) int row, col; {
6370 /* Windows NT and Windows 95 do not provide ANSI emulation */
6371 /* Therefore we might as well not use it for OS/2 either */
6374 move(row, col) int row, col; {
6376 SetCurPos(row, col);
6377 #endif /* ONETERMUPD */
6378 lgotoxy( VCMD, col+1, row+1);
6388 if (VscrnGetBufferSize(VCMD) > 0) {
6389 VscrnScroll(VCMD, UPWARD, 0,
6390 VscrnGetHeight(VCMD)-(1),
6391 VscrnGetHeight(VCMD)-(0), TRUE, CHR_SP);
6392 cleartermscreen(VCMD);
6397 WrtNCell(cell, cmd_rows * cmd_cols, 0, 0);
6398 #endif /* ONETERMUPD */
6410 GetCurPos(&row, &col );
6411 WrtNCell(cell, cmd_cols - col -1, row, col);
6412 #endif /* ONETERMUPD */
6413 clrtoeoln(VCMD,CHR_SP);
6419 ck_curpos(row, col) int row, col; {
6435 #endif /* MYCURSES */
6441 /* Termcap/Terminfo section */
6443 static char cur_cls[32] = { NUL, NUL };
6444 static char cur_cleol[32] = { NUL, NUL };
6445 static char cur_cm[64] = { NUL, NUL };
6446 static char tgsbuf[128] = { NUL, NUL };
6451 #endif /* CK_ANSIC */
6452 ck_termset(x) int x; {
6457 debug(F100,"tgetent is a macro","",0);
6458 #endif /* tgetent */
6460 debug(F100,"tgetstr is a macro","",0);
6461 #endif /* tgetstr */
6463 debug(F100,"tputs is a macro","",0);
6466 debug(F100,"tgoto is a macro","",0);
6469 /* tgetstr() gets a segmentation fault on OSF/1 */
6470 debug(F100,"ck_termset NOTERMCAP","",0);
6473 debug(F100,"ck_termset notermcap","",0);
6476 debug(F101,"ck_termset x","",x);
6481 debug(F110,"ck_termset calling tgetstr","cl",0);
6482 if (tgetstr("cl", &bp)) { /* Get clear-screen code */
6483 debug(F110,"ck_termset tgetstr cl",tgsbuf,"");
6484 if ((int)strlen(tgsbuf) < 32)
6485 ckstrncpy(cur_cls,tgsbuf,32);
6489 if (tgetstr("ce", &bp)) { /* Get clear-to-end-of-line code */
6490 debug(F110,"ck_termset tgetstr ce",tgsbuf,"");
6491 if ((int)strlen(tgsbuf) < 32)
6492 ckstrncpy(cur_cleol,tgsbuf,32);
6496 if (tgetstr("cm", &bp)) { /* Get cursor-movement code */
6497 debug(F110,"ck_termset tgetstr cm",tgsbuf,"");
6498 if ((int)strlen(tgsbuf) < 64)
6499 ckstrncpy(cur_cm,tgsbuf,64);
6503 #endif /* NOTERMCAP */
6508 #define TPUTSFNTYPE void
6510 #define TPUTSFNTYPE int
6511 #endif /* TPUTSISVOID */
6512 #endif /* TPUTSFNTYPE */
6514 #ifndef TPUTSARGTYPE
6516 #define TPUTSARGTYPE char
6519 #define TPUTSARGTYPE char
6521 #define TPUTSARGTYPE int
6524 #endif /* TPUTSARGTYPE */
6528 ck_outc(TPUTSARGTYPE x)
6530 ck_outc(x) TPUTSARGTYPE x;
6531 #endif /* CK_ANSIC */
6532 { /* To satisfy tputs() arg3 prototype */
6536 rc = (inserver) ? ttoc(c) : conoc(c);
6539 #endif /* TPUTSISVOID */
6543 ck_curpos(row, col) int row, col; {
6545 TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
6547 TPUTSFNTYPE (*fn)();
6548 #endif /* CK_ANSIC */
6551 if (!cur_cm[0]) { /* We don't have escape sequences */
6553 return(-1); /* Do nothing */
6555 /* Both C-Kermit's SCREEN command and ANSI/VT100 are 1-based */
6556 printf("\033[%d;%dH", row, col); /* Or default to ANSI */
6557 #endif /* COMMENT */
6560 /* termcap/terminfo is 0-based */
6562 #ifdef TPUTSARG1CONST
6564 #endif /* TPUTSARG1CONST */
6565 tgoto(cur_cm,col-1,row-1),1,fn);
6573 TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
6575 TPUTSFNTYPE (*fn)();
6576 #endif /* CK_ANSIC */
6579 if (!cur_cls[0]) { /* If we don't have escape sequences */
6581 return(-1); /* Do nothing */
6583 printf("\033[;H\033[2J"); /* Or default to ANSI */
6584 #endif /* COMMENT */
6587 debug(F111,"ck_cls 2",cur_cls,fxd_inited);
6588 tputs(cur_cls,cmd_rows,fn);
6596 TPUTSFNTYPE (*fn)(TPUTSARGTYPE);
6598 TPUTSFNTYPE (*fn)();
6599 #endif /* CK_ANSIC */
6602 if (!cur_cleol[0]) { /* If we don't have escape sequences */
6604 return(-1); /* Do nothing */
6606 printf("\033[K"); /* Or use ANSI */
6607 #endif /* COMMENT */
6610 tputs(cur_cleol,1,fn);
6614 #endif /* CK_CURPOS */
6617 ck_termset(x) int x; {
6620 #endif /* NOTERMCAP */
6626 printf("\033[;H\033[2J");
6637 ck_curpos(row, col) int row, col; {
6638 printf("\033[%d;%dH", row, col);
6641 #endif /* CK_CURPOS */
6645 static int cinit = 0; /* Flag for curses init'd */
6646 static int cendw = 0; /* endwin() was called */
6649 #ifdef CK_ANSIC /* Because VOID used by curses.h */
6656 #endif /* MYCURSES */
6657 #endif /* CK_ANSIC */
6658 #ifdef CK_ANSIC /* Update % transfered and % bar */
6659 updpct(long old, long new)
6660 #else /* CK_ANSIC */
6661 updpct(old, new) long old, new;
6662 #endif /* CK_ANSIC */
6670 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_PCD, (long) new);
6681 move(CW_PCD, 26 + m);
6685 if ((m + 1) % 5 == 0)
6692 if (new % 2 != 0) printw("-");
6693 /* move(CW_PCD, 22+53); */
6696 printw("%c", '\333');
6700 printw("%c", '\261');
6703 #endif /* CK_PCT_BAR */
6705 #else /* !COMMENT */
6707 #define CHAR1 '\333' /* OS2 - CP437 */
6708 #define CHAR2 '\261'
6710 #define CHAR1 '/' /* Default */
6713 debug(F101,"updpct old","",old);
6714 debug(F101,"updpct new","",new);
6716 printw("%-3ld", new); /* (was) printw("%ld", new); */
6719 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) new );
6736 printw("%c", CHAR1);
6738 printw("%c", CHAR2);
6741 #endif /* CK_PCT_BAR */
6742 #endif /* COMMENT */
6745 static CK_OFF_T old_tr = (CK_OFF_T)-1; /* Time remaining previously */
6749 shoetl(CK_OFF_T old_tr, long cps, CK_OFF_T fsiz, CK_OFF_T howfar)
6751 shoetl(old_tr, cps, fsiz, howfar) long cps; CK_OFF_T old_tr, fsiz, howfar;
6752 #endif /* CK_ANSIC */
6753 /* shoetl */ { /* Estimated time left in transfer */
6754 CK_OFF_T tr; /* Time remaining, seconds */
6757 if (fsiz > 0L && cps > 0L)
6758 tr = (CK_OFF_T)((CKFLOAT)(fsiz - howfar) / (CKFLOAT)cps);
6762 tr = (fsiz > 0L && cps > 0L) ?
6763 ((fsiz - howfar) / cps) :
6765 #endif /* GFTIMER */
6767 if (tr > (CK_OFF_T)-1) {
6769 printw("%s",hhmmss(tr));
6772 KuiSetProperty(KUI_FILE_TRANSFER, (long)CW_TR, (long)hhmmss(tr));
6778 printw("(unknown)");
6781 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "(unknown)" );
6791 shocps(int pct, CK_OFF_T fsiz, CK_OFF_T howfar)
6793 shocps(pct, fsiz, howfar) int pct; CK_OFF_T fsiz, howfar;
6794 #endif /* CK_ANSIC */
6797 static CK_OFF_T oldffc = 0L;
6798 #endif /* CPS_WEIGHTED */
6803 #endif /* GFTIMER */
6806 xx = (gtv >= 0.0) ? gtv : 0.0; /* Floating-point version */
6808 if ((gtv - oldgtv) < (CKFLOAT) 1.0) /* Only do this once per second */
6812 xx = (gtv >= 0) ? gtv : 0; /* Whole-number version */
6814 if ((gtv - oldgtv) < 1)
6817 #endif /* GFTIMER */
6820 /* debug(F100,"SHOCPS: WEIGHTED","",0); */
6821 if (gtv != oldgtv) { /* The first packet is ignored */
6825 if (oldcps && oldgtv >
6830 #endif /* GFTIMER */
6831 ) { /* The first second is ignored */
6833 This version of shocps() produces a weighted average that some
6834 people like, but most people find it disconcerting and bombard us
6835 with questions and complaints about why the CPS figure fluctuates so
6836 wildly. So now you only get the weighted average if you build the
6837 program yourself with CPS_WEIGHTED defined.
6841 cps = (long)((((CKFLOAT)oldcps * 3.0) +
6842 (CKFLOAT)(ffc - oldffc) / (gtv-oldgtv) ) / 4.0);
6844 cps = ( (oldcps * 3) + (ffc - oldffc) / (gtv-oldgtv) ) / 4;
6845 #endif /* GFTIMER */
6847 /* And an alternate weighting scheme from Vincent Fatica... */
6849 ((1+pct/300)*oldffc/oldgtv+(1-pct/100)*(ffc-oldffc)/(gtv-oldgtv)))
6851 #endif /* CPS_VINCE */
6853 /* No weighted average since there is nothing to weigh */
6855 cps = (long)(gtv != 0.0 ?
6856 (CKFLOAT)(ffc - oldffc) / (gtv - oldgtv) :
6859 cps = gtv ? (ffc - oldffc) / (gtv - oldgtv) : (ffc - oldffc) ;
6860 #endif /* GFTIMER */
6865 debug(F101,"SHOCPS: pct ","",pct);
6866 debug(F101,"SHOCPS: gtv ","",gtv);
6867 debug(F101,"SHOCPS: oldgtv","",oldgtv);
6868 debug(F101,"SHOCPS: dgtv ","",(long)(gtv-oldgtv));
6869 debug(F101,"SHOCPS: ffc ","",ffc);
6870 debug(F101,"SHOCPS: oldffc","",oldffc);
6871 debug(F101,"SHOCPS: dffc ","",ffc-oldffc);
6872 debug(F101,"SHOCPS: cps ","",cps);
6875 #endif /* COMMENT */
6880 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
6886 #else /* !CPS_WEIGHTED */
6890 debug(F100,"SHOCPS: NOT WEIGHTED","",0);
6891 debug(F101,"SHOCPS: pct ","",pct);
6892 debug(F101,"SHOCPS: gtv ","",gtv);
6893 debug(F101,"SHOCPS: oldgtv ","",oldgtv);
6894 debug(F101,"SHOCPS: dgtv ","",(long)gtv - (long)oldgtv);
6895 debug(F101,"SHOCPS: ffc ","",ffc);
6896 debug(F101,"SHOCPS: oldffc ","",oldffc);
6897 debug(F101,"SHOCPS: dffc ","",ffc-oldffc);
6898 debug(F101,"SHOCPS: cps ","",cps);
6899 debug(F101,"SHOCPS: filcnt ","",filcnt);
6901 debug(F101,"SHOCPS: fpfsecs","",fpfsecs);
6902 #endif /* GFTIMER */
6904 debug(F101,"shocps gtv","",gtv);
6907 #endif /* COMMENT */
6908 /* debug(F101,"shocps fpfsecs","",fpfsecs); */
6909 secs = gtv - fpfsecs;
6910 /* debug(F101,"shocps secs","",(long)secs); */
6912 cps = (long)((CKFLOAT) ffc / secs);
6913 /* debug(F101,"shocps cps","",cps); */
6917 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
6923 #else /* Not GFTIMER */
6924 if ((secs = gtv - fsecs) > 0) {
6925 cps = (secs < 1L) ? ffc : ffc / secs;
6929 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, (long) cps );
6935 #endif /* GFTIMER */
6936 #endif /* CPS_WEIGHTED */
6938 if (cps > peakcps && /* Peak transfer rate */
6939 ((what & W_SEND && spackets > wslots + 4) ||
6940 (!(what & W_SEND) && spackets > 10))) {
6943 old_tr = shoetl(old_tr, cps, fsiz, howfar);
6948 #ifdef CK_ANSIC /* Because VOID used by curses.h */
6955 #endif /* MYCURSES */
6956 #endif /* CK_ANSIC */
6957 scrft() { /* Display file type */
6960 debug(F101,"scrft binary","",binary);
6964 ckstrncpy(xferstr,"LABELED",256);
6967 ckstrncpy(xferstr,"IMAGE",256);
6970 ckstrncpy(xferstr,"BINARY UNDEFINED",256);
6973 ckstrncpy(xferstr,"MACBINARY",256);
6976 ckstrncpy(xferstr,"TENEX",256);
6980 ckstrncpy(xferstr,"BINARY",256);
6984 if (what & W_SEND && sendstart > 0L) {
6985 if (sendmode == SM_PSEND) {
6986 ckstrncat(xferstr, " / partial", 256);
6987 } else if (sendmode == SM_RESEND) {
6988 ckstrncat(xferstr, " / resend", 256);
6990 } else if (what & W_RECV && rs_len > 0L) {
6991 ckstrncat(xferstr, " / resend", 256);
6993 #endif /* CK_RESEND */
6997 ckstrncpy(xferstr,"TEXT",256);
7002 ckstrncat(xferstr," (no translation)", 256);
7004 ckmakxmsg(&xferstr[4],252,
7006 fcsinfo[(what & W_SEND) ? ftp_csl : ftp_csx].keyword,
7008 fcsinfo[(what & W_SEND) ? ftp_csx : ftp_csl].keyword,
7010 NULL,NULL,NULL,NULL,NULL,NULL,NULL
7013 #endif /* NOUNICODE */
7015 if (tcharset == TC_TRANSP) {
7016 ckstrncat(xferstr, " (no translation)", 256);
7018 if (what & W_SEND) {
7019 sprintf( &xferstr[strlen(xferstr)], /* safe */
7021 fcsinfo[fcharset].keyword, /* built-in keywords */
7022 tcsinfo[tcharset].keyword /* lengths are controlled */
7025 sprintf( &xferstr[strlen(xferstr)], /* safe */
7027 tcsinfo[tcharset].keyword, /* built-in keywords */
7028 fcsinfo[fcharset].keyword); /* lengths controlled */
7031 #endif /* NOCSETS */
7034 printw("%s", xferstr);
7038 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TYP, (long) xferstr );
7045 static FILE *ck_stdout = NULL;
7046 static int ck_fd = -1;
7047 #endif /* CK_NEWTERM */
7049 static long pct = 0L, oldpct = 0L, oldrtt = -1L;
7050 static int oldtyp = 0, oldwin = -1, oldtry = -1, oldlen = -1, oldtim = -1;
7053 static char *netname[] = {
7055 "TCP/IP", /* 01 TCP (Sockets) */
7056 "TCP/IP", /* 02 TCP (Streams) */
7057 "X.25", /* 03 SunLink X.24 */
7058 "DECnet", /* 04 DECnet */
7059 "VAX PSI", /* 05 VAX PSI */
7060 "Named Pipes", /* 06 LAN Manager Named Pipe */
7061 "X.25", /* 07 Stratus VOS X.25 */
7062 "NetBIOS", /* 08 IBM NETBIOS */
7063 "SuperLAT", /* 07 Meridian SuperLAT */
7064 "File", /* 10 File */
7065 "Command", /* 11 Subprocess (pipe) */
7066 "DLL", /* 12 DLL does i/o */
7067 "X.25", /* 13 IBM AIXLink X.25 */
7068 "X.25", /* 14 HP-UX X.25 */
7069 "PTY", /* 15 Pseudoterminal */
7071 "<ERROR>", /* 17 In case new types are added */
7072 "<ERROR>", /* 18 but nobody remembers to update */
7073 "<ERROR>", /* 19 this table ... */
7076 static int nnetname = (sizeof(netname) / sizeof(char *));
7078 #endif /* NETCONN */
7082 screenc(int f, char c,CK_OFF_T n,char *s)
7086 int f; /* argument descriptor */
7087 char c; /* a character or small integer */
7088 CK_OFF_T n; /* a long integer */
7089 char *s; /* a string */
7090 #endif /* CK_ANSIC */
7093 extern int tls_active_flag, ssl_active_flag;
7096 extern int ttnproto;
7097 #endif /* RLOGCODE */
7099 static long fcnt = 0L; /* Number of files transferred */
7100 static CK_OFF_T fsiz = (CK_OFF_T)-1; /* Copy of file size */
7101 static CK_OFF_T fbyt = 0L; /* Total file bytes of all files transferred */
7102 static CK_OFF_T howfar = 0L; /* How much of current file has been xfer'd */
7103 static int pctlbl = 0L; /* Percent done vs Bytes so far */
7109 int len; /* Length of string */
7110 int errors = 0; /* Error counter */
7113 debug(F101,"screenc cinit","",cinit);
7114 debug(F101,"screenc cendw","",cendw);
7116 if (!s) s = ""; /* Always do this. */
7118 ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit */
7119 net = network || ftp;
7120 xnet = ftp ? 1 : nettype; /* NET_TCPB == 1 */
7122 if (cinit == 0 || cendw > 0) { /* Handle borderline cases... */
7123 if (f == SCR_CW) { /* Close window, but it's not open */
7127 debug(F111,"screenc A",s,f);
7129 (f == SCR_PT && c == 'E')) { /* Fatal error before window open */
7130 conoll(""); conoc('?'); conoll(s); return; /* Regular display */
7133 if (cinit == 0) { /* Only call initscr() once */
7135 /* Check these now -- if they are defined but not numeric */
7136 /* they can crash curses */
7137 s = getenv("LINES");
7138 if (s) if (!rdigits(s)) {
7139 printf("?LINES variable not numeric: \"%s\".\n",s);
7140 printf("(Fullscreen display disabled)\n");
7144 s = getenv("COLUMNS");
7145 if (s) if (!rdigits(s)) {
7146 printf("?COLUMNS variable not numeric: \"%s\".\n",s);
7147 printf("(Fullscreen display disabled)\n");
7151 cendw = 1; /* New window needs repainting */
7153 if (!initscr()) { /* Oops, can't initialize window? */
7155 In fact, this doesn't happen. "man curses" says initscr() halts the
7156 entire program if it fails, which is true on the systems where I've
7157 tested it. It will fail if your terminal type is not known to it.
7158 That's why SET FILE DISPLAY FULLSCREEN calls tgetent() to make sure the
7159 terminal type is known before allowing a curses display.
7161 fprintf(stderr,"CURSES INITSCR ERROR\r\n");
7162 fdispla = XYFD_S; /* Fall back to CRT display */
7165 cinit++; /* Window initialized ok */
7166 debug(F100,"CURSES INITSCR OK","",0);
7168 #else /* Save some memory. */
7170 /* (From Andy Fyfe <andy@vlsi.cs.caltech.edu>)
7171 System V curses seems to reserve the right to alter the buffering
7172 on the output FILE* without restoring it. Fortunately System V
7173 curses provides newterm(), an alternative to initscr(), that
7174 allows us to specify explicitly the terminal type and input and
7175 output FILE pointers. Thus we duplicate stdout, and let curses
7176 have the copy. The original remains unaltered. Unfortunately,
7177 newterm() seems to be particular to System V.
7181 ck_fd = dup(fileno(stdout));
7182 ck_stdout = (ck_fd >= 0) ? (FILE *)fdopen(ck_fd, "w") : NULL;
7184 debug(F100,"screenc newterm...","",0);
7186 /* NOTE: It might be necessary to do this with stdin too! */
7187 /* This would have been the case in FreeBSD 4.1 but they fixed the */
7188 /* problem by restoring the buffering of stdin before the final release. */
7189 /* (But T.E. Dickey says stdin is not buffered?) */
7191 if (ck_stdout == NULL || newterm(s, ck_stdout, stdin) == 0) {
7193 "Fullscreen display not supported for terminal type: %s\r\n",s);
7194 fdispla = XYFD_S; /* Use CRT instead */
7197 debug(F100,"screenc newterm ok","",0);
7199 debug(F100,"screen calling initscr","",0);
7200 initscr(); /* Initialize curses. */
7201 debug(F100,"screen initscr ok","",0);
7202 #endif /* CK_NEWTERM */
7203 cinit++; /* Remember curses was initialized. */
7204 #endif /* COMMENT */
7206 ft_win = 1; /* Window is open */
7210 This totally repaints the screen, just what we want, but we can only
7211 do this with real curses, and then only if clearok() and wrefresh() are
7212 provided in the curses library.
7219 clearok(stdscr, 1); /* QNX doesn't have curscr */
7226 #else /* No CK_WREFRESH */
7228 Kermit's do-it-yourself method, works with all types of fullscreen
7229 support, but does not repaint all the fields. For example, the filename
7230 is lost, because it arrives at a certain time and never comes again, and
7231 Kermit presently does not save it anywhere. Making this method work for
7232 all fields would be a rather major recoding task, duplicating what curses
7233 already does, and would add a lot of complexity and storage space.
7236 #endif /* CK_WREFRESH */
7239 if (cendw) { /* endwin() was called previously */
7241 initscr(); /* (or should have been!) */
7248 In QNX, if we don't call initscr() here we core dump.
7249 I don't have any QNX curses documentation, but other curses manuals
7250 say that initscr() should be called only once per application, and
7251 experience shows that on other systems, calling initscr() here generally
7252 results in a core dump.
7254 debug(F100,"screenc re-calling initscr QNX","",0);
7260 But even so, second and subsequent curses displays are messed up.
7261 Calling touchwin, refresh, etc, doesn't make any difference.
7263 debug(F100,"screenc calling touchwin QNX","",0);
7265 debug(F100,"screenc calling refresh QNX","",0);
7267 #endif /* COMMENT */
7269 #else /* All others... */
7270 debug(F100,"screenc calling clear","",0);
7272 debug(F100,"screenc clear ok","",0);
7275 debug(F100,"screenc setup ok","",0);
7276 debug(F100,"screenc doing first move","",0);
7277 move(CW_BAN,0); /* Display the banner */
7278 debug(F110,"screenc myhost",myhost,0);
7280 debug(F110,"screenc myipaddr",myipaddr,0);
7281 #endif /* TCPSOCKET */
7283 debug(F100,"screenc calling first printw...","",0);
7284 /* Right here is where HP-UX 10.10 libxcurse.1 Rev 76.20 hangs... */
7285 #endif /* HPUX1010 */
7290 /* We need to perform this test because on non-TCP/IP */
7291 /* systems the call to getlocalipaddr() results in a */
7292 /* DNS Lookup which takes several minutes to time out */
7294 (xnet == NET_TCPA || xnet == NET_TCPB
7297 #endif /* SSHBUILTIN */
7302 if (myipaddr[0] && strcmp((char *)myhost,(char *)myipaddr))
7303 printw("%s, %s [%s]",versio,(char *)myhost,(char *)myipaddr);
7305 #endif /* TCPSOCKET */
7306 printw("%s, %s",versio,(char *)myhost);
7308 printw("%s",versio);
7311 debug(F100,"screenc first printw returns","",0);
7312 #endif /* HPUX1010 */
7314 printw("Current Directory: %s",zgtdir());
7317 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) zgtdir() );
7322 printw("Network Host: %s",
7324 ftp ? (ftp_host ? ftp_host : "(unknown)") :
7330 printw("Communication Device: %s",ttname);
7334 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_LIN, (long) ttname );
7340 printw("Network Type: ");
7343 printw("Communication Speed: ");
7345 move(CW_SPD,22); /* Serial speed or network type */
7350 if (xnet > nnetname)
7353 xname = netname[xnet];
7363 #endif /* SSHBUILTIN */
7364 #ifdef CK_ENCRYPTION
7365 || ck_tn_encrypting() && ck_tn_decrypting()
7366 #endif /* CK_ENCRYPTION */
7368 || tls_active_flag || ssl_active_flag
7372 #ifdef CK_ENCRYPTION
7373 || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
7374 #endif /* CK_ENCRYPTION */
7375 #endif /* CK_KERBEROS */
7376 #endif /* RLOGCODE */
7384 sprintf(buf,"%s (SECURE)",xname);
7385 KuiSetProperty(KUI_FILE_TRANSFER,
7391 printw("%s (SECURE)",xname);
7396 KuiSetProperty(KUI_FILE_TRANSFER,
7404 printw("(network)");
7407 KuiSetProperty(KUI_FILE_TRANSFER,
7413 #endif /* NETCONN */
7418 if (speed == 8880) {
7422 KuiSetProperty(KUI_FILE_TRANSFER,
7430 sprintf(speedbuf, "%ld", speed);
7431 printw("%s",speedbuf);
7434 KuiSetProperty(KUI_FILE_TRANSFER,
7445 KuiSetProperty(KUI_FILE_TRANSFER,
7454 printw("Parity: %s",ftp ? "none" : parnam((char)parity));
7457 KuiSetProperty(KUI_FILE_TRANSFER,
7459 (long) parnam((char)parity)
7464 if (/* rttflg && */ protocol == PROTO_K) {
7465 move(CW_TMO, 9); printw("RTT/Timeout:"); }
7466 #endif /* CK_TIMERS */
7467 move(CW_TYP,11); printw("File Type:");
7468 move(CW_SIZ,11); printw("File Size:");
7471 pctlbl = (what & W_SEND);
7472 printw("%s:", pctlbl ? "Percent Done" : "Bytes So Far");
7476 printw("%10s Protocol:", ftp ? "FTP" : ptab[protocol].p_name);
7477 #endif /* XYZ_INTERNAL */
7482 printw(" ...10...20...30...40...50...60...70...80...90..100");
7485 #endif /* CK_PCT_BAR */
7486 move(CW_TR, 1); printw("Estimated Time Left:");
7487 move(CW_CP, 2); printw("Transfer Rate, CPS:");
7488 move(CW_WS, 8); printw("Window Slots:%s",
7489 ((protocol == PROTO_K) && !ftp) ?
7492 move(CW_PT, 9); printw("Packet Type:");
7493 if (ftp || protocol != PROTO_K) {
7495 printw("%s", "N/A");
7496 move(CW_PC, 11); printw("I/O Count:");
7497 move(CW_PL, 10); printw("I/O Length:");
7499 move(CW_PC, 8); printw("Packet Count:");
7500 move(CW_PL, 7); printw("Packet Length:");
7503 move(CW_PR, 9); printw("Error Count:");
7505 move(CW_PR, 2); printw("Packet Retry Count:");
7508 move(CW_PB, 2); printw("Packet Block Check:");
7509 #endif /* COMMENT */
7510 move(CW_ERR,10); printw("Last Error:");
7511 move(CW_MSG, 8); printw("Last Message:");
7513 move(CW_MSG, 22); printw("%s",xfrmsg);
7514 makestr(&xfrmsg,NULL);
7518 printw("(Transfer interruption is disabled)");
7522 "<%s>X to cancel file, <%s>Z to cancel group, <%s><CR> to resend last packet",
7523 dbchr(escape), dbchr(escape), dbchr(escape)
7525 move(CW_INT + 1, 0);
7527 "<%s>E to send Error packet, ^C to quit immediately, <%s>L to refresh screen.",
7528 dbchr(escape), dbchr(escape)
7530 #else /* !CK_NEED_SIG */
7533 if (protocol == PROTO_K) {
7535 "X to cancel file, Z to cancel group, <Enter> to resend last packet,"
7539 #ifdef VMS /* In VMS avoid bottom line */
7541 "X: Cancel this file; E: Cancel transfer; ^C: Quit now; ^W: Refresh screen."
7545 "X to cancel file, Z to cancel group, <CR> to resend last packet,"
7551 move(CW_INT + 1, 0);
7552 if (protocol == PROTO_K) {
7554 "E to send Error packet, ^C to quit immediately, ^L to refresh screen."
7557 printw("^C to cancel file transfer.");
7560 #endif /* CK_NEED_SIG */
7565 debug(F101,"SCREENC switch","",f);
7566 debug(F000,"SCREENC c","",c);
7567 debug(F101,"SCREENC n","",n);
7569 len = strlen(s); /* Length of argument string */
7570 switch (f) { /* Handle our function code */
7571 case SCR_FN: /* Filename */
7572 oldpct = pct = 0L; /* Reset percents */
7574 gtv = (CKFLOAT) -1.0;
7575 /* oldgtv = (CKFLOAT) -1.0; */
7579 #endif /* GFTIMER */
7581 fsiz = (CK_OFF_T)-1; /* Invalidate previous file size */
7582 move(CW_PCD,22); /* Erase percent done from last time */
7585 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) 0 );
7586 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_FFC, (long) 0 );
7590 move(CW_SIZ,22); /* Erase file size from last time */
7593 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) 0 );
7597 move(CW_ERR,22); /* And last error message */
7600 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) "" );
7606 if (protocol == PROTO_K && streamok) {
7609 printw(" Kermit STREAMING:");
7611 printw(" STREAMING:");
7612 #endif /* XYZ_INTERNAL */
7614 #endif /* STREAMING */
7615 #endif /* COMMENT */
7617 if (what & W_SEND) { /* If we're sending... */
7619 if (what & W_FTP) { /* FTP */
7621 printw(" FTP PUT:");
7625 switch (sendmode) { /* Kermit */
7628 printw(" RESENDING:");
7632 printw(" SENDING:");
7637 printw(" SENDING:");
7638 #endif /* CK_RESEND */
7640 } else if (what & W_RECV) { /* If we're receiving... */
7642 if (what & W_FTP) { /* FTP */
7644 printw(" FTP GET:");
7648 printw(" RECEIVING:");
7651 } else if (what == (W_FTP|W_FT_DELE)) {
7653 printw("FTP DELETE:");
7655 } else { /* If we don't know... */
7656 move(CW_NAM,10); /* (should never see this) */
7657 printw(" File Name:");
7659 move(CW_NAM,22); /* Display the filename */
7661 printw("%.55s..",s);
7663 } else printw("%s",s);
7666 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
7669 q = len; /* Remember name length for later */
7671 scrft(); /* Display file type (can change) */
7678 case SCR_AN: /* File as-name */
7679 if (q + len + 4 < 58) { /* Will fit */
7680 move(CW_NAM, 22 + q);
7684 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
7687 } else { /* Too long */
7688 move(CW_NAM, 22); /* Overwrite previous name */
7690 if (len + 4 > 57) { /* wg15 */
7691 printw(" => %.51s..",s); /* wg15 */
7692 len = 53; /* wg15 */
7693 } else printw(" => %s",s); /* wg15 */
7696 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
7700 q += len + 4; /* Remember horizontal position */
7708 case SCR_FS: /* File size */
7711 if (fsiz > (CK_OFF_T)-1) {
7714 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) n );
7717 printw("%s",ckfstoa(n));
7720 printw("POSSIBLY EXCEEDS LOCAL FILE SIZE LIMIT");
7725 if (fsiz > (CK_OFF_T)-1) { /* Put up percent label */
7728 printw("Percent Done:");
7733 if (fsiz > (CK_OFF_T)-1) { /* Put up percent label */
7735 printw("Percent Done:");
7738 printw("Bytes So Far:");
7740 #endif /* COMMENT */
7742 scrft(); /* File type */
7749 case SCR_PT: /* Packet type or pseudotype */
7751 extern int sysindex;
7752 extern struct sysdata sysidlist[];
7753 /* Things that won't change after the 4th packet */
7755 printw("%s",parnam((char)parity));
7758 KuiSetProperty( KUI_FILE_TRANSFER,
7760 (long) parnam((char)parity)
7766 move(CW_PB, 22); /* Block check on this packet */
7772 #endif /* COMMENT */
7775 (ftp && (spackets == 1 || rpackets == 1)) ||
7784 ((protocol == PROTO_K) && (sysindex > -1))
7788 printw("Network Host: %s (%s)",
7790 ftp ? (ftp_host ? ftp_host : "") :
7796 sysidlist[sysindex].sid_name
7800 printw("Communication Device: %s (remote host is %s)",
7802 sysidlist[sysindex].sid_name
7810 if (/* rttflg && */ protocol == PROTO_K) {
7814 streaming && oldwin != -2
7817 #endif /* STREAMING */
7823 xx = (rttdelay + 500) / 1000;
7824 if (xx != oldrtt || rcvtimo != oldtim) {
7826 printw("%02ld / %02d", xx, rcvtimo);
7833 #endif /* CK_TIMERS */
7835 x = (what & W_RECV) ? /* Packet length */
7836 rpktl+(protocol==PROTO_K?1:0) :
7838 if (x != oldlen) { /* But only if it changed. */
7843 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PL, (long) x );
7849 move(CW_PC, 22); /* Packet count (always). */
7851 printw("%d", (what & W_RECV) ? rpackets : spackets);
7854 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PC, (long) spackets );
7859 if (protocol == PROTO_K && !ftp) { /* Window slots */
7866 sprintf(ws,"STREAMING");
7871 #endif /* STREAMING */
7872 if (wcur != oldwin) {
7873 sprintf(ws, "%d of %d", wcur < 1 ? 1 : wcur, wslotn);
7883 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_WS, (long) ws );
7888 errors = retrans + crunched + timeouts;
7889 if (errors != oldtry) { /* Retry count, if changed */
7891 printw("%d",errors);
7894 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PR, (long) errors );
7900 /* Sender's packet type */
7901 if (!ftp && (c != oldtyp && c != 'Y' && c != 'N')) {
7903 sprintf(type, "%c",c);
7908 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PT, (long) type );
7914 switch (c) { /* Now handle specific packet types */
7915 case 'S': /* Beginning of transfer */
7916 fcnt = fbyt = 0L; /* Clear counters */
7920 gtv = -1L; /* And old/new things... */
7921 #endif /* GFTIMER */
7925 case 'Z': /* or EOF */
7926 debug(F101,"screenc SCR_PT Z pktnum","",n);
7927 debug(F101,"screenc SCR_PT Z oldpct","",oldpct);
7928 debug(F101,"screenc SCR_PT Z pct","",pct);
7929 case 'D': /* Data packet */
7930 if (fsiz > 0L) { /* Show percent done if known */
7931 oldpct = pct; /* Remember previous percent */
7934 if (what & W_SEND) /* Account for PSEND or RESEND */
7935 howfar += sendstart;
7936 else if (what & W_RECV)
7938 #endif /* CK_RESEND */
7939 /* Percent done, to be displayed... */
7941 if (!discard && !cxseen && !czseen) pct = 100L;
7943 pct = (fsiz > 99L) ? (howfar / (fsiz / 100L)) : 0L;
7944 if (pct > 100L || /* Allow for expansion and */
7945 (oldpct == 99L && pct < 0L)) /* other boundary conditions */
7947 if (pct != oldpct) /* Only do this 100 times per file */
7948 updpct(oldpct, pct);
7951 printw("%s", ckfstoa(ffc));
7955 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) howfar);
7958 cps = shocps((int) pct, fsiz, howfar);
7959 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
7962 case '%': /* Timeouts, retransmissions */
7963 cps = shocps((int) pct, fsiz, howfar);
7964 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
7966 errors = retrans + crunched + timeouts;
7967 if (errors != oldtry) { /* Error count, if changed */
7969 printw("%d",errors);
7973 KuiSetProperty(KUI_FILE_TRANSFER,
7974 (long) CW_PR, (long) errors
7986 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_ERR, (long) s);
7992 case 'E': /* Error packet */
7994 move(CW_ERR,22); /* Print its data field */
7999 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
8004 #endif /* COMMENT */
8005 fcnt = fbyt = 0L; /* So no bytes for this file */
8007 case 'Q': /* Crunched packet */
8008 cps = shocps((int) pct, fsiz, howfar);
8009 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8011 printw("Damaged Packet");
8014 KuiSetProperty(KUI_FILE_TRANSFER,
8016 (long) "Damaged Packet"
8022 case 'q': /* Ctrl-C or connection lost */
8026 printw(*s ? s : "User interruption or connection lost");
8029 KuiSetProperty(KUI_FILE_TRANSFER,
8036 case 'T': /* Timeout */
8037 cps = shocps((int) pct, fsiz, howfar);
8038 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8040 printw("Timeout %d sec",rcvtimo);
8043 KuiSetProperty(KUI_FILE_TRANSFER,
8050 errors = retrans + crunched + timeouts;
8051 if (errors != oldtry) { /* Error count, if changed */
8053 printw("%d",errors);
8056 KuiSetProperty(KUI_FILE_TRANSFER,
8057 (long) CW_PR, (long) errors
8065 default: /* Others, do nothing */
8074 case SCR_ST: /* File transfer status */
8075 debug(F101,"screenc SCR_ST c","",c);
8076 debug(F101,"screenc SCR_ST success","",success);
8077 debug(F101,"screenc SCR_ST cxseen","",cxseen);
8079 move(CW_PCD,22); /* Update percent done */
8080 if (c == ST_OK) { /* OK, print 100 % */
8084 printw("%s", ckfstoa(ffc));
8087 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8092 } else if (fsiz > 0L) /* Not OK, update final percent */
8094 The else part writes all over the screen -- howfar and/or fsiz have
8095 been reset as a consequence of the not-OKness of the transfer.
8098 updpct(oldpct, (howfar * 100L) / fsiz);
8101 if (c == ST_OK) { /* OK, print 100 % */
8102 move(CW_PCD,22); /* Update percent done */
8104 if (oldpct == 0) /* Switching from "bytes so far" */
8105 clrtoeol(); /* to "percent done"... */
8108 printw("%s", ckfstoa(ffc));
8111 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8117 #endif /* COMMENT */
8120 #endif /* COMMENT */
8123 /* No, leave it there so they can read it */
8124 move(CW_MSG,22); /* Remove any previous message */
8127 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_MSG, (long) "" );
8130 clrtoeol(); refresh();
8131 #endif /* COMMENT */
8136 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "" );
8139 clrtoeol(); refresh();
8141 switch (c) { /* Print new status message */
8142 case ST_OK: /* Transfer OK */
8143 fcnt++; /* Count this file */
8144 if (what == (W_FTP|W_FT_DELE)) {
8147 printw("Delete OK");
8152 printw("Transfer OK");
8156 KuiSetProperty(KUI_FILE_TRANSFER,
8158 (long) "Transfer OK"
8162 clrtoeol(); refresh();
8165 case ST_DISC: /* Discarded */
8167 printw("File discarded");
8170 KuiSetProperty(KUI_FILE_TRANSFER,
8172 (long) "File discarded"
8178 #endif /* COMMENT */
8179 clrtoeol(); refresh();
8182 case ST_INT: /* Interrupted */
8184 printw("Transfer interrupted");
8187 KuiSetProperty(KUI_FILE_TRANSFER,
8189 (long) "Transfer interrupted"
8195 #endif /* COMMENT */
8196 clrtoeol(); refresh();
8199 case ST_SKIP: /* Skipped */
8201 if (n > 0 && n < nskreason)
8202 printw("File skipped (%s)",skreason[n]);
8204 printw("File skipped");
8207 KuiSetProperty(KUI_FILE_TRANSFER,
8209 (long) "File skipped"
8215 #endif /* COMMENT */
8216 clrtoeol(); refresh();
8219 case ST_ERR: /* Error message */
8221 if (!s) s = (char *)epktmsg;
8225 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
8230 #endif /* COMMENT */
8231 clrtoeol(); refresh();
8234 case ST_REFU: /* Refused */
8238 sprintf( errbuf, "Refused, %s", s ) ;
8239 printw("%s", errbuf);
8242 KuiSetProperty(KUI_FILE_TRANSFER,(long) CW_ERR,(long) errbuf);
8249 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Refused");
8255 #endif /* COMMENT */
8256 clrtoeol(); refresh();
8261 printw("Incomplete");
8264 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Incomplete");
8269 #endif /* COMMENT */
8270 clrtoeol(); refresh();
8278 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_MSG,(long)s);
8281 clrtoeol(); refresh();
8284 default: /* Bad call */
8286 printw("*** screen() called with bad status ***");
8289 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR,
8290 (long) "*** screen() called with bad status ***" );
8293 clrtoeol(); refresh(); return;
8296 case SCR_TC: { /* Transaction complete */
8298 move(CW_CP,22); /* Overall transfer rate */
8301 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, tfcps);
8304 printw("%s", ckfstoa(tfcps));
8307 move(CW_MSG,22); /* Print statistics in message line */
8312 "SUCCESS. Files: %ld, Bytes: %s, %ld CPS",
8317 printw("%s", msgbuf);
8320 KuiSetProperty(KUI_FILE_TRANSFER,
8330 printw(" Elapsed Time: %s",hhmmss((long)
8335 #endif /* GFTIMER */
8339 KuiSetProperty(KUI_FILE_TRANSFER,
8341 (long) hhmmss((long)
8346 #endif /* GFTIMER */
8351 move(23,0); clrtoeol(); /* Clear instructions lines */
8352 move(22,0); clrtoeol(); /* to make room for prompt. */
8356 oldgtv = (CKFLOAT) -1.0;
8359 #endif /* GFTIMER */
8362 debug(F100,"screenc endwin A","",0);
8366 Why and when was this call to conres() added? It makes no sense,
8367 and it breaks echoing on Solaris 8.
8371 #endif /* SOLARIS */
8372 #endif /* COMMENT */
8373 #endif /* VMSCURSE */
8376 pct = 100; oldpct = 0; /* Reset these for next time. */
8377 #endif /* COMMENT */
8378 oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
8381 if (xfrbel) bleep(BP_NOTE); /* Close window, then beep. */
8385 ft_win = 0; /* Window closed. */
8388 case SCR_EM: /* Error packet (fatal) */
8390 printw("FAILURE: %s",s);
8393 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
8396 if (xfrbel) bleep(BP_FAIL);
8399 #endif /* COMMENT */
8400 clrtoeol(); refresh(); return;
8402 case SCR_QE: /* Quantity equals */
8403 case SCR_TU: /* Undelimited text */
8404 case SCR_TN: /* Text delimited at start */
8405 case SCR_TZ: /* Text delimited at end */
8406 return; /* (ignored in fullscreen display) */
8408 case SCR_MS: /* Message from Kermit partner */
8411 clrtoeol(); refresh(); return;
8413 case SCR_XD: /* X-packet data */
8419 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
8422 clrtoeol(); refresh(); return;
8424 case SCR_CW: /* Close Window */
8425 clrtoeol(); move(23,0); clrtoeol(); move(22,0); clrtoeol();
8428 pct = 100; oldpct = 0; /* Reset these for next time. */
8429 #endif /* COMMENT */
8430 oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
8434 debug(F100,"screenc endwin B","",0);
8436 #endif /* VMSCURSE */
8437 ft_win = 0; /* Flag that window is closed. */
8440 case SCR_CD: /* Display current directory */
8445 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) s );
8455 default: /* Bad call */
8459 KuiSetProperty(KUI_FILE_TRANSFER,
8461 (long) "*** screen() called with bad function code ***"
8465 printw("*** screen() called with bad function code ***");
8466 clrtoeol(); refresh(); return;
8469 #endif /* CK_CURSES */
8474 screeng(int f, char c,long n,char *s)
8478 int f; /* argument descriptor */
8479 char c; /* a character or small integer */
8480 long n; /* a long integer */
8481 char *s; /* a string */
8482 #endif /* CK_ANSIC */
8485 extern int tls_active_flag, ssl_active_flag;
8488 extern int ttnproto;
8489 #endif /* RLOGCODE */
8491 static CK_OFF_T fsiz = (CK_OFF_T)-1; /* Copy of file size */
8492 static long fcnt = 0L; /* Number of files transferred */
8493 static long fbyt = 0L; /* Total file bytes of all files transferred */
8494 static CK_OFF_T howfar = (CK_OFF_T)0; /* How much of file xfer'd so far */
8495 static int pctlbl = 0L; /* Percent done vs Bytes so far */
8501 int len; /* Length of string */
8502 int errors = 0; /* Error counter */
8505 debug(F101,"screeng cinit","",cinit);
8506 debug(F101,"screeng cendw","",cendw);
8508 if (!s) s = ""; /* Always do this. */
8510 ftp = (what & W_FTP) ? 1 : 0; /* FTP or Kermit */
8511 net = network || ftp;
8512 xnet = ftp ? 1 : nettype; /* NET_TCPB == 1 */
8514 if (cinit == 0 || cendw > 0) { /* Handle borderline cases... */
8515 if (f == SCR_CW) { /* Close window, but it's not open */
8519 debug(F111,"screeng A",s,f);
8521 (f == SCR_PT && c == 'E')) { /* Fatal error before window open */
8522 conoll(""); conoc('?'); conoll(s); return; /* Regular display */
8525 if (cinit == 0) { /* Only call initscr() once */
8526 /* Check these now -- if they are defined but not numeric */
8527 /* they can crash curses */
8528 cendw = 1; /* New window needs repainting */
8529 debug(F100,"screeng calling initscr","",0);
8530 initscr(); /* Initialize curses. */
8531 debug(F100,"screeng initscr ok","",0);
8532 cinit++; /* Remember curses was initialized. */
8534 ft_win = 1; /* Window is open */
8538 This totally repaints the screen, just what we want, but we can only
8539 do this with real curses, and then only if clearok() and wrefresh() are
8540 provided in the curses library.
8543 #else /* No CK_WREFRESH */
8545 Kermit's do-it-yourself method, works with all types of fullscreen
8546 support, but does not repaint all the fields. For example, the filename
8547 is lost, because it arrives at a certain time and never comes again, and
8548 Kermit presently does not save it anywhere. Making this method work for
8549 all fields would be a rather major recoding task, duplicating what curses
8550 already does, and would add a lot of complexity and storage space.
8553 #endif /* CK_WREFRESH */
8556 if (cendw) { /* endwin() was called previously */
8557 debug(F100,"screeng setup ok","",0);
8558 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) zgtdir() );
8559 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_LIN,
8562 ftp ? (ftp_host ? ftp_host : "(unknown)") :
8570 if (xnet > nnetname)
8573 xname = netname[xnet];
8583 #endif /* SSHBUILTIN */
8584 #ifdef CK_ENCRYPTION
8585 || ck_tn_encrypting() && ck_tn_decrypting()
8586 #endif /* CK_ENCRYPTION */
8588 || tls_active_flag || ssl_active_flag
8592 #ifdef CK_ENCRYPTION
8593 || ttnproto == NP_EK4LOGIN || ttnproto == NP_EK5LOGIN
8594 #endif /* CK_ENCRYPTION */
8595 #endif /* CK_KERBEROS */
8596 #endif /* RLOGCODE */
8602 sprintf(buf,"%s (SECURE)",xname);
8603 KuiSetProperty(KUI_FILE_TRANSFER,
8608 KuiSetProperty(KUI_FILE_TRANSFER,
8614 KuiSetProperty(KUI_FILE_TRANSFER,
8618 #endif /* NETCONN */
8623 if (speed == 8880) {
8624 KuiSetProperty(KUI_FILE_TRANSFER,
8630 sprintf(speedbuf, "%ld", speed);
8631 KuiSetProperty(KUI_FILE_TRANSFER,
8637 KuiSetProperty(KUI_FILE_TRANSFER,
8643 KuiSetProperty(KUI_FILE_TRANSFER,
8645 (long) parnam((char)parity)
8647 pctlbl = (what & W_SEND);
8650 debug(F101,"SCREENC switch","",f);
8651 debug(F000,"SCREENC c","",c);
8652 debug(F101,"SCREENC n","",n);
8654 len = strlen(s); /* Length of argument string */
8655 switch (f) { /* Handle our function code */
8656 case SCR_FN: /* Filename */
8657 oldpct = pct = 0L; /* Reset percents */
8659 gtv = (CKFLOAT) -1.0;
8660 /* oldgtv = (CKFLOAT) -1.0; */
8664 #endif /* GFTIMER */
8666 fsiz = (CK_OFF_T)-1L; /* Invalidate previous file size */
8667 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PCD, (long) 0 );
8668 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_FFC, (long) 0 );
8669 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) 0 );
8670 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) "" );
8672 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
8673 q = len; /* Remember name length for later */
8674 scrft(); /* Display file type (can change) */
8680 case SCR_AN: /* File as-name */
8681 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
8687 case SCR_FS: /* File size */
8689 if (fsiz > (CK_OFF_T)-1) {
8690 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_SIZ, (long) n );
8692 if (fsiz > (CK_OFF_T)-1) { /* Put up percent label */
8697 scrft(); /* File type */
8703 case SCR_PT: /* Packet type or pseudotype */
8705 extern int sysindex;
8706 extern struct sysdata sysidlist[];
8707 /* Things that won't change after the 4th packet */
8708 KuiSetProperty( KUI_FILE_TRANSFER,
8710 (long) parnam((char)parity)
8714 (ftp && (spackets == 1 || rpackets == 1)) ||
8722 ((protocol == PROTO_K) && (sysindex > -1))
8726 sprintf(msgbuf,"Network Host: %s (%s)",
8728 ftp ? (ftp_host ? ftp_host : "") :
8734 sysidlist[sysindex].sid_name
8738 "Communication Device: %s (remote host is %s)",
8740 sysidlist[sysindex].sid_name
8743 KuiSetProperty( KUI_FILE_TRANSFER,
8751 if (/* rttflg && */ protocol == PROTO_K) {
8755 streaming && oldwin != -2
8758 #endif /* STREAMING */
8761 sprintf(msgbuf,"00 / 00");
8762 KuiSetProperty( KUI_FILE_TRANSFER,
8767 xx = (rttdelay + 500) / 1000;
8768 if (xx != oldrtt || rcvtimo != oldtim) {
8770 sprintf(msgbuf,"%02ld / %02d", xx, rcvtimo);
8771 KuiSetProperty( KUI_FILE_TRANSFER,
8781 #endif /* CK_TIMERS */
8783 x = (what & W_RECV) ? /* Packet length */
8784 rpktl+(protocol==PROTO_K?1:0) :
8786 if (x != oldlen) { /* But only if it changed. */
8787 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PL, (long) x );
8790 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PC, (long) spackets );
8792 if (protocol == PROTO_K && !ftp) { /* Window slots */
8799 sprintf(ws,"STREAMING");
8804 #endif /* STREAMING */
8805 if (wcur != oldwin) {
8806 sprintf(ws, "%d of %d", wcur < 1 ? 1 : wcur, wslotn);
8811 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_WS, (long) ws );
8814 errors = retrans + crunched + timeouts;
8815 if (errors != oldtry) { /* Retry count, if changed */
8816 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PR, (long) errors );
8819 /* Sender's packet type */
8820 if (!ftp && (c != oldtyp && c != 'Y' && c != 'N')) {
8822 sprintf(type, "%c",c);
8823 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_PT, (long) type );
8826 switch (c) { /* Now handle specific packet types */
8827 case 'S': /* Beginning of transfer */
8828 fcnt = fbyt = 0L; /* Clear counters */
8832 gtv = -1L; /* And old/new things... */
8833 #endif /* GFTIMER */
8837 case 'Z': /* or EOF */
8838 debug(F101,"screeng SCR_PT Z pktnum","",n);
8839 debug(F101,"screeng SCR_PT Z oldpct","",oldpct);
8840 debug(F101,"screeng SCR_PT Z pct","",pct);
8841 case 'D': /* Data packet */
8842 if (fsiz > 0L) { /* Show percent done if known */
8843 oldpct = pct; /* Remember previous percent */
8846 if (what & W_SEND) /* Account for PSEND or RESEND */
8847 howfar += sendstart;
8848 else if (what & W_RECV)
8850 #endif /* CK_RESEND */
8851 /* Percent done, to be displayed... */
8853 if (!discard && !cxseen && !czseen) pct = 100L;
8855 pct = (fsiz > 99L) ? (howfar / (fsiz / 100L)) : 0L;
8856 if (pct > 100L || /* Allow for expansion and */
8857 (oldpct == 99L && pct < 0L)) /* other boundary conditions */
8859 if (pct != oldpct) /* Only do this 100 times per file */
8860 updpct(oldpct, pct);
8862 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8864 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) howfar);
8865 cps = shocps((int) pct, fsiz, howfar);
8866 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8869 case '%': /* Timeouts, retransmissions */
8870 cps = shocps((int) pct, fsiz, howfar);
8871 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8873 errors = retrans + crunched + timeouts;
8874 if (errors != oldtry) { /* Error count, if changed */
8875 KuiSetProperty(KUI_FILE_TRANSFER,
8882 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_ERR, (long) s);
8886 case 'E': /* Error packet */
8888 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
8890 fcnt = fbyt = 0L; /* So no bytes for this file */
8892 case 'Q': /* Crunched packet */
8893 cps = shocps((int) pct, fsiz, howfar);
8894 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8895 KuiSetProperty(KUI_FILE_TRANSFER,
8897 (long) "Damaged Packet"
8900 case 'q': /* Ctrl-C or connection lost */
8902 if (!*s) s = "User interruption or connection lost";
8903 KuiSetProperty(KUI_FILE_TRANSFER,
8908 case 'T': /* Timeout */
8909 cps = shocps((int) pct, fsiz, howfar);
8910 /* old_tr = shoetl(old_tr, cps, fsiz, howfar); */
8911 KuiSetProperty(KUI_FILE_TRANSFER,
8915 errors = retrans + crunched + timeouts;
8916 if (errors != oldtry) { /* Error count, if changed */
8917 KuiSetProperty(KUI_FILE_TRANSFER,
8918 (long) CW_PR, (long) errors
8923 default: /* Others, do nothing */
8931 case SCR_ST: /* File transfer status */
8932 debug(F101,"screeng SCR_ST c","",c);
8933 debug(F101,"screeng SCR_ST success","",success);
8934 debug(F101,"screeng SCR_ST cxseen","",cxseen);
8936 if (c == ST_OK) { /* OK, print 100 % */
8940 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8943 } else if (fsiz > 0L) /* Not OK, update final percent */
8945 The else part writes all over the screen -- howfar and/or fsiz have
8946 been reset as a consequence of the not-OKness of the transfer.
8949 updpct(oldpct, (howfar * 100L) / fsiz);
8951 if (c == ST_OK) { /* OK, print 100 % */
8955 KuiSetProperty(KUI_FILE_TRANSFER, (long) CW_FFC, (long) ffc);
8959 #endif /* COMMENT */
8961 #endif /* COMMENT */
8963 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_TR, (long) "" );
8965 switch (c) { /* Print new status message */
8966 case ST_OK: /* Transfer OK */
8967 fcnt++; /* Count this file */
8968 if (what == (W_FTP|W_FT_DELE)) {
8969 KuiSetProperty(KUI_FILE_TRANSFER,
8975 KuiSetProperty(KUI_FILE_TRANSFER,
8977 (long) "Transfer OK"
8982 case ST_DISC: /* Discarded */
8983 KuiSetProperty(KUI_FILE_TRANSFER,
8985 (long) "File discarded"
8989 #endif /* COMMENT */
8992 case ST_INT: /* Interrupted */
8993 KuiSetProperty(KUI_FILE_TRANSFER,
8995 (long) "Transfer interrupted"
8999 #endif /* COMMENT */
9002 case ST_SKIP: { /* Skipped */
9004 if (n > 0 && n < nskreason)
9005 sprintf( errbuf, "File skipped, (%s)", skreason[n] ) ;
9007 sprintf( errbuf, "File skipped" ) ;
9008 KuiSetProperty(KUI_FILE_TRANSFER,
9014 #endif /* COMMENT */
9017 case ST_ERR: /* Error message */
9018 if (!s) s = (char *)epktmsg;
9019 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
9022 #endif /* COMMENT */
9025 case ST_REFU: /* Refused */
9028 sprintf( errbuf, "Refused, %s", s ) ;
9029 KuiSetProperty(KUI_FILE_TRANSFER,(long) CW_ERR,(long) errbuf);
9031 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Refused");
9035 #endif /* COMMENT */
9039 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_ERR,(long)"Incomplete");
9042 #endif /* COMMENT */
9046 KuiSetProperty(KUI_FILE_TRANSFER,(long)CW_MSG,(long)s);
9049 default: /* Bad call */
9050 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR,
9051 (long) "*** screen() called with bad status ***" );
9055 case SCR_TC: { /* Transaction complete */
9057 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_CP, tfcps);
9060 "SUCCESS. Files: %s, Bytes: %ld, %ld CPS",
9065 KuiSetProperty(KUI_FILE_TRANSFER,
9070 KuiSetProperty(KUI_FILE_TRANSFER,
9072 (long) hhmmss((long)
9077 #endif /* GFTIMER */
9081 oldgtv = (CKFLOAT) -1.0;
9084 #endif /* GFTIMER */
9087 pct = 100; oldpct = 0; /* Reset these for next time. */
9088 #endif /* COMMENT */
9089 oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
9092 if (xfrbel) bleep(BP_NOTE); /* Close window, then beep. */
9093 ft_win = 0; /* Window closed. */
9096 case SCR_EM: /* Error packet (fatal) */
9097 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_ERR, (long) s );
9098 if (xfrbel) bleep(BP_FAIL);
9101 #endif /* COMMENT */
9104 case SCR_QE: /* Quantity equals */
9105 case SCR_TU: /* Undelimited text */
9106 case SCR_TN: /* Text delimited at start */
9107 case SCR_TZ: /* Text delimited at end */
9108 return; /* (ignored in fullscreen display) */
9110 case SCR_XD: /* X-packet data */
9112 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_NAM, (long) s );
9115 case SCR_CW: /* Close Window */
9117 pct = 100; oldpct = 0; /* Reset these for next time. */
9118 #endif /* COMMENT */
9119 oldtyp = 0; oldrtt = -1L; oldtry = -1; oldlen = -1;
9122 ft_win = 0; /* Flag that window is closed. */
9125 case SCR_CD: /* Display current directory */
9126 KuiSetProperty( KUI_FILE_TRANSFER, (long) CW_DIR, (long) s );
9132 default: /* Bad call */
9133 KuiSetProperty(KUI_FILE_TRANSFER,
9135 (long) "*** screen() called with bad function code ***"
9146 /* Dummies for when cursor control is not supported */
9148 ck_curpos(row, col) {
9161 #endif /* CK_CURPOS */
9166 struct iksdbfld dbfld[] = {
9167 /* Offset Length Type */
9168 { DB_FLAGS, dB_FLAGS, DBT_HEX }, /* 0 db_FLAGS Flags */
9169 { DB_ATYPE, dB_ATYPE, DBT_HEX }, /* 1 db_ATYPE Auth type */
9170 { DB_AMODE, dB_AMODE, DBT_HEX }, /* 3 db_AMODE Auth mode */
9171 { DB_STATE, dB_STATE, DBT_HEX }, /* 2 db_STATE State */
9172 { DB_MYPID, dB_MYPID, DBT_HEX }, /* 5 db_MYPID PID */
9173 { DB_SADDR, dB_SADDR, DBT_HEX }, /* 4 db_SADDR Server address */
9174 { DB_CADDR, dB_CADDR, DBT_HEX }, /* 6 db_CADDR Client address */
9175 { DB_START, dB_START, DBT_DAT }, /* 7 db_START Session start */
9176 { DB_LASTU, dB_LASTU, DBT_DAT }, /* 8 db_LASTU Last update */
9177 { DB_ULEN, dB_ULEN, DBT_HEX }, /* 9 db_ULEN Username length */
9178 { DB_DLEN, dB_DLEN, DBT_HEX }, /* 10 db_DLEN Directory name length */
9179 { DB_ILEN, dB_ILEN, DBT_HEX }, /* 11 db_ILEN Info length */
9180 { DB_PAD1, dB_PAD1, DBT_UND }, /* 12 db_PAD1 (Reserved) */
9181 { DB_USER, dB_USER, DBT_STR }, /* 13 db_USER Username */
9182 { DB_DIR, dB_DIR, DBT_STR }, /* 14 db_DIR Current Directory */
9183 { DB_INFO, dB_INFO, DBT_STR } /* 15 db_INFO State-specific info */
9186 static char lcknam[CKMAXPATH+1]; /* Lockfile pathname */
9187 static char tmplck[CKMAXPATH+1]; /* Temporary lockfile name */
9189 static char * updmode = /* Update mode for fopen() */
9201 /* D B I N I T -- Initialize the IKSD database... */
9205 extern int dbinited;
9207 debug(F110,"dbinit dbdir 1",dbdir,0);
9208 debug(F110,"dbinit dbfile 1",dbfile,0);
9216 p = getenv("SystemRoot");
9218 p = getenv("winbootdir");
9219 if (!p) p = getenv("windir");
9222 dbdir = malloc(strlen(p)+2);
9223 strcpy(dbdir,p); /* safe */
9230 if (*(p-1) != '/' ) {
9235 makestr(&dbdir,"C:/");
9240 makestr(&dbdir,IK_DBASEDIR);
9246 if (dbdir[x-1] != '/') {
9250 x += (int)strlen(IK_DBASEFIL);
9251 dbfile = (char *)malloc(x+1);
9252 sprintf(dbfile,"%s%s%s",dbdir,s,IK_DBASEFIL);
9254 debug(F110,"dbinit dbdir 2",dbdir,0);
9255 debug(F110,"dbinit dbfile 2",dbfile,0);
9256 mypid = getpid(); /* Get my pid */
9257 debug(F101,"dbinit mypid","",mypid);
9259 if (!myhexip[0]) { /* Set my hex IP address */
9261 extern unsigned long myxipaddr;
9262 if (getlocalipaddr() > -1) {
9264 sprintf(myhexip,"%08lx",myip); /* (Needs fixing for IPv6) */
9266 #endif /* TCPSOCKET */
9267 ckstrncpy(myhexip,"00000000",9);
9269 debug(F111,"dbinit myip",myhexip,myip);
9270 if (!peerhexip[0]) { /* Get peer's hex IP address */
9272 extern unsigned long peerxipaddr;
9274 peerip = peerxipaddr;
9275 sprintf(peerhexip,"%08lx",peerip); /* (Needs fixing for IPv6) */
9276 debug(F111,"dbinit peerip",peerhexip,peerip);
9278 debug(F101,"dbinit ckgetpeer failure","",errno);
9279 ckstrncpy(peerhexip,"00000000",9);
9282 ckstrncpy(peerhexip,"00000000",9);
9283 #endif /* TCPSOCKET */
9285 debug(F111,"dbinit peerip",peerhexip,peerip);
9286 debug(F101,"dbinit dbenabled","",dbenabled);
9287 if (dbenabled && inserver) {
9288 mydbslot = getslot();
9289 debug(F111,"dbinit getslot",ckitoa(ikdbopen),x);
9290 if (ikdbopen) dbinited = 1;
9295 /* U P D S L O T -- Update slot n */
9298 Opens the database if necessary, seeks to slot n, writes current record
9299 and adds current time to last-update field. n is the record sequence number
9300 (0, 1, 2, ...), not the seek pointer. Returns -1 on failure, 0 on success.
9303 updslot(n) int n; { /* Update our slot */
9307 debug(F111,"updslot","ikdbopen",ikdbopen);
9308 if (!ikdbopen) /* Not if not ok */
9310 if (!dbfp) { /* Open database if not open */
9311 dbfp = fopen(dbfile,updmode); /* In update no-truncate mode */
9313 debug(F110,"updslot fopen failed",dbfile,0);
9318 /* debug(F111,"updslot dbfile",dbfile,dbfp); */
9319 position = n * DB_RECL;
9320 if (CKFSEEK(dbfp,position,0) < 0) { /* Seek to desired slot */
9321 debug(F111,"updslot fseek failed",dbfile,mydbseek);
9325 /* Update the update time */
9326 strncpy(&dbrec[dbfld[db_LASTU].off],
9330 if (fwrite(dbrec,1,DB_RECL,dbfp) < DB_RECL) { /* Write the record */
9331 debug(F110,"updslot fwrite failed",dbfile,0);
9334 } else { /* Flush the write */
9341 /* I N I T S L O T -- Initialize slot n with my info */
9344 initslot(n) int n; { /* Initialize slot */
9347 extern unsigned long peerxipaddr;
9348 #endif /* TCPSOCKET */
9350 debug(F101,"initslot","",n);
9353 memset(dbrec,32,DB_RECL);
9355 for (k = 0; k < DB_RECL; k++)
9357 #endif /* USE_MEMCPY */
9359 myflags = DBF_INUSE; /* Set in-use flag */
9360 mystate = W_NOTHING;
9364 k = dbfld[db_FLAGS].len; /* Length of flags field */
9365 strncpy(&dbrec[dbfld[db_FLAGS].off],ulongtohex(myflags,k),k);
9367 k = dbfld[db_ATYPE].len;
9368 strncpy(&dbrec[dbfld[db_ATYPE].off],ulongtohex(myatype,k),k);
9370 k = dbfld[db_AMODE].len;
9371 strncpy(&dbrec[dbfld[db_AMODE].off],ulongtohex(myamode,k),k);
9373 k = dbfld[db_STATE].len;
9374 strncpy(&dbrec[dbfld[db_STATE].off],ulongtohex(mystate,k),k);
9376 k = dbfld[db_SADDR].len;
9377 strncpy(&dbrec[dbfld[db_SADDR].off],ulongtohex(myip,k),k);
9381 k = dbfld[db_CADDR].len;
9382 strncpy(&dbrec[dbfld[db_CADDR].off],ulongtohex(peerxipaddr,k),k);
9384 k = dbfld[db_CADDR].len;
9385 strncpy(&dbrec[dbfld[db_CADDR].off],ulongtohex(0L,k),k);
9386 #endif /* TCPSOCKET */
9388 k = dbfld[db_MYPID].len;
9389 strncpy(&dbrec[dbfld[db_MYPID].off],ulongtohex(mypid,k),k);
9391 k = dbfld[db_START].len;
9392 strncpy(&dbrec[dbfld[db_START].off],ckdate(),k);
9394 k = dbfld[db_ULEN].len;
9395 strncpy(&dbrec[dbfld[db_ULEN].off],"0000",4);
9397 k = dbfld[db_DLEN].len;
9398 strncpy(&dbrec[dbfld[db_DLEN].off],"0000",4);
9400 k = dbfld[db_ILEN].len;
9401 strncpy(&dbrec[dbfld[db_ILEN].off],"0000",4);
9403 strncpy(&dbrec[dbfld[db_INFO].off],"INIT",4);
9408 slotstate(x,s1,s2,s3) int x; char *s1, *s2, *s3; {
9409 int k, l1, l2, l3, z;
9411 debug(F101,"slotstate ikdbopen","",ikdbopen);
9420 strncpy(&dbrec[DB_STATE],ulongtohex(mystate,4),4);
9421 k = dbfld[db_ILEN].len;
9422 z = l1 + l2 + l3 + 2;
9425 strncpy(&dbrec[DB_ILEN],ulongtohex((unsigned long)z,k),k);
9426 k = dbfld[db_INFO].len;
9427 z = dbfld[db_INFO].off;
9429 lset(&dbrec[z],s1,l1+1,32);
9433 lset(&dbrec[z],s2,l2+1,32);
9437 lset(&dbrec[z],s3,k,32);
9444 strncpy(buf,&dbrec[DB_INFO],127);
9446 for (i = 126; i > 0 && buf[i] == 32; i--) buf[i] = 0;
9447 debug(F111,"slotstate",buf,mystate);
9450 z = updslot(mydbslot);
9451 debug(F101,"slotstate updslot","",z);
9456 slotdir(s1,s2) char * s1, * s2; { /* Update current directory */
9464 k = dbfld[db_DLEN].len;
9465 strncpy(&dbrec[DB_DLEN],ulongtohex((unsigned long)(len1+len2),k),k);
9466 k = dbfld[db_DIR].len;
9468 lset(&dbrec[dbfld[db_DIR].off],s1,len1,32);
9469 lset(&dbrec[dbfld[db_DIR].off+len1],s2,k-len1,32);
9471 lset(&dbrec[dbfld[db_DIR].off],s2,k,32);
9473 return(updslot(mydbslot));
9476 /* F R E E S L O T -- Free slot n */
9479 freeslot(n) int n; {
9484 if (n == mydbslot) {
9485 dbflags = myflags & ~DBF_INUSE;
9486 dbflags &= ~DBF_LOGGED;
9488 k = dbfld[db_FLAGS].len;
9489 strncpy(&dbrec[dbfld[db_FLAGS].off],ulongtohex(dbflags,k),k);
9493 /* G E T S L O T -- Find a free database slot; returns slot number */
9496 #include <fcntl.h> /* For creat() */
9500 getslot() { /* Find a free slot for us */
9501 FILE * rfp = NULL; /* Returns slot number (0, 1, ...) */
9502 char idstring[64]; /* PID string buffer (decimal) */
9503 char pidbuf[64], * s;
9504 int j, k, n, x, rc = -1;
9505 int lockfd, tries, haveslot = 0;
9508 /* char ipbuf[17]; */
9510 if (!myhexip[0]) /* Set my hex IP address if not set */
9511 ckstrncpy((char *)myhexip,"7F000001",33);
9512 sprintf(idstring,"%08lx:%010ld\n",myip,mypid);
9513 debug(F110,"getslot idstring", idstring, 0);
9515 /* Make temporary lockfile name IP.PID (hex.hex) */
9516 /* This should fit in 14 chars -- huge PIDs are usually not possible */
9517 /* on 14-char filename systems. */
9519 sprintf(tmplck,"%s%08lx.%lx",dbdir,myip,mypid);
9520 debug(F110,"getslot tempfile",tmplck,0);
9522 /* Make a temporary file */
9524 lockfd = creat(tmplck, 0600); /* BUT THIS ISN'T PORTABLE */
9526 debug(F111,"getslock temp lockfile create failure", tmplck, errno);
9529 /* Write my (decimal) PID into the temp file */
9531 write(lockfd,idstring,(int)strlen(idstring));
9532 if (close(lockfd) < 0) { /* Close lockfile */
9533 debug(F101,"getslot error closing temp lockfile", "", errno);
9536 sprintf(lcknam,"%s%s",dbdir,IK_LOCKFILE); /* Build lockfile name */
9537 debug(F110,"getslot lockfile",lcknam,0);
9539 rfp = fopen(lcknam,"r"); /* See if lockfile exists */
9540 if (rfp) { /* If so... */
9541 rset(pidbuf,"",64,0);
9542 x = fread(pidbuf,1,63,rfp); /* Read ID string from it */
9543 fclose(rfp); /* and close it quickly */
9544 debug(F110,"getslot lock exists",pidbuf,0);
9545 if (x > 0) { /* If we have a PID, check it */
9548 if (islower(*s)) *s = toupper(*s);
9551 debug(F110,"getslot lock IP",pidbuf,0);
9552 debug(F110,"gteslot my IP",myhexip,0);
9553 if (!strcmp(pidbuf,myhexip)) { /* Same IP address? */
9554 lockpid = atol(s+1); /* Yes, now get PID */
9555 debug(F101,"getslot lockpid","",lockpid);
9557 /* Check if PID lockpid on this computer is alive */
9558 x = zchkpid(lockpid);
9560 debug(F100,"getslot PID stale,removing lock","",0);
9569 debug(F111,"getslot lockfile open failure",lcknam,errno);
9572 /* Try IK_LCKTRIES (16) times to rename temp file to lockfile */
9574 for (tries = IK_LCKTRIES; tries > 0; tries--) {
9575 if (zrename(tmplck,lcknam) == 0)
9577 debug(F101,"getslot database locked by pid", "", dbpid);
9580 if (tries < 1) { /* Couldn't */
9581 debug(F110,"getslot create lock failure",lcknam,0);
9584 /* Have lock, open database */
9586 debug(F110,"getslot has lock",lcknam,0); /* Have lock */
9591 /* If database doesn't exist, create it. */
9593 debug(F110,"getslot dbfile",dbfile,0);
9594 if (zchki(dbfile) < 0) {
9595 debug(F110,"getslot creating new database",dbfile,0);
9596 x = creat(dbfile,0660);
9598 debug(F111,"getslot creat() failed", dbfile, errno);
9603 dbfp = fopen(dbfile,updmode); /* Open it in update mode */
9605 debug(F111,"getslot fopen failed",dbfile,errno);
9608 /* Now find a free (or new) slot... */
9610 dblastused = 0L; /* Seek pointer to last record inuse */
9611 mydbseek = 0L; /* Seek pointer for my record */
9613 /* Quickly read the whole database; n = record counter, i = seek pointer */
9615 for (n = 0, i = 0; !feof(dbfp); i += DB_RECL, n++) {
9616 x = fread(dbrec,1,DB_RECL,dbfp); /* Read a record */
9617 if (x < 1) /* EOF not caught by feof() */
9620 if (x != DB_RECL) { /* Watch out for trailing junk */
9621 debug(F101,"getslot bad size","",x); /* (Shouldn't happen...) */
9623 chsize(fileno(dbfp),i);
9625 ftruncate(fileno(dbfp),(CK_OFF_T)i);
9626 #endif /* COHERENT */
9631 #endif /* NOFTRUNCATE */
9632 debug(F101,"getslot record","",n);
9633 k = dbfld[db_FLAGS].off;
9634 j = dbfld[db_FLAGS].len;
9635 dbflags = hextoulong(&dbrec[k],j);
9636 debug(F001,"getslot dbflags","",dbflags);
9637 k = dbfld[db_MYPID].off;
9638 j = dbfld[db_MYPID].len;
9639 dbpid = hextoulong(&dbrec[k],j);
9640 debug(F001,"getslot dbpid","",dbpid);
9641 k = dbfld[db_SADDR].off;
9642 j = dbfld[db_SADDR].len;
9643 dbip = hextoulong(&dbrec[k],j);
9644 debug(F001,"getslot dbip","",dbip);
9646 if (dbflags & DBF_INUSE) { /* Remember last slot in use */
9647 x = 0; /* Make sure it's REALLY in use */
9648 if (dbpid == mypid && dbip == myip) { /* Check for PID == my PID */
9650 debug(F101,"getslot record pid","",dbpid);
9651 } else { /* Or for stale PID */
9653 debug(F101,"getslot zchkpid()","",x);
9655 if (!x) { /* Bogus record */
9657 debug(F101,"getslot stale record pid: freeslot()","",x);
9658 if (x > -1 && !haveslot)
9660 } else { /* It's really in use */
9664 if (!haveslot) { /* If I don't have a slot yet */
9665 if (!(dbflags & DBF_INUSE)) { /* Claim this one */
9666 debug(F101,"getslot free slot", "", n);
9669 mydbslot = n; /* But keep going... */
9673 /* Come here with i == seek pointer to first record after eof */
9675 if (!haveslot) { /* Found no free slot so add to end */
9676 debug(F101,"getslot new slot","",n);
9681 ikdbopen = 1; /* OK to make database entries */
9682 debug(F101,"getslot records","",n);
9683 debug(F101,"getslot dblastused","",dblastused);
9684 debug(F101,"getslot i","",i);
9686 /* Trim stale records from end */
9689 if (i > dblastused+DB_RECL) {
9690 debug(F101,"getslot truncating at","",dblastused+DB_RECL);
9692 x = chsize(fileno(dbfp),dblastused+DB_RECL);
9694 x = ftruncate(fileno(dbfp),(CK_OFF_T)(dblastused+DB_RECL));
9695 #endif /* COHERENT */
9696 if (x < 0) /* (Not fatal) */
9697 debug(F101,"getslot ftruncate failed", "", errno);
9699 #endif /* NOFTRUNCATE */
9701 /* Initialize my record */
9703 if (initslot(mydbslot) < 0) {
9704 debug(F101,"getslot initslot() error","",n);
9708 debug(F101,"getslot OK","",mydbslot);
9709 rc = mydbslot; /* OK return code */
9711 xslot: /* Unlock the database and return */
9712 if (unlink(lcknam) < 0) {
9713 debug(F111,"getslot lockfile removal failed",lcknam,errno);