1: /* C K U U S X -- "User Interface" common functions. */ 2: 3: /* 4: Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET), 5: Columbia University Center for Computing Activities. 6: First released January 1985. 7: Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New 8: York. Permission is granted to any individual or institution to use this 9: software as long as it is not sold for profit. This copyright notice must be 10: retained. This software may not be included in commercial products without 11: written permission of Columbia University. 12: */ 13: 14: /* 15: This module contains user interface functions needed by both the interactive 16: user interface and the command-line-only user interface. 17: */ 18: 19: /* Includes */ 20: 21: #include "ckcdeb.h" 22: #include "ckcasc.h" 23: #include "ckcker.h" 24: #include "ckuusr.h" 25: #ifndef WINTCP 26: #include <signal.h> 27: #endif /* WINTCP */ 28: 29: #ifdef VMS 30: #ifdef WINTCP 31: #include <descrip.h> 32: #include <ssdef.h> 33: #include <stsdef.h> 34: #include <signal.h> 35: #else 36: #include <descrip.h> 37: #include <ssdef.h> 38: #include <stsdef.h> 39: #endif /* WINTCP */ 40: #endif /* VMS */ 41: 42: /* Used internally */ 43: _PROTOTYP( VOID screenc, (int, char, long, char *) ); 44: static int ft_win = 0; /* Fullscreen file transfer display window is active */ 45: 46: /* Variables declared here */ 47: 48: int fdispla = XYFD_R; /* File transfer display type */ 49: int tt_crd = 0; /* Carriage return display */ 50: 51: #ifdef DEBUG 52: char debfil[50]; /* Debugging log file name */ 53: #endif /* DEBUG */ 54: 55: #ifdef TLOG 56: char trafil[50]; /* Transaction log file name */ 57: #endif /* TLOG */ 58: 59: char pktfil[50]; /* Packet log file name */ 60: char sesfil[50]; /* Session log file name */ 61: 62: #ifndef NOFRILLS 63: char optbuf[100]; /* Options for MAIL or REMOTE PRINT */ 64: #endif /* NOFRILLS */ 65: char cmdstr[256]; /* Place to build generic command */ 66: 67: char fspec[FSPECL]; /* Filename string for \v(filespec) */ 68: 69: /* C C N T A B -- Names of ASCII control characters 0-31 */ 70: 71: char *ccntab[] = { "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", 72: "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", 73: "DLE", "DC1/XON", "DC2", "DC3/XOFF", "DC4", "NAK", "SYN", "ETB", "CAN", 74: "EM", "SUB", "ESC", "FS", "GS", "RS", "US" 75: }; 76: 77: int success = 1, /* Command success/failure flag */ 78: 79: #ifndef NOSPL 80: cmdlvl = 0, /* Command level */ 81: #endif /* NOSPL */ 82: action, /* Action selected on command line*/ 83: sessft = 0, /* Session log file type, 0 = text */ 84: pflag = 1, /* Print prompt */ 85: msgflg = 1; /* Print informational messages */ 86: 87: #ifndef NOMSEND /* Multiple SEND */ 88: char *msfiles[MSENDMAX]; 89: #endif /* NOMSEND */ 90: 91: /* External variables */ 92: 93: #ifndef NODIAL 94: extern FILE * dialfd; /* Dialing directory */ 95: #endif /* NODIAL */ 96: 97: extern int local, quiet, binary, bctu, rptflg, ebqflg, network, server, 98: what, spsiz, urpsiz, wmax, czseen, cxseen, winlo, displa, timint, parity, 99: npad, ebq, ebqflg, bctr, rptq, atcapu, lpcapu, swcapu, wslotn, wslotr, rtimo, 100: mypadn, sq, capas, rpsiz, tsecs, dfloc, tralog, pktlog, seslog, lscapu, 101: xitsta, escape, tlevel, bgset, backgrd, wslots, suspend, srvdis, 102: spackets, spktl, rpktl, retrans, wcur, numerrs, fsecs; 103: 104: #ifdef datageneral /* 2/12/92 ENH */ 105: #include <sysid.h> 106: extern int con_reads_mt, conint_ch, conint_avl; 107: #endif /* datageneral */ 108: 109: extern long speed, filcnt, ffc, tfc, rptn, fsize; 110: 111: extern CHAR *rdatap, padch, seol, ctlq, mypadc, eol; 112: 113: extern char ttname[], *dftty, *cmarg, **cmlist, *versio, myhost[]; 114: #ifndef NOICP 115: #ifdef DCMDBUF 116: extern char *cmdbuf; /* Command buffer */ 117: #else 118: extern char cmdbuf[]; /* Command buffer */ 119: #endif /* DCMDBUF */ 120: #endif /* NOICP */ 121: 122: #ifndef NOCCTRAP 123: #include <setjmp.h> /* Control-C trap */ 124: jmp_buf cmjbuf; 125: #endif /* NOCCTRAP */ 126: 127: 128: /* P A R N A M -- Return parity name */ 129: 130: char * 131: #ifdef CK_ANSIC 132: parnam(char c) 133: #else 134: parnam(c) char c; 135: #endif /* CK_ANSIC */ 136: /* parnam */ { 137: switch (c) { 138: case 'e': return("even"); 139: case 'o': return("odd"); 140: case 'm': return("mark"); 141: case 's': return("space"); 142: case 0: return("none"); 143: default: return("invalid"); 144: } 145: } 146: 147: /* S H O M D M -- Show modem signals */ 148: 149: VOID 150: shomdm() { 151: /* 152: Note use of "\r\n" to make sure this report prints right, even when 153: called during CONNECT mode. 154: */ 155: int y; 156: y = ttgmdm(); 157: switch (y) { 158: case -3: printf( 159: "Modem signals unavailable in this version of Kermit\r\n"); 160: break; 161: case -2: printf("No modem control for this device\r\n"); break; 162: case -1: printf("Modem signals unavailable\r\n"); break; 163: default: 164: #ifndef MAC 165: printf( 166: " Carrier Detect (CD): %s\r\n",(y & BM_DCD) ? "On": "Off"); 167: printf( 168: " Dataset Ready (DSR): %s\r\n",(y & BM_DSR) ? "On": "Off"); 169: #endif /* MAC */ 170: printf( 171: " Clear To Send (CTS): %s\r\n",(y & BM_CTS) ? "On": "Off"); 172: #ifndef MAC 173: printf( 174: " Ring Indicator (RI): %s\r\n",(y & BM_RNG) ? "On": "Off"); 175: #endif /* MAC */ 176: printf( 177: " Data Terminal Ready (DTR): %s\r\n",(y & BM_DTR) ? "On": "Off"); 178: #ifndef MAC 179: printf( 180: " Request to Send (RTS): %s\r\n",(y & BM_RTS) ? "On": "Off"); 181: #endif /* MAC */ 182: } 183: } 184: 185: /* S D E B U -- Record spar results in debugging log */ 186: 187: VOID 188: sdebu(len) int len; { 189: debug(F111,"spar: data",(char *) rdatap,len); 190: debug(F101," spsiz ","", spsiz); 191: debug(F101," timint","",timint); 192: debug(F101," npad ","", npad); 193: debug(F101," padch ","", padch); 194: debug(F101," seol ","", seol); 195: debug(F101," ctlq ","", ctlq); 196: debug(F101," ebq ","", ebq); 197: debug(F101," ebqflg","",ebqflg); 198: debug(F101," bctr ","", bctr); 199: debug(F101," rptq ","", rptq); 200: debug(F101," rptflg","",rptflg); 201: debug(F101," lscapu","",lscapu); 202: debug(F101," atcapu","",atcapu); 203: debug(F101," lpcapu","",lpcapu); 204: debug(F101," swcapu","",swcapu); 205: debug(F101," wslotn","", wslotn); 206: } 207: /* R D E B U -- Debugging display of rpar() values */ 208: 209: VOID 210: rdebu(d,len) CHAR *d; int len; { 211: debug(F111,"rpar: data",d,len); 212: debug(F101," rpsiz ","", xunchar(d[0])); 213: debug(F101," rtimo ","", rtimo); 214: debug(F101," mypadn","",mypadn); 215: debug(F101," mypadc","",mypadc); 216: debug(F101," eol ","", eol); 217: debug(F101," ctlq ","", ctlq); 218: debug(F101," sq ","", sq); 219: debug(F101," ebq ","", ebq); 220: debug(F101," ebqflg","",ebqflg); 221: debug(F101," bctr ","", bctr); 222: debug(F101," rptq ","", d[8]); 223: debug(F101," rptflg","",rptflg); 224: debug(F101," capas ","", capas); 225: debug(F101," bits ","",d[capas]); 226: debug(F101," lscapu","",lscapu); 227: debug(F101," atcapu","",atcapu); 228: debug(F101," lpcapu","",lpcapu); 229: debug(F101," swcapu","",swcapu); 230: debug(F101," wslotr","", wslotr); 231: debug(F101," rpsiz(extended)","",rpsiz); 232: } 233: 234: #ifdef COMMENT 235: /* C H K E R R -- Decide whether to exit upon a protocol error */ 236: 237: VOID 238: chkerr() { 239: if (backgrd && !server) fatal("Protocol error"); 240: } 241: #endif /* COMMENT */ 242: 243: /* F A T A L -- Fatal error message */ 244: 245: VOID 246: fatal(msg) char *msg; { 247: #ifdef VMS 248: #ifndef NOICP 249: if (strncmp(msg,"%CKERMIT",8)) { 250: sprintf(cmdbuf,"%%CKERMIT-E-FATAL, %s",msg); 251: msg = cmdbuf; 252: } 253: #endif /* NOICP */ 254: conoll(msg); 255: #else 256: screen(SCR_EM,0,0L,msg); 257: #endif /* VMS */ 258: debug(F110,"fatal",msg,0); 259: tlog(F110,"Fatal:",msg,0L); 260: doexit(BAD_EXIT,xitsta | 1); /* Exit indicating failure */ 261: } 262: 263: /* B L D L E N -- Make length-encoded copy of string */ 264: 265: char * 266: bldlen(str,dest) char *str, *dest; { 267: int len; 268: len = (int)strlen(str); 269: *dest = tochar(len); 270: strcpy(dest+1,str); 271: return(dest+len+1); 272: } 273: 274: 275: /* S E T G E N -- Construct a generic command */ 276: 277: CHAR 278: #ifdef CK_ANSIC 279: setgen(char type,char * arg1, char * arg2, char * arg3) 280: #else 281: setgen(type,arg1,arg2,arg3) char type, *arg1, *arg2, *arg3; 282: #endif /* CK_ANSIC */ 283: /* setgen */ { 284: char *upstr, *cp; 285: 286: cp = cmdstr; 287: *cp++ = type; 288: *cp = NUL; 289: if (*arg1 != NUL) { 290: upstr = bldlen(arg1,cp); 291: if (*arg2 != NUL) { 292: upstr = bldlen(arg2,upstr); 293: if (*arg3 != NUL) bldlen(arg3,upstr); 294: } 295: } 296: cmarg = cmdstr; 297: debug(F110,"setgen",cmarg,0); 298: 299: return('g'); 300: } 301: 302: #ifndef NOMSEND 303: static char *mgbufp = NULL; 304: 305: /* F N P A R S E -- */ 306: 307: /* 308: Argument is a character string containing one or more filespecs. 309: This function breaks the string apart into an array of pointers, one 310: to each filespec, and returns the number of filespecs. Used by server 311: when it receives a GET command to allow it to process multiple file 312: specifications in one transaction. Sets cmlist to point to a list of 313: file pointers, exactly as if they were command line arguments. 314: 315: This version of fnparse treats spaces as filename separators. If your 316: operating system allows spaces in filenames, you'll need a different 317: separator. 318: 319: This version of fnparse mallocs a string buffer to contain the names. It 320: cannot assume that the string that is pointed to by the argument is safe. 321: */ 322: int 323: fnparse(string) char *string; { 324: char *p, *s, *q; 325: int r = 0, x; /* Return code */ 326: 327: if (mgbufp) free(mgbufp); /* Free this from last time. */ 328: mgbufp = malloc((int)strlen(string)+2); 329: if (!mgbufp) { 330: debug(F100,"fnparse malloc error","",0); 331: return(0); 332: } 333: #ifndef NOICP 334: #ifndef NOSPL 335: strncpy(fspec,string,FSPECL); /* Make copy for \v(filespec) */ 336: #endif /* NOSPL */ 337: #endif /* NOICP */ 338: s = string; /* Input string */ 339: p = q = mgbufp; /* Point to the copy */ 340: r = 0; /* Initialize our return code */ 341: while (*s == SP || *s == HT) /* Skip leading spaces and tabs */ 342: s++; 343: for (x = strlen(s); /* Strip trailing spaces */ 344: (x > 1) && (s[x-1] == SP || s[x-1] == HT); 345: x--) 346: s[x-1] = NUL; 347: while (1) { /* Loop through rest of string */ 348: if (*s == CMDQ) { /* Backslash (quote character)? */ 349: if ((x = xxesc(&s)) > -1) { /* Go interpret it. */ 350: *q++ = (char) x; /* Numeric backslash code, ok */ 351: } else { /* Just let it quote next char */ 352: s++; /* get past the backslash */ 353: *q++ = *s++; /* deposit next char */ 354: } 355: continue; 356: } else if (*s == SP || *s == NUL) { /* Unquoted space or NUL? */ 357: *q++ = NUL; /* End of output filename. */ 358: msfiles[r] = p; /* Add this filename to the list */ 359: debug(F111,"fnparse",msfiles[r],r); 360: r++; /* Count it */ 361: if (*s == NUL) break; /* End of string? */ 362: while (*s == SP) s++; /* Skip repeated spaces */ 363: p = q; /* Start of next name */ 364: continue; 365: } else *q++ = *s; /* Otherwise copy the character */ 366: s++; /* Next input character */ 367: } 368: debug(F101,"fnparse r","",r); 369: msfiles[r] = ""; /* Put empty string at end of list */ 370: cmlist = msfiles; 371: return(r); 372: } 373: #endif /* NOMSEND */ 374: 375: char * /* dbchr() for DEBUG SESSION */ 376: dbchr(c) int c; { 377: static char s[8]; 378: char *cp = s; 379: 380: c &= 0xff; 381: if (c & 0x80) { /* 8th bit on */ 382: *cp++ = '~'; 383: c &= 0x7f; 384: } 385: if (c < SP) { /* Control character */ 386: *cp++ = '^'; 387: *cp++ = ctl(c); 388: } else if (c == DEL) { 389: *cp++ = '^'; 390: *cp++ = '?'; 391: } else { /* Printing character */ 392: *cp++ = c; 393: } 394: *cp = '\0'; /* Terminate string */ 395: cp = s; /* Return pointer to it */ 396: return(cp); 397: } 398: 399: /* C K H O S T -- Get name of local host (where C-Kermit is running) */ 400: 401: /* 402: Call with pointer to buffer to put hostname in, and length of buffer. 403: Copies hostname into buffer on success, puts null string in buffer on 404: failure. 405: */ 406: #ifdef BSD44 407: #define BSD4 408: #undef ATTSV 409: #endif /* BSD44 */ 410: 411: #ifdef ATTSV 412: #include <sys/utsname.h> 413: #endif /* ATTSV */ 414: 415: VOID 416: ckhost(vvbuf,vvlen) char * vvbuf; int vvlen; { 417: char *g; 418: #ifdef VMS 419: int x; 420: #endif /* VMS */ 421: #ifdef ATTSV 422: struct utsname hname; 423: #endif /* ATTSV */ 424: #ifdef datageneral 425: int ac0 = (char *) vvbuf, ac1 = -1, ac2 = 0; 426: #endif /* datageneral */ 427: 428: *vvbuf = NUL; 429: #ifdef ATTSV 430: if (uname(&hname) > -1) strncpy(vvbuf,hname.nodename,vvlen); 431: #else 432: #ifdef BSD4 433: if (gethostname(vvbuf,vvlen) < 0) *vvbuf = NUL; 434: #else 435: #ifdef VMS 436: g = getenv("SYS$NODE"); 437: if (g) strncpy(vvbuf,g,vvlen); 438: x = (int)strlen(vvbuf); 439: if (x > 1 && vvbuf[x-1] == ':' && vvbuf[x-2] == ':') vvbuf[x-2] = NUL; 440: #else 441: #ifdef datageneral 442: if (sys($HNAME,&ac0,&ac1,&ac2) == 0) /* successful */ 443: vvlen = ac2 + 1; /* enh - have to add one */ 444: #else 445: #ifdef OS2 /* OS/2 */ 446: g = getenv("SYSTEMNAME"); 447: if (!g) g = getenv("HOSTNAME"); 448: if (g) strncpy(vvbuf,g,vvlen); 449: #endif /* OS2 */ 450: #endif /* datageneral */ 451: #endif /* VMS */ 452: #endif /* BSD4 */ 453: #endif /* ATTSV */ 454: if (*vvbuf == NUL) { /* If it's still empty */ 455: g = getenv("HOST"); /* try this */ 456: if (g) strncpy(vvbuf,g,vvlen); 457: } 458: vvbuf[vvlen-1] = NUL; /* Make sure result is terminated. */ 459: } 460: #ifdef BSD44 461: #undef BSD4 462: #define ATTSV 463: #endif /* BSD44 */ 464: 465: 466: #ifndef NOSPL 467: #define ASKMORE 468: #endif /* NOSPL */ 469: #ifndef NOHELP 470: #ifndef ASKMORE 471: #define ASKMORE 472: #endif /* ASKMORE */ 473: #endif /* NOHELP */ 474: 475: #ifdef ASKMORE 476: /* 477: A S K M O R E -- Poor person's "more". 478: Returns 0 if no more, 1 if more wanted. 479: Presently used by SHO MAC, SHO GLOB, SHO VAR, and HELP, so compiled out if 480: those options are also compiled out. 481: */ 482: int 483: askmore() { 484: char c; int rv; 485: 486: rv = -1; 487: while (rv < 0) { 488: #ifndef OS2 489: printf("more? "); 490: #ifdef UNIX 491: #ifdef NOSETBUF 492: fflush(stdout); 493: #endif /* NOSETBUF */ 494: #endif /* UNIX */ 495: #else 496: printf("more? (Y or space-bar for yes, N for no) "); 497: fflush(stdout); 498: #endif /* OS2 */ 499: c = coninc(0); 500: switch (c) { 501: /* Yes */ 502: case SP: case 'y': case 'Y': case 012: case 015: 503: printf("\015 \015"); 504: rv = 1; 505: break; 506: /* No */ 507: case 'n': case 'N': case 'q': case 'Q': 508: printf("\015\012"); 509: rv = 0; 510: break; 511: /* Invalid answer */ 512: default: 513: printf("Y or space-bar for yes, N for no\n"); 514: continue; 515: } 516: #ifdef OS2 517: printf("\r \r"); 518: fflush(stdout); 519: #endif /* OS2 */ 520: } 521: return(rv); 522: } 523: #endif /* ASKMORE */ 524: 525: /* T R A P -- Terminal interrupt handler */ 526: 527: SIGTYP 528: trap(sig) int sig; { 529: #ifdef VMS 530: int i; FILE *f; 531: #endif /* VMS */ 532: #ifdef __EMX__ 533: signal(SIGINT, SIG_ACK); 534: #endif 535: #ifdef GEMDOS 536: /* GEM is not reentrant, no i/o from interrupt level */ 537: longjmp(cmjbuf,1); /* Jump back to parser now! */ 538: #endif /* GEMDOS */ 539: debug(F101,"^C trap() caught signal","",sig); 540: zclose(ZIFILE); /* If we were transferring a file, */ 541: zclose(ZOFILE); /* close it. */ 542: #ifdef VMS 543: /* 544: Fix terminal. 545: */ 546: if (ft_win) { /* If curses window open */ 547: screen(SCR_CW,0,0L,""); /* Close it */ 548: conres(); /* Restore terminal */ 549: i = printf("^C..."); /* Echo ^C to standard output */ 550: } else { 551: conres(); 552: i = printf("^C...\n"); /* Echo ^C to standard output */ 553: } 554: if (i < 1 && ferror(stdout)) { /* If there was an error */ 555: fclose(stdout); /* close standard output */ 556: f = fopen(dftty, "w"); /* open the controlling terminal */ 557: if (f) stdout = f; /* and make it standard output */ 558: printf("^C...\n"); /* and echo the ^C again. */ 559: } 560: #else /* Not VMS */ 561: if (ft_win) { /* If curses window open, */ 562: screen(SCR_CW,0,0L,""); /* close it. */ 563: printf("^C..."); /* Echo ^C to standard output */ 564: } else { 565: printf("^C...\n"); 566: } 567: #endif /* VMS */ 568: #ifdef datageneral 569: connoi_mt(); /* Kill asynch task that listens to */ 570: ttimoff(); /* the keyboard */ 571: conres(); 572: #endif /* datageneral */ 573: 574: #ifndef NOCCTRAP 575: #ifdef UNIX 576: ttimoff(); /* Turn off any timer interrupts */ 577: #endif /* UNIX */ 578: #ifdef OSK 579: ttimoff(); /* Turn off any timer interrupts */ 580: sigmask(-1); 581: /* 582: We are in an intercept routine but do not perform a F$RTE (done implicitly 583: but rts). We have to decrement the sigmask as F$RTE does. Warning: 584: longjump only restores the cpu registers, NOT the fpu registers. So don't 585: use fpu at all or at least don't use common fpu (double or float) register 586: variables. 587: */ 588: #endif /* OSK */ 589: longjmp(cmjbuf,1); /* Jump back to parser */ 590: #else 591: /* No Ctrl-C trap, just exit. */ 592: #ifdef CK_CURSES /* Curses support? */ 593: screen(SCR_CW,0,0L,""); /* Close curses window */ 594: #endif /* CK_CURSES */ 595: doexit(BAD_EXIT,what); /* Exit poorly */ 596: #endif /* NOCCTRAP */ 597: SIGRETURN; 598: } 599: 600: /* C C _ C L E A N -- Cleanup after terminal interrupt handler */ 601: 602: #ifdef GEMDOS 603: int 604: cc_clean() { 605: zclose(ZIFILE); /* If we were transferring a file, */ 606: zclose(ZOFILE); /* close it. */ 607: printf("^C...\n"); /* Not VMS, no problem... */ 608: } 609: #endif /* GEMDOS */ 610: 611: 612: /* S T P T R A P -- Handle SIGTSTP (suspend) signals */ 613: 614: SIGTYP 615: stptrap(sig) int sig; { 616: #ifndef NOJC 617: int x; extern int cmflgs; 618: debug(F101,"stptrap() caught signal","",sig); 619: if (!suspend) { 620: printf("\r\nsuspend disabled\r\n"); 621: #ifndef NOICP 622: if (what == W_COMMAND) { /* If we were parsing commands */ 623: prompt(xxstring); /* reissue the prompt and partial */ 624: if (!cmflgs) /* command (if any) */ 625: printf("%s",cmdbuf); 626: } 627: #endif /* NOICP */ 628: } else { 629: conres(); /* Reset the console */ 630: #ifndef OS2 631: /* Flush pending output first, in case we are continued */ 632: /* in the background, which could make us block */ 633: fflush(stdout); 634: 635: x = psuspend(suspend); /* Try to suspend. */ 636: if (x < 0) 637: #endif /* OS2 */ 638: printf("Job control not supported\r\n"); 639: conint(trap,stptrap); /* Rearm the trap. */ 640: debug(F100,"stptrap back from suspend","",0); 641: switch (what) { 642: case W_CONNECT: /* If suspended during CONNECT? */ 643: conbin((char)escape); /* put console back in binary mode */ 644: debug(F100,"stptrap W_CONNECT","",0); 645: break; 646: #ifndef NOICP 647: case W_COMMAND: /* Suspended in command mode */ 648: debug(F101,"stptrap W_COMMAND pflag","",pflag); 649: concb((char)escape); /* Put back CBREAK tty mode */ 650: if (pflag) { /* If command parsing was */ 651: prompt(xxstring); /* reissue the prompt and partial */ 652: if (!cmflgs) /* command (if any) */ 653: printf("%s",cmdbuf); 654: } 655: break; 656: #endif /* NOICP */ 657: default: /* All other cases... */ 658: debug(F100,"stptrap default","",0); 659: concb((char)escape); /* Put it back in CBREAK mode */ 660: break; 661: } 662: } 663: #endif /* NOJC */ 664: SIGRETURN; 665: } 666: 667: #ifndef MAC 668: /* 669: The rest of this file is for all implementations but the Macintosh. 670: */ 671: 672: /* C H K I N T -- Check for console interrupts */ 673: 674: int 675: chkint() { 676: int ch, cn; long zz; 677: 678: if ((!local) || (quiet)) return(0); /* Only do this if local & not quiet */ 679: #ifdef datageneral 680: if (con_reads_mt) /* if conint_mt task is active */ 681: if (conint_avl) { /* and there's an interrupt pending */ 682: cn = 1; /* process it */ 683: ch = conint_ch; 684: conint_avl = 0; /* turn off flag so conint_mt can */ 685: } else /* proceed */ 686: return(0); 687: else /* if conint_mt not active */ 688: if ((ch = coninc(2)) < 0) /* try to get char manually */ 689: return(0); /* I/O error, or no data */ 690: else /* if successful, set cn so we */ 691: cn = 1; /* know we got one */ 692: debug(F101,"chkint got keyboard character",ch,cn); 693: #else 694: cn = conchk(); /* Any input waiting? */ 695: debug(F101,"conchk","",cn); 696: if (cn < 1) return(0); 697: if ((ch = coninc(5)) < 0) return(0); 698: #endif /* datageneral */ 699: 700: switch (ch & 0177) { 701: case 'A': case 'a': case 0001: /* Status report */ 702: if (fdispla != XYFD_R && fdispla != XYFD_S) 703: return(0); /* Only for serial or simple */ 704: screen(SCR_TN,0,0l,"Status report:"); 705: screen(SCR_TN,0,0l," file type: "); 706: if (binary) { 707: #ifdef VMS 708: if (binary == XYFT_I) /* VMS-only file types */ 709: screen(SCR_TZ,0,0l,"image"); 710: else if (binary == XYFT_L) 711: screen(SCR_TZ,0,0l,"labeled"); 712: else screen(SCR_TZ,0,0l,"binary"); 713: #else 714: screen(SCR_TZ,0,0l,"binary"); 715: #endif /* VMS */ 716: } else { 717: screen(SCR_TZ,0,0l,"text"); 718: } 719: screen(SCR_QE,0,filcnt," file number"); 720: if (fsize) screen(SCR_QE,0,fsize," size"); 721: screen(SCR_QE,0,ffc, " characters so far"); 722: if (fsize > 0L) { 723: zz = ( ffc * 100L ) / fsize; 724: screen(SCR_QE,0,zz, " percent done"); 725: } 726: if (bctu == 4) { /* Block check */ 727: screen(SCR_TU,0,0L," block check: "); 728: screen(SCR_TZ,0,0L,"blank-free-2"); 729: } else screen(SCR_QE,0,(long)bctu, " block check"); 730: screen(SCR_QE,0,(long)rptflg," compression"); 731: screen(SCR_QE,0,(long)ebqflg," 8th-bit prefixing"); 732: screen(SCR_QE,0,(long)lscapu," locking shifts"); 733: if (!network) 734: screen(SCR_QE,0, speed, " speed"); 735: if (what == W_SEND) 736: screen(SCR_QE,0,(long)spsiz, " packet length"); 737: else if (what == W_RECV || what == W_REMO) 738: screen(SCR_QE,0,(long)urpsiz," packet length"); 739: screen(SCR_QE,0,(long)wslots, " window slots"); 740: return(0); 741: 742: case 'B': case 'b': case 0002: /* Cancel batch */ 743: case 'Z': case 'z': case 0032: 744: screen(SCR_TN,0,0l,"Cancelling Batch "); 745: czseen = 1; 746: return(0); 747: 748: case 'F': case 'f': case 0006: /* Cancel file */ 749: case 'X': case 'x': case 0030: 750: screen(SCR_TN,0,0l,"Cancelling File "); 751: cxseen = 1; 752: return(0); 753: 754: case 'R': case 'r': case 0022: /* Resend */ 755: case 0015: case 0012: 756: screen(SCR_TN,0,0l,"Resending packet "); 757: numerrs++; 758: resend(winlo); 759: return(1); 760: 761: case 'E': case 'e': /* Send error packet */ 762: case 0005: 763: return(-1); 764: 765: #ifdef datageneral 766: case '\03': /* We're not trapping ^C's with */ 767: trap(0); /* signals, so we check here */ 768: #endif /* datageneral */ 769: 770: default: /* Anything else, print message */ 771: intmsg(1); 772: return(0); 773: } 774: } 775: 776: /* I N T M S G -- Issue message about terminal interrupts */ 777: 778: VOID 779: #ifdef CK_ANSIC 780: intmsg(long n) 781: #else 782: intmsg(n) long n; 783: #endif /* CK_ANSIC */ 784: /* intmsg */ { 785: char buf[80]; 786: 787: if (!displa || quiet) /* Not if we're being quiet */ 788: return; 789: if (server && (!srvdis || n > -1L)) /* Special for server */ 790: return; 791: buf[0] = NUL; /* Keep compilers happy */ 792: #ifdef SVORPOSIX 793: conchk(); /* Clear out pending escape-signals */ 794: #endif /* SVORPOSIX */ 795: #ifdef VMS 796: conres(); /* So Ctrl-C will work */ 797: #endif /* VMS */ 798: if ((!server && n == 1L) || (server && n < 0L)) { 799: 800: #ifdef SVORPOSIX /* We need to signal before kb input */ 801: #ifndef aegis 802: #ifndef datageneral 803: sprintf(buf,"Type escape character (%s) followed by:",dbchr(escape)); 804: screen(SCR_TN,0,0l,buf); 805: #endif /* datageneral */ 806: #endif /* aegis */ 807: #endif /* SVORPOSIX */ 808: 809: screen(SCR_TN,0,0l,"X to cancel file, CR to resend current packet"); 810: screen(SCR_TN,0,0l,"Z to cancel group, A for status report"); 811: screen(SCR_TN,0,0l,"E to send Error packet, Ctrl-C to quit immediately: "); 812: /* if (server) */ screen(SCR_TN,0,0l,""); 813: } 814: else screen(SCR_TU,0,0l," "); 815: } 816: 817: static int newdpy = 0; /* New display flag */ 818: static char fbuf[80]; /* Filename buffer */ 819: static char abuf[80]; /* As-name buffer */ 820: static long oldffc = 0L; 821: static long dots = 0L; 822: static int hpos = 0; 823: 824: static VOID /* Initialize Serial or CTR display */ 825: dpyinit() { 826: newdpy = 0; /* Don't do this again */ 827: oldffc = 0L; /* Reset this */ 828: dots = 0L; /* and this.. */ 829: conoll(""); /* New line */ 830: if (what == W_SEND) conol("Sending: "); /* Action */ 831: else if (what == W_RECV) conol("Receiving: "); 832: conol(fbuf); 833: if (*abuf) conol(" => "); conoll(abuf); /* Names */ 834: *fbuf = NUL; *abuf = NUL; 835: if (fsize > -1L) { /* Size */ 836: sprintf(fbuf,"Size: %ld, Type: ",fsize); 837: conol(fbuf); *fbuf = NUL; 838: } else conol("Size: unknown, Type: "); 839: if (binary) { /* Type */ 840: #ifdef VMS 841: if (binary == XYFT_I) /* VMS-only file types */ 842: conoll("image"); 843: else if (binary == XYFT_L) 844: conoll("labeled"); 845: else 846: #endif /* VMS */ 847: conoll("binary"); 848: } else conoll("text"); 849: if (fdispla == XYFD_S) { /* CRT field headings */ 850: 851: /* 852: Define CK_CPS to show current transfer rate. 853: Leave it undefined to show estimated time remaining. 854: Estimated-time-remaining code from Andy Fyfe, not tested on 855: pathological cases. 856: */ 857: #define CK_CPS 858: 859: #ifdef CK_CPS 860: conoll(" File Percent Packet"); 861: conoll(" Bytes Done CPS Length"); 862: #else 863: conoll(" File Percent Secs Packet"); 864: conoll(" Bytes Done Left Length"); 865: #endif /* CK_CPS */ 866: newdpy = 0; 867: } 868: hpos = 0; 869: } 870: 871: /* 872: showpkt(c) 873: c = completion code: 0 means transfer in progress, nonzero means it's done. 874: show the file transfer progress counter and perhaps verbose packet type. 875: Original by: Kai Uwe Rommel. 876: */ 877: VOID 878: #ifdef CK_ANSIC 879: showpkt(char c) 880: #else 881: showpkt(c) char c; 882: #endif /* CK_ANSIC */ 883: /* showpkt */ { 884: 885: if (newdpy) /* Put up filenames, etc, */ 886: dpyinit(); /* if they're not there already. */ 887: 888: if (fdispla == XYFD_S) { /* CRT display */ 889: char buffer[40]; 890: long et; /* Elapsed time, entire batch */ 891: long pd; /* Percent done, this file */ 892: long tp; /* Transfer rate, entire batch */ 893: long ps; /* Packet size, current packet */ 894: long myffc, mytfc; /* Local copies of byte counters */ 895: 896: et = gtimer(); /* Elapsed time */ 897: ps = (what == W_RECV) ? rpktl+1 : spktl+1; /* Packet length */ 898: pd = -1; /* Percent done. */ 899: if (c == NUL) { /* Still going, figure % done */ 900: if (fsize == 0L) return; /* Empty file, don't bother */ 901: pd = (fsize > 99L) ? (ffc / (fsize / 100L)) : 0L; 902: if (pd > 100) pd = 100; /* Expansion */ 903: } else pd = 100; /* File complete, so 100%. */ 904: 905: #ifndef CK_CPS 906: /* 907: fsecs = time (from gtimer) that this file started (set in sfile()). 908: Rate so far is ffc / (et - fsecs), estimated time for remaining bytes 909: is (fsize - ffc) / ( ffc / (et - fsecs )). 910: */ 911: tp = (ffc > 0L) ? (fsize - ffc) * (et - fsecs) / ffc : 0L; 912: #endif /* CK_CPS */ 913: 914: myffc = (ffc > 0) ? ffc - 1L : ffc; /* No, I don't know why... */ 915: if (myffc < 0L) myffc = 0L; 916: #ifdef CK_CPS 917: mytfc = (pd < 100) ? tfc + myffc : tfc; 918: tp = (et > 0) ? mytfc / et : 0; /* Transfer rate */ 919: if (c && (tp == 0)) /* Watch out for subsecond times */ 920: tp = myffc; 921: #endif /* CK_CPS */ 922: if (pd > -1L) 923: sprintf(buffer, "%c%9ld%5ld%%%8ld%8ld ", CR, myffc, pd, tp, ps); 924: else 925: sprintf(buffer, "%c%9ld %8ld%8ld ", CR, myffc, tp, ps); 926: conol(buffer); 927: hpos = 31; 928: } else { /* SERIAL display */ 929: long i, k; 930: if (ffc - oldffc < 1024) /* Update display every 1K */ 931: return; 932: oldffc = ffc; /* Time for new display */ 933: k = (ffc / 1024L) - dots; /* How many K so far */ 934: for (i = 0L; i < k; i++) { 935: if (hpos++ > 77) { /* Time to wrap? */ 936: conoll(""); 937: hpos = 0; 938: } 939: conoc('.'); /* Print a dot for this K */ 940: dots++; /* Count it */ 941: } 942: } 943: } 944: 945: /* S C R E E N -- Screen display function */ 946: 947: /* 948: screen(f,c,n,s) 949: f - argument descriptor 950: c - a character or small integer 951: n - a long integer 952: s - a string. 953: Fill in this routine with the appropriate display update for the system. 954: FILE DISPLAY SERIAL: Default, works on any terminal, even hardcopy. 955: FILE DISPLAY CRT: Works on any CRT, writes over current line. 956: FILE DISPLAY FULLSCREEN: Requires terminal-dependent screen control. 957: */ 958: VOID 959: #ifdef CK_ANSIC 960: screen(int f, char c,long n,char *s) 961: #else 962: screen(f,c,n,s) int f; char c; long n; char *s; 963: #endif /* CK_ANSIC */ 964: /* screen */ { 965: char buf[80]; 966: int len; /* Length of string */ 967: #ifdef UNIX 968: #ifndef NOJC 969: int obg; 970: _PROTOTYP( VOID conbgt, (int) ); 971: 972: if (local) { 973: obg = backgrd; /* Previous background status */ 974: conbgt(1); /* See if running in background */ 975: if (!backgrd && obg) { /* Just came into foreground? */ 976: concb((char)escape); /* Put console back in CBREAK mode */ 977: conint(trap,stptrap); /* Turn interrupts back on. */ 978: } 979: } 980: #endif /* NOJC */ 981: #endif /* UNIX */ 982: 983: if ((f != SCR_WM) && (f != SCR_EM)) /* Always update warnings & errors */ 984: if (!displa || quiet || backgrd || fdispla == XYFD_N || 985: (server && !srvdis)) 986: return; 987: 988: #ifdef CK_CURSES 989: if (fdispla == XYFD_C) { /* If fullscreen display selected */ 990: screenc(f,c,n,s); /* call the fullscreen version */ 991: return; 992: } 993: #endif /* CK_CURSES */ 994: 995: len = (int)strlen(s); /* Length of string */ 996: 997: switch (f) { /* Handle our function code */ 998: 999: case SCR_FN: /* Filename */ 1000: #ifdef MAC 1001: conoll(""); conol(s); conoc(SP); hpos = len + 1; 1002: #else 1003: strncpy(fbuf,s,80); 1004: newdpy = 1; /* New file so refresh display */ 1005: #endif /* MAC */ 1006: return; 1007: 1008: case SCR_AN: /* As-name */ 1009: #ifdef MAC 1010: if (hpos + len > 75) { conoll(""); hpos = 0; } 1011: conol("=> "); conol(s); 1012: if ((hpos += (len + 3)) > 78) { conoll(""); hpos = 0; } 1013: #else 1014: strncpy(abuf,s,80); 1015: #endif /* MAC */ 1016: return; 1017: 1018: case SCR_FS: /* File-size */ 1019: #ifdef MAC 1020: sprintf(buf,", Size: %ld",n); conoll(buf); hpos = 0; 1021: #endif /* MAC */ 1022: return; 1023: 1024: case SCR_XD: /* X-packet data */ 1025: #ifdef MAC 1026: conoll(""); conoll(s); hpos = 0; 1027: #else 1028: strncpy(fbuf,s,80); 1029: #endif /* MAC */ 1030: return; 1031: 1032: case SCR_ST: /* File status */ 1033: switch (c) { 1034: case ST_OK: /* Transferred OK */ 1035: showpkt('Z'); /* Update numbers one last time */ 1036: if ((hpos += 5) > 78) conoll(""); /* Wrap screen line if necessary. */ 1037: conoll(" [OK]"); hpos = 0; /* Print OK message. */ 1038: if (fdispla == XYFD_S) { /* We didn't show Z packet when */ 1039: conoc('Z'); /* it came, so show it now. */ 1040: hpos = 1; 1041: } 1042: return; 1043: 1044: case ST_DISC: /* Discarded */ 1045: if ((hpos += 12) > 78) conoll(""); 1046: conoll(" [discarded]"); hpos = 0; 1047: return; 1048: 1049: case ST_INT: /* Interrupted */ 1050: if ((hpos += 14) > 78) conoll(""); 1051: conoll(" [interrupted]"); hpos = 0; 1052: return; 1053: 1054: case ST_SKIP: /* Skipped */ 1055: if ((hpos += 10) > 78) conoll(""); 1056: conol(" [skipped]"); hpos = 0; 1057: return; 1058: 1059: case ST_ERR: /* Error */ 1060: conoll(""); 1061: conol("Error: "); conoll(s); hpos = 0; 1062: return; 1063: 1064: case ST_REFU: /* Refused */ 1065: conoll(""); 1066: conol("Refused: "); conoll(s); hpos = 0; 1067: return; 1068: 1069: case ST_INC: /* Incomplete */ 1070: if ((hpos += 12) > 78) conoll(""); 1071: conoll(" [incomplete]"); hpos = 0; 1072: return; 1073: 1074: default: 1075: conoll("*** screen() called with bad status ***"); 1076: hpos = 0; 1077: return; 1078: } 1079: 1080: #ifdef MAC 1081: case SCR_PN: /* Packet number */ 1082: sprintf(buf,"%s: %ld",s,n); conol(buf); hpos += (int)strlen(buf); return; 1083: #endif /* MAC */ 1084: 1085: case SCR_PT: /* Packet type or pseudotype */ 1086: if (c == 'Y') return; /* Don't bother with ACKs */ 1087: if (c == 'D') { /* In data transfer phase, */ 1088: showpkt(NUL); /* show progress. */ 1089: return; 1090: } 1091: #ifndef AMIGA 1092: if (hpos++ > 77) { /* If near right margin, */ 1093: conoll(""); /* Start new line */ 1094: hpos = 0; /* and reset counter. */ 1095: } 1096: #endif /* AMIGA */ 1097: if (c == 'Z' && fdispla == XYFD_S) 1098: return; 1099: else 1100: conoc(c); /* Display the packet type. */ 1101: #ifdef AMIGA 1102: if (c == 'G') conoll(""); /* New line after G packets */ 1103: #endif /* AMIGA */ 1104: return; 1105: 1106: case SCR_TC: /* Transaction complete */ 1107: conoc(BEL); conoll(""); return; 1108: 1109: case SCR_EM: /* Error message */ 1110: conoll(""); conoc('?'); conoll(s); hpos = 0; return; 1111: 1112: case SCR_WM: /* Warning message */ 1113: conoll(""); conoll(s); hpos = 0; return; 1114: 1115: case SCR_TU: /* Undelimited text */ 1116: if ((hpos += len) > 77) { conoll(""); hpos = len; } 1117: conol(s); return; 1118: 1119: case SCR_TN: /* Text delimited at beginning */ 1120: conoll(""); conol(s); hpos = len; return; 1121: 1122: case SCR_TZ: /* Text delimited at end */ 1123: if ((hpos += len) > 77) { conoll(""); hpos = len; } 1124: conoll(s); return; 1125: 1126: case SCR_QE: /* Quantity equals */ 1127: sprintf(buf,"%s: %ld",s,n); 1128: conoll(buf); hpos = 0; return; 1129: 1130: case SCR_CW: /* Close fullscreen window */ 1131: return; /* No window to close */ 1132: 1133: default: 1134: conoll("*** screen() called with bad object ***"); 1135: hpos = 0; 1136: return; 1137: } 1138: } 1139: 1140: /* E R M S G -- Nonfatal error message */ 1141: 1142: /* Should be used only for printing the message text from an Error packet. */ 1143: 1144: VOID 1145: ermsg(msg) char *msg; { /* Print error message */ 1146: if (local) 1147: screen(SCR_EM,0,0L,msg); 1148: tlog(F110,"Protocol Error:",msg,0L); 1149: } 1150: 1151: VOID 1152: doclean() { /* General cleanup upon exit */ 1153: #ifndef NOICP 1154: #ifndef NOSPL 1155: extern struct mtab *mactab; /* For ON_EXIT macro. */ 1156: extern int nmac; 1157: #endif /* NOSPL */ 1158: #endif /* NOICP */ 1159: 1160: #ifdef DEBUG 1161: if (deblog) { /* Close any open logs. */ 1162: debug(F100,"Debug Log Closed","",0); 1163: *debfil = '\0'; 1164: deblog = 0; 1165: zclose(ZDFILE); 1166: } 1167: #endif /* DEBUG */ 1168: if (pktlog) { 1169: *pktfil = '\0'; 1170: pktlog = 0; 1171: zclose(ZPFILE); 1172: } 1173: if (seslog) { 1174: *sesfil = '\0'; 1175: seslog = 0; 1176: zclose(ZSFILE); 1177: } 1178: #ifdef TLOG 1179: if (tralog) { 1180: tlog(F100,"Transaction Log Closed","",0L); 1181: *trafil = '\0'; 1182: tralog = 0; 1183: zclose(ZTFILE); 1184: } 1185: #endif /* TLOG */ 1186: 1187: #ifndef NOICP 1188: #ifndef NOSPL 1189: zclose(ZRFILE); /* READ and WRITE files, if any. */ 1190: zclose(ZWFILE); 1191: #ifndef NODIAL 1192: if (dialfd) fclose(dialfd); /* Dial directory, if any. */ 1193: #endif /* NODIAL */ 1194: /* 1195: If a macro named "on_exit" is defined, execute it. Also remove it from the 1196: macro table, in case its definition includes an EXIT or QUIT command, which 1197: would cause much recursion and would prevent the program from ever actually 1198: EXITing. 1199: */ 1200: if (nmac) { /* Any macros defined? */ 1201: int k; /* Yes */ 1202: k = mlook(mactab,"on_exit",nmac); /* Look up "on_exit" */ 1203: if (k >= 0) { /* If found, */ 1204: *(mactab[k].kwd) = NUL; /* poke its name from the table, */ 1205: if (dodo(k,"") > -1) /* set it up, */ 1206: parser(1); /* and execute it */ 1207: } 1208: } 1209: #endif /* NOSPL */ 1210: #endif /* NOICP */ 1211: 1212: /* 1213: Put console terminal back to normal. This is done here because the 1214: ON_EXIT macro calls the parser, which meddles with console terminal modes. 1215: */ 1216: ttclos(0); /* Close external line, if any */ 1217: if (local) { 1218: strcpy(ttname,dftty); /* Restore default tty */ 1219: local = dfloc; /* And default remote/local status */ 1220: } 1221: conres(); /* Restore console terminal. */ 1222: 1223: #ifdef COMMENT 1224: /* Should be no need for this, and maybe it's screwing things up? */ 1225: connoi(); /* Turn off console interrupt traps */ 1226: #endif /* COMMENT */ 1227: 1228: syscleanup(); /* System-dependent cleanup, last */ 1229: } 1230: 1231: /* D O E X I T -- Exit from the program. */ 1232: 1233: /* 1234: First arg is general, system-independent symbol: GOOD_EXIT or BAD_EXIT. 1235: If second arg is -1, take 1st arg literally. 1236: If second arg is not -1, work it into the exit code. 1237: */ 1238: VOID 1239: doexit(exitstat,what) int exitstat, what; { 1240: #ifdef VMS 1241: char envstr[64]; 1242: static $DESCRIPTOR(symnam,"CKERMIT_STATUS"); 1243: static struct dsc$descriptor_s symval; 1244: int i; 1245: #endif /* VMS */ 1246: 1247: debug(F101,"doexit exitstat","",exitstat); 1248: debug(F101,"doexit what","",what); 1249: 1250: doclean(); /* First, clean up everything */ 1251: 1252: #ifdef VMS 1253: if (what == -1) 1254: what = 0; /* Since we set two different items */ 1255: sprintf(envstr,"%d", exitstat | what); 1256: symval.dsc$w_length = (int)strlen(envstr); 1257: symval.dsc$a_pointer = envstr; 1258: symval.dsc$b_class = DSC$K_CLASS_S; 1259: symval.dsc$b_dtype = DSC$K_DTYPE_T; 1260: i = 2; /* Store in global table */ 1261: LIB$SET_SYMBOL(&symnam, &symval, &i); 1262: if (exitstat == BAD_EXIT) 1263: exitstat = SS$_ABORT | STS$M_INHIB_MSG; 1264: if (exitstat == GOOD_EXIT) 1265: exitstat = SS$_NORMAL | STS$M_INHIB_MSG; 1266: exit(exitstat); 1267: #else /* Not VMS */ 1268: if (what == -1) /* Take 1st arg literally */ 1269: exit(exitstat); /* e.g. user-supplied exit code */ 1270: else /* otherwise */ 1271: exit(exitstat | what); /* OR in the bits */ 1272: #endif /* VMS */ 1273: } 1274: 1275: /* Set up interrupts */ 1276: 1277: VOID 1278: setint() { 1279: conint(trap,stptrap); /* Turn on console terminal interrupts. */ 1280: bgchk(); /* Check background status */ 1281: } 1282: 1283: VOID 1284: bgchk() { /* Check background status */ 1285: if (bgset < 0) 1286: pflag = !backgrd; /* Set prompt flag */ 1287: else /* based on foreground/background */ 1288: pflag = (bgset == 0 ? 1 : 0); 1289: 1290: /* Message flag on only if at top level, pflag is on, and QUIET is OFF */ 1291: 1292: if ( 1293: #ifndef NOSPL 1294: cmdlvl == 0 1295: #else 1296: tlevel < 0 1297: #endif /* NOSPL */ 1298: ) 1299: msgflg = (pflag == 0) ? 0 : !quiet; 1300: else msgflg = 0; 1301: } 1302: 1303: #ifdef DEBUG 1304: /* D E B U G -- Enter a record in the debugging log */ 1305: 1306: /* 1307: Call with a format, two strings, and a number: 1308: f - Format, a bit string in range 0-7. 1309: If bit x is on, then argument number x is printed. 1310: s1 - String, argument number 1. If selected, printed as is. 1311: s2 - String, argument number 2. If selected, printed in brackets. 1312: n - Int, argument 3. If selected, printed preceded by equals sign. 1313: 1314: f=0 is special: print s1,s2, and interpret n as a char. 1315: */ 1316: #define DBUFL 2300 1317: static char *dbptr = (char *)0; 1318: 1319: int 1320: dodebug(f,s1,s2,n) int f; char *s1, *s2; long n; { 1321: char *sp; 1322: 1323: if (!deblog) return(0); /* If no debug log, don't. */ 1324: if (!dbptr) { 1325: dbptr = malloc(DBUFL+1); 1326: if (!dbptr) 1327: return(0); 1328: } 1329: sp = dbptr; 1330: if (!s1) s1="(NULL)"; 1331: if (!s2) s2="(NULL)"; 1332: switch (f) { 1333: case F000: /* 0, print both strings, and n as a char */ 1334: if ((int)strlen(s1) + (int)strlen(s2) + 5 > DBUFL) { 1335: sprintf(sp,"DEBUG string too long\n"); 1336: } else { 1337: if (n > 31 && n < 127) 1338: sprintf(sp,"%s%s:%c\n",s1,s2,n); 1339: else if (n < 32 || n == 127) 1340: sprintf(sp,"%s%s:^%c\n",s1,s2,(n+64) & 0x7F); 1341: else if (n > 127 && n < 160) 1342: sprintf(sp,"%s%s:~^%c\n",s1,s2,(n-64) & 0x7F); 1343: else if (n > 159 && n < 256) 1344: sprintf(sp,"%s%s:~%c\n",s1,s2,n & 0x7F); 1345: else sprintf(sp,"%s%s:%ld\n",s1,s2,n); 1346: } 1347: if (zsout(ZDFILE,dbptr) < 0) deblog = 0; 1348: break; 1349: case F001: /* 1, "=n" */ 1350: sprintf(sp,"=%ld\n",n); 1351: if (zsout(ZDFILE,dbptr) < 0) deblog = 0; 1352: break; 1353: case F010: /* 2, "[s2]" */ 1354: if ((int)strlen(s2) + 4 > DBUFL) 1355: sprintf(sp,"DEBUG string too long\n"); 1356: else sprintf(sp,"[%s]\n",s2); 1357: if (zsout(ZDFILE,"") < 0) deblog = 0; 1358: break; 1359: case F011: /* 3, "[s2]=n" */ 1360: if ((int)strlen(s2) + 15 > DBUFL) 1361: sprintf(sp,"DEBUG string too long\n"); 1362: else sprintf(sp,"[%s]=%ld\n",s2,n); 1363: if (zsout(ZDFILE,dbptr) < 0) deblog = 0; 1364: break; 1365: case F100: /* 4, "s1" */ 1366: if (zsoutl(ZDFILE,s1) < 0) deblog = 0; 1367: break; 1368: case F101: /* 5, "s1=n" */ 1369: if ((int)strlen(s1) + 15 > DBUFL) 1370: sprintf(sp,"DEBUG string too long\n"); 1371: else sprintf(sp,"%s=%ld\n",s1,n); 1372: if (zsout(ZDFILE,dbptr) < 0) deblog = 0; 1373: break; 1374: case F110: /* 6, "s1[s2]" */ 1375: if ((int)strlen(s1) + (int)strlen(s2) + 4 > DBUFL) 1376: sprintf(sp,"DEBUG string too long\n"); 1377: else sprintf(sp,"%s[%s]\n",s1,s2); 1378: if (zsout(ZDFILE,dbptr) < 0) deblog = 0; 1379: break; 1380: case F111: /* 7, "s1[s2]=n" */ 1381: if ((int)strlen(s1) + (int)strlen(s2) + 15 > DBUFL) 1382: sprintf(sp,"DEBUG string too long\n"); 1383: else sprintf(sp,"%s[%s]=%ld\n",s1,s2,n); 1384: if (zsout(ZDFILE,dbptr) < 0) deblog = 0; 1385: break; 1386: default: 1387: sprintf(sp,"\n?Invalid format for debug() - %d\n",f); 1388: if (zsout(ZDFILE,dbptr) < 0) deblog = 0; 1389: } 1390: return(0); 1391: } 1392: #endif /* DEBUG */ 1393: 1394: #ifdef TLOG 1395: #define TBUFL 300 1396: /* T L O G -- Log a record in the transaction file */ 1397: /* 1398: Call with a format and 3 arguments: two strings and a number: 1399: f - Format, a bit string in range 0-7, bit x is on, arg #x is printed. 1400: s1,s2 - String arguments 1 and 2. 1401: n - Int, argument 3. 1402: */ 1403: VOID 1404: tlog(f,s1,s2,n) int f; long n; char *s1, *s2; { 1405: static char s[TBUFL]; 1406: char *sp = s; int x; 1407: 1408: if (!tralog) return; /* If no transaction log, don't */ 1409: switch (f) { 1410: case F000: /* 0 (special) "s1 n s2" */ 1411: if ((int)strlen(s1) + (int)strlen(s2) + 15 > TBUFL) 1412: sprintf(sp,"?T-Log string too long\n"); 1413: else sprintf(sp,"%s %ld %s\n",s1,n,s2); 1414: if (zsout(ZTFILE,s) < 0) tralog = 0; 1415: break; 1416: case F001: /* 1, " n" */ 1417: sprintf(sp," %ld\n",n); 1418: if (zsout(ZTFILE,s) < 0) tralog = 0; 1419: break; 1420: case F010: /* 2, "[s2]" */ 1421: x = (int)strlen(s2); 1422: if (s2[x] == '\n') s2[x] = '\0'; 1423: if (x + 6 > TBUFL) 1424: sprintf(sp,"?T-Log string too long\n"); 1425: else sprintf(sp,"[%s]\n",s2); 1426: if (zsout(ZTFILE,"") < 0) tralog = 0; 1427: break; 1428: case F011: /* 3, "[s2] n" */ 1429: x = (int)strlen(s2); 1430: if (s2[x] == '\n') s2[x] = '\0'; 1431: if (x + 6 > TBUFL) 1432: sprintf(sp,"?T-Log string too long\n"); 1433: else sprintf(sp,"[%s] %ld\n",s2,n); 1434: if (zsout(ZTFILE,s) < 0) tralog = 0; 1435: break; 1436: case F100: /* 4, "s1" */ 1437: if (zsoutl(ZTFILE,s1) < 0) tralog = 0; 1438: break; 1439: case F101: /* 5, "s1: n" */ 1440: if ((int)strlen(s1) + 15 > TBUFL) 1441: sprintf(sp,"?T-Log string too long\n"); 1442: else sprintf(sp,"%s: %ld\n",s1,n); 1443: if (zsout(ZTFILE,s) < 0) tralog = 0; 1444: break; 1445: case F110: /* 6, "s1 s2" */ 1446: x = (int)strlen(s2); 1447: if (s2[x] == '\n') s2[x] = '\0'; 1448: if ((int)strlen(s1) + x + 4 > TBUFL) 1449: sprintf(sp,"?T-Log string too long\n"); 1450: else sprintf(sp,"%s %s\n",s1,s2); 1451: if (zsout(ZTFILE,s) < 0) tralog = 0; 1452: break; 1453: case F111: /* 7, "s1 s2: n" */ 1454: x = (int)strlen(s2); 1455: if (s2[x] == '\n') s2[x] = '\0'; 1456: if ((int)strlen(s1) + x + 15 > TBUFL) 1457: sprintf(sp,"?T-Log string too long\n"); 1458: else sprintf(sp,"%s %s: %ld\n",s1,s2,n); 1459: if (zsout(ZTFILE,s) < 0) tralog = 0; 1460: break; 1461: default: 1462: sprintf(sp,"\n?Invalid format for tlog() - %ld\n",n); 1463: if (zsout(ZTFILE,s) < 0) tralog = 0; 1464: } 1465: } 1466: #endif /* TLOG */ 1467: 1468: #ifdef CK_CURSES 1469: 1470: /* 1471: There are three different ways to do fullscreen on VMS. 1472: 1. Use the real curses library, VAXCCURSE. 1473: 2. Use do-it-yourself code. 1474: 3. Use the Screen Manager, SMG$. 1475: 1476: Method 1 doesn't work quite right; you can't call endwin(), so once you've 1477: started curses mode, you can never leave. 1478: 1479: Method 2 doesn't optimize the screen, and so much more time is spent in 1480: screen writes. This actually causes file transfers to fail because the 1481: tty device input buffer can be overrun while the screen is being updated, 1482: especially on a slow MicroVAX that has small typeahead buffers. 1483: 1484: In the following #ifdef block, #define one of them and #undef the other 2. 1485: 1486: So now let's try method 3... 1487: */ 1488: #ifdef VMS 1489: #define CK_SMG /* Screen Manager */ 1490: #undef MYCURSES /* Do-it-yourself */ 1491: #undef VMSCURSE /* VAXCCURSE library */ 1492: #endif /* VMS */ 1493: 1494: /* S C R E E N C -- Screen display function, uses curses */ 1495: 1496: /* Idea for curses display contributed by Chris Pratt of APV Baker, UK */ 1497: 1498: /* Avoid conficts with curses.h */ 1499: 1500: #ifndef MYCURSES 1501: #undef VOID /* This was defined in ckcdeb.h */ 1502: #endif /* MYCURSES */ 1503: 1504: #undef BS /* These were defined in ckcasc.h */ 1505: #undef CR 1506: #undef NL 1507: #undef SO 1508: #undef US 1509: 1510: #ifdef VMS /* VMS fullscreen display */ 1511: #ifdef MYCURSES /* Do-it-yourself method */ 1512: extern int isvt52; /* From CKVTIO.C */ 1513: #define printw printf 1514: #else 1515: #ifdef VMSCURSE /* VMS curses library VAXCCURSE */ 1516: #include <curses.h> 1517: /* Note: Screen manager doesn't need a header file */ 1518: #endif /* VMSCURSE */ 1519: #endif /* MYCURSES */ 1520: #else /* Not VMS */ 1521: #ifdef MYCURSES /* Do-it-yourself method */ 1522: #define isvt52 0 /* Used by OS/2, VT-100/ANSI always */ 1523: #define printw printf 1524: #else 1525: #include <curses.h> /* So use real curses */ 1526: #endif /* MYCURSES */ 1527: #endif /* VMS */ 1528: 1529: #ifdef CK_SMG 1530: /* 1531: Long section for Screen Manager starts here... 1532: By William Bader. 1533: */ 1534: #include "ckvvms.h" 1535: /* #include <smgdef.h> */ 1536: /* #include <smgmsg.h> */ 1537: 1538: extern unsigned int vms_status; /* Used for system service return status */ 1539: 1540: static long smg_pasteboard_id = -1; /* pasteboard identifier */ 1541: static long smg_display_id = -1; /* display identifier */ 1542: static int smg_open = 0; /* flag if smg current open */ 1543: 1544: #define clrtoeol() SMG$ERASE_LINE(&smg_display_id, 0, 0) 1545: 1546: #define clear() SMG$ERASE_DISPLAY(&smg_display_id, 0, 0, 0, 0) 1547: 1548: #define touchwin(scr) SMG$REPAINT_SCREEN(&smg_pasteboard_id) 1549: 1550: static void 1551: move(row, col) int row, col; { 1552: /* Change from 0-based for curses to 1-based for SMG */ 1553: ++row; ++col; 1554: CHECK_ERR("move: smg$set_cursor_abs", 1555: SMG$SET_CURSOR_ABS(&smg_display_id, &row, &col)); 1556: } 1557: 1558: static void 1559: refresh() { 1560: CHECK_ERR("refresh: smg$end_pasteboard_update", 1561: SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id)); 1562: CHECK_ERR("refresh: smg$begin_pasteboard_update", 1563: SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id)); 1564: } 1565: 1566: #ifdef VMS_V40 1567: #define OLD_VMS 1568: #endif /* VMS_V40 */ 1569: #ifdef VMS_V42 1570: #define OLD_VMS 1571: #endif /* VMS_V42 */ 1572: #ifdef VMS_V44 1573: #define OLD_VMS 1574: #endif /* VMS_V44 */ 1575: 1576: static int 1577: initscr() { 1578: int rows = 24, cols = 80; 1579: int row = 1, col = 1; 1580: 1581: if (smg_pasteboard_id == -1) { /* Open the screen */ 1582: #ifdef OLD_VMS 1583: CHECK_ERR("initscr: smg$create_pasteboard", 1584: SMG$CREATE_PASTEBOARD(&smg_pasteboard_id, 0, 0, 0, 0)); 1585: #else 1586: /* For VMS V5, not tested */ 1587: CHECK_ERR("initscr: smg$create_pasteboard", 1588: SMG$CREATE_PASTEBOARD(&smg_pasteboard_id, 0, 0, 0, 0, 0)); 1589: #endif /* OLD_VMS */ 1590: } 1591: 1592: if (smg_display_id == -1) { /* Create a display window */ 1593: 1594: CHECK_ERR("initscr: smg$create_virtual_display", 1595: SMG$CREATE_VIRTUAL_DISPLAY(&rows, &cols, &smg_display_id, 1596: 0, 0, 0)); 1597: 1598: /* Connect the display window to the screen */ 1599: CHECK_ERR("initscr: smg$paste_virtual_display", 1600: SMG$PASTE_VIRTUAL_DISPLAY(&smg_display_id,&smg_pasteboard_id, 1601: &row,&col)); 1602: } 1603: 1604: if (!smg_open) { /* Start a batch update */ 1605: smg_open = 1; 1606: CHECK_ERR("initscr: smg$begin_pasteboard_update", 1607: SMG$BEGIN_PASTEBOARD_UPDATE(&smg_pasteboard_id)); 1608: } 1609: return(1); 1610: } 1611: 1612: static void 1613: endwin() { 1614: if (!smg_open) 1615: return; 1616: 1617: smg_open = 0; 1618: 1619: CHECK_ERR("endwin: smg$end_pasteboard_update", 1620: SMG$END_PASTEBOARD_UPDATE(&smg_pasteboard_id)); 1621: 1622: move(22, 0); 1623: 1624: #ifdef COMMENT 1625: /* 1626: These calls clear the screen. 1627: */ 1628: CHECK_ERR("endwin: smg$delete_virtual_display", 1629: SMG$DELETE_VIRTUAL_DISPLAY(&smg_display_id)); 1630: smg_display_id = -1; 1631: 1632: CHECK_ERR("endwin: smg$delete_pasteboard", 1633: SMG$DELETE_PASTEBOARD(&smg_pasteboard_id, 0)); 1634: smg_pasteboard_id = -1; 1635: #endif /* COMMENT */ 1636: } 1637: 1638: static void printw(str, a1, a2, a3, a4, a5, a6, a7, a8) 1639: char *str; 1640: long a1, a2, a3, a4, a5, a6, a7, a8; 1641: /* printw */ { 1642: char buf[255]; 1643: $DESCRIPTOR(text_dsc, buf); 1644: 1645: text_dsc.dsc$w_length = sprintf(buf, str, a1, a2, a3, a4, a5, a6, a7, a8); 1646: CHECK_ERR("printw: smg$put_chars", 1647: SMG$PUT_CHARS(&smg_display_id, &text_dsc, 0, 0, 0, 0, 0)); 1648: } 1649: #endif /* CK_SMG */ 1650: 1651: #ifdef MYCURSES 1652: /* 1653: Do-it-yourself curses implementation for VMS, OS/2 and other ANSI/VT-100's. 1654: Supports only the VT52 and VT1xx (and later VT2xx/3xx/4xx) terminals. 1655: By Terry Kennedy, St Peters College. 1656: 1657: First, some stuff we can just ignore: 1658: */ 1659: 1660: int 1661: touchwin(x) int x; { 1662: } 1663: int 1664: initscr() { 1665: } 1666: int 1667: refresh() { 1668: } 1669: int 1670: endwin() { 1671: } 1672: 1673: /* 1674: * Now, some stuff we need to do: 1675: */ 1676: 1677: _PROTOTYP( int move, (int, int) ); 1678: 1679: int 1680: move(row, col) int row, col; { 1681: if (isvt52) 1682: printf("\033Y%c%c", row + 037, col + 037); 1683: else 1684: printf("\033[%d;%dH", row + 1, col + 1); 1685: } 1686: 1687: int 1688: clear() { 1689: move(1,1); 1690: if (isvt52) 1691: printf("\033J"); 1692: else 1693: printf("\033[J"); 1694: } 1695: 1696: int 1697: clrtoeol() { 1698: if (isvt52) 1699: printf("\033K"); 1700: else 1701: printf("\033[K"); 1702: } 1703: #endif /* MYCURSES */ 1704: 1705: /* Screen line numbers */ 1706: 1707: #define CW_BAN 0 /* Curses Window Banner */ 1708: #define CW_DIR 2 /* Current directory */ 1709: #define CW_LIN 3 /* Communication device */ 1710: #define CW_SPD 4 /* Communication speed */ 1711: #define CW_PAR 5 /* Parity */ 1712: #define CW_NAM 7 /* Filename */ 1713: #define CW_TYP 8 /* File type */ 1714: #define CW_SIZ 9 /* File size */ 1715: #define CW_PCD 10 /* Percent done */ 1716: #define CW_TR 11 /* Time remaining */ 1717: #define CW_WS 12 /* Window slots */ 1718: #define CW_PT 13 /* Packet type */ 1719: #define CW_PC 14 /* Packet count */ 1720: #define CW_PL 15 /* Packet length */ 1721: #define CW_PR 16 /* Packet retry */ 1722: #define CW_PB 17 /* Packet block check */ 1723: #define CW_ERR 19 /* Error message */ 1724: #define CW_MSG 20 /* Info message */ 1725: #define CW_INT 22 /* Instructions */ 1726: 1727: static int cinit = 0; /* Flag for curses init'd */ 1728: static int cendw = 0; /* endwin() was called */ 1729: 1730: static 1731: #ifdef CK_ANSIC /* Because VOID used by curses.h */ 1732: void 1733: #else 1734: #ifdef MYCURSES 1735: VOID 1736: #else 1737: int 1738: #endif /* MYCURSES */ 1739: #endif /* CK_ANSIC */ 1740: scrft() { /* Display file type */ 1741: move(CW_TYP,22); 1742: if (binary) { 1743: #ifdef VMS 1744: if (binary == XYFT_I) 1745: printw("image"); 1746: else if (binary == XYFT_L) 1747: printw("labeled"); 1748: else printw("binary"); 1749: #else /* Not VMS */ 1750: printw("binary"); 1751: #endif /* VMS */ 1752: } else { 1753: printw("text"); 1754: } 1755: clrtoeol(); 1756: return; 1757: } 1758: 1759: char * /* Convert seconds to hh:mm:ss */ 1760: #ifdef CK_ANSIC 1761: hhmmss(long x) 1762: #else 1763: hhmmss(x) long x; 1764: #endif /* CK_ANSIC */ 1765: /* hhmmss(x) */ { 1766: static char buf[10]; 1767: long s, h, m; 1768: h = x / 3600L; /* Hours */ 1769: x = x % 3600L; 1770: m = x / 60L; /* Minutes */ 1771: s = x % 60L; /* Seconds */ 1772: if (x > -1L) 1773: sprintf(buf,"%02ld:%02ld:%02ld",h,m,s); 1774: else buf[0] = NUL; 1775: return((char *)buf); 1776: } 1777: 1778: #ifdef CK_NEWTERM 1779: static FILE *ck_stdout = NULL; 1780: static int ck_fd = -1; 1781: #endif /* CK_NEWTERM */ 1782: 1783: static long pct = 100, oldpct = 0; /* Percent done */ 1784: static int oldtyp = 0, oldwin = -1, oldtry = -1, oldlen = -1; 1785: 1786: #ifdef CK_ANSIC 1787: void 1788: screenc(int f, char c,long n,char *s) 1789: #else 1790: #ifdef MYCURSES 1791: VOID 1792: #else 1793: int 1794: #endif /* MYCURSES */ 1795: screenc(f,c,n,s) 1796: int f; /* argument descriptor */ 1797: char c; /* a character or small integer */ 1798: long n; /* a long integer */ 1799: char *s; /* a string */ 1800: #endif /* CK_ANSIC */ 1801: /* screenc() */ { 1802: 1803: static int q = 0; 1804: static long fsiz = -1L; /* Copy of file size */ 1805: static long fcnt = 0L; /* File count */ 1806: static long fbyt = 0L; /* Total file bytes */ 1807: 1808: int len; /* Length of string */ 1809: int x; /* Worker */ 1810: 1811: if (cinit == 0 || cendw > 0) { /* Handle borderline cases... */ 1812: if (f == SCR_CW) { /* Close window, but it's not open */ 1813: ft_win = 0; 1814: return; 1815: } 1816: if (f == SCR_EM || 1817: (f == SCR_PT && c == 'E')) { /* Fatal error before window open */ 1818: conoll(""); conoc('?'); conoll(s); return; /* Regular display */ 1819: } 1820: } 1821: if (cinit == 0) { /* Only call initscr() once */ 1822: cendw = 1; /* New window needs repainting */ 1823: #ifdef COMMENT 1824: if (!initscr()) { /* Oops, can't initialize window? */ 1825: /* 1826: In fact, this doesn't happen. "man curses" says initscr() halts the 1827: entire program if it fails, which is true on the systems where I've 1828: tested it. It will fail if your terminal type is not known to it. 1829: That's why SET FILE DISPLAY FULLSCREEN calls tgetent() to make sure the 1830: terminal type is known before allowing a curses display. 1831: */ 1832: fprintf(stderr,"CURSES INITSCR ERROR\r\n"); 1833: fdispla = XYFD_R; /* Go back to regular display */ 1834: return; 1835: } else { 1836: cinit++; /* Window initialized ok */ 1837: debug(F100,"CURSES INITSCR OK","",0); 1838: } 1839: #else /* Save some memory. */ 1840: #ifdef CK_NEWTERM 1841: /* (From Andy Fyfe <andy@vlsi.cs.caltech.edu>) 1842: System V curses seems to reserve the right to alter the buffering 1843: on the output FILE* without restoring it. Fortunately System V 1844: curses provides newterm(), an alternative to initscr(), that 1845: allows us to specify explicitly the terminal type and input and 1846: output FILE pointers. Thus we duplicate stdout, and let curses 1847: have the copy. The original remains unaltered. Unfortunately, 1848: newterm() seems to be particular to System V. 1849: */ 1850: s = getenv("TERM"); 1851: if (ck_fd < 0) { 1852: ck_fd = dup(fileno(stdout)); 1853: ck_stdout = (ck_fd >= 0) ? fdopen(ck_fd, "w") : NULL; 1854: } 1855: if (ck_stdout == NULL || newterm(s, ck_stdout, stdin) == 0) { 1856: fprintf(stderr, 1857: "Fullscreen display not supported for terminal type: %s\r\n",s); 1858: fdispla = XYFD_R; /* Go back to regular display */ 1859: return; 1860: } 1861: #else 1862: initscr(); /* Initialize curses. */ 1863: #endif /* CK_NEWTERM */ 1864: cinit++; /* Remember curses was initialized. */ 1865: #endif /* COMMENT */ 1866: } 1867: ft_win = 1; /* Window is open */ 1868: if (cendw) { /* endwin() was called previously */ 1869: #ifdef VMS 1870: initscr(); /* (or should have been!) */ 1871: clear(); 1872: touchwin(stdscr); 1873: refresh(); 1874: #else /* All others... */ 1875: clear(); 1876: #endif /* VMS */ 1877: 1878: move(CW_BAN,0); /* Display the banner */ 1879: if (*myhost) printw("%s, %s",versio,(char *)myhost); 1880: else printw("%s",versio); 1881: move(CW_DIR,3); printw("Current Directory: %s",zgtdir()); 1882: if (network) { 1883: move(CW_LIN,9); printw("Remote Host: %s",ttname); 1884: } else { 1885: move(CW_LIN,0); printw("Communication Device: %s",ttname); 1886: } 1887: move(CW_SPD,1); printw("Communication Speed: "); 1888: move(CW_SPD,22); /* Speed */ 1889: if (network) { 1890: printw("(network)"); 1891: } else { 1892: if (speed < 0L) speed = ttgspd(); 1893: if (speed > 0L) { 1894: if (speed == 8880) printw("75/1200"); 1895: else printw("%ld",speed); 1896: } else printw("unknown"); 1897: } 1898: move(CW_PAR,14); printw("Parity: %s",parnam((char)parity)); 1899: move(CW_TYP,11); printw("File Type:"); 1900: move(CW_SIZ,11); printw("File Size:"); 1901: move(CW_PCD, 8); printw("Percent Done:"); 1902: move(CW_TR, 1); printw("Estimated Time Left:"); 1903: move(CW_WS, 8); printw("Window Slots:"); 1904: move(CW_PT, 9); printw("Packet Type:"); 1905: move(CW_PC, 8); printw("Packet Count:"); 1906: move(CW_PL, 7); printw("Packet Length:"); 1907: move(CW_PR, 2); printw("Packet Retry Count:"); 1908: move(CW_PB, 2); printw("Packet Block Check:"); 1909: move(CW_ERR,10); printw("Last Error:"); 1910: move(CW_MSG, 8); printw("Last Message:"); 1911: #ifdef ATTSV 1912: #ifndef aegis 1913: #ifndef datageneral 1914: #define CK_NEED_SIG 1915: #endif /* datageneral */ 1916: #endif /* aegis */ 1917: #endif /* ATTSV */ 1918: #ifdef POSIX 1919: #ifndef CK_NEED_SIG 1920: #define CK_NEED_SIG 1921: #endif /* CK_NEED_SIG */ 1922: #endif /* POSIX */ 1923: 1924: #ifdef CK_NEED_SIG 1925: move(CW_INT, 0); printw( 1926: "<%s>X to cancel file, <%s>Z to cancel group, <%s><CR> to resend packet", 1927: dbchr(escape), dbchr(escape), dbchr(escape)); 1928: move(CW_INT + 1, 0); printw( 1929: "<%s>E to send Error packet, or Ctrl-C to quit immediately.", dbchr(escape)); 1930: #else 1931: move(CW_INT, 0); 1932: #ifdef OS2 1933: printw( 1934: "X to cancel file, Z to cancel group, <Enter> to resend packet,"); 1935: #else 1936: printw("X to cancel file, Z to cancel group, <CR> to resend packet,"); 1937: #endif /* OS2 */ 1938: move(CW_INT + 1, 0); 1939: printw("E to send Error packet, or Ctrl-C to quit immediately."); 1940: #endif /* CK_NEED_SIG */ 1941: refresh(); 1942: cendw = 0; 1943: } 1944: len = strlen(s); /* Length of argument string */ 1945: 1946: debug(F101,"SCREENC switch","",f); /* Handle our function code */ 1947: switch (f) { 1948: case SCR_FN: /* Filename */ 1949: fsiz = -1L; /* Invalidate previous file size */ 1950: move(CW_PCD,22); /* Erase percent done from last time */ 1951: clrtoeol(); 1952: move(CW_SIZ,22); /* Erase file size from last time */ 1953: clrtoeol(); 1954: move(CW_ERR,22); /* And last error message */ 1955: clrtoeol(); 1956: if (what == W_SEND) { /* If we're sending... */ 1957: move(CW_NAM,13); 1958: printw("Sending:"); 1959: } else if (what == W_RECV) { /* If we're receiving... */ 1960: move(CW_NAM,11); 1961: printw("Receiving:"); 1962: } else { /* If we don't know... */ 1963: move(CW_NAM,11); /* (should never see this) */ 1964: printw("File Name:"); 1965: } 1966: move(CW_NAM,22); /* Display the filename */ 1967: if (len > 57) { 1968: printw("%.54s..",s); 1969: len = 57; 1970: } else printw("%s",s); 1971: q = len; /* Remember name length for later */ 1972: clrtoeol(); 1973: scrft(); /* Display file type */ 1974: refresh(); return; 1975: 1976: case SCR_AN: /* File as-name */ 1977: if (q + len < 58) { /* Will fit */ 1978: move(CW_NAM, 22 + q); 1979: printw(" => %s",s); 1980: } else { /* Too long */ 1981: move(CW_NAM, 22); /* Overwrite previous name */ 1982: q = 0; 1983: len = 54; 1984: printw(" => %.51s..", s); /* Truncate */ 1985: } 1986: q += len + 4; /* Remember horizontal position */ 1987: clrtoeol(); refresh(); return; 1988: 1989: case SCR_FS: /* File size */ 1990: fsiz = n; 1991: move(CW_SIZ,22); 1992: if (fsiz > -1L) printw("%ld",n); 1993: clrtoeol(); 1994: scrft(); /* File type */ 1995: refresh(); return; 1996: 1997: case SCR_PT: /* Packet type or pseudotype */ 1998: if (spackets < 5) { 1999: /* Things that won't change after the 4th packet */ 2000: move(CW_PAR,22); printw("%s",parnam((char)parity)); clrtoeol(); 2001: clrtoeol(); 2002: move(CW_PB, 22); /* Block check on this packet */ 2003: if (bctu == 4) printw("B"); else printw("%d",bctu); 2004: clrtoeol(); 2005: } 2006: 2007: x = (what == W_RECV) ? /* Packet length */ 2008: rpktl+1 : 2009: spktl+1; 2010: if (x != oldlen) { /* But only if it changed. */ 2011: move(CW_PL, 22); 2012: printw("%d",x); 2013: clrtoeol(); 2014: oldlen = x; 2015: } 2016: move(CW_PC, 22); /* Packet count (always). */ 2017: printw("%d",spackets); /* WARNING: this can slow us way */ 2018: clrtoeol(); /* down with short packets. */ 2019: 2020: if (wcur != oldwin) { /* Window slots, if changed. */ 2021: move(CW_WS, 22); 2022: printw("%d of %d",wcur,wslotr); 2023: clrtoeol(); 2024: oldwin = wcur; 2025: } 2026: if (retrans != oldtry) { /* Retry count, if changed */ 2027: move(CW_PR, 22); 2028: printw("%d",retrans); 2029: clrtoeol(); 2030: oldtry = retrans; 2031: } 2032: if (c != oldtyp && c != 'Y' && c != 'N') { /* Sender's packet type */ 2033: move(CW_PT,22); 2034: printw("%c",c); 2035: clrtoeol(); 2036: oldtyp = c; 2037: } 2038: switch (c) { /* Now handle specific packet types */ 2039: case 'S': /* Beginning of transfer */ 2040: fcnt = fbyt = 0L; /* Clear counters */ 2041: break; 2042: case 'D': /* Data packet */ 2043: if (fsiz > 0L) { /* Show percent done if known */ 2044: long s, x; 2045: oldpct = pct; /* Remember previous percent */ 2046: pct = (fsiz > 99L) ? (ffc / (fsiz / 100L)) : 0L; /* New one */ 2047: if (pct > 100L || /* Allow expansion */ 2048: oldpct == 99L && pct < 0L) /* other boundary conditions */ 2049: pct = 100L; 2050: if (pct != oldpct) { /* Only do this 100 times per file */ 2051: move(CW_PCD,22); 2052: printw("%ld", pct); 2053: clrtoeol(); 2054: 2055: /* Time remaining for this file */ 2056: 2057: s = (long) ((unsigned) gtimer() - fsecs); /* Secs so far */ 2058: if (s > 0L) { 2059: /* 2060: Time remaining must be calculated using the smallest 2061: possible quantities, to prevent overflow: 2062: (seconds_so_far * percent_left) / percent_done. 2063: And avoid divide_by_zero. 2064: */ 2065: x = (pct > 0L) ? ((s * (100 - pct)) / pct) : -1L; 2066: if (x > -1L) { 2067: move(CW_TR,22); 2068: printw("%s",hhmmss(x)); 2069: clrtoeol(); 2070: } 2071: } 2072: } 2073: } 2074: break; 2075: case 'E': /* Error packet */ 2076: #ifdef COMMENT 2077: move(CW_ERR,22); /* Print its data field */ 2078: if (*s) printw("%s",s); 2079: clrtoeol(); 2080: #endif /* COMMENT */ 2081: fcnt = fbyt = 0; /* So no bytes for this file */ 2082: break; 2083: case 'Q': /* Crunched packet */ 2084: move(CW_ERR,22); 2085: printw("Damaged Packet"); 2086: clrtoeol(); 2087: break; 2088: case 'T': /* Timeout */ 2089: move(CW_ERR,22); 2090: printw("Timeout"); 2091: clrtoeol(); 2092: break; 2093: default: /* Others, do nothing */ 2094: break; 2095: } 2096: refresh(); return; 2097: 2098: case SCR_ST: /* File transfer status */ 2099: move(CW_PCD,22); /* Update percent done */ 2100: if (c == ST_OK) { /* OK, print 100 % */ 2101: pct = 100; 2102: printw("100"); 2103: } else if (fsiz > 0L) /* Not OK, update final percent */ 2104: printw("%ld",( ffc * 100L ) / fsiz); 2105: clrtoeol(); 2106: move(CW_MSG,22); /* Remove any previous message */ 2107: clrtoeol(); refresh(); 2108: move(CW_TR, 22); 2109: clrtoeol(); refresh(); 2110: 2111: switch (c) { /* Print new status message */ 2112: case ST_OK: /* Transfer OK */ 2113: fcnt++; /* Count this file */ 2114: if (ffc > 0L) /* For some reason ffc is off by 1 */ 2115: fbyt += ffc - 1L; /* Count its bytes */ 2116: move(CW_MSG,22); 2117: printw("Transfer OK"); /* Say Transfer was OK */ 2118: clrtoeol(); refresh(); 2119: return; 2120: 2121: case ST_DISC: /* Discarded */ 2122: move(CW_ERR,22); printw("File discarded"); 2123: clrtoeol(); refresh(); 2124: return; 2125: 2126: case ST_INT: /* Interrupted */ 2127: move(CW_ERR,22); printw("Transfer interrupted"); 2128: clrtoeol(); refresh(); 2129: return; 2130: 2131: case ST_SKIP: /* Skipped */ 2132: move(CW_ERR,22); printw("File skipped"); 2133: clrtoeol(); refresh(); 2134: return; 2135: 2136: case ST_ERR: /* Error message */ 2137: move(CW_ERR,22); printw("%s",s); 2138: clrtoeol(); refresh(); 2139: return; 2140: 2141: case ST_REFU: /* Refused */ 2142: move(CW_ERR,22); 2143: if (*s) 2144: printw("Refused, %s",s); 2145: else printw("Refused"); 2146: clrtoeol(); refresh(); 2147: return; 2148: 2149: case ST_INC: 2150: move(CW_ERR,22); printw("Incomplete"); 2151: clrtoeol(); refresh(); 2152: return; 2153: 2154: default: /* Bad call */ 2155: move(CW_ERR,22); printw("*** screen() called with bad status ***"); 2156: clrtoeol(); refresh(); return; 2157: } 2158: 2159: case SCR_TC: /* Transaction complete */ 2160: move(CW_MSG,22); /* Print statistics in message line */ 2161: if (tsecs > 0) 2162: printw("Files: %ld, Total Bytes: %ld, %ld cps", 2163: fcnt, fbyt, ((fbyt * 10L) / (long) tsecs) / 10L); 2164: else printw("Files: %ld, Total Bytes: %ld",fcnt,fbyt); 2165: clrtoeol(); 2166: move(CW_TR, 1); 2167: printw(" Elapsed Time: %s",hhmmss((long)tsecs)); 2168: clrtoeol(); 2169: move(23,0); clrtoeol(); /* Clear instructions lines */ 2170: move(22,0); clrtoeol(); /* to make room for prompt. */ 2171: refresh(); 2172: #ifndef VMSCURSE 2173: endwin(); 2174: #endif /* VMSCURSE */ 2175: pct = 100; oldpct = 0; /* Reset these for next time. */ 2176: oldtyp = 0; oldwin = -1; oldtry = -1; oldlen = -1; 2177: cendw = 1; conoc(BEL); /* Close window, then beep. */ 2178: ft_win = 0; /* Window closed. */ 2179: return; 2180: 2181: case SCR_EM: /* Error packet (fatal) */ 2182: move (CW_ERR,22); 2183: printw("? %s",s); 2184: conoc(BEL); 2185: clrtoeol(); refresh(); return; 2186: 2187: case SCR_QE: /* Quantity equals */ 2188: case SCR_TU: /* Undelimited text */ 2189: case SCR_TN: /* Text delimited at start */ 2190: case SCR_TZ: /* Text delimited at end */ 2191: return; /* (ignored in fullscreen display) */ 2192: 2193: case SCR_XD: /* X-packet data */ 2194: move(CW_NAM,22); 2195: printw("%s",s); 2196: clrtoeol(); refresh(); return; 2197: 2198: case SCR_CW: /* Close Window */ 2199: clrtoeol(); move(23,0); clrtoeol(); move(22,0); clrtoeol(); 2200: refresh(); 2201: pct = 100; oldpct = 0; /* Reset these for next time. */ 2202: oldtyp = 0; oldwin = -1; oldtry = -1; oldlen = -1; 2203: 2204: #ifndef VMSCURSE 2205: endwin(); 2206: #endif /* VMSCURSE */ 2207: ft_win = 0; /* Flag that window is closed. */ 2208: cendw = 1; return; 2209: 2210: default: /* Bad call */ 2211: move (CW_ERR,22); 2212: printw("*** screen() called with bad function code ***"); 2213: clrtoeol(); refresh(); return; 2214: } 2215: } 2216: #endif /* CK_CURSES */ 2217: 2218: #endif /* MAC */