home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume16 / ecu3 / part20 < prev    next >
Encoding:
Internet Message Format  |  1991-01-06  |  44.3 KB

  1. From: wht@n4hgf.uucp (Warren Tucker)
  2. Newsgroups: comp.sources.misc
  3. Subject: v16i044:  ECU async comm package rev 3.0, Part20/35
  4. Message-ID: <1991Jan6.052424.28312@sparky.IMD.Sterling.COM>
  5. Date: 6 Jan 91 05:24:24 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Checksum-Snefru: 247f138b f6611abf a6bd94b9 d6f279cd
  8.  
  9. Submitted-by: wht@n4hgf.uucp (Warren Tucker)
  10. Posting-number: Volume 16, Issue 44
  11. Archive-name: ecu3/part20
  12.  
  13. ---- Cut Here and feed the following to sh ----
  14. #!/bin/sh
  15. # This is part 20 of ecu3
  16. if touch 2>&1 | fgrep 'amc' > /dev/null
  17.  then TOUCH=touch
  18.  else TOUCH=true
  19. fi
  20. # ============= z/ecusz.c ==============
  21. if test ! -d 'z'; then
  22.     echo 'x - creating directory z'
  23.     mkdir 'z'
  24. fi
  25. echo 'x - extracting z/ecusz.c (Text)'
  26. sed 's/^X//' << 'SHAR_EOF' > 'z/ecusz.c' &&
  27. Xchar *numeric_revision = "ecusz 3.04";
  28. X#define BUFFERED_WRITE
  29. X/*+-------------------------------------------------------------------------
  30. X    ecusz.c - X/Y/ZMODEM send program
  31. X  Derived from public domain source by Chuck Forsberg, Omen Technologies
  32. X  Adaptation for ecu 1989 wht@n4hgf.Mt-Park.GA.US
  33. X
  34. X    Usage:    ecusz [-X -Y -Z] [-12+abdefkLlNnquvwy] [-] file ...
  35. X        (Y) = Option applies to YMODEM only
  36. X        (Z) = Option applies to ZMODEM only
  37. X        a (ASCII) change NL to CR/LF
  38. X        b Binary file transfer override
  39. X        f send Full pathname (Y/Z)
  40. X        k Send 1024 byte packets (Y)
  41. X        L N Limit subpacket length to N bytes (Z)
  42. X        l N Limit frame length to N bytes (l>=L) (Z)
  43. X        n send file if source newer (Z)
  44. X        N send file if source newer or longer (Z)
  45. X        o Use 16 bit CRC instead of 32 bit CRC (Z)
  46. X        p Protect existing destination file (Z)
  47. X        r Resume/Recover interrupted file transfer (Z)
  48. X        q Quiet (no progress reports)
  49. X        u Unlink file after transmission
  50. X        w N Window is N bytes (Z)
  51. X        y Yes,overwrite existing file (Z)
  52. X        @file reads a list of filenames from 'file'
  53. X
  54. X  Defined functions:
  55. X    SIGALRM_handler()
  56. X    bye_bye(sig)
  57. X    cancel_transaction(sig)
  58. X    determine_transaction_time()
  59. X    flushline()
  60. X    get_file_list_name(namep)
  61. X    getinsync(flag)
  62. X    getnak()
  63. X    getzrxinit()
  64. X    log_packet_buffer(buf,len)
  65. X    main(argc,argv)
  66. X    onintr()
  67. X    purgeline()
  68. X    readline(n)
  69. X    readock(timeout,count)
  70. X    report_rcvr_cancelled(place_happened)
  71. X    report_rcvr_skipped()
  72. X    report_send_stats(filepos)
  73. X    report_send_transaction()
  74. X    rewind_file_list()
  75. X    saybibi()
  76. X    send_cancel(error)
  77. X    sendline(ch)
  78. X    sendzsinit()
  79. X    set_file_list(pathc,pathv)
  80. X    substr(s,t)
  81. X    usage()
  82. X    wcputsec(buf,sectnum,cseclen)
  83. X    wcs(oname)
  84. X    wcsend()
  85. X    wctx(flen)
  86. X    wctxpn(name)
  87. X    xbuf_build(buf,count)
  88. X    xsendline(ch)
  89. X    zbuf_build(buf,count)
  90. X    zsendfdata()
  91. X    zsendfile(buf,blen)
  92. X
  93. X--------------------------------------------------------------------------*/
  94. X/*+:EDITS:*/
  95. X/*:12-18-1990-21:26-wht@n4hgf-better output control */
  96. X/*:09-19-1990-19:36-wht@n4hgf-ecu_log_event now gets pid for log from caller */
  97. X/*:08-14-1990-20:40-wht@n4hgf-ecu3.00-flush old edit history */
  98. X
  99. X/*
  100. X  Error return conditions
  101. X    255:     usage
  102. X    254:     protocol failed (bad line conditions,brain dead remote)
  103. X    253:     could not open any files
  104. X    128-192: process terminated with signal==code-128 (64 signals allowed for)
  105. X             signal 0 == program logic error (see cancel_transaction)
  106. X    127:     127 or more files not transmitted (see ~/.ecu/log)
  107. X    1-126:   count of files not transmitted (see ~/.ecu/log)
  108. X    0:       file transfer completely successful
  109. X*/
  110. X
  111. Xchar *substr(),*getenv();
  112. X
  113. X#include <stdio.h>
  114. X#include <signal.h>
  115. X#include <setjmp.h>
  116. X#include <ctype.h>
  117. X#include <fcntl.h>
  118. X#include "zmodem.h"
  119. X#include "zlint.h"
  120. X
  121. Xextern char *sys_errlist[];
  122. Xextern unsigned short crctab[];    /* wht */
  123. Xextern unsigned long total_data_chars_xfered; /* zcurses.c */
  124. Xextern int errno;
  125. Xextern int show_window;
  126. Xextern int Rxtimeout;    /* Tenths of seconds to wait for something */
  127. Xextern char Rxhdr[4];    /* Received header */
  128. Xextern char Txhdr[4];    /* Transmitted header */
  129. Xextern int Txfcs32;        /* TURE means send binary frames with 32 bit FCS */
  130. Xextern long Rxpos;    /* Received file position */
  131. Xextern long Txpos;    /* Transmitted file position */
  132. Xextern char *frametypes[];
  133. Xextern char Attn[];        /* Attention string rx sends to tx on err */
  134. Xextern char s256[];
  135. X
  136. X#define RETRYMAX 10        /* non-zmodem retry count on block send */
  137. X#define VMIN_COUNT 2    /* must not exceed 255 */
  138. Xunsigned char vmin_count = VMIN_COUNT;
  139. Xint iofd = 0;        /* line io fd */
  140. X#ifdef BUFFERED_WRITE
  141. XFILE *iofp;
  142. X#endif
  143. X
  144. X
  145. X/*
  146. X * Attention string to be executed by receiver to interrupt streaming data
  147. X *  when an error is detected.  A pause (0336) may be needed before the
  148. X *  ^C (03) or after it.
  149. X */
  150. X#if defined(READCHECK)
  151. Xchar Myattn[] = { 0 };
  152. X#else
  153. X#if defined(M_SYS5)
  154. Xchar Myattn[] = { 03,0336,0 };
  155. X#else
  156. Xchar Myattn[] = { 0 };
  157. X#endif
  158. X#endif
  159. X
  160. XFILE *in;
  161. X
  162. Xchar *Cmdstr;        /* Pointer to the command string */
  163. Xchar *bottom_label = (char *)0;
  164. Xchar Crcflg;
  165. Xchar Lastrx;
  166. Xchar Lzconv;        /* Local ZMODEM file conversion request */
  167. Xchar Lzmanag;        /* Local ZMODEM file management request */
  168. Xchar Lztrans;
  169. Xchar Pathname[PATHLEN];
  170. Xchar curr_dir[256];
  171. Xchar s128[128];
  172. Xchar txbuf[1024];
  173. Xchar zconv;                /* ZMODEM file conversion request */
  174. Xchar zmanag;            /* ZMODEM file management request */
  175. Xchar ztrans;            /* ZMODEM file transport request */
  176. Xint Ascii=0;            /* Add CR's for brain damaged programs */
  177. Xint Cmdack1;            /* Rx ACKs command,then do it */
  178. Xint Cmdtries = 11;
  179. Xint Command = 0;        /* Send a command,then exit. */
  180. Xint Dontread;            /* Don't read the buffer,it's still there */
  181. Xint Dottoslash=0;        /* Change foo.bar.baz to foo/bar/baz */
  182. Xint Exitcode = 0;
  183. Xint Filcnt=0;            /* count of number of files opened */
  184. Xint FilesTotal;
  185. Xint Filesleft;
  186. Xint Fullname=0;            /* transmit full pathname */
  187. Xint Lastn;                /* Count of last buffer read or -1 */
  188. Xint Lfseen=0;
  189. Xint Noeofseen;
  190. Xint Nozmodem = 0;
  191. Xint Optiong;            /* no wait for block ACK's */
  192. Xint Quiet=0;            /* overrides logic that would otherwise set verbose */
  193. Xint Rxflags = 0;
  194. Xint SameZrposAgain=0;    /* How many times we've been ZRPOS'd same place (wht) */
  195. Xint Tframlen = 0;        /* Override for tx frame length */
  196. Xint Totsecs;            /* total number of blocks this file */
  197. Xint Twostop = 0;        /* use two stop bits */
  198. Xint Unlinkafter=0;        /* Unlink file after it is sent */
  199. Xint Wantfcs32 = TRUE;    /* want to send 32 bit FCS */
  200. Xint Xmodem=0;            /* XMODEM Protocol - don't send pathnames */
  201. Xint Zctlesc;            /* Encode control characters */
  202. Xint Zmodem=0;            /* ZMODEM protocol requested by receiver */
  203. Xint Zrwindow = 1400;    /* RX window size (controls garbage count) */
  204. Xint blklen=128;            /* length of transmitted records */
  205. Xint blklen_original;
  206. Xint blkopt=0;            /* Override value for zmodem blklen */
  207. Xint ecusz_flag = 1;
  208. Xint force_no_curses = 0;
  209. Xint skip_count = 0;        /* skipped files */
  210. Xint errors;
  211. Xint firstsec;
  212. Xint log_packets = 0;
  213. Xint no_files = 0;
  214. Xint npats = 0;
  215. Xlong Lastread;        /* Beginning offset of last buffer read */
  216. Xlong Lastsync;        /* Last offset to which we got a ZRPOS */
  217. Xlong Lrxpos;            /* Receiver's last reported offset */
  218. Xlong TotalLeft;
  219. Xlong TotalToSend;
  220. Xlong bytcnt;
  221. Xlong rx_char_count = 0L;
  222. Xlong this_file_length;
  223. Xlong tx_char_count = 0L;
  224. Xunsigned Baudrate;
  225. Xunsigned Rxbuflen = 16384;    /* Receiver's max buffer length */
  226. Xunsigned Txwcnt;        /* Counter used to space ack requests */
  227. Xunsigned Txwindow;        /* Control the size of the transmitted window */
  228. Xunsigned Txwspac;        /* Spacing between zcrcq requests */
  229. Xunsigned int bad_condx_blklen = 0;    /* if <>0,blklen has been reduced (wht) */
  230. Xunsigned int bad_condx_frame_count = 0;    /* frame # last SameZrposAgain (wht) */
  231. Xunsigned int this_file_frame_count;    /* count of frames sent this file (wht) */
  232. X
  233. X#define MAX_PATHS 512
  234. Xchar *paths[MAX_PATHS];
  235. X
  236. Xjmp_buf tohere;        /* For the interrupt on RX timeout */
  237. Xjmp_buf intrjmp;    /* For the interrupt on RX CAN */
  238. X
  239. Xint file_list_pathc;
  240. Xint file_list_path_current;
  241. Xchar **file_list_pathv;
  242. Xint required_type = 0;
  243. XFILE *fpflst = (FILE *)0;
  244. X
  245. X/*+-------------------------------------------------------------------------
  246. X    log_packet_buffer(buf,len)
  247. X--------------------------------------------------------------------------*/
  248. Xvoid
  249. Xlog_packet_buffer(buf,len)
  250. Xregister unsigned char *buf;
  251. Xregister int len;
  252. X{
  253. Xchar xbuf[32];
  254. X
  255. X    while(len--)
  256. X    {
  257. X        sprintf(xbuf,"%02x ",*buf++);
  258. X        write(log_packets,xbuf,strlen(xbuf));
  259. X    }
  260. X    write(log_packets,"\n",1);
  261. X
  262. X}    /* end of log_packet_buffer */
  263. X
  264. X/*+-------------------------------------------------------------------------
  265. X    rewind_file_list()
  266. X--------------------------------------------------------------------------*/
  267. Xvoid
  268. Xrewind_file_list()
  269. X{
  270. X    file_list_path_current = 0;
  271. X    if(fpflst)
  272. X    {
  273. X        fclose(fpflst);
  274. X        fpflst = (FILE *)0;
  275. X    }
  276. X}    /* end of rewind_file_list */
  277. X
  278. X/*+-------------------------------------------------------------------------
  279. X    set_file_list(pathc,pathv)
  280. X--------------------------------------------------------------------------*/
  281. Xvoid
  282. Xset_file_list(pathc,pathv)
  283. Xint pathc;
  284. Xchar **pathv;
  285. X{
  286. X
  287. X    file_list_pathc = pathc;
  288. X    file_list_pathv = pathv;
  289. X    rewind_file_list();
  290. X}    /* end of set_file_list */
  291. X
  292. X/*+-------------------------------------------------------------------------
  293. X    get_file_list_name(namep)
  294. X--------------------------------------------------------------------------*/
  295. Xget_file_list_name(namep)
  296. Xchar **namep;
  297. X{
  298. Xregister char *cptr;
  299. Xstatic char name[256];
  300. X
  301. Xtry_fpflst:
  302. X    if(fpflst)
  303. X    {
  304. X        if(fgets(name,sizeof(name),fpflst) != NULL)
  305. X        {
  306. X            name[strlen(name) - 1] = 0;
  307. X            *namep = name;
  308. X            return(1);
  309. X        }
  310. X        fclose(fpflst);
  311. X        fpflst = (FILE *)0;
  312. X    }
  313. X
  314. Xnext_arg:
  315. X    if(file_list_path_current == file_list_pathc)
  316. X        return(0);
  317. X    cptr = file_list_pathv[file_list_path_current++];
  318. X    if(*cptr != '@')
  319. X    {
  320. X        *namep = cptr;
  321. X        return(1);
  322. X    }
  323. X    cptr++;
  324. X    if((fpflst = fopen(cptr,"r")) == NULL)
  325. X        goto next_arg;
  326. X    goto try_fpflst;
  327. X
  328. X}    /* end of get_file_list_name */
  329. X
  330. X/*+-------------------------------------------------------------------------
  331. X    bye_bye(sig)
  332. X--------------------------------------------------------------------------*/
  333. Xvoid
  334. Xbye_bye(sig)
  335. Xint sig;
  336. X{
  337. X    exit(sig+128);
  338. X}    /* end of bye_bye */
  339. X
  340. X/*+-------------------------------------------------------------------------
  341. X    cancel_transaction(sig)
  342. Xcalled by signal interrupt or terminate to clean things up
  343. X--------------------------------------------------------------------------*/
  344. Xvoid
  345. Xcancel_transaction(sig)
  346. X{
  347. X    if(Zmodem)
  348. X        zmputs(Attn);
  349. X    send_cancel(1);
  350. X    mode(0);
  351. X    if(sig >= 0)
  352. X    {
  353. X        sprintf(s128,"ecusz aborted (signal %d)",sig);
  354. X        report_str(s128,0);
  355. X    }
  356. X    report_tx_ind(0);
  357. X    report_rx_ind(0);
  358. X    report_uninit(0);
  359. X    bye_bye(sig);
  360. X}    /* end of cancel_transaction */
  361. X
  362. X/* Called when ZMODEM gets an interrupt (^X) */
  363. Xonintr()
  364. X{
  365. X    signal(SIGINT,SIG_IGN);
  366. X#if defined(M_SYS5)
  367. X    report_rx_ind(0);
  368. X    report_tx_ind(0);
  369. X#endif
  370. X    longjmp(intrjmp,-1);
  371. X}
  372. X
  373. X
  374. X/*+-------------------------------------------------------------------------
  375. X    report_send_transaction()
  376. X--------------------------------------------------------------------------*/
  377. Xvoid
  378. Xreport_send_transaction()
  379. X{
  380. X    if(Xmodem)
  381. X    {
  382. X        long blocks = (TotalToSend >> 7) + ((TotalToSend % 128) != 0);
  383. X        long secs = 7        /* slightly worse than average first nak delay */
  384. X            + (blocks / 5L)                /* assume .2 sec ack time */
  385. X            + ((blocks * (128L + 16L)) / (Baudrate / 10));
  386. X        if(!secs)
  387. X            secs = 10L;
  388. X        sprintf(s128,"Sending %ld blocks time ~= %ld:%02ld",
  389. X            blocks,secs/60,secs % 60);
  390. X    }
  391. X    else
  392. X    {
  393. X        long min_100 =
  394. X            (FilesTotal * 2L) + (((TotalToSend * 11L)) * 10L) / (Baudrate * 6L);
  395. X        if(!min_100)
  396. X            min_100 = 4L;
  397. X#if defined(M_I286)    /* slower */
  398. X        else if(Baudrate > 4800)
  399. X        {
  400. X            min_100 *= 13;
  401. X            min_100 /= 9;    /* yech ... empirical */
  402. X        }
  403. X#endif
  404. X        sprintf(s128,
  405. X            "Total transaction %ld bytes (xfer time ~= %2lu:%02lu)",
  406. X            TotalToSend,min_100 / 100,((min_100 % 100) * 60L) / 100L);
  407. X    }
  408. X    report_transaction(s128);
  409. X
  410. X}    /* end of report_send_transaction */
  411. X
  412. X/*+-------------------------------------------------------------------------
  413. X    report_send_stats(filepos)
  414. X--------------------------------------------------------------------------*/
  415. Xvoid
  416. Xreport_send_stats(filepos)
  417. Xlong filepos;
  418. X{
  419. X
  420. X    if(Xmodem)
  421. X        sprintf(s128,"File %d%% complete",
  422. X            (this_file_length == 0) ? (int)100 :
  423. X            (int)((filepos * 100L) / this_file_length));
  424. X    else
  425. X        sprintf(s128,"This file %d%%, transaction %d%% complete",
  426. X            (this_file_length == 0) ? (int)100 :
  427. X                    (int)((filepos * 100L)/this_file_length),
  428. X            (TotalToSend == 0) ? (int)100 :
  429. X                    (int)(((total_data_chars_xfered + filepos) * 100L)
  430. X                        / TotalToSend));
  431. X    report_str(s128,0);
  432. X    report_txpos(filepos);
  433. X
  434. X}    /* end of report_send_stats */
  435. X
  436. X/*+-------------------------------------------------------------------------
  437. X    report_rcvr_cancelled(place_happened)
  438. X--------------------------------------------------------------------------*/
  439. Xvoid
  440. Xreport_rcvr_cancelled(place_happened)
  441. Xchar *place_happened;
  442. X{
  443. X    strcpy(s128,"SEND CANCELLED");
  444. X    report_str(s128 + 5,1);
  445. X#if defined(LOG_XFER)
  446. X    strcat(s128," (");
  447. X    strcat(s128,place_happened);
  448. X    strcat(s128,")");
  449. X    ecu_log_event(getppid(),s128);
  450. X#endif
  451. X    skip_count++;
  452. X    report_error_count();
  453. X}    /* end of report_rcvr_cancelled */
  454. X
  455. X/*+-------------------------------------------------------------------------
  456. X    report_rcvr_skipped()
  457. X--------------------------------------------------------------------------*/
  458. Xvoid
  459. Xreport_rcvr_skipped()
  460. X{
  461. X    sprintf(s128,"SEND skipped: %s",Pathname);
  462. X    report_str(s128 + 5,-1);
  463. X#if defined(LOG_SKIP)
  464. X    ecu_log_event(getppid(),s128);
  465. X#endif
  466. X    skip_count++;
  467. X    report_error_count();
  468. X    TotalToSend -= this_file_length;
  469. X    report_send_transaction();
  470. X}    /* end of report_rcvr_skipped */
  471. X
  472. X
  473. X/*+-------------------------------------------------------------------------
  474. X    xsendline(ch)
  475. X--------------------------------------------------------------------------*/
  476. Xxsendline(ch)
  477. Xchar ch;
  478. X{
  479. X#ifdef BUFFERED_WRITE
  480. X    fputc(ch,iofp);
  481. X#else
  482. X    write(iofd,&ch,1);
  483. X#endif
  484. X    ++tx_char_count;
  485. X}    /* end of xsendline */
  486. X
  487. X/*+-------------------------------------------------------------------------
  488. X    sendline(ch)
  489. X--------------------------------------------------------------------------*/
  490. Xsendline(ch)
  491. Xchar ch;
  492. X{
  493. X    xsendline(ch);
  494. X}    /* end of sendline */
  495. X
  496. Xflushline()
  497. X{
  498. X#ifdef BUFFERED_WRITE
  499. X    fflush(iofp);
  500. X#endif
  501. X}
  502. X
  503. Xmain(argc,argv)
  504. Xchar *argv[];
  505. X{
  506. Xregister char *cp;
  507. Xlong min_100;
  508. Xchar **patts = paths;
  509. Xchar **gargv = argv;
  510. Xint gargc = argc;
  511. X
  512. X    signal(SIGINT,bye_bye);
  513. X    signal(SIGTERM,bye_bye);
  514. X
  515. X    get_curr_dir(curr_dir,sizeof(curr_dir));
  516. X
  517. X    Rxtimeout = 600;
  518. X    npats=0;
  519. X    if(argc<2)
  520. X        usage();
  521. X    while(--argc)
  522. X    {
  523. X        cp = *++argv;
  524. X        if(*cp == '-')
  525. X        {
  526. X            cp++;
  527. X            switch(*cp++)
  528. X            {
  529. X            case 'X':
  530. X                required_type = 1;
  531. X                Xmodem = TRUE;
  532. X                break;
  533. X            case 'Y':
  534. X                required_type = 1;
  535. X                Nozmodem = TRUE;
  536. X                blklen=1024;
  537. X                break;
  538. X            case 'Z':
  539. X                show_window = 1;
  540. X                required_type = 1;
  541. X                break;
  542. X
  543. X            case '+':
  544. X                Lzmanag = ZMAPND;
  545. X                break;
  546. X            case 'a':
  547. X                Lzconv = ZCNL;
  548. X                Ascii = TRUE;
  549. X                break;
  550. X            case 'b':
  551. X                Lzconv = ZCBIN;
  552. X                break;
  553. X            case 'd':
  554. X                ++Dottoslash;
  555. X                /* **** FALL THROUGH TO **** */
  556. X            case 'f':
  557. X                Fullname=TRUE;
  558. X                break;
  559. X            case ',':
  560. X                log_packets = 1;
  561. X                break;
  562. X            case '@':
  563. X                force_no_curses = 1;
  564. X                break;
  565. X            case '/':
  566. X                if(--argc < 1)
  567. X                    usage();
  568. X                strcpy(curr_dir,*++argv);
  569. X                break;
  570. X            case '.':
  571. X                if(--argc < 1)
  572. X                    usage();
  573. X                iofd = atoi(*++argv);
  574. X                break;
  575. X            case 'C':
  576. X                if(--argc < 1)
  577. X                    usage("no label after -C");
  578. X                bottom_label = *++argv;
  579. X                break;
  580. X            case 'e':
  581. X                Zctlesc = 1;
  582. X                break;
  583. X            case 'k':
  584. X                blklen=1024;
  585. X                break;
  586. X            case 'L':
  587. X                if(--argc < 1)
  588. X                {
  589. X                    usage();
  590. X                }
  591. X                blkopt = atoi(*++argv);
  592. X                if(blkopt<24 || blkopt>1024)
  593. X                        usage();
  594. X                break;
  595. X            case 'l':
  596. X                if(--argc < 1)
  597. X                {
  598. X                    usage();
  599. X                }
  600. X                Tframlen = atoi(*++argv);
  601. X                if(Tframlen<32 || Tframlen>1024)
  602. X                    usage();
  603. X                break;
  604. X            case 'N':
  605. X                Lzmanag = ZMNEWL;
  606. X                break;
  607. X            case 'n':
  608. X                Lzmanag = ZMNEW;
  609. X                break;
  610. X            case 'o':
  611. X                Wantfcs32 = FALSE;
  612. X                break;
  613. X            case 'p':
  614. X                    Lzmanag = ZMPROT;
  615. X                    break;
  616. X            case 'r':
  617. X                Lzconv = ZCRESUM;
  618. X            case 't':
  619. X                if(--argc < 1)
  620. X                {
  621. X                    usage();
  622. X                }
  623. X                Rxtimeout = atoi(*++argv);
  624. X                if(Rxtimeout<10 || Rxtimeout>1000)
  625. X                    usage();
  626. X                break;
  627. X            case 'u':
  628. X                ++Unlinkafter;
  629. X                break;
  630. X            case 'w':
  631. X                if(--argc < 1)
  632. X                {
  633. X                    usage();
  634. X                }
  635. X                Txwindow = atoi(*++argv);
  636. X                if(Txwindow < 256)
  637. X                    Txwindow = 256;
  638. X                Txwindow = (Txwindow/64) * 64;
  639. X                Txwspac = Txwindow/4;
  640. X                if(blkopt > Txwspac || (!blkopt && Txwspac < 1024))
  641. X                    blkopt = Txwspac;
  642. X                break;
  643. X            case 'y':
  644. X                Lzmanag = ZMCLOB;
  645. X                break;
  646. X            default:
  647. X                usage();
  648. X            }
  649. X        }
  650. X        else if(argc > 0)
  651. X        {
  652. X            if(npats < MAX_PATHS)
  653. X            {
  654. X                npats++;
  655. X                *patts++ = cp;
  656. X            }
  657. X            else
  658. X            {
  659. X                printf("too many filenames to send\n");
  660. X                exit(255);
  661. X            }
  662. X        }
  663. X    }
  664. X    if(!required_type || !iofd)
  665. X    {
  666. X        printf("can only be run by ecu\n");
  667. X        exit(255);
  668. X    }
  669. X
  670. X    if(determine_output_mode())
  671. X    {
  672. X        setbuf(stdout,NULL);
  673. X        setbuf(stderr,NULL);
  674. X    }
  675. X
  676. X    if(npats < 1 && !Command)
  677. X        usage();
  678. X
  679. X    set_file_list(npats,paths);
  680. X    sprintf(s128,"%s",numeric_revision);
  681. X
  682. X    if(log_packets)
  683. X    {
  684. X    char log_packets_name[64];
  685. X    FILE *ftmp;
  686. X    int iargv;
  687. X        sprintf(log_packets_name,"/tmp/sz%05d.plog",getpid());
  688. X        unlink(log_packets_name);
  689. X        ftmp = fopen(log_packets_name,"w");
  690. X        fclose(ftmp);
  691. X        log_packets = open(log_packets_name,O_WRONLY,0644);
  692. X        if(log_packets < 0)
  693. X            log_packets = 0;
  694. X        else
  695. X        {
  696. X            write(log_packets,"exec: ",6);
  697. X            for(iargv = 0; iargv < gargc; iargv++)
  698. X            {
  699. X                write(log_packets,gargv[iargv],strlen(gargv[iargv]));
  700. X                write(log_packets," ",1);
  701. X            }
  702. X            write(log_packets,"\n",1);
  703. X        }
  704. X    }
  705. X
  706. X    report_init(s128);
  707. X    mode(1);
  708. X
  709. X    if(signal(SIGINT,cancel_transaction) == SIG_IGN)
  710. X        signal(SIGINT,SIG_IGN);
  711. X    else
  712. X        signal(SIGINT,cancel_transaction);
  713. X    signal(SIGTERM,cancel_transaction);
  714. X
  715. X    report_str("calculating transaction time",-1);
  716. X    determine_transaction_time();
  717. X#ifdef BUFFERED_WRITE
  718. X    iofp = fdopen(iofd,"w");
  719. X#endif
  720. X    if(!Xmodem)
  721. X    {
  722. X        TotalToSend = TotalLeft;
  723. X        report_send_transaction();
  724. X        report_str("starting remote receiver",-1);
  725. X        report_last_txhdr("begin transfer",0);
  726. X        if(!Nozmodem)
  727. X            write(iofd,"rz\r",3);
  728. X        else    /* wht -- why not? */
  729. X            write(iofd,"rb\r",3);        /* wht */
  730. X        nap(2000L);
  731. X        report_str("",-1);
  732. X        if(!Nozmodem)
  733. X        {
  734. X            stohdr(0L);
  735. X            zshhdr(ZRQINIT,Txhdr);
  736. X        }
  737. X    }
  738. X    else
  739. X    {
  740. X        report_str("",-1);
  741. X        report_last_txhdr("begin transfer",0);
  742. X    }
  743. X
  744. X    if(wcsend()==ERROR)
  745. X    {
  746. X        Exitcode=254;        /*wht was 0200 */
  747. X        send_cancel(1);
  748. X    }
  749. X    mode(0);
  750. X    report_uninit(0);
  751. X    if(no_files)
  752. X        Exitcode = 253;
  753. X    exit(Exitcode ? Exitcode : (skip_count > 127) ? 127 : skip_count);
  754. X    /*NOTREACHED*/
  755. X}
  756. X
  757. X/*+-------------------------------------------------------------------------
  758. X    wcsend(argc,argp) -- send group of files
  759. X--------------------------------------------------------------------------*/
  760. Xwcsend()
  761. X{
  762. X    register n;
  763. X    char *name;
  764. X
  765. X    Crcflg=FALSE;
  766. X    firstsec=TRUE;
  767. X    bytcnt = -1;
  768. X    rewind_file_list();
  769. X    while(get_file_list_name(&name))
  770. X    {
  771. X        Totsecs = 0;
  772. X        if(wcs(name)==ERROR)
  773. X            return(ERROR);
  774. X    }
  775. X    Totsecs = 0;
  776. X    if(Filcnt==0)
  777. X    {    /* bitch if we couldn't open ANY files */
  778. X        send_cancel(1);
  779. X        strcpy(s128,"SEND cannot open any requested files");
  780. X        report_str(s128 + 5,1);
  781. X#if defined(LOG_XFER)
  782. X        ecu_log_event(getppid(),s128);
  783. X#endif
  784. X        sleep(2);        /* allow time for other rz to get ready */
  785. X        no_files = 1;
  786. X        return(ERROR);    /* ... then cancel */
  787. X    }
  788. X    if(Zmodem)
  789. X        saybibi();
  790. X    else if(!Xmodem)
  791. X        wctxpn("");
  792. X    return(OK);
  793. X}
  794. X
  795. X/*+-------------------------------------------------------------------------
  796. X    wcs(oname) -- send a file
  797. X--------------------------------------------------------------------------*/
  798. Xwcs(oname)
  799. Xchar *oname;
  800. X{
  801. Xregister c;
  802. Xregister char *p;
  803. Xstruct stat f;
  804. X
  805. X    strcpy(Pathname,oname);    /* global copy of name */
  806. X
  807. X    if((in=fopen(oname,"r"))==NULL)
  808. X    {
  809. X        sprintf(s128,"SEND %s: %s",sys_errlist[errno],oname);
  810. X#if defined(LOG_XFER)
  811. X        ecu_log_event(getppid(),s128);
  812. X#endif
  813. X        report_str(s128 + 5,1);
  814. X        skip_count++;
  815. X        report_error_count();
  816. X        return(OK);    /* pass over it,there may be others */
  817. X    }
  818. X    ++Noeofseen;
  819. X    Lastread = 0;
  820. X    Lastn = -1;
  821. X    Dontread = FALSE;
  822. X    /* Check for directory or block special files */
  823. X    fstat(fileno(in),&f);
  824. X    c = f.st_mode & S_IFMT;
  825. X    if(c == S_IFDIR || c == S_IFBLK)
  826. X    {
  827. X        sprintf(s128,"SEND %s: %s",
  828. X            (c == S_IFDIR) ? "directory" : "block device",oname);
  829. X        report_str(s128 + 5,1);
  830. X#if defined(LOG_SKIP)
  831. X        ecu_log_event(getppid(),s128);
  832. X#endif
  833. X        skip_count++;
  834. X        report_error_count();
  835. X        fclose(in);
  836. X        return(OK);
  837. X    }
  838. X    f.st_mode &= ~(S_ISUID | S_ISGID);
  839. X    Filcnt++;
  840. X    report_file_send_open(oname,&f);
  841. X    this_file_length = f.st_size;
  842. X    report_send_stats(0L);
  843. X    switch(wctxpn(Pathname))
  844. X    {
  845. X    case ERROR:
  846. X        sprintf(s128,"SEND protocol failure: %s",oname);
  847. X        report_str(s128 + 5,1);
  848. X#if defined(LOG_XFER)
  849. X        ecu_log_event(getppid(),s128);
  850. X#endif
  851. X        skip_count++;
  852. X        report_error_count();
  853. X        report_file_close();
  854. X        fclose(in);
  855. X        return(ERROR);
  856. X    case ZSKIP:
  857. X        report_rcvr_skipped();
  858. X        return(OK);
  859. X    }
  860. X    if(!Zmodem && wctx(f.st_size)==ERROR)
  861. X        return(ERROR);
  862. X    if(Unlinkafter)
  863. X        unlink(oname);
  864. X    return(0);
  865. X}
  866. X
  867. X/*
  868. X * generate and transmit pathname block consisting of
  869. X *  pathname (null terminated),
  870. X *  file length,mode time and file mode in octal
  871. X *  as provided by the Unix fstat call.
  872. X *  N.B.: modifies the passed name,may extend it!
  873. X */
  874. Xwctxpn(name)
  875. Xchar *name;
  876. X{
  877. X    register char *p,*q;
  878. X    char name2[PATHLEN];
  879. X    struct stat f;
  880. X
  881. X    if(Xmodem)
  882. X    {
  883. X        if((in!=stdin) && *name && fstat(fileno(in),&f)!= -1)
  884. X        {
  885. X            TotalToSend = f.st_size;
  886. X            report_protocol_type("XMODEM");
  887. X            report_send_transaction();
  888. X            report_xfer_mode((Ascii) ? "ASCII" : "BINARY");
  889. X            report_last_txhdr("Waiting on NAK",0);
  890. X        }
  891. X        return(OK);
  892. X    }
  893. X    if(!Zmodem)
  894. X    {
  895. X        report_last_txhdr("START PENDING",0);
  896. X        if(getnak())
  897. X        {
  898. X            report_str("Timeout on pathname nak",1);
  899. X            return(ERROR);
  900. X        }
  901. X    }
  902. X
  903. X    q = (char *) 0;
  904. X    if(Dottoslash)
  905. X    {        /* change . to . */
  906. X        for(p=name; *p; ++p)
  907. X        {
  908. X            if(*p == '/')
  909. X                q = p;
  910. X            else if(*p == '.')
  911. X                *(q=p) = '/';
  912. X        }
  913. X        if(q && strlen(++q) > 8)
  914. X        {    /* If name>8 chars */
  915. X            q += 8;            /*   make it .ext */
  916. X            strcpy(name2,q);    /* save excess of name */
  917. X            *q = '.';
  918. X            strcpy(++q,name2);    /* add it back */
  919. X        }
  920. X    }
  921. X
  922. X    for(p=name,q=txbuf ; *p; )
  923. X        if((*q++ = *p++) == '/' && !Fullname)
  924. X            q = txbuf;
  925. X    *q++ = 0;
  926. X    p=q;
  927. X    while(q < (txbuf + 1024))
  928. X        *q++ = 0;
  929. X    if(!Ascii && (in != stdin) && *name && !fstat(fileno(in),&f))
  930. X        sprintf(p,"%lu %lo %o 0 %d %ld",f.st_size,f.st_mtime,
  931. X            f.st_mode &= ~(S_ISUID | S_ISGID),
  932. X            Filesleft,TotalLeft);
  933. X    report_xfer_mode((Lzconv == ZCNL) ? "ASCII" : "BINARY");
  934. X    TotalLeft -= f.st_size;
  935. X    if(--Filesleft <= 0)
  936. X        TotalLeft = 0;
  937. X    if(TotalLeft < 0)
  938. X        TotalLeft = 0;
  939. X
  940. X    /* force 1k blocks if name won't fit in 128 byte block */
  941. X    if(txbuf[125])
  942. X        blklen=1024;
  943. X    else
  944. X    {        /* A little goodie for IMP/KMD */
  945. X        txbuf[127] = (f.st_size + 127) >>7;
  946. X        txbuf[126] = (f.st_size + 127) >>15;
  947. X    }
  948. X    if(Zmodem)
  949. X        return(zsendfile(txbuf,1+strlen(p)+(p-txbuf)));
  950. X    report_protocol_type("YMODEM");
  951. X    if(wcputsec(txbuf,0,128)==ERROR)
  952. X        return(ERROR);
  953. X    return(OK);
  954. X}
  955. X
  956. Xgetnak()
  957. X{
  958. X    register firstch;
  959. X
  960. X    Lastrx = 0;
  961. X    for(;;)
  962. X    {
  963. X        switch(firstch = readock(50,1))        /* 50 was 800 (80 secs!!) wht */
  964. X        {
  965. X        case ZPAD:
  966. X            if(getzrxinit())
  967. X                return(ERROR);
  968. X            Ascii = 0;    /* Receiver does the conversion */
  969. X            return(FALSE);
  970. X        case TIMEOUT:
  971. X            report_str("Timeout",1);
  972. X            return(TRUE);
  973. X        case WANTG:
  974. X#if defined(MODE2OK)
  975. X            mode(2);    /* Set cbreak,XON/XOFF,etc. */
  976. X#endif
  977. X            Optiong = TRUE;
  978. X            blklen=1024;
  979. X        case WANTCRC:
  980. X            Crcflg = TRUE;
  981. X        case NAK:
  982. X            return(FALSE);
  983. X        case CAN:
  984. X            if((firstch = readock(20,1)) == CAN && Lastrx == CAN)
  985. X                return(TRUE);
  986. X        default:
  987. X            break;
  988. X        }
  989. X        Lastrx = firstch;
  990. X    }
  991. X}
  992. X
  993. X/*+-------------------------------------------------------------------------
  994. X    wctx(flen)
  995. X--------------------------------------------------------------------------*/
  996. Xwctx(flen)
  997. Xlong flen;
  998. X{
  999. Xregister int thisblklen;
  1000. Xregister int firstch;
  1001. Xregister int sectnum;
  1002. Xregister int attempts;
  1003. Xlong charssent;
  1004. X
  1005. X    charssent = 0;
  1006. X    firstsec=TRUE;
  1007. X    thisblklen = blklen;
  1008. X    report_txblklen(blklen);
  1009. X
  1010. X    attempts = 8;
  1011. X    while(((firstch = readock(Rxtimeout,2)) != NAK) &&
  1012. X        (firstch  !=  WANTCRC) && (firstch  !=  WANTG) &&
  1013. X        (firstch != TIMEOUT) && (firstch != CAN))
  1014. X    {
  1015. X        if(!--attempts)
  1016. X        {
  1017. X            report_str("bad start stimulus",1);
  1018. X            send_cancel(1);
  1019. X            return(ERROR);
  1020. X        }
  1021. X    }
  1022. X
  1023. X    if(firstch==CAN)
  1024. X    {
  1025. X        report_str("receiver CAN",1);
  1026. X        return(ERROR);
  1027. X    }
  1028. X
  1029. X    if((firstch==WANTCRC) || (firstch==WANTG))
  1030. X        Crcflg=TRUE;
  1031. X
  1032. X    report_protocol_crc_type((Crcflg)
  1033. X            ? ((firstch== WANTG) ? "/CRC-g" : "/CRC")
  1034. X            : "/CHK");
  1035. X
  1036. X    sectnum=0;
  1037. X    for(;;)
  1038. X    {
  1039. X        if(flen <= (charssent + 896L))
  1040. X        {
  1041. X            thisblklen = 128;
  1042. X            report_txblklen(thisblklen);
  1043. X        }
  1044. X        if(!xbuf_build(txbuf,thisblklen))
  1045. X            break;
  1046. X        if(wcputsec(txbuf,++sectnum,thisblklen)==ERROR)
  1047. X            return(ERROR);
  1048. X        charssent += thisblklen;
  1049. X    }
  1050. X
  1051. X    /* file transfer completed */
  1052. X    report_file_byte_io(this_file_length);
  1053. X    report_file_close();
  1054. X    fclose(in);
  1055. X
  1056. X#if defined(LOG_XFER)
  1057. X    sprintf(s256,"SEND success: %s",Pathname);
  1058. X    ecu_log_event(getppid(),s256);
  1059. X#endif
  1060. X
  1061. X    attempts=0;
  1062. X    do
  1063. X    {
  1064. X        purgeline();
  1065. X        sendline(EOT);
  1066. X        flushline();
  1067. X        report_last_txhdr("EOT",0);
  1068. X        ++attempts;
  1069. X    }    while((firstch=(readock(Rxtimeout,1)) != ACK) && attempts < RETRYMAX);
  1070. X    if(attempts == RETRYMAX)
  1071. X    {
  1072. X        report_str("No ACK on EOT",1);
  1073. X        return(ERROR);
  1074. X    }
  1075. X    else
  1076. X        return(OK);
  1077. X}
  1078. X
  1079. Xwcputsec(buf,sectnum,cseclen)
  1080. Xchar *buf;
  1081. Xint sectnum;
  1082. Xint cseclen;    /* data length of this block to send */
  1083. X{
  1084. X    register int checksum;
  1085. X    register int wcj;
  1086. X    register unsigned char *cp;
  1087. X    unsigned short oldcrc;
  1088. X    int firstch;
  1089. X    int attempts;
  1090. X
  1091. X    firstch=0;    /* part of logic to detect CAN CAN */
  1092. X
  1093. X    sprintf(s128,"Sending block %d",sectnum);
  1094. X    report_last_txhdr(s128,0);
  1095. X    if(log_packets)
  1096. X    {
  1097. X        log_packet_buffer(buf,cseclen);
  1098. X    }
  1099. X
  1100. X    for(attempts=0; attempts <= RETRYMAX; attempts++)
  1101. X    {
  1102. X        Lastrx= firstch;
  1103. X        sendline(cseclen == 1024 ? STX : SOH);
  1104. X        sendline(sectnum);
  1105. X        sendline(-sectnum - 1);
  1106. X        oldcrc=checksum=0;
  1107. X
  1108. X        for(wcj = cseclen,cp = buf; --wcj >= 0; )
  1109. X        {
  1110. X            sendline(*cp);
  1111. X            oldcrc=updcrc(*cp,oldcrc);
  1112. X            checksum += *cp++;
  1113. X        }
  1114. X        if(Crcflg)
  1115. X        {
  1116. X            oldcrc=updcrc(0,updcrc(0,oldcrc));
  1117. X            sendline((int)(oldcrc >> 8));
  1118. X            sendline((int)(oldcrc & 0xFF));
  1119. X        }
  1120. X        else
  1121. X            sendline(checksum);
  1122. X        flushline();
  1123. X
  1124. X        if(Optiong)
  1125. X        {
  1126. X            firstsec = FALSE;
  1127. X            return(OK);
  1128. X        }
  1129. X        firstch = readock(Rxtimeout,(Noeofseen&§num) ? 2:1);
  1130. Xgotnak:
  1131. X        switch(firstch)
  1132. X        {
  1133. X        case CAN:
  1134. X            if(Lastrx == CAN)
  1135. X            {
  1136. Xcancan:
  1137. X                report_last_rxhdr("CAN",1);
  1138. X                return(ERROR);
  1139. X            }
  1140. X            break;
  1141. X        case TIMEOUT:
  1142. X            report_last_rxhdr("Timeout",1);
  1143. X            continue;
  1144. X        case WANTCRC:
  1145. X            if(firstsec)
  1146. X                Crcflg = TRUE;
  1147. X        case NAK:
  1148. X            report_last_rxhdr("NAK",1);
  1149. X            continue;
  1150. X        case ACK:
  1151. X            report_last_rxhdr("ACK",0);
  1152. X            firstsec=FALSE;
  1153. X            Totsecs += (cseclen>>7);
  1154. X            return(OK);
  1155. X        case ERROR:
  1156. X            report_last_rxhdr("Noise",0);
  1157. X            break;
  1158. X        default:
  1159. X            sprintf(s128,"0x%02x ???",firstch);
  1160. X            report_last_rxhdr(s128,1);
  1161. X            break;
  1162. X        }
  1163. X        for(;;)
  1164. X        {
  1165. X            Lastrx = firstch;
  1166. X            if((firstch = readock(Rxtimeout,2)) == TIMEOUT)
  1167. X                break;
  1168. X            if(firstch == NAK || firstch == WANTCRC)
  1169. X                goto gotnak;
  1170. X            if(firstch == CAN && Lastrx == CAN)
  1171. X                goto cancan;
  1172. X        }
  1173. X    }
  1174. X    report_str("retry count exceeded",1);
  1175. X    return(ERROR);
  1176. X}
  1177. X
  1178. X/* fill buf with count chars padding with ^Z for CPM */
  1179. Xxbuf_build(buf,count)
  1180. Xregister char *buf;
  1181. X{
  1182. Xregister c,m;
  1183. Xlong lseek();
  1184. Xlong X_txpos = lseek(fileno(in),0L,1);
  1185. Xchar diag_str[64];
  1186. X
  1187. X    report_send_stats(X_txpos);
  1188. X    if( !Ascii)
  1189. X    {
  1190. X        m = read(fileno(in),buf,count);
  1191. X        if(log_packets)
  1192. X        {
  1193. X            sprintf(diag_str,"read rtnd %d of %d",m,count);
  1194. X            report_str(diag_str,1);
  1195. X        }
  1196. X        if(m <= 0)
  1197. X            return(0);
  1198. X        while(m < count)
  1199. X            buf[m++] = 032;
  1200. X        return(count);
  1201. X    }
  1202. X    m=count;
  1203. X    if(Lfseen)
  1204. X    {
  1205. X        *buf++ = 012;
  1206. X        --m;
  1207. X        Lfseen = 0;
  1208. X    }
  1209. X    while((c=getc(in))!=EOF)
  1210. X    {
  1211. X        if(c == 012)
  1212. X        {
  1213. X            *buf++ = 015;
  1214. X            if(--m == 0)
  1215. X            {
  1216. X                Lfseen = TRUE;
  1217. X                break;
  1218. X            }
  1219. X        }
  1220. X        *buf++ =c;
  1221. X        if(--m == 0)
  1222. X            break;
  1223. X    }
  1224. X    if(m==count)
  1225. X        return(0);
  1226. X    else
  1227. X        while(--m>=0)
  1228. X            *buf++ = CPMEOF;
  1229. X    return(count);
  1230. X}
  1231. X
  1232. X/*+-------------------------------------------------------------------------
  1233. X    zbuf_build(buf,count) - fill buf with count chars 
  1234. X--------------------------------------------------------------------------*/
  1235. Xzbuf_build(buf,count)
  1236. Xregister char *buf;
  1237. Xint count;
  1238. X{
  1239. Xregister c,m;
  1240. X
  1241. X    m=count;
  1242. X    while((c=getc(in))!=EOF)
  1243. X    {
  1244. X        *buf++ =c;
  1245. X        if(--m == 0)
  1246. X            break;
  1247. X    }
  1248. X    return(count - m);
  1249. X}    /* end of zbuf_build */
  1250. X
  1251. X/*+-------------------------------------------------------------------------
  1252. X    SIGALRM_handler()
  1253. X--------------------------------------------------------------------------*/
  1254. XSIGALRM_handler()
  1255. X{
  1256. X#if defined(M_SYS5)
  1257. X    report_rx_ind(0);
  1258. X    report_tx_ind(0);
  1259. X#endif
  1260. X    longjmp(tohere,-1);
  1261. X}    /* end of SIGALRM_handler */
  1262. X
  1263. X/*+-------------------------------------------------------------------------
  1264. X    readock(timeout,count)
  1265. Xtimeout is in tenths of seconds reads character(s) from file
  1266. Xdescriptor 'fd' read 'count' characters, (1 <= count <= 3) if more than
  1267. Xone received, return ERROR unless all are CAN normal response is NAK,
  1268. XACK, CAN, G or C
  1269. X--------------------------------------------------------------------------*/
  1270. Xreadock(timeout,count)
  1271. Xint timeout;
  1272. Xint count;
  1273. X{
  1274. X    register int c;
  1275. X    static char byt[5];
  1276. X
  1277. X    if(setjmp(tohere))
  1278. X    {
  1279. X        report_str("TIMEOUT",1);
  1280. X        return(TIMEOUT);
  1281. X    }
  1282. X    c = timeout/10;
  1283. X    if(c<2)
  1284. X        c = 2;
  1285. X    signal(SIGALRM,SIGALRM_handler);
  1286. X    alarm(c);
  1287. X#if defined(ONEREAD)
  1288. X    c=read(iofd,byt,1);        /* regulus raw read is unique */
  1289. X#else
  1290. X    c=read(iofd,byt,count);
  1291. X#endif
  1292. X    rx_char_count += c;
  1293. X    alarm(0);
  1294. X    if(c<1)
  1295. X        return(TIMEOUT);
  1296. X    if(c==1)
  1297. X        return(byt[0]&0377);
  1298. X    else
  1299. X        while(c)
  1300. X            if(byt[--c] != CAN)
  1301. X                return(ERROR);
  1302. X    return(CAN);
  1303. X}    /* end of readock */
  1304. X
  1305. X
  1306. X/*+-------------------------------------------------------------------------
  1307. X    readline(n)
  1308. X--------------------------------------------------------------------------*/
  1309. Xreadline(n)
  1310. Xint n;
  1311. X{
  1312. X    return(readock(n,1));
  1313. X}    /* end of readline */
  1314. X
  1315. X
  1316. X
  1317. X/*+-------------------------------------------------------------------------
  1318. X    purgeline()
  1319. X--------------------------------------------------------------------------*/
  1320. Xpurgeline()
  1321. X{
  1322. X#if defined(M_SYS5)
  1323. X    ioctl(iofd,TCFLSH,0);
  1324. X#else
  1325. X    lseek(iofd,0L,2);
  1326. X#endif
  1327. X}    /* end of purgeline */
  1328. X
  1329. X
  1330. X/*+-------------------------------------------------------------------------
  1331. X    send_cancel(error) - send cancel to remote
  1332. X--------------------------------------------------------------------------*/
  1333. Xsend_cancel(error)
  1334. Xint error;
  1335. X{
  1336. X    static char canistr[] =
  1337. X    {
  1338. X        24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
  1339. X    };
  1340. X    register char *cptr = canistr;
  1341. X
  1342. X    report_last_txhdr("^X CAN",!!error);
  1343. X    while(*cptr)
  1344. X        sendline(*cptr++);
  1345. X    flushline();
  1346. X}    /* end of send_cancel */
  1347. X
  1348. X
  1349. X/*+-------------------------------------------------------------------------
  1350. X    substr(str,substr) - searches for substr in string str
  1351. X--------------------------------------------------------------------------*/
  1352. Xchar *
  1353. Xsubstr(str,substr)
  1354. Xregister char *str,*substr;
  1355. X{
  1356. Xregister char *sptr;
  1357. Xregister char *ssptr;
  1358. X
  1359. X    for(sptr = str; *str; str++)
  1360. X    {
  1361. X        if(*str == *substr)
  1362. X        {
  1363. X            sptr = str;
  1364. X            ssptr = substr;
  1365. X            while(1)
  1366. X            {
  1367. X                if(*ssptr == 0)
  1368. X                    return(str);
  1369. X                if(*sptr++ != *ssptr++)
  1370. X                    break;
  1371. X            }
  1372. X        }
  1373. X    }
  1374. X    return(NULL);
  1375. X}    /* end of substr */
  1376. X
  1377. X/*+-------------------------------------------------------------------------
  1378. X    usage()
  1379. X--------------------------------------------------------------------------*/
  1380. Xusage()
  1381. X{
  1382. X    exit(255);
  1383. X}    /* end of usage */
  1384. X
  1385. X/*+-------------------------------------------------------------------------
  1386. X    getzrxinit() - Get the receiver's init parameters
  1387. X--------------------------------------------------------------------------*/
  1388. Xgetzrxinit()
  1389. X{
  1390. X    register n;
  1391. X    struct stat f;
  1392. X
  1393. X    for(n=10; --n>=0; )
  1394. X    {
  1395. X        switch(zgethdr(Rxhdr,1))
  1396. X        {
  1397. X        case ZCHALLENGE:    /* Echo receiver's challenge numbr */
  1398. X            stohdr(Rxpos);
  1399. X            zshhdr(ZACK,Txhdr);
  1400. X            continue;
  1401. X        case ZCOMMAND:        /* They didn't see out ZRQINIT */
  1402. X            stohdr(0L);
  1403. X            zshhdr(ZRQINIT,Txhdr);
  1404. X            continue;
  1405. X        case ZRINIT:
  1406. X            Rxflags = 0377 & Rxhdr[ZF0];
  1407. X            Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32));
  1408. X            report_protocol_type("ZMODEM");
  1409. X            report_protocol_crc_type((Txfcs32) ? "/CRC32" : "/CRC16");
  1410. X            Zctlesc |= Rxflags & TESCCTL;
  1411. X            Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8);
  1412. X            if( !(Rxflags & CANFDX))
  1413. X                Txwindow = 0;
  1414. X#if defined(MODE2OK)
  1415. X            mode(2);    /* Set cbreak,XON/XOFF,etc. */
  1416. X#endif
  1417. X#if !defined(READCHECK)
  1418. X#if !defined(M_SYS5)
  1419. X            /* Use 1024 byte frames if no sample/interrupt */
  1420. X            if(Rxbuflen < 32 || Rxbuflen > 1024)
  1421. X            {
  1422. X                Rxbuflen = 1024;
  1423. X            }
  1424. X#endif
  1425. X#endif
  1426. X            /* Override to force shorter frame length */
  1427. X            if(Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=32))
  1428. X                Rxbuflen = Tframlen;
  1429. X            if( !Rxbuflen && (Tframlen>=32) && (Tframlen<=1024))
  1430. X                Rxbuflen = Tframlen;
  1431. X
  1432. X            /* If using a pipe for testing set lower buf len */
  1433. X            fstat(iofd,&f);
  1434. X            if((f.st_mode & S_IFMT) != S_IFCHR
  1435. X                && (Rxbuflen == 0 || Rxbuflen > 4096))
  1436. X                Rxbuflen = 4096;
  1437. X            sprintf(s128,"Remote: CRC32 %c  duplex %c",
  1438. X                (Rxflags & CANFC32) ? 'y' : 'n',
  1439. X                (Rxflags & CANFDX)  ? 'y' : 'n');
  1440. X            if(Rxbuflen)
  1441. X                sprintf(&s128[strlen(s128)],"  buflen %u",Rxbuflen);
  1442. X            else
  1443. X                strcat(s128,"  continuous stream y");
  1444. X            report_str(s128,2);
  1445. X            /*
  1446. X             * If input is not a regular file,force ACK's each 1024
  1447. X             *  (A smarter strategey could be used here ...)
  1448. X             */
  1449. X            if( !Command)
  1450. X            {
  1451. X                fstat(fileno(in),&f);
  1452. X                if(((f.st_mode & S_IFMT) != S_IFREG)
  1453. X                    && (Rxbuflen == 0 || Rxbuflen > 1024))
  1454. X                    Rxbuflen = 1024;
  1455. X            }
  1456. X
  1457. X            if(Baudrate > 300)    /* Set initial subpacket len */
  1458. X                blklen = 256;
  1459. X            if(Baudrate > 1200)
  1460. X                blklen = 512;
  1461. X            if(Baudrate >= 2400)    /* original code had > 2400 here ****/
  1462. X                blklen = 1024;
  1463. X            if(Rxbuflen && blklen>Rxbuflen)
  1464. X                blklen = Rxbuflen;
  1465. X            if(blkopt && blklen > blkopt)
  1466. X                blklen = blkopt;
  1467. X            blklen_original = blklen;
  1468. X            report_txblklen(blklen);
  1469. X            return(sendzsinit());
  1470. X        case ZCAN:
  1471. X        case TIMEOUT:
  1472. X            return(ERROR);
  1473. X        case ZRQINIT:
  1474. X            if(Rxhdr[ZF0] == ZCOMMAND)
  1475. X                continue;
  1476. X        default:
  1477. X            zshhdr(ZNAK,Txhdr);
  1478. X            continue;
  1479. X        }
  1480. X    }
  1481. X    return(ERROR);
  1482. X}    /* end of getzrxinit */
  1483. X
  1484. X
  1485. X/*+-------------------------------------------------------------------------
  1486. X    sendzsinit() - send send-init information
  1487. X--------------------------------------------------------------------------*/
  1488. Xsendzsinit()
  1489. X{
  1490. X    register c;
  1491. X
  1492. X    if(Myattn[0] == '\0' && (!Zctlesc || (Rxflags & TESCCTL)))
  1493. X        return(OK);
  1494. X    errors = 0;
  1495. X    for(;;)
  1496. X    {
  1497. X        stohdr(0L);
  1498. X        if(Zctlesc)
  1499. X        {
  1500. X            Txhdr[ZF0] |= TESCCTL;
  1501. X            zshhdr(ZSINIT,Txhdr);
  1502. X        }
  1503. X        else
  1504. X            zsbhdr(ZSINIT,Txhdr);
  1505. X        zsdata(Myattn,1+strlen(Myattn),ZCRCW);
  1506. X        c = zgethdr(Rxhdr,1);
  1507. X        switch(c)
  1508. X        {
  1509. X        case ZCAN:
  1510. X            return(ERROR);
  1511. X        case ZACK:
  1512. X            return(OK);
  1513. X        default:
  1514. X            if(++errors > 19)
  1515. X                return(ERROR);
  1516. X            continue;
  1517. X        }
  1518. X    }
  1519. X}    /* end of sendzsinit */
  1520. X
  1521. X/*+-------------------------------------------------------------------------
  1522. X    zsendfile(buf,blen) - send file name & info
  1523. X--------------------------------------------------------------------------*/
  1524. Xzsendfile(buf,blen)
  1525. Xchar *buf;
  1526. Xint blen;
  1527. X{
  1528. X    register c;
  1529. X
  1530. X    for(;;)
  1531. X    {
  1532. X        blklen = blklen_original;
  1533. X        report_txblklen(blklen);
  1534. X        Txhdr[ZF0] = Lzconv;    /* file conversion request */
  1535. X        Txhdr[ZF1] = Lzmanag;    /* file management request */
  1536. X        Txhdr[ZF2] = Lztrans;    /* file transport request */
  1537. X        Txhdr[ZF3] = 0;
  1538. X        zsbhdr(ZFILE,Txhdr);
  1539. X        zsdata(buf,blen,ZCRCW);
  1540. Xagain:
  1541. X        c = zgethdr(Rxhdr,1);
  1542. X        switch(c)
  1543. X        {
  1544. X        case ZRINIT:
  1545. X            while((c = readline(50)) > 0)
  1546. X                if(c == ZPAD)
  1547. X                {
  1548. X                    goto again;
  1549. X                }
  1550. X            /* **** FALL THRU TO **** */
  1551. X        default:
  1552. X            continue;
  1553. X        case ZCAN:
  1554. X        case TIMEOUT:
  1555. X        case ZABORT:
  1556. X        case ZFIN:
  1557. X            return(ERROR);
  1558. X        case ZSKIP:
  1559. X            report_file_close();
  1560. X            fclose(in);
  1561. X            return(c);
  1562. X        case ZRPOS:
  1563. X            /*
  1564. X             * Suppress zcrcw request otherwise triggered by
  1565. X             * lastyunc==bytcnt
  1566. X             */
  1567. X            Lastsync = (bytcnt = Txpos = Rxpos) -1;
  1568. X            fseek(in,Rxpos,0);
  1569. X            Dontread = FALSE;
  1570. X            report_send_stats(Txpos);
  1571. X            return(zsendfdata());
  1572. X        }
  1573. X    }
  1574. X}    /* end of zsendfile */
  1575. X
  1576. X/*+-------------------------------------------------------------------------
  1577. X    zsendfdata() - send data in the file
  1578. X--------------------------------------------------------------------------*/
  1579. Xzsendfdata()
  1580. X{
  1581. Xregister c,e,n;
  1582. Xregister newcnt;
  1583. Xregister long tcount = 0;
  1584. Xint junkcount;        /* Counts garbage chars received by TX */
  1585. Xstatic int tleft = 6;    /* Counter for test mode */
  1586. Xint err;
  1587. X
  1588. X    Lrxpos = 0;
  1589. X    junkcount = 0;
  1590. X    SameZrposAgain = FALSE;        /* variable was named Beenhereb4 (wht) */
  1591. X    this_file_frame_count = 0;    /* we've sent no frames (wht) */
  1592. Xsomemore:
  1593. X    if(setjmp(intrjmp))
  1594. X    {
  1595. Xwaitack:
  1596. X        junkcount = 0;
  1597. X        c = getinsync(0);
  1598. Xgotack:
  1599. X        switch(c)
  1600. X        {
  1601. X        default:
  1602. X        case ZCAN:
  1603. X            report_rcvr_cancelled("zfdata-1");
  1604. X            report_file_close();
  1605. X            fclose(in);
  1606. X            return(ERROR);
  1607. X        case ZSKIP:
  1608. X            report_file_close();
  1609. X            fclose(in);
  1610. X            return(c);
  1611. X        case ZACK:
  1612. X        case ZRPOS:
  1613. X            break;
  1614. X        case ZRINIT:
  1615. X            return(OK);
  1616. X        }
  1617. X#if defined(READCHECK)
  1618. X        /*
  1619. X         * If the reverse channel can be tested for data,
  1620. X         *  this logic may be used to detect error packets
  1621. X         *  sent by the receiver,in place of setjmp/longjmp
  1622. X         *  rdchk(fdes) returns non 0 if a character is available
  1623. X         */
  1624. X        while(rdchk(iofd))
  1625. X        {
  1626. X            switch(readline(1))
  1627. X            {
  1628. X            case CAN:
  1629. X            case ZPAD:
  1630. X                c = getinsync(1);
  1631. X                goto gotack;
  1632. X            case XOFF:        /* Wait a while for an XON */
  1633. X            case XOFF|0200:
  1634. X                readline(100);
  1635. X            }
  1636. X        }
  1637. X#endif
  1638. X    }
  1639. X
  1640. X    newcnt = Rxbuflen;
  1641. X    Txwcnt = 0;
  1642. X    stohdr(Txpos);
  1643. X    zsbhdr(ZDATA,Txhdr);
  1644. X
  1645. X    do
  1646. X    {
  1647. X        if(Dontread)
  1648. X        {
  1649. X            n = Lastn;
  1650. X        } else
  1651. X        {
  1652. X            n = zbuf_build(txbuf,blklen);
  1653. X            Lastread = Txpos;
  1654. X            Lastn = n;
  1655. X        }
  1656. X        Dontread = FALSE;
  1657. X        if(n < blklen)
  1658. X            e = ZCRCE;
  1659. X        else if(junkcount > 3)
  1660. X            e = ZCRCW;
  1661. X        else if(bytcnt == Lastsync)
  1662. X            e = ZCRCW;
  1663. X        else if(Rxbuflen && (newcnt -= n) <= 0)
  1664. X            e = ZCRCW;
  1665. X        else if(Txwindow && (Txwcnt += n) >= Txwspac)
  1666. X        {
  1667. X            Txwcnt = 0;
  1668. X            e = ZCRCQ;
  1669. X        }
  1670. X        else
  1671. X            e = ZCRCG;
  1672. X        zsdata(txbuf,n,e);
  1673. X        this_file_frame_count++;        /* wht */
  1674. X        if(bad_condx_blklen)            /* wht */
  1675. X        {
  1676. X            /* if we have sent four frames since last ZRPOS to same pos (wht)*/
  1677. X            if((this_file_frame_count - bad_condx_frame_count) > 4) /*wht*/
  1678. X            {
  1679. X                if(blklen == bad_condx_blklen)
  1680. X                    bad_condx_blklen = 0;
  1681. X                else
  1682. X                {
  1683. X                    blklen *= 2;
  1684. X                    report_txblklen(blklen);
  1685. X                }
  1686. X                SameZrposAgain = 0;
  1687. X            }
  1688. X        }
  1689. X        bytcnt = Txpos += n;
  1690. X        report_send_stats(Txpos);
  1691. X        if(e == ZCRCW)
  1692. X            goto waitack;
  1693. X#if defined(READCHECK)
  1694. X        /*
  1695. X         * If the reverse channel can be tested for data,
  1696. X         *  this logic may be used to detect error packets
  1697. X         *  sent by the receiver,in place of setjmp/longjmp
  1698. X         *  rdchk(fdes) returns non 0 if a character is available
  1699. X         */
  1700. X        while(rdchk(iofd))
  1701. X        {
  1702. X            switch(readline(1))
  1703. X            {
  1704. X            case CAN:
  1705. X            case ZPAD:
  1706. X                c = getinsync(1);
  1707. X                if(c == ZACK)
  1708. X                    break;
  1709. X#if defined(TCFLSH)
  1710. X                ioctl(iofd,TCFLSH,1);
  1711. X#endif
  1712. X                /* zcrce - dinna wanna starta ping-pong game */
  1713. X                zsdata(txbuf,0,ZCRCE);
  1714. X                goto gotack;
  1715. X
  1716. X            case XOFF:        /* Wait a while for an XON */
  1717. X            case XOFF|0200:
  1718. X                readline(100);
  1719. X
  1720. X            default:
  1721. X                ++junkcount;
  1722. X            }
  1723. X        }
  1724. X#endif    /* READCHECK */
  1725. X        if(Txwindow)
  1726. X        {
  1727. X            while((tcount = Txpos - Lrxpos) >= Txwindow)
  1728. X            {
  1729. X                if(e != ZCRCQ)
  1730. X                    zsdata(txbuf,0,e = ZCRCQ);
  1731. X                c = getinsync(1);
  1732. X                if(c != ZACK)
  1733. X                {
  1734. X#if defined(TCFLSH)
  1735. X                    ioctl(iofd,TCFLSH,1);
  1736. X#endif
  1737. X                    zsdata(txbuf,0,ZCRCE);
  1738. X                    goto gotack;
  1739. X                }
  1740. X            }
  1741. X        }
  1742. X    } while(n == blklen);
  1743. X
  1744. X    for(;;)
  1745. X    {
  1746. X        stohdr(Txpos);
  1747. X        zsbhdr(ZEOF,Txhdr);
  1748. X        switch(err = getinsync(0))
  1749. X        {
  1750. X        case ZACK:
  1751. X            continue;
  1752. X        case ZRPOS:
  1753. X            goto somemore;
  1754. X        case ZRINIT:
  1755. X            return(OK);
  1756. X        case ZSKIP:
  1757. X            report_file_close();
  1758. X            fclose(in);
  1759. X            return(c);
  1760. X        default:
  1761. X            sprintf(s128,"SEND protocol sync error 0x%04x: %s",err,Pathname);
  1762. X            ecu_log_event(getppid(),s128);    /* always log this */
  1763. X            report_str(s128 + 5,1);
  1764. X            skip_count++;
  1765. X            report_error_count();
  1766. X            report_file_byte_io(this_file_length);
  1767. X            report_file_close();
  1768. X            fclose(in);
  1769. X            return(ERROR);
  1770. X        }
  1771. X    }
  1772. X}    /* end of zsendfdata */
  1773. X
  1774. X/*+-------------------------------------------------------------------------
  1775. X    getinsync(flag) - get back in sync with receiver
  1776. X--------------------------------------------------------------------------*/
  1777. Xgetinsync(flag)
  1778. X{
  1779. X    register c;
  1780. X
  1781. X    for(;;)
  1782. X    {
  1783. X        switch(c = zgethdr(Rxhdr,0))
  1784. X        {
  1785. X        case ZCAN:
  1786. X        case ZABORT:
  1787. X        case ZFIN:
  1788. X        case TIMEOUT:
  1789. X            sprintf(s128,"Receiver %s",frametypes[c+FTOFFSET]);
  1790. X            report_str(s128,1);
  1791. X            return(ERROR);
  1792. X        case ZRPOS:
  1793. X            report_str("Receiver ZRPOS",1);
  1794. X            /* ************************************* */
  1795. X            /*  If sending to a modem buffer,you     */
  1796. X            /*   might send a break at this point to */
  1797. X            /*   dump the modem's buffer.            */
  1798. X            /* ************************************* */
  1799. X            if(Lastn >= 0 && Lastread == Rxpos)
  1800. X            {
  1801. X                Dontread = TRUE;
  1802. X            } else
  1803. X            {
  1804. X                clearerr(in);    /* In case file EOF seen */
  1805. X                fseek(in,Rxpos,0);
  1806. X            }
  1807. X            bytcnt = Lrxpos = Txpos = Rxpos;
  1808. X            if(Lastsync == Rxpos)                    /* wht - original code */
  1809. X            {                                        /* wht - original code */
  1810. X                /* save frame count at time of each occurrence (wht) */
  1811. X                bad_condx_frame_count = this_file_frame_count;    /* wht */
  1812. X                /* save block length at time of error (wht) */
  1813. X                if(++SameZrposAgain > 4)            /* wht - original code */
  1814. X                {                                    /* wht */
  1815. X                    if(bad_condx_blklen == 0)        /* wht */
  1816. X                        bad_condx_blklen = blklen;    /* wht */
  1817. X                    if(blklen > 256)                /* wht - 32->256 */
  1818. X                    {
  1819. X                        blklen /= 2;                /* wht - original code */
  1820. X                        report_txblklen(blklen);
  1821. X                    }
  1822. X                }                                    /* wht */
  1823. X            }                                        /* wht - original code */
  1824. X            Lastsync = Rxpos;
  1825. X            report_send_stats(Txpos);
  1826. X            return(c);
  1827. X        case ZACK:
  1828. X            report_str("",-1);
  1829. X            Lrxpos = Rxpos;
  1830. X            if(flag || Txpos == Rxpos)
  1831. X                return(ZACK);
  1832. X            continue;
  1833. X
  1834. X        case ZRINIT:
  1835. X            report_str("",-1);
  1836. X#if defined(LOG_XFER)
  1837. X            sprintf(s256,"SEND success: %s",Pathname);
  1838. X            ecu_log_event(getppid(),s256);
  1839. X#endif
  1840. X        case ZSKIP:
  1841. X            report_file_byte_io(this_file_length);
  1842. X            report_file_close();
  1843. X            fclose(in);
  1844. X            return(c);
  1845. X        case ERROR:
  1846. X        default:
  1847. X            report_str("Sending ZNAK",0);
  1848. X            zsbhdr(ZNAK,Txhdr);
  1849. X            continue;
  1850. X        }
  1851. X    }
  1852. X}    /* end of getinsync */
  1853. X
  1854. X/*+-------------------------------------------------------------------------
  1855. X    saybibi() - Say "bibi" to the receiver, try to do it cleanly
  1856. X--------------------------------------------------------------------------*/
  1857. Xsaybibi()
  1858. X{
  1859. X    for(;;)
  1860. X    {
  1861. X        stohdr(0L);        /* CAF Was zsbhdr - minor change */
  1862. X        zshhdr(ZFIN,Txhdr);    /*  to make debugging easier */
  1863. X        switch(zgethdr(Rxhdr,0))
  1864. X        {
  1865. X        case ZFIN:
  1866. X            sendline('O');
  1867. X            sendline('O');
  1868. X            flushline();
  1869. X        case ZCAN:
  1870. X        case TIMEOUT:
  1871. X            return;
  1872. X        }
  1873. X    }
  1874. X}    /* end of saybibi */
  1875. X
  1876. X/*+-------------------------------------------------------------------------
  1877. X    determine_transaction_time()
  1878. X--------------------------------------------------------------------------*/
  1879. Xdetermine_transaction_time()
  1880. X{
  1881. Xregister c;
  1882. Xstruct stat f;
  1883. Xchar *name;
  1884. X
  1885. X    rewind_file_list();
  1886. X    TotalLeft = 0;
  1887. X    Filesleft = 0;
  1888. X    while(get_file_list_name(&name))
  1889. X    {
  1890. X        f.st_size = -1;
  1891. X        if((access(name,04) >= 0) && (stat(name,&f) >= 0))
  1892. X        {
  1893. X            c = f.st_mode & S_IFMT;
  1894. X            if(c != S_IFDIR && c != S_IFBLK)
  1895. X            {
  1896. X                ++Filesleft;
  1897. X                TotalLeft += f.st_size;
  1898. X            }
  1899. X        }
  1900. X    }
  1901. X    FilesTotal = Filesleft;
  1902. X    rewind_file_list();
  1903. X}    /* end of determine_transaction_time */
  1904. X
  1905. X/* vi: set tabstop=4 shiftwidth=4: */
  1906. X/* end of ecusz.c */
  1907. SHAR_EOF
  1908. $TOUCH -am 1220170590 'z/ecusz.c' &&
  1909. chmod 0644 z/ecusz.c ||
  1910. echo 'restore of z/ecusz.c failed'
  1911. Wc_c="`wc -c < 'z/ecusz.c'`"
  1912. test 41872 -eq "$Wc_c" ||
  1913.     echo 'z/ecusz.c: original size 41872, current size' "$Wc_c"
  1914. true || echo 'restore of z/zcommon.c failed'
  1915. echo End of part 20, continue with part 21
  1916. exit 0
  1917. --------------------------------------------------------------------
  1918. Warren Tucker, TuckerWare emory!n4hgf!wht or wht@n4hgf.Mt-Park.GA.US
  1919. Hacker Extraordinaire  d' async PADs,  pods,  proteins and protocols
  1920.  
  1921. exit 0 # Just in case...
  1922. -- 
  1923. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1924. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1925. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1926. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1927.