home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1998 September / PCO_0998.ISO / filesbbs / dos / sbbs_src.exe / STP / STP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-25  |  49.2 KB  |  2,018 lines

  1. /* STP.C */
  2.  
  3. /* Developed 1990-1997 by Rob Swindell; PO Box 501, Yorba Linda, CA 92885 */
  4.  
  5. /* Synchronet Transfer Protocols */
  6.  
  7. #include <io.h>
  8. #include <dos.h>
  9. #include <dir.h>
  10. #include <time.h>
  11. #include <alloc.h>
  12. #include <stdio.h>
  13. #include <fcntl.h>
  14. #include <errno.h>
  15. #include <string.h>
  16. #include <stdlib.h>
  17. #include <stdarg.h>
  18. #include <sys/stat.h>
  19.  
  20. #define STP 1
  21.  
  22. #include "zmodem.h"
  23.  
  24. #define MAXERRORS    10
  25.  
  26. #define ERROR -1
  27.                             /* Various Character/Ctrl-Code Definitions    */
  28. #define SP            32        /* Space bar                                */
  29. #define ESC            27        /* ESC Char                                 */
  30. #define    CR            13        /* Carriage Return                            */
  31. #define FF          12      /* Form Feed                                */
  32. #define    LF            10        /* Line Feed                                */
  33. #define TAB            9        /* Horizontal Tabulation                    */
  34. #define BS            8        /* Back Space                                */
  35. #define SOH         1        /* Start of header                            */
  36. #define STX         2        /* Start of text                            */
  37. #define ETX         3       /* End of text                              */
  38. #define EOT         4        /* End of transmission                        */
  39. #define ACK         6        /* Acknowledge                                */
  40. #define DLE         16        /* Data link escape                         */
  41. #define XON         17        /* Ctrl-Q - resume transmission             */
  42. #define XOFF        19        /* Ctrl-S - pause transmission                */
  43. #define NAK         21        /* Negative Acknowledge                     */
  44. #define CAN         24        /* Cancel                                    */
  45. #define CPMEOF        26        /* CP/M End of file (^Z)                    */
  46. #define LOC_ABORT    0x2e03    /* Local abort key    (^C)                    */
  47.  
  48. #define uchar    unsigned char
  49. #define uint    unsigned int
  50. #define ulong   unsigned long
  51.  
  52. #define SEND        (1<<0)    /* Sending file(s)                            */
  53. #define RECV        (1<<1)    /* Receiving file(s)                        */
  54. #define XMODEM        (1<<2)    /* Use Xmodem                                */
  55. #define YMODEM        (1<<3)    /* Use Ymodem                                */
  56. #define ZMODEM        (1<<4)    /* Use Zmodem                                */
  57. #define CRC         (1<<5)    /* Use CRC error correction                 */
  58. #define GMODE        (1<<6)    /* For Qmodem-G and Ymodem-G                */
  59. #define DIR         (1<<7)    /* Directory specified to download to        */
  60. #define DEBUG        (1<<8)    /* Debug output                             */
  61. #define OVERWRITE    (1<<9)    /* Overwrite receiving files                */
  62. #define IGNORE_DCD    (1<<10) /* Ignore DCD                                */
  63. #define ALARM        (1<<11) /* Alarm when starting and stopping xfer    */
  64. #define NO_LOCAL    (1<<12) /* Don't check local keyboard               */
  65.  
  66.                             /* Zmodem mode bits                         */
  67. #define CTRL_ESC    (1<<0)    /* Escape all control chars                 */
  68. #define VAR_HDRS    (1<<1)    /* Use variable headers                     */
  69.  
  70. #define LOOP_NOPEN    50
  71.  
  72. #define MAX_FNAMES    100     /* Up to 100 filenames                        */
  73.  
  74. /************************/
  75. /* Remote I/O Constants */
  76. /************************/
  77.  
  78.                             /* i/o mode and state flags */
  79. #define CTSCK 0x1000         /* check cts (mode only) */
  80. #define RTSCK 0x2000        /* check rts (mode only) */
  81. #define TXBOF 0x0800        /* transmit buffer overflow (outcom only) */
  82. #define ABORT 0x0400         /* check for ^C (mode), aborting (state) */
  83. #define PAUSE 0x0200         /* check for ^S (mode), pausing (state) */
  84. #define NOINP 0x0100         /* input buffer empty (incom only) */
  85.  
  86.                             /* status flags */
  87. #define DCD     0x80           /* DCD on */
  88. #define RI        0x40        /* Ring indicate */
  89. #define DSR     0x20        /* Dataset ready */
  90. #define CTS     0x10           /* CTS on */
  91. #define FERR     0x08        /* Frameing error */
  92. #define PERR     0x04        /* Parity error */
  93. #define OVRR     0x02        /* Overrun */
  94. #define RXLOST     0x01           /* Receive buffer overflow */
  95.  
  96. /* rioctl() arguments */
  97. /* returns mode or state flags in high 8 bits, status flags in low 8 bits */
  98.  
  99.                             /* the following return mode in high 8 bits */
  100. #define IOMODE 0            /* no operation */
  101. #define IOSM 1              /* i/o set mode flags */
  102. #define IOCM 2              /* i/o clear mode flags */
  103.  
  104. #define GVERS 0x007         /* get version */
  105. #define GUART 0x107         /* get uart */
  106. #define GIRQN 0x207         /* get IRQ number */
  107. #define GBAUD 0x307         /* get baud */
  108.  
  109.                             /* the following return state in high 8 bits */
  110. #define IOSTATE 4           /* no operation */
  111. #define IOSS 5              /* i/o set state flags */
  112. #define IOCS 6              /* i/o clear state flags */
  113. #define IOFB 0x308          /* i/o buffer flush */
  114. #define IOFI 0x208          /* input buffer flush */
  115. #define IOFO 0x108          /* output buffer flush */
  116. #define IOCE 9              /* i/o clear error flags */
  117.  
  118. #define TS_INT28     1
  119. #define TS_WINOS2     2
  120. #define TS_NODV      4
  121.  
  122.                             /* return count (16bit)    */
  123. #define RXBC    0x000a        /* get receive buffer count */
  124. #define RXBS    0x010a        /* get receive buffer size */
  125. #define TXBC    0x000b        /* get transmit buffer count */
  126. #define TXBS    0x010b        /* get transmit buffer size */
  127. #define TXBF    0x020b        /* get transmit buffer free space */
  128. #define TXSYNC    0x000c        /* sync transmition (seconds<<8|0x0c) */
  129. #define IDLE    0x000d        /* suspend communication routines */
  130. #define RESUME    0x010d        /* return from suspended state */
  131. #define RLERC    0x000e        /* read line error count and clear */
  132. #define CPTON    0x0110        /* set input translation flag for ctrl-p on */
  133. #define CPTOFF    0x0010        /* set input translation flag for ctrl-p off */
  134. #define GETCPT    0x8010        /* return the status of ctrl-p translation */
  135. #define MSR     0x0011        /* read modem status register */
  136. #define FIFOCTL 0x0012        /* FIFO UART control */
  137. #define TSTYPE    0x0013        /* Time-slice API type */
  138. #define GETTST    0x8013        /* Get Time-slice API type */
  139.  
  140.                             /* ivhctl() arguments */
  141. #define INT29R 1             /* copy int 29h output to remote */
  142. #define INT29L 2            /* Use _putlc for int 29h */
  143. #define INT16  0x10          /* return remote chars to int 16h calls */
  144. #define INTCLR 0            /* release int 16h, int 29h */
  145.  
  146. #define DCDHIGH (rioctl(IOSTATE)&DCD || mode&IGNORE_DCD)
  147.  
  148. /**************/
  149. /* Prototypes */
  150. /**************/
  151.  
  152. /* LCLOLL.ASM */
  153. int     lclini(int);
  154. void lclxy(int,int);
  155. int  lclwx(void);
  156. int  lclwy(void);
  157. int  lclatr(int);
  158. int  lclaes(void);
  159. void lputc(int);
  160. long lputs(char far *);
  161. uint lkbrd(int);
  162.  
  163. /* RCIOLL.ASM */
  164.  
  165. int  rioini(int com,int irq);          /* initialize com,irq */
  166. int  setbaud(int rate);                /* set baud rate */
  167. int  rioctl(int action);               /* remote i/o control */
  168. int  dtr(char onoff);                  /* set/reset dtr */
  169. int  incom(void);                      /* receive character */
  170. int  ivhctl(int intcode);              /* local i/o redirection */
  171.  
  172. void riosync();
  173. void cancel();
  174.  
  175. extern    mswtyp;
  176. extern uint riobp;
  177.  
  178. uint    asmrev;
  179.  
  180. /***************/
  181. /* Global Vars */
  182. /***************/
  183. long    mode=0L;                        /* Program mode                     */
  184. long    zmode=0L;                        /* Zmodem mode                        */
  185. uchar    hdr_block_num;                    /* Block number received in header    */
  186. uchar    block[1024];                    /* Block buffer                     */
  187. uint    block_size;                     /* Block size (128 or 1024)         */
  188. ulong    block_num;                        /* Block number                     */
  189. ulong    last_block_num;                 /* Last block number sent            */
  190. uint    flows=0;                        /* Number of flow controls            */
  191.  
  192. /**************************************/
  193. /* Zmodem specific, from Chuck's RZSZ */
  194. /**************************************/
  195. char    Txhdr[ZMAXHLEN];                /* Zmodem transmit header            */
  196. char    Rxhdr[ZMAXHLEN];                /* Zmodem receive header            */
  197. char    attn[ZATTNLEN];                 /* Attention string for sender        */
  198. char    zconv;
  199. char    zmanag;
  200. char    ztrans;
  201. int     tryzhdrtype;
  202. int     Rxtimeout = 100;        /* Tenths of seconds to wait for something */
  203. int     Rxframeind;             /* ZBIN ZBIN32, or ZHEX type of frame */
  204. int     Rxtype;                 /* Type of header received */
  205. int     Rxhlen;                 /* Length of header received */
  206. int     Rxcount;                /* Count of data bytes received */
  207.  
  208. /********/
  209. /* Code */
  210. /********/
  211.  
  212. int cbreakh()
  213. {
  214. return(1);
  215. }
  216.  
  217. /****************************************************************************/
  218. /* Performs printf() through local assembly routines                        */
  219. /****************************************************************************/
  220. int lprintf(char *fmat, ...)
  221. {
  222.     va_list argptr;
  223.     char sbuf[2048];
  224.     int chcount;
  225.  
  226. va_start(argptr,fmat);
  227. chcount=vsprintf(sbuf,fmat,argptr);
  228. va_end(argptr);
  229. lputs(sbuf);
  230. return(chcount);
  231. }
  232.  
  233. void newline()
  234. {
  235. if(lclwx()>1)
  236.     lputs("\r\n");
  237. }
  238.  
  239. /****************************************************************************/
  240. /* Network open function. Opens all files DENYALL and retries LOOP_NOPEN    */
  241. /* number of times if the attempted file is already open or denying access  */
  242. /* for some other reason.    All files are opened in BINARY mode.            */
  243. /****************************************************************************/
  244. int nopen(char *str, int access)
  245. {
  246.     char count=0,logstr[256];
  247.     int file,share;
  248.  
  249. if(access==O_RDONLY) share=O_DENYWRITE;
  250.     else share=O_DENYALL;
  251. while(((file=open(str,O_BINARY|share|access,S_IWRITE))==-1)
  252.     && errno==EACCES && count++<LOOP_NOPEN);
  253. if(file==-1 && errno==EACCES)
  254.     lprintf("\7\r\nNOPEN: ACCESS DENIED\r\n\7");
  255. return(file);
  256. }
  257.  
  258.  
  259. /****************************************************************************/
  260. /* Converts an ASCII Hex string into an ulong                                */
  261. /****************************************************************************/
  262. ulong ahtoul(char *str)
  263. {
  264.     ulong l,val=0;
  265.  
  266. while((l=(*str++)|0x20)!=0x20)
  267.     val=(l&0xf)+(l>>6&1)*9+val*16;
  268. return(val);
  269. }
  270.  
  271. /****************************************************************************/
  272. /* Checks the disk drive for the existence of a file. Returns 1 if it       */
  273. /* exists, 0 if it doesn't.                                                 */
  274. /****************************************************************************/
  275. char fexist(char *filespec)
  276. {
  277.     struct ffblk f;
  278.  
  279. if(findfirst(filespec,&f,0)==NULL)
  280.     return(1);
  281. return(0);
  282. }
  283.  
  284. /****************************************************************************/
  285. /* Truncates white-space chars off end of 'str' and terminates at first tab */
  286. /****************************************************************************/
  287. void truncsp(char *str)
  288. {
  289.     char c;
  290.  
  291. str[strcspn(str,"\t")]=0;
  292. c=strlen(str);
  293. while(c && str[c-1]<=SP) c--;
  294. str[c]=0;
  295. }
  296.  
  297. /**************/
  298. /* Exit Point */
  299. /**************/
  300. void bail(int code)
  301. {
  302.  
  303. if(mode&ALARM) {
  304.     sound(2000);
  305.     mswait(500);
  306.     sound(1000);
  307.     mswait(500);
  308.     nosound(); }
  309. riosync();
  310. rioini(0,0);    /* uninstall com routines */
  311. newline();
  312. lprintf("Exiting - Error level: %d  Flow restraint count: %u\r\n",code,flows);
  313. fcloseall();
  314. exit(code);
  315. }
  316.  
  317. /************************************************************/
  318. /* Get a character from com port, time out after 10 seconds */
  319. /************************************************************/
  320. int getcom(char timeout)
  321. {
  322.     uint    i,ch;
  323.     time_t    start;
  324.  
  325. if((ch=incom())!=NOINP)
  326.     return(ch);
  327. for(i=0;i<10000;i++)               /* ten consecutive re-tries */
  328.     if((ch=incom())!=NOINP)
  329.         return(ch);
  330. flows++;
  331. start=time(NULL);
  332. while(time(NULL)-start<(long)timeout) {   /* wait up to ten seconds */
  333.     if((ch=incom())!=NOINP)
  334.         return(ch);
  335.     if(!DCDHIGH) {
  336.         newline();
  337.         lprintf("No carrier\r\n");
  338.         bail(1); }
  339.     mswait(0);
  340.     if(!(mode&NO_LOCAL) && lkbrd(0)==LOC_ABORT) {
  341.         newline();
  342.         lprintf("Local abort\r\n");
  343.         cancel();
  344.         bail(1); } }
  345. newline();
  346. lprintf("Input timeout\r\n");
  347. return(NOINP);
  348. }
  349.  
  350. /**********************************/
  351. /* Output a character to COM port */
  352. /**********************************/
  353. void putcom(uchar ch)
  354. {
  355.     int i=0;
  356.  
  357. while(outcom(ch)&TXBOF && i<180) { /* 10 sec delay */
  358.     if(!i) lputc('F');
  359.     if(!DCDHIGH) {
  360.         newline();
  361.         lprintf("No carrier\r\n");
  362.         bail(1); }
  363.     i++;
  364.     mswait(1);
  365.     if(!(mode&NO_LOCAL) && lkbrd(0)==LOC_ABORT) {
  366.         newline();
  367.         lprintf("Local abort\r\n");
  368.         bail(1); } }
  369. if(i) {
  370.     lprintf("\b \b");
  371.     flows++;
  372.     if(i==180) {
  373.         newline();
  374.         lprintf("Output timeout\r\n");
  375.         bail(1); } }
  376. }
  377.  
  378. void put_nak()
  379. {
  380. while(getcom(1)!=NOINP && (mode&NO_LOCAL || lkbrd(0)!=LOC_ABORT))
  381.     ;                /* wait for any trailing data */
  382. putcom(NAK);
  383. }
  384.  
  385. void cancel()
  386. {
  387.     int i;
  388.  
  389. for(i=0;i<10;i++)
  390.     putcom(CAN);
  391. for(i=0;i<10;i++)
  392.     putcom(BS);
  393. }
  394.  
  395. /********************************/
  396. /* Update the CRC bytes         */
  397. /********************************/
  398. /****
  399. void update_crc(uchar c, uchar *crc1, uchar *crc2)
  400. {
  401.     int i, temp;
  402.     uchar carry, c_crc1, c_crc2;
  403.  
  404. for (i=0; i < 8; i++) {
  405.     temp = c * 2;
  406.     c = temp;            /* rotate left */
  407.     carry = ((temp > 255) ? 1 : 0);
  408.     temp = (*crc2) * 2;
  409.     (*crc2) = temp;
  410.     (*crc2) |= carry;           /* rotate with carry */
  411.     c_crc2 = ((temp > 255) ? 1 : 0);
  412.     temp = (*crc1) * 2;
  413.     (*crc1) = temp;
  414.     (*crc1) |= c_crc2;
  415.     c_crc1 = ((temp > 255) ? 1 : 0);
  416.     if (c_crc1) {
  417.         (*crc2) ^= 0x21;
  418.         (*crc1) ^= 0x10; } }
  419. }
  420. ****/
  421.  
  422. void ucrc16(uchar ch, uint *rcrc) {
  423.     uint i, cy;
  424.     uchar nch=ch;
  425.  
  426. for (i=0; i<8; i++) {
  427.     cy=*rcrc & 0x8000;
  428.     *rcrc<<=1;
  429.     if (nch & 0x80) *rcrc |= 1;
  430.     nch<<=1;
  431.     if (cy) *rcrc ^= 0x1021; }
  432. }
  433.  
  434.  
  435. char *chr(uchar ch)
  436. {
  437.     static char str[25];
  438.  
  439. switch(ch) {
  440.     case SOH:
  441.         return("SOH");
  442.     case STX:
  443.         return("STX");
  444.     case ETX:
  445.         return("ETX");
  446.     case EOT:
  447.         return("EOT");
  448.     case ACK:
  449.         return("ACK");
  450.     case NAK:
  451.         return("NAK");
  452.     case CAN:
  453.         return("CAN");
  454.     default:
  455.         sprintf(str,"%02Xh",ch);
  456.         return(str); }
  457. }
  458.  
  459. /****************************************************************/
  460. /* Gets the filename from the filename and optional path in buf */
  461. /****************************************************************/
  462. char *justfname(char *buf, char *out)
  463. {
  464.     char *p1,*p2;
  465.  
  466. if(mode&DEBUG)
  467.     lprintf("justfname:  in: '%s'\r\n",buf);
  468. p1=buf;
  469. while(*p1) {
  470.     if((p2=strchr(p1,':'))!=NULL) {      /* Remove path */
  471.         p1=p2+1;
  472.         continue; }
  473.     if((p2=strchr(p1,'/'))!=NULL) {
  474.         p1=p2+1;
  475.         continue; }
  476.     if((p2=strchr(p1,'\\'))!=NULL) {
  477.         p1=p2+1;
  478.         continue; }
  479.     break; }
  480. if(!*p1) {
  481.     lprintf("Invalid filename\r\n");
  482.     strcpy(out,""); }
  483. else
  484.     strcpy(out,p1);                        /* Use just the filename */
  485. if(mode&DEBUG)
  486.     lprintf("justfname: out: '%s'\r\n",out);
  487. return(out);
  488. }
  489.  
  490. /****************************************************************************/
  491. /* Receive a X/Y/Zmodem block (sector) from COM port                        */
  492. /* hdrblock is 1 if attempting to get Ymodem header block, 0 if data block    */
  493. /* Returns 0 if all went well, -1 on error or CAN, and EOT if EOT            */
  494. /****************************************************************************/
  495. int get_block(int hdrblock)
  496. {
  497.     uchar chksum,calc_chksum;
  498.     int i,b,errors,eot=0,can=0;
  499.     uint crc,calc_crc;
  500.  
  501. for(errors=0;errors<MAXERRORS;errors++) {
  502.     i=getcom(10);
  503.     if(eot && i!=EOT)
  504.         eot=0;
  505.     if(can && i!=CAN)
  506.         can=0;
  507.     switch(i) {
  508.         case SOH: /* 128 byte blocks */
  509.             block_size=128;
  510.             break;
  511.         case STX: /* 1024 byte blocks */
  512.             block_size=1024;
  513.             break;
  514.         case EOT:
  515.             if((mode&(YMODEM|GMODE))==YMODEM && !eot) {
  516.                 eot=1;
  517.                 put_nak();        /* chuck's double EOT trick */
  518.                 continue; }
  519.             return(EOT);
  520.         case CAN:
  521.             newline();
  522.             if(!can) {            /* must get two CANs in a row */
  523.                 can=1;
  524.                 lprintf("Received CAN  Expected SOH, STX, or EOT\r\n");
  525.                 continue; }
  526.             lprintf("Cancelled remotely\r\n");
  527.             return(-1);
  528.         case NOINP:     /* Nothing came in */
  529.             continue;
  530.         default:
  531.             newline();
  532.             lprintf("Received %s  Expected SOH, STX, or EOT\r\n",chr(i));
  533.             if(hdrblock)  /* Trying to get Ymodem header block */
  534.                 return(-1);
  535.             put_nak();
  536.             continue; }
  537.     i=getcom(1);
  538.     if(i==NOINP) {
  539.         put_nak();
  540.         continue; }
  541.     hdr_block_num=i;
  542.     i=getcom(1);
  543.     if(i==NOINP) {
  544.         put_nak();
  545.         continue; }
  546.     if(hdr_block_num!=(uchar)~i) {
  547.         newline();
  548.         lprintf("Block number error\r\n");
  549.         put_nak();
  550.         continue; }
  551.     calc_crc=calc_chksum=0;
  552.     for(b=0;b<block_size;b++) {
  553.         i=getcom(1);
  554.         if(i==NOINP)
  555.             break;
  556.         block[b]=i;
  557.         if(mode&CRC)
  558.             ucrc16(block[b],&calc_crc);
  559.         else
  560.             calc_chksum+=block[b]; }
  561.  
  562.     if(b<block_size) {
  563.         put_nak();
  564.         continue; }
  565.  
  566.     if(mode&CRC) {
  567.         crc=getcom(1)<<8;
  568.         crc|=getcom(1); }
  569.     else
  570.         chksum=getcom(1);
  571.  
  572.     if(mode&CRC) {
  573.         ucrc16(0,&calc_crc);
  574.         ucrc16(0,&calc_crc);
  575.         if(crc==calc_crc)
  576.             break;
  577.         newline();
  578.         lprintf("CRC error\r\n"); }
  579.  
  580.     else {    /* CHKSUM */
  581.         if(chksum==calc_chksum)
  582.             break;
  583.         newline();
  584.         lprintf("Checksum error\r\n"); }
  585.  
  586.     if(mode&GMODE) {    /* Don't bother sending a NAK. He's not listening */
  587.         cancel();
  588.         bail(1); }
  589.     put_nak(); }
  590.  
  591. if(errors>=MAXERRORS) {
  592.     newline();
  593.     lprintf("Too many errors\r\n");
  594.     return(-1); }
  595. return(0);
  596. }
  597.  
  598. /*****************/
  599. /* Sends a block */
  600. /*****************/
  601. void put_block()
  602. {
  603.     uchar ch,chksum;
  604.     int i;
  605.     uint crc;
  606.  
  607. if(block_size==128)
  608.     putcom(SOH);
  609. else            /* 1024 */
  610.     putcom(STX);
  611. ch=(block_num&0xff);
  612. putcom(ch);
  613. putcom(~ch);
  614. chksum=crc=0;
  615. for(i=0;i<block_size;i++) {
  616.     putcom(block[i]);
  617.     if(mode&CRC)
  618.         ucrc16(block[i],&crc);
  619.     else
  620.         chksum+=block[i]; }
  621.  
  622. if(mode&CRC) {
  623.     ucrc16(0,&crc);
  624.     ucrc16(0,&crc);
  625.     putcom(crc>>8);
  626.     putcom(crc&0xff); }
  627. else
  628.     putcom(chksum);
  629. }
  630.  
  631. /************************************************************/
  632. /* Gets an acknowledgement - usually after sending a block    */
  633. /* Returns 1 if ack received, 0 otherwise.                    */
  634. /************************************************************/
  635. int get_ack()
  636. {
  637.     int i,errors,can=0;
  638.  
  639. for(errors=0;errors<MAXERRORS;errors++) {
  640.  
  641.     if(mode&GMODE) {        /* Don't wait for ACK on Ymodem-G */
  642.         if(incom()==CAN) {
  643.             newline();
  644.             lprintf("Cancelled remotely\r\n");
  645.             cancel();
  646.             bail(1); }
  647.         return(1); }
  648.  
  649.     i=getcom(10);
  650.     if(can && i!=CAN)
  651.         can=0;
  652.     if(i==ACK)
  653.         return(1);
  654.     if(i==CAN) {
  655.         if(can) {
  656.             newline();
  657.             lprintf("Cancelled remotely\r\n");
  658.             cancel();
  659.             bail(1); }
  660.         can=1; }
  661.     if(i!=NOINP) {
  662.         newline();
  663.         lprintf("Received %s  Expected ACK\r\n",chr(i));
  664.         if(i!=CAN)
  665.             return(0); } }
  666.  
  667. return(0);
  668. }
  669.  
  670. /****************************************************************************/
  671. /* Syncronizes the remote and local machines                                */
  672. /****************************************************************************/
  673. void riosync()
  674. {
  675.     int     i=0;
  676.  
  677. while(rioctl(TXBC) && i<180) { /* 10 sec */
  678.     if(!(mode&NO_LOCAL) && lkbrd(0)==LOC_ABORT) {
  679.         newline();
  680.         lprintf("Local abort\r\n");
  681.         cancel();
  682.         break; }
  683.     if(!DCDHIGH)
  684.         break;
  685.     mswait(1);
  686.     i++; }
  687. }
  688.  
  689. /*********************************************************/
  690. /* Returns the number of blocks required to send n bytes */
  691. /*********************************************************/
  692. long blocks(long n)
  693. {
  694.     long l;
  695.  
  696. l=n/(long)block_size;
  697. if(l*(long)block_size<n)
  698.     l++;
  699. return(l);
  700. }
  701.  
  702. /****************************************/
  703. /* Zmodem specific functions start here */
  704. /****************************************/
  705.  
  706. /**********************************************/
  707. /* Output single byte as two hex ASCII digits */
  708. /**********************************************/
  709. void putzhex(uchar val)
  710. {
  711.     char *digits="0123456789abcdef";
  712.  
  713. putcom(digits[(val&0xF0)>>4]);
  714. putcom(digits[val&0xF]);
  715. }
  716.  
  717. /***********************/
  718. /* Output a hex header */
  719. /***********************/
  720. void putzhhdr(char type)
  721. {
  722.     uint i,crc=0;
  723.  
  724. putcom(ZPAD);
  725. putcom(ZPAD);
  726. putcom(ZDLE);
  727. if(zmode&VAR_HDRS) {
  728.     putcom(ZVHEX);
  729.     putzhex(4); }
  730. else
  731.     putcom(ZHEX);
  732. putzhex(type);
  733. ucrc16(type,&crc);
  734. for(i=0;i<4;i++) {
  735.     putzhex(Txhdr[i]);
  736.     ucrc16(Txhdr[i],&crc); }
  737. ucrc16(0,&crc);
  738. ucrc16(0,&crc);
  739. putzhex(crc>>8);
  740. putzhex(crc&0xff);
  741. putcom(CR);
  742. putcom(LF);     /* Chuck's RZ.C sends LF|0x80 for some unknown reason */
  743. if(type!=ZFIN && type!=ZACK)
  744.     putcom(XON);
  745. }
  746.  
  747. /****************************************************************************/
  748. /* Stores a long in the Zmodem transmit header (usually position offset)    */
  749. /****************************************************************************/
  750. void ltohdr(long l)
  751. {
  752.  
  753. Txhdr[ZP0] = l;
  754. Txhdr[ZP1] = l>>8;
  755. Txhdr[ZP2] = l>>16;
  756. Txhdr[ZP3] = l>>24;
  757. }
  758.  
  759. /****************************************************************************/
  760. /* Outputs single Zmodem character, escaping with ZDLE when appropriate     */
  761. /****************************************************************************/
  762. void putzcom(uchar ch)
  763. {
  764.     static lastsent;
  765.  
  766. if(ch&0x60) /* not a control char */
  767.     putcom(lastsent=ch);
  768. else
  769.     switch(ch) {
  770.         case DLE:
  771.         case DLE|0x80:          /* even if high-bit set */
  772.         case XON:
  773.         case XON|0x80:
  774.         case XOFF:
  775.         case XOFF|0x80:
  776.         case ZDLE:
  777.             putcom(ZDLE);
  778.             ch^=0x40;
  779.             putcom(lastsent=ch);
  780.             break;
  781.         case CR:
  782.         case CR|0x80:
  783.             if(!(zmode&CTRL_ESC) && (lastsent&0x7f)!='@')
  784.                 putcom(lastsent=ch);
  785.             else {
  786.                 putcom(ZDLE);
  787.                 ch^=0x40;
  788.                 putcom(lastsent=ch); }
  789.             break;
  790.         default:
  791.             if(zmode&CTRL_ESC && !(ch&0x60)) {  /* it's a ctrl char */
  792.                 putcom(ZDLE);
  793.                 ch^=0x40; }
  794.             putcom(lastsent=ch);
  795.             break; }
  796. }
  797.  
  798. /*
  799.  * Read a byte, checking for ZMODEM escape encoding
  800.  *  including CAN*5 which represents a quick abort
  801.  */
  802. int getzcom()
  803. {
  804.     int i;
  805.  
  806. while(1) {
  807.     /* Quick check for non control characters */
  808.     if((i=getcom(Rxtimeout))&0x60)
  809.         return(i);
  810.     if(i==ZDLE)
  811.         break;
  812.     if((i&0x7f)==XOFF || (i&0x7f)==XON)
  813.         continue;
  814.     if(zmode&CTRL_ESC && !(i&0x60))
  815.         continue;
  816.     return(i); }
  817.  
  818. while(1) {    /* Escaped characters */
  819.     if((i=getcom(Rxtimeout))<0)
  820.         return(i);
  821.     if(i==CAN && (i=getcom(Rxtimeout))<0)
  822.         return(i);
  823.     if(i==CAN && (i=getcom(Rxtimeout))<0)
  824.         return(i);
  825.     if(i==CAN && (i=getcom(Rxtimeout))<0)
  826.         return(i);
  827.     switch (i) {
  828.         case CAN:
  829.             return(GOTCAN);
  830.         case ZCRCE:
  831.         case ZCRCG:
  832.         case ZCRCQ:
  833.         case ZCRCW:
  834.             return(i|GOTOR);
  835.         case ZRUB0:
  836.             return(0x7f);
  837.         case ZRUB1:
  838.             return(0xff);
  839.         case XON:
  840.         case XON|0x80:
  841.         case XOFF:
  842.         case XOFF|0x80:
  843.             continue;
  844.         default:
  845.             if (zmode&CTRL_ESC && !(i&0x60))
  846.                 continue;
  847.             if ((i&0x60)==0x40)
  848.                 return(i^0x40);
  849.             break; }
  850.     break; }
  851. return(ERROR);
  852. }
  853.  
  854.  
  855.  
  856. /*
  857.  * Read a character from the modem line with timeout.
  858.  *  Eat parity, XON and XOFF characters.
  859.  */
  860. int getcom7()
  861. {
  862.     int i;
  863.  
  864. while(1) {
  865.     i=getcom(10);
  866.     switch(i) {
  867.         case XON:
  868.         case XOFF:
  869.             continue;
  870.         case CR:
  871.         case LF:
  872.         case NOINP:
  873.         case ZDLE:
  874.             return(i);
  875.         default:
  876.             if(!(i&0x60) && zmode&CTRL_ESC)
  877.                 continue;
  878.             return(i); } }
  879. }
  880.  
  881.  
  882. #if 0
  883.  
  884. int getzhdr()
  885. {
  886.     int done=0;
  887.  
  888. while(!done) {
  889.     i=getcom(10);
  890.     switch(i) {
  891.         case NOINP:
  892.             done=1;
  893.             continue;
  894.         case XON:
  895.         case XON|0x80:
  896.             continue;
  897.         case ZPAD|0x80:
  898.         case ZPAD:
  899.             break;
  900.         case CAN:
  901.             cancount++;
  902.             if(cancount>=5) {
  903.                 i=ZCAN;
  904.                 done=1;
  905.                 break; }
  906.             i=getcom(10);
  907.             switch(i) {
  908.                 case NOINP:
  909.                     continue;
  910.                 case ZCRCW:
  911.                     switch(getcom(10)) {
  912.                         case NOINP:
  913.                             i=ERROR
  914.                             done=1;
  915.                             break;
  916.                         case RCDO:
  917.                             done=1;
  918.                             break;
  919.                         default:
  920.                             continue; }
  921.                     break;
  922.                 case RCDO:
  923.                     done=1;
  924.                     break;
  925.                 case CAN:
  926.                     cancount++;
  927.                     if(cancount>=5) {
  928.                         i=ZCAN;
  929.                         done=1;
  930.                     continue;
  931.                 default:
  932.                     break; }
  933.             continue;
  934.         default:
  935.             continue; }
  936.  
  937.     i=Rxframeind=getcom7();
  938.     switch (i) {
  939.         case ZVBIN32:
  940.             if((Rxhlen=c=getzcom())<0)
  941.                 goto fifi;
  942.             if(c>ZMAXHLEN)
  943.                 goto agn2;
  944.             Crc32r=1;
  945.             c=zrbhd32(hdr);
  946.             break;
  947.         case ZBIN32:
  948.             if(zmode&VAR_HDRS)
  949.                 goto agn2;
  950.             Crc32r=1;
  951.             c=zrbhd32(hdr);
  952.             break;
  953.         case ZVBINR32:
  954.             if((Rxhlen=c=getzcom())<0)
  955.                 goto fifi;
  956.             if(c>ZMAXHLEN)
  957.                 goto agn2;
  958.             Crc32r=2;
  959.             c=zrbhd32(hdr);
  960.             break;
  961.         case ZBINR32:
  962.             if(zmode&VAR_HDRS)
  963.                 goto agn2;
  964.             Crc32r=2;
  965.             c=zrbhd32(hdr);
  966.             break;
  967.         case RCDO:
  968.         case TIMEOUT:
  969.             goto fifi;
  970.         case ZVBIN:
  971.             if((Rxhlen=c=getzcom())<0)
  972.                 goto fifi;
  973.             if(c>ZMAXHLEN)
  974.                 goto agn2;
  975.             Crc32r=0;
  976.             c=zrbhdr(hdr);
  977.             break;
  978.         case ZBIN:
  979.             if(zmode&VAR_HDRS)
  980.                 goto agn2;
  981.             Crc32r=0;
  982.             c=zrbhdr(hdr);
  983.             break;
  984.         case ZVHEX:
  985.             if((Rxhlen=c=zgethex()) < 0)
  986.                 goto fifi;
  987.             if(c>ZMAXHLEN)
  988.                 goto agn2;
  989.             Crc32r=0;
  990.             c=zrhhdr(hdr);
  991.             break;
  992.         case ZHEX:
  993.             if(zmode&VAR_HDRS)
  994.                 goto agn2;
  995.             Crc32r=0;
  996.             c=zrhhdr(hdr);
  997.             break;
  998.         case CAN:
  999.             goto gotcan;
  1000.         default:
  1001.             goto agn2;
  1002.         }
  1003.  
  1004.  
  1005.  
  1006. /****************************************************************************/
  1007. /* Get the receiver's init parameters                                       */
  1008. /****************************************************************************/
  1009. int getzrxinit()
  1010. {
  1011.     int i;
  1012.     struct stat f;
  1013.  
  1014. for(i=0;i<10;i++) {
  1015.     switch(zgethdr(Rxhdr,1)) {
  1016.         case ZCHALLENGE:    /* Echo receiver's challenge numbr */
  1017.             ltohdr(Rxpos);
  1018.             putzhhdr(ZACK);
  1019.             continue;
  1020.         case ZCOMMAND:        /* They didn't see out ZRQINIT */
  1021.             ltohdr(0L);
  1022.             putzhhdr(ZRQINIT);
  1023.             continue;
  1024.         case ZRINIT:
  1025.             Rxflags=Rxhdr[ZF0]&0x7f;
  1026.             if(Rxhdr[ZF1]&CANVHDR)
  1027.                 zmode|=VAR_HDRS;
  1028.             Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32));
  1029.             Zctlesc |= Rxflags & TESCCTL;
  1030.             Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8);
  1031.             if ( !(Rxflags & CANFDX))
  1032.                 Txwindow = 0;
  1033.  
  1034.             /* Override to force shorter frame length */
  1035.             if (Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=32))
  1036.                 Rxbuflen = Tframlen;
  1037.             if ( !Rxbuflen && (Tframlen>=32) && (Tframlen<=1024))
  1038.                 Rxbuflen = Tframlen;
  1039.             vfile("Rxbuflen=%d", Rxbuflen);
  1040.  
  1041.             /*
  1042.              * If input is not a regular file, force ACK's to
  1043.              *    prevent running beyond the buffer limits
  1044.              */
  1045.             if ( !Command) {
  1046.                 fstat(fileno(in), &f);
  1047.                 if ((f.st_mode & S_IFMT) != S_IFREG) {
  1048.                     Canseek = -1;
  1049.     ef TXBSIZE
  1050.                     Txwindow = TXBSIZE - 1024;
  1051.                     Txwspac = TXBSIZE/4;
  1052.     e
  1053.                     return ERROR;
  1054.     if
  1055.                 }
  1056.             }
  1057.  
  1058.             /* Set initial subpacket length */
  1059.             if (blklen < 1024) {    /* Command line override? */
  1060.                 if (Effbaud > 300)
  1061.                     blklen = 256;
  1062.                 if (Effbaud > 1200)
  1063.                     blklen = 512;
  1064.                 if (Effbaud > 2400)
  1065.                     blklen = 1024;
  1066.             }
  1067.             if (Rxbuflen && blklen>Rxbuflen)
  1068.                 blklen = Rxbuflen;
  1069.             if (blkopt && blklen > blkopt)
  1070.                 blklen = blkopt;
  1071.             vfile("Rxbuflen=%d blklen=%d", Rxbuflen, blklen);
  1072.             vfile("Txwindow = %u Txwspac = %d", Txwindow, Txwspac);
  1073.  
  1074.  
  1075.             if (Lztrans == ZTRLE && (Rxflags & CANRLE))
  1076.                 Txfcs32 = 2;
  1077.             else
  1078.                 Lztrans = 0;
  1079.  
  1080.             return (sendzsinit());
  1081.         case ZCAN:
  1082.         case TIMEOUT:
  1083.             return ERROR;
  1084.         case ZRQINIT:
  1085.             if (Rxhdr[ZF0] == ZCOMMAND)
  1086.                 continue;
  1087.         default:
  1088.             putzhhdr(ZNAK);
  1089.             continue; } }
  1090. return(ERROR);
  1091. }
  1092.  
  1093.  
  1094. getzdata(char *buf, int length)
  1095. {
  1096.     int c,d;
  1097.     uint crc;
  1098.     char *end;
  1099.  
  1100.     switch (Crc32r) {
  1101.     case 1:
  1102.         return zrdat32(buf, length);
  1103.     case 2:
  1104.         return zrdatr32(buf, length);
  1105.     }
  1106.  
  1107.     crc = Rxcount = 0;  end = buf + length;
  1108.     while (buf <= end) {
  1109.         if ((c = getzcom()) & ~0377) {
  1110. crcfoo:
  1111.             switch (c) {
  1112.             case GOTCRCE:
  1113.             case GOTCRCG:
  1114.             case GOTCRCQ:
  1115.             case GOTCRCW:
  1116.                 crc = updcrc((d=c)&0377, crc);
  1117.                 if ((c = getzcom()) & ~0377)
  1118.                     goto crcfoo;
  1119.                 crc = updcrc(c, crc);
  1120.                 if ((c = getzcom()) & ~0377)
  1121.                     goto crcfoo;
  1122.                 crc = updcrc(c, crc);
  1123.                 if (crc & 0xFFFF) {
  1124.                     zperr(badcrc);
  1125.                     return ERROR;
  1126.                 }
  1127.                 Rxcount = length - (end - buf);
  1128. #ifndef DSZ
  1129.                 vfile("zrdata: %d  %s", Rxcount,
  1130.                  Zendnames[d-GOTCRCE&3]);
  1131. #endif
  1132.                 return d;
  1133.             case GOTCAN:
  1134.                 zperr("Sender Canceled");
  1135.                 return ZCAN;
  1136.             case TIMEOUT:
  1137.                 zperr("TIMEOUT");
  1138.                 return c;
  1139.             default:
  1140.                 garbitch(); return c;
  1141.             }
  1142.         }
  1143.         *buf++ = c;
  1144.         crc = updcrc(c, crc);
  1145.     }
  1146. #ifdef DSZ
  1147.     garbitch(); 
  1148. #else
  1149.     zperr("Data subpacket too long");
  1150. #endif
  1151.     return ERROR;
  1152. }
  1153.  
  1154. #endif
  1155.  
  1156. /************************************************/
  1157. /* Dump the current blockm contents - for debug */
  1158. /************************************************/
  1159. void dump_block()
  1160. {
  1161.     long l;
  1162.  
  1163. for(l=0;l<block_size;l++)
  1164.     lprintf("%02X  ",block[l]);
  1165. lputs("\r\n");
  1166. }
  1167.  
  1168. char    *usage=
  1169. "usage: STP <port> [chan] [opts] <cmd> [file | path | +list]\r\n\r\n"
  1170. "where:\r\n\r\n"
  1171. "port   = COM port (1-4), D for DigiBoard, or UART I/O address (hex)\r\n"
  1172. "chan   = IRQ channel (2-15) or DigiBoard channel (4+)\r\n"
  1173. "opts   = b# to set DTE rate to #bps\r\n"
  1174. "         t# to set time-slice API type (default=1)\r\n"
  1175. "         o  to overwrite files when receiving\r\n"
  1176. "         d  to disable dropped carrier detection\r\n"
  1177. "         a  to sound alarm at start and stop of transfer\r\n"
  1178. "         l  to disable local keyboard (Ctrl-C) checking\r\n"
  1179. "cmd    = sx to send Xmodem     rx to recv Xmodem\r\n"
  1180. "         sX to send Xmodem-1k  rc to recv Xmodem-CRC\r\n"
  1181. "         sy to send Ymodem     ry to recv Ymodem\r\n"
  1182. "         sY to send Ymodem-1k  rg to recv Ymodem-G\r\n"
  1183. "         sz to send Zmodem     rz to recv Zmodem\r\n"
  1184. "file   = filename to send or receive\r\n"
  1185. "path   = path to receive files into\r\n"
  1186. "list   = name of text file with list of filenames to send or receive\r\n";
  1187.  
  1188. /***************/
  1189. /* Entry Point */
  1190. /***************/
  1191. int main(int argc, char **argv)
  1192. {
  1193.     char    str[256],tmp[256],tmp2[256],irq,errors,*p,*p2,first_block
  1194.             ,*fname[MAX_FNAMES],fnames=0,fnum,success;
  1195.     int     ch,i,j,k,file,last,total_files=0,sent_files=0,can;
  1196.     uint    base=0,baud=0,cps;
  1197.     long    b,l,m,file_bytes_left,serial_num;
  1198.     ulong    file_bytes=0,total_bytes=0,sent_bytes=0;
  1199.     time_t    t,startall,startfile,ftime;
  1200.     struct    ffblk ff;
  1201.     struct    ftime ft;
  1202.     struct    date dosdate;
  1203.     struct    time dostime;
  1204.     FILE    *stream,*log=NULL;
  1205.  
  1206. mswtyp=TS_INT28;   /* default to int 28 only */
  1207.  
  1208. ctrlbrk(cbreakh);
  1209.  
  1210. if((asmrev=*(&riobp-1))!=19) {
  1211.     printf("Wrong rciol.obj\n");
  1212.     exit(1); }
  1213.  
  1214. lclini(0xd<<8);
  1215.  
  1216. lprintf("\r\nSynchronet Transfer Protocols v1.00"
  1217.     "  Developed 1993-1997 Rob Swindell\r\n\r\n");
  1218.  
  1219. lputs("Command line: ");
  1220. for(i=1;i<argc;i++)
  1221.     lprintf("%s ",argv[i]);
  1222. lputs("\r\n");
  1223.  
  1224. if(argc<3) {
  1225.     lprintf(usage);
  1226.     exit(1); }
  1227.  
  1228. i=1;
  1229.  
  1230. base=ahtoul(argv[i]);
  1231. if(base>4 && base<0x100)    /* 'D' and 'FFFF' are the same */
  1232.     base=0xffff;
  1233. if(base!=0xffff && base<5)
  1234.     switch(atoi(argv[i])) {
  1235.         case 1:
  1236.             base=0x3f8;
  1237.             irq=4;
  1238.             break;
  1239.         case 2:
  1240.             base=0x2f8;
  1241.             irq=3;
  1242.             break;
  1243.         case 3:
  1244.             base=0x3e8;
  1245.             irq=4;
  1246.             break;
  1247.         case 4:
  1248.             base=0x2e8;
  1249.             irq=3;
  1250.             break;
  1251.         default:
  1252.             lprintf("Invalid COM Port (%s)\r\n",argv[1]);
  1253.             lprintf(usage);
  1254.             exit(1); }
  1255.  
  1256. if(base>4 || isdigit(argv[i+1][0]))
  1257.     irq=atoi(argv[++i]);
  1258.  
  1259. for(i++;i<argc;i++) {
  1260.  
  1261.     if(!(mode&(SEND|RECV))) {
  1262.         if(toupper(argv[i][0])=='S' || toupper(argv[i][0])=='R') { /* cmd */
  1263.             if(toupper(argv[i][0])=='R')
  1264.                 mode|=RECV;
  1265.             else
  1266.                 mode|=SEND;
  1267.  
  1268.             block_size=1024;
  1269.  
  1270.             switch(argv[i][1]) {
  1271.                 case 'c':
  1272.                 case 'C':
  1273.                     mode|=CRC;
  1274.                 case 'x':
  1275.                     block_size=128;
  1276.                 case 'X':
  1277.                     mode|=XMODEM;
  1278.                     break;
  1279.                 case 'y':
  1280.                     block_size=128;
  1281.                 case 'Y':
  1282.                     mode|=(YMODEM|CRC);
  1283.                     break;
  1284.                 case 'g':
  1285.                 case 'G':
  1286.                     mode|=(YMODEM|CRC|GMODE);
  1287.                     break;
  1288.                 case 'z':
  1289.                 case 'Z':
  1290.                     mode|=(ZMODEM|CRC);
  1291.                     break;
  1292.                 default:
  1293.                     lprintf("Unrecognized command '%s'\r\n\r\n",argv[i]);
  1294.                     lprintf(usage);
  1295.                     exit(1); } }
  1296.  
  1297.         else if(toupper(argv[i][0])=='B')
  1298.             baud=atoi(argv[i]+1);
  1299.  
  1300.         else if(toupper(argv[i][0])=='T')
  1301.             mswtyp=atoi(argv[i]+1);
  1302.  
  1303.         else if(toupper(argv[i][0])=='O')
  1304.             mode|=OVERWRITE;
  1305.  
  1306.         else if(toupper(argv[i][0])=='D')
  1307.             mode|=IGNORE_DCD;
  1308.  
  1309.         else if(toupper(argv[i][0])=='A')
  1310.             mode|=ALARM;
  1311.  
  1312.         else if(toupper(argv[i][0])=='L')
  1313.             mode|=NO_LOCAL;
  1314.  
  1315.         else if(argv[i][0]=='*')
  1316.             mode|=DEBUG; }
  1317.  
  1318.     else if(argv[i][0]=='+') {
  1319.         if(mode&DIR) {
  1320.             lprintf("Cannot specify both directory and filename\r\n");
  1321.             exit(1); }
  1322.         sprintf(str,"%s",argv[i]+1);
  1323.         if((file=nopen(str,O_RDONLY))==-1
  1324.             || (stream=fdopen(file,"rb"))==NULL) {
  1325.             lprintf("Error opening filelist %s\r\n",str);
  1326.             exit(1); }
  1327.         while(!feof(stream) && !ferror(stream) && fnames<MAX_FNAMES) {
  1328.             if(!fgets(str,128,stream))
  1329.                 break;
  1330.             truncsp(str);
  1331.             strupr(str);
  1332.             if((fname[fnames]=(char *)malloc(strlen(str)+1))==NULL) {
  1333.                 lprintf("Error allocating memory for filename\r\n");
  1334.                 exit(1); }
  1335.             strcpy(fname[fnames++],str); }
  1336.         fclose(stream); }
  1337.  
  1338.     else if(mode&(SEND|RECV)){
  1339.         if((fname[fnames]=(char *)malloc(128))==NULL) {
  1340.             lprintf("Error allocating memory for filename\r\n");
  1341.             exit(1); }
  1342.         strcpy(fname[fnames],argv[i]);
  1343.         strupr(fname[fnames]);
  1344.         j=strlen(fname[fnames]);
  1345.         if(fname[fnames][j-1]=='\\'                 /* Ends in \ */
  1346.             || !strcmp(fname[fnames]+1,":")) {      /* Drive letter only */
  1347. /*              || !findfirst(fname[fnames],&ff,FA_DIREC)) {      is a directory */
  1348.             if(mode&DIR) {
  1349.                 lprintf("Only one directory can be specified\r\n");
  1350.                 exit(1); }
  1351.             if(fnames) {
  1352.                 lprintf("Cannot specify both directory and filename\r\n");
  1353.                 exit(1); }
  1354.             if(mode&SEND) {
  1355.                 lprintf("Cannot send directory '%s'\r\n",fname[fnames]);
  1356.                 exit(1);}
  1357.             mode|=DIR; }
  1358.         fnames++; } }
  1359.  
  1360. if(!(mode&(SEND|RECV))) {
  1361.     lprintf("No command specified\r\n");
  1362.     lprintf(usage);
  1363.     exit(1); }
  1364.  
  1365. if(mode&(SEND|XMODEM) && !fnames) { /* Sending with any or recv w/Xmodem */
  1366.     lprintf("Must specify filename or filelist\r\n");
  1367.     lprintf(usage);
  1368.     exit(1); }
  1369.  
  1370. i=strlen(fname[0]);     /* Make sure the directory ends in \ or : */
  1371. if(mode&DIR && fname[0][i-1]!='\\' && fname[0][i-1]!=':')
  1372.     strcat(fname[0],"\\");
  1373.  
  1374. i=rioini(base,irq);
  1375. if(i) {
  1376.     lprintf("STP: Error (%d) initializing COM port base %x irq %d\r\n"
  1377.         ,i,base,irq);
  1378.     exit(1); }
  1379.  
  1380. if(mode&ALARM) {
  1381.     sound(1000);
  1382.     mswait(500);
  1383.     sound(2000);
  1384.     mswait(500);
  1385.     nosound(); }
  1386.  
  1387. if(baud) {
  1388.     i=setbaud(baud);
  1389.     if(i) {
  1390.         lprintf("STP: Error setting baud rate to %u\r\n",baud);
  1391.         bail(1); } }
  1392. else
  1393.     baud=rioctl(GBAUD);
  1394.  
  1395. rioctl(IOSM|CTSCK|RTSCK);
  1396.  
  1397. rioctl(TSTYPE|mswtyp);            /* set time-slice API type */
  1398.  
  1399. if(!DCDHIGH) {
  1400.     newline();
  1401.     lprintf("No carrier\r\n");
  1402.     bail(1); }
  1403.  
  1404. p=getenv("DSZLOG");
  1405. if(p) {
  1406.     if((file=open(p,O_WRONLY|O_BINARY|O_CREAT,S_IWRITE|S_IREAD))==-1
  1407.         || (log=fdopen(file,"wb"))==NULL) {
  1408.         lprintf("Error opening DSZLOG file '%s'\r\n",p);
  1409.         bail(1); }
  1410.     setvbuf(log,NULL,_IOFBF,16*1024); }
  1411.  
  1412. startall=time(NULL);
  1413.  
  1414. if(mode&RECV) {
  1415.     if(fnames>1)
  1416.         lprintf("Receiving %u files\r\n",fnames);
  1417.     fnum=0;
  1418.     while(1) {
  1419.         if(mode&XMODEM) {
  1420.             strcpy(str,fname[0]);
  1421.             file_bytes=file_bytes_left=0x7fffffff;
  1422.             serial_num=-1; }
  1423.  
  1424.         else if(mode&YMODEM) {
  1425.             lprintf("Fetching Ymodem header block\r\n");
  1426.             for(errors=0;errors<MAXERRORS;errors++) {
  1427.                 if(errors>3 && mode&CRC && !(mode&GMODE))
  1428.                     mode&=~CRC;
  1429.                 if(mode&GMODE)        /* G for Ymodem-G */
  1430.                     putcom('G');
  1431.                 else if(mode&CRC)    /* C for CRC */
  1432.                     putcom('C');
  1433.                 else                /* NAK for checksum */
  1434.                     putcom(NAK);
  1435.                 for(i=60;i;i--) {
  1436.                     if(rioctl(RXBC))    /* no chars in-bound */
  1437.                         break;
  1438.                     mswait(100); }        /* so wait */
  1439.  
  1440.                 if(!i) {                /* none after 6 secs */
  1441.                     if(errors)
  1442.                         lprintf("Ymodem header timeout (%d)\r\n",errors);
  1443.                     continue; }
  1444.                 if(!get_block(1)) {      /* block received successfully */
  1445.                     putcom(ACK);
  1446.                     break; } }
  1447.             if(errors==MAXERRORS) {
  1448.                 lprintf("Error fetching Ymodem header block\r\n");
  1449.                 cancel();
  1450.                 bail(1); }
  1451.             if(!block[0]) {
  1452.                 lputs("Received Ymodem termination block\r\n");
  1453.                 bail(0); }
  1454.             p=block+strlen(block)+1;
  1455.             sscanf(p,"%ld %lo %lo %lo %d %ld"
  1456.                 ,&file_bytes            /* file size (decimal) */
  1457.                 ,&ftime                 /* file time (octal unix format) */
  1458.                 ,&m                     /* file mode (not used) */
  1459.                 ,&serial_num            /* program serial number */
  1460.                 ,&total_files            /* remaining files to be sent */
  1461.                 ,&total_bytes            /* remaining bytes to be sent */
  1462.                 );
  1463.             if(!file_bytes)
  1464.                 file_bytes=0x7fffffff;
  1465.             file_bytes_left=file_bytes;
  1466.             if(!total_files)
  1467.                 total_files=fnames-fnum;
  1468.             if(!total_files)
  1469.                 total_files=1;
  1470.             if(total_bytes<file_bytes)
  1471.                 total_bytes=file_bytes;
  1472.             if(!serial_num)
  1473.                 serial_num=-1;
  1474.             strupr(block);
  1475.             lprintf("Incoming filename: %.64s ",block);
  1476.             if(mode&DIR)
  1477.                 sprintf(str,"%s%s",fname[0],justfname(block,tmp));
  1478.             else {
  1479.                 justfname(block,str);
  1480.                 for(i=0;i<fnames;i++) {
  1481.                     if(!fname[i][0])    /* name blank or already used */
  1482.                         continue;
  1483.                     justfname(fname[i],tmp);
  1484.                     if(!stricmp(tmp,str)) {
  1485.                         strcpy(str,fname[i]);
  1486.                         fname[i][0]=0;
  1487.                         break; } }
  1488.                 if(i==fnames) {                 /* Not found in list */
  1489.                     if(fnames)
  1490.                         lputs(" - Not in receive list!");
  1491.                     if(!fnames || fnum>=fnames || !fname[fnum][0])
  1492.                         justfname(block,str);    /* worst case */
  1493.                     else {
  1494.                         strcpy(str,fname[fnum]);
  1495.                         fname[fnum][0]=0; } } }
  1496.             lputs("\r\n"); }
  1497.  
  1498.         else {    /* Zmodem */
  1499. #if 0
  1500.             tryzhdrtype=ZRINIT;
  1501.             while(1) {
  1502.                 Txhdr[ZF0]=(CANFC32|CANFDX|CANOVIO|CANRLE);
  1503.                 /* add CANBRK if we can send break signal */
  1504.                 if(zmode&CTRL_ESC)
  1505.                     Txhdr[ZF0]|=TESCCTL;
  1506.                 Txhdr[ZF1]=CANVHDR;
  1507.                 Txhdr[ZP0]=0;
  1508.                 Txhdr[ZP1]=0;
  1509.                 putzhhdr(tryzhdrtype);
  1510.                 done=0;
  1511.                 while(!done) {
  1512.                     done=1;
  1513.                     switch(getzhdr()) {
  1514.                         case ZRQINIT:
  1515.                             if(Rxhdr[ZF3]&0x80)
  1516.                                 zmode|=VAR_HDRS;   /* we can var header */
  1517.                             break;
  1518.                         case ZFILE:
  1519.                             zconv=Rxhdr[ZF0];
  1520.                             zmanag=Rxhdr[ZF1];
  1521.                             ztrans=Rxhdr[ZF2];
  1522.                             if(Rxhdr[ZF3]&ZCANVHDR)
  1523.                                 zmode|=VAR_HDRS;
  1524.                             tryzhdrtype=ZRINIT;
  1525.                             if(getzdata(block, 1024)==GOTCRCW) {
  1526.                                 /* something */
  1527.                                 done=1; }
  1528.                             putzhhdr(ZNAK);
  1529.                             done=0;
  1530.                             break;
  1531.                         case ZSINIT:
  1532.                             if(Rxhdr[ZF0]&TESCCTL)
  1533.                                 zmode|=CTRL_ESC;
  1534.                             if (getzdata(attn,ZATTNLEN)==GOTCRCW) {
  1535.                                 ltohdr(1L);
  1536.                                 putzhhdr(ZACK); }
  1537.                             else
  1538.                                 putzhhdr(ZNAK);
  1539.                             done=0;
  1540.                             break;
  1541.                         case ZFREECNT:
  1542.                             ltohdr(0);            /* should be free disk space */
  1543.                             putzhhdr(ZACK);
  1544.                             done=0;
  1545.                             break;
  1546.                         case ZCOMMAND:
  1547. /***
  1548.                             cmdzack1flg = Rxhdr[ZF0];
  1549.                             if(getzdata(block,1024)==GOTCRCW) {
  1550.                                 if (cmdzack1flg & ZCACK1)
  1551.                                     ltohdr(0L);
  1552.                                 else
  1553.                                     ltohdr((long)sys2(block));
  1554.                                 purgeline();    /* dump impatient questions */
  1555.                                 do {
  1556.                                     zshhdr(4,ZCOMPL, Txhdr);
  1557.                                 }
  1558.                                 while (++errors<20 && zgethdr(Rxhdr,1)!=ZFIN);
  1559.                                 ackbibi();
  1560.                                 if (cmdzack1flg & ZCACK1)
  1561.                                     exec2(block);
  1562.                                 return ZCOMPL;
  1563.                             }
  1564. ***/
  1565.                             putzhhdr(ZNAK);
  1566.                             done=0;
  1567.                             break;
  1568.                         case ZCOMPL:
  1569.                             done=0;
  1570.                             break;
  1571.                         case ZFIN:
  1572.                             ackbibi();
  1573.                             return ZCOMPL;
  1574.                         case ZCAN:
  1575.                             return ERROR; } }
  1576. #endif
  1577.             }
  1578.  
  1579.         fnum++;
  1580.  
  1581.         if(!(mode&DIR) && fnames && fnum>fnames) {
  1582.             newline();
  1583.             lprintf("Attempt to send more files than specified\r\n");
  1584.             cancel();
  1585.             break; }
  1586.  
  1587.         k=strlen(str);    /* strip out control characters and high ASCII */
  1588.         for(i=j=0;i<k;i++)
  1589.             if(str[i]>SP && (uchar)str[i]<0x7f)
  1590.                 str[j++]=str[i];
  1591.         str[j]=0;
  1592.         strupr(str);
  1593.         if(fexist(str) && !(mode&OVERWRITE)) {
  1594.             lprintf("%s already exists\r\n",str);
  1595.             cancel();
  1596.             bail(1); }
  1597.         if((file=nopen(str,O_WRONLY|O_CREAT|O_TRUNC))==-1
  1598.             || (stream=fdopen(file,"wb"))==NULL) {
  1599.             lprintf("Error creating %s\r\n",str);
  1600.             cancel();
  1601.             bail(1); }
  1602.         setvbuf(stream,NULL,_IOFBF,8*1024);
  1603.         startfile=time(NULL);
  1604.         lprintf("Receiving %s (%lu bytes) via %s %s\r\n"
  1605.             ,str
  1606.             ,mode&XMODEM ? 0 : file_bytes
  1607.             ,mode&XMODEM ? "Xmodem" : mode&YMODEM ? mode&GMODE ? "Ymodem-G"
  1608.             : "Ymodem" :"Zmodem"
  1609.             ,mode&CRC ? "CRC-16":"Checksum");
  1610.  
  1611.         errors=0;
  1612.         block_num=0;
  1613.         if(mode&GMODE)        /* G for Ymodem-G */
  1614.             putcom('G');
  1615.         else if(mode&CRC)    /* C for CRC */
  1616.             putcom('C');
  1617.         else                /* NAK for checksum */
  1618.             putcom(NAK);
  1619.         while(errors<MAXERRORS) {
  1620.             if(block_num && !(mode&GMODE))
  1621.                 putcom(ACK);
  1622.             i=get_block(0);     /* returns 0 if block okay */
  1623.             if(i==EOT)            /* end of transfer */
  1624.                 break;
  1625.             if(i) {             /* other error */
  1626.                 cancel();
  1627.                 bail(1); }
  1628.             if(file_bytes_left<=0L)  { /* No more bytes to send */
  1629.                 newline();
  1630.                 lputs("Attempt to send more than header specified\r\n");
  1631.                 break; }
  1632.             if(hdr_block_num==((block_num+1)&0xff)) {    /* correct block */
  1633.                 block_num++;
  1634.                 if(file_bytes_left<block_size) {
  1635.                     if(fwrite(block,1,file_bytes_left,stream)
  1636.                         !=file_bytes_left) {
  1637.                         newline();
  1638.                         lprintf("Error writing to file\r\n");
  1639.                         cancel();
  1640.                         bail(1); } }
  1641.                 else {
  1642.                     if(fwrite(block,1,block_size,stream)
  1643.                         !=block_size) {
  1644.                         newline();
  1645.                         lprintf("Error writing to file\r\n");
  1646.                         cancel();
  1647.                         bail(1); } }
  1648.                 file_bytes_left-=block_size; }
  1649.             else {
  1650.                 newline();
  1651.                 lprintf("Block number %u instead of %u\r\n"
  1652.                     ,hdr_block_num,(block_num+1)&0xff);
  1653.                 // dump_block();
  1654.                 errors++; }
  1655.             t=time(NULL)-startfile;
  1656.             if(!t) t=1;
  1657.             cps=(uint)((block_num*(long)block_size)/t);     /* cps so far */
  1658.             if(!cps) cps=1;
  1659.             l=file_bytes/cps;  /* total transfer est time */
  1660.             l-=t;                /* now, it's est time left */
  1661.             if(l<0) l=0;
  1662.             b=blocks(file_bytes);
  1663.             if(mode&YMODEM)
  1664.                 lprintf("\rBlock (%lu%s): %lu/%lu  Byte: %lu  Time: %lu:%02lu  "
  1665.                     "Left: %lu:%02lu  CPS: %u  %lu%% "
  1666.                     ,block_size%1024L ? block_size: block_size/1024L
  1667.                     ,block_size%1024L ? "" : "k"
  1668.                     ,block_num
  1669.                     ,b
  1670.                     ,block_num*(long)block_size
  1671.                     ,t/60L
  1672.                     ,t%60L
  1673.                     ,l/60L
  1674.                     ,l%60L
  1675.                     ,cps
  1676.                     ,(long)(((float)block_num/(float)b)*100.0)
  1677.                     );
  1678.             else    /* Xmodem */
  1679.                 lprintf("\rBlock (%lu%s): %lu  Byte: %lu  Time: %lu:%02lu  "
  1680.                     "CPS: %u "
  1681.                     ,block_size%1024L ? block_size: block_size/1024L
  1682.                     ,block_size%1024L ? "" : "k"
  1683.                     ,block_num
  1684.                     ,block_num*(long)block_size
  1685.                     ,t/60L
  1686.                     ,t%60L
  1687.                     ,cps
  1688.                     );
  1689.         }
  1690.  
  1691.         putcom(ACK);
  1692.         if(!(mode&XMODEM) && ftime) {
  1693.             unixtodos(ftime,&dosdate,&dostime);
  1694.             if(dosdate.da_year>=1980) {
  1695.                 ft.ft_min=dostime.ti_min;
  1696.                 ft.ft_hour=dostime.ti_hour;
  1697.                 ft.ft_tsec=dostime.ti_sec/2;
  1698.                 ft.ft_year=dosdate.da_year-1980;
  1699.                 ft.ft_day=dosdate.da_day;
  1700.                 ft.ft_month=dosdate.da_mon;
  1701.                 setftime(file,&ft); } }
  1702.         fclose(stream);
  1703.         t=time(NULL)-startfile;
  1704.         if(!t) t=1;
  1705.         l=(block_num-1)*(long)block_size;
  1706.         if(l>file_bytes)
  1707.             l=file_bytes;
  1708.         newline();
  1709.         lprintf("Successsful - Time: %lu:%02lu  CPS: %lu\r\n"
  1710.             ,t/60,t%60,l/t);
  1711.         if(log) {
  1712.             fprintf(log,"%c %6lu %5u bps %4lu cps %3u errors %5u %4u "
  1713.                 "%s %d\r\n"
  1714.                 ,mode&ZMODEM ? 'Z' : 'R'
  1715.                 ,l
  1716.                 ,baud
  1717.                 ,l/t
  1718.                 ,errors
  1719.                 ,flows
  1720.                 ,block_size
  1721.                 ,str
  1722.                 ,serial_num); }
  1723.         if(mode&XMODEM)
  1724.             break;
  1725.         total_files--;
  1726.         total_bytes-=file_bytes;
  1727.         if(total_files>1 && total_bytes)
  1728.             lprintf("Remaining - Time: %lu:%02lu  Files: %u  Bytes: %lu\r\n"
  1729.                 ,(total_bytes/cps)/60
  1730.                 ,(total_bytes/cps)%60
  1731.                 ,total_files
  1732.                 ,total_bytes
  1733.                 );
  1734.         }
  1735.     bail(0); }
  1736.  
  1737. /********/
  1738. /* SEND */
  1739. /********/
  1740.  
  1741. /****************************************************/
  1742. /* Search through all to find total files and bytes */
  1743. /****************************************************/
  1744. for(fnum=0;fnum<fnames;fnum++) {
  1745.     last=findfirst(fname[fnum],&ff,0);    /* incase wildcards are used */
  1746.     if(last)
  1747.         lprintf("%s not found\r\n",fname[fnum]);
  1748.     while(!last) {
  1749.         total_files++;
  1750.         total_bytes+=ff.ff_fsize;
  1751.         last=findnext(&ff); } }
  1752.  
  1753. if(fnames>1)
  1754.     lprintf("Sending %u files (%lu bytes total)\r\n"
  1755.         ,total_files,total_bytes);
  1756.  
  1757. rioctl(IOFB);
  1758.  
  1759. /***********************************************/
  1760. /* Send every file matching names or filespecs */
  1761. /***********************************************/
  1762. for(fnum=0;fnum<fnames;fnum++) {
  1763.     last=findfirst(fname[fnum],&ff,0);
  1764.     while(!last) {
  1765.         if(mode&ZMODEM) {
  1766. #if 0
  1767.             putcom('r'); putcom('z'); putcom(CR);       /* send rz\r */
  1768.             ltohdr(0L);     /* Zero the header */
  1769.             putzhhdr(ZRQINIT);
  1770.             getzrxinit();
  1771. #endif
  1772.             } /* Zmodem */
  1773.         else {
  1774.             mode&=~GMODE;
  1775.             flows=0;
  1776.             for(errors=can=0;errors<MAXERRORS;errors++) {
  1777.                 i=getcom(10);
  1778.                 if(can && i!=CAN)
  1779.                     can=0;
  1780.                 if(i==NAK) {        /* csum */
  1781.                     mode&=~CRC;
  1782.                     break; }
  1783.                 if(i=='C') {
  1784.                     mode|=CRC;
  1785.                     break; }
  1786.                 if(i=='G') {
  1787.                     mode|=(GMODE|CRC);
  1788.                     break; }
  1789.                 if(i==CAN) {
  1790.                     if(can) {
  1791.                         newline();
  1792.                         lprintf("Cancelled remotely\r\n");
  1793.                         bail(1); }
  1794.                     can=1; }
  1795.                 rioctl(IOFB);    /* flush buffers cause we have crap-o-la */
  1796.                 if(i!=NOINP) {
  1797.                     newline();
  1798.                     lprintf("Received %s  Expected NAK, C, or G\r\n"
  1799.                         ,chr(i)); } }
  1800.             if(errors==MAXERRORS) {
  1801.                 lprintf("Timeout starting transfer\r\n");
  1802.                 cancel();
  1803.                 bail(1); } } /* X/Ymodem */
  1804.  
  1805.         strcpy(str,fname[fnum]);
  1806.         if(strchr(str,'*') || strchr(str,'?')) {    /* wildcards used */
  1807.             p=strrchr(str,'\\');
  1808.             if(!p)
  1809.                 p=strchr(str,':');
  1810.             if(p)
  1811.                 *(p+1)=NULL;
  1812.             else
  1813.                 str[0]=0;
  1814.             strcat(str,ff.ff_name); }
  1815.  
  1816.         lprintf("Sending %s (%lu bytes) via %s %s\r\n"
  1817.             ,str,ff.ff_fsize
  1818.             ,mode&XMODEM ? "Xmodem" : mode&YMODEM ? mode&GMODE ? "Ymodem-G"
  1819.             : "Ymodem" :"Zmodem"
  1820.             ,mode&CRC ? "CRC-16":"Checksum");
  1821.  
  1822.         if((file=nopen(str,O_RDONLY))==-1
  1823.             || (stream=fdopen(file,"rb"))==NULL) {
  1824.             lprintf("Error opening %s for read\r\n",str);
  1825.             cancel();
  1826.             bail(1); }
  1827.         setvbuf(stream,NULL,_IOFBF,8*1024);
  1828.         rioctl(IOFB);    /* flush buffers cause extra 'G', 'C', or NAKs */
  1829.         if(!(mode&XMODEM)) {
  1830.             getftime(file,&ft);
  1831.             dostime.ti_min=ft.ft_min;
  1832.             dostime.ti_hour=ft.ft_hour;
  1833.             dostime.ti_hund=0;
  1834.             dostime.ti_sec=ft.ft_tsec*2;
  1835.             dosdate.da_year=1980+ft.ft_year;
  1836.             dosdate.da_day=ft.ft_day;
  1837.             dosdate.da_mon=ft.ft_month;
  1838.             t=dostounix(&dosdate,&dostime);
  1839.             memset(block,NULL,128);
  1840.             strcpy(block,ff.ff_name);
  1841.             strlwr(block);
  1842.             sprintf(block+strlen(block)+1,"%lu %lo 0 0 %d %ld"
  1843.                 ,ff.ff_fsize,t,total_files-sent_files,total_bytes-sent_bytes);
  1844.             /*
  1845.             lprintf("Sending Ymodem block '%s'\r\n",block+strlen(block)+1);
  1846.             */
  1847.             block_num=0;
  1848.             i=block_size;
  1849.             block_size=128;     /* Always use 128 for first block */
  1850.             for(errors=0;errors<MAXERRORS;errors++) {
  1851.                 put_block();
  1852.                 if(get_ack())
  1853.                     break; }
  1854.             if(errors==MAXERRORS) {
  1855.                 newline();
  1856.                 lprintf("Failed to send header block\r\n");
  1857.                 cancel();
  1858.                 bail(1); }
  1859.             block_size=i;        /* Restore block size */
  1860.             mode&=~GMODE;
  1861.             for(errors=can=0;errors<MAXERRORS;errors++) {
  1862.                 i=getcom(10);
  1863.                 if(can && i!=CAN)
  1864.                     can=0;
  1865.                 if(i==NAK) {        /* csum */
  1866.                     mode&=~CRC;
  1867.                     break; }
  1868.                 if(i=='C') {
  1869.                     mode|=CRC;
  1870.                     break; }
  1871.                 if(i=='G') {
  1872.                     mode|=(GMODE|CRC);
  1873.                     break; }
  1874.                 if(i==CAN) {
  1875.                     if(can) {
  1876.                         newline();
  1877.                         lprintf("Cancelled remotely\r\n");
  1878.                         bail(1); }
  1879.                     can=1; }
  1880.                 rioctl(IOFB);
  1881.                 if(i!=NOINP) {
  1882.                     newline();
  1883.                     lprintf("Received %s  Expected NAK, C, or G\r\n"
  1884.                         ,chr(i)); } }
  1885.             if(errors==MAXERRORS) {
  1886.                 newline();
  1887.                 lprintf("Too many errors waiting for receiver\r\n");
  1888.                 cancel();
  1889.                 bail(1); } }
  1890.         last_block_num=block_num=1;
  1891.         startfile=time(NULL);
  1892.         errors=0;
  1893.         while((block_num-1)*(long)block_size<ff.ff_fsize && errors<MAXERRORS) {
  1894.             if(last_block_num==block_num) {  /* block_num didn't increment */
  1895.                 fseek(stream,(block_num-1)*(long)block_size,SEEK_SET);
  1896.                 i=fread(block,1,block_size,stream);
  1897.                 while(i<block_size)
  1898.                     block[i++]=CPMEOF; }
  1899.             last_block_num=block_num;
  1900.             put_block();
  1901.             i=fread(block,1,block_size,stream); /* read next block from disk */
  1902.             while(i<block_size)
  1903.                 block[i++]=CPMEOF;
  1904.             t=time(NULL)-startfile;
  1905.             if(!t) t=1;         /* t is time so far */
  1906.             cps=(uint)((block_num*(long)block_size)/t);     /* cps so far */
  1907.             if(!cps) cps=1;
  1908.             l=ff.ff_fsize/cps;    /* total transfer est time */
  1909.             l-=t;                /* now, it's est time left */
  1910.             if(l<0) l=0;
  1911.             b=blocks(ff.ff_fsize);
  1912.             lprintf("\rBlock (%lu%s): %lu/%lu  Byte: %lu  "
  1913.                 "Time: %lu:%02lu  Left: %lu:%02lu  CPS: %u  %lu%% "
  1914.                 ,block_size%1024L ? block_size: block_size/1024L
  1915.                 ,block_size%1024L ? "" : "k"
  1916.                 ,block_num
  1917.                 ,b
  1918.                 ,block_num*(long)block_size
  1919.                 ,t/60L
  1920.                 ,t%60L
  1921.                 ,l/60L
  1922.                 ,l%60L
  1923.                 ,cps
  1924.                 ,(long)(((float)block_num/(float)b)*100.0)
  1925.                 );
  1926.             if(!get_ack())
  1927.                 errors++;
  1928.             else
  1929.                 block_num++; }
  1930.         fclose(stream);
  1931.         success=0;
  1932.         if((block_num-1)*(long)block_size>=ff.ff_fsize) {
  1933.             sent_files++;
  1934.             sent_bytes+=ff.ff_fsize;
  1935.             riosync();
  1936.             lprintf("\n");
  1937.  
  1938.             for(i=0;i<10;i++) {
  1939.                 lprintf("\rSending EOT (%d)",i+1);
  1940.                 rioctl(IOFI);
  1941.                 putcom(EOT);
  1942.                 ch=getcom(10);
  1943.                 if(ch==ACK)
  1944.                     break;
  1945.                 if(ch==NAK && i==0 && (mode&(YMODEM|GMODE))==YMODEM)
  1946.                     continue;  /* chuck's double EOT trick so don't complain */
  1947.                 if(ch!=NOINP) {
  1948.                     newline();
  1949.                     lprintf("Received %s  Expected ACK\r\n"
  1950.                         ,chr(ch)); } }
  1951.             if(i==3)
  1952.                 lprintf("\rNo ACK on EOT   \n");
  1953.             t=time(NULL)-startfile;
  1954.             if(!t) t=1;
  1955.             lprintf("\rSuccesssful - Time: %lu:%02lu  CPS: %lu\r\n"
  1956.                 ,t/60,t%60,ff.ff_fsize/t);
  1957.             success=1; }
  1958.         else {
  1959.             newline();
  1960.             lputs("Unsuccessful!\r\n");
  1961.             t=time(NULL)-startfile;
  1962.             if(!t) t=1; }
  1963.  
  1964.         if(total_files>1 && total_files-sent_files>1)
  1965.             lprintf("Remaining - Time: %lu:%02lu  Files: %u  Bytes: %lu\r\n"
  1966.                 ,((total_bytes-sent_bytes)/cps)/60
  1967.                 ,((total_bytes-sent_bytes)/cps)%60
  1968.                 ,total_files-sent_files
  1969.                 ,total_bytes-sent_bytes
  1970.                 );
  1971.         if(log) {
  1972.             l=(block_num-1)*(long)block_size;
  1973.             if(l>ff.ff_fsize)
  1974.                 l=ff.ff_fsize;
  1975.             fprintf(log,"%c %6lu %5u bps %4lu cps %3u errors %5u %4u "
  1976.                 "%s -1\r\n"
  1977.                 ,success ? (mode&ZMODEM ? 'z':'S') : 'E'
  1978.                 ,l
  1979.                 ,baud
  1980.                 ,l/t
  1981.                 ,errors
  1982.                 ,flows
  1983.                 ,block_size
  1984.                 ,fname[fnum]); }
  1985.  
  1986.         last=findnext(&ff); } }
  1987. if(mode&XMODEM)
  1988.     bail(0);
  1989. mode&=~GMODE;
  1990. i=getcom(10);
  1991. if(i==NAK)
  1992.     mode&=~CRC;
  1993. else if(i=='C')
  1994.     mode|=CRC;
  1995. else if(i=='G')
  1996.     mode|=(GMODE|CRC);
  1997. if(i!=NOINP && i!=NAK && i!='C' && i!='G') {
  1998.     newline();
  1999.     lprintf("Received %s  Expected NAK, C, or G\r\n",chr(i)); }
  2000. else if(i!=NOINP) {
  2001.     block_num=0;
  2002.     block[0]=0;
  2003.     block_size=128;
  2004.     put_block();
  2005.     if(!get_ack()) {
  2006.         newline();
  2007.         lprintf("Failed to receive ACK after terminating block\r\n"); } }
  2008. if(total_files>1) {
  2009.     t=time(NULL)-startall;
  2010.     if(!t) t=1;
  2011.     newline();
  2012.     lprintf("Overall - Time %02lu:%02lu  Bytes: %lu  CPS: %lu\r\n"
  2013.         ,t/60,t%60,sent_bytes,sent_bytes/t); }
  2014. bail(0);
  2015. return(0);
  2016. }
  2017.  
  2018.