home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume13 / xmodem3.4 / part02 < prev    next >
Encoding:
Internet Message Format  |  1988-03-13  |  30.7 KB

  1. Subject:  v13i094:  Full featured xmodem program, v3.4, Part02/03
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Steve Grandi <grandi@noao.arizona.edu>
  7. Posting-number: Volume 13, Issue 94
  8. Archive-name: xmodem3.4/part02
  9.  
  10. : This is a shar archive.  Extract with sh, not csh.
  11. echo x - getput.c
  12. sed -e 's/^X//' > getput.c << '!Funky!Stuff!'
  13. X/*
  14. X * Contains system routines to get and put bytes, change tty modes, etc
  15. X * Most of the routines are VERY 4.2BSD Specific!!!
  16. X */
  17. X
  18. X#include "xmodem.h"
  19. X
  20. X/*
  21. X *
  22. X *    Get a byte from the specified file.  Buffer the read so we don't
  23. X *    have to use a system call for each character.
  24. X *
  25. X */
  26. Xgetbyte(fildes, ch)                /* Buffered disk read */
  27. Xint fildes;
  28. Xchar *ch;
  29. X
  30. X    {
  31. X    static char buf[BUFSIZ];    /* Remember buffer */
  32. X    static char *bufp = buf;    /* Remember where we are in buffer */
  33. X    
  34. X    if (nbchr == 0)            /* Buffer exausted; read some more */
  35. X        {
  36. X        if ((nbchr = read(fildes, buf, BUFSIZ)) < 0)
  37. X            error("File Read Error", TRUE);
  38. X        bufp = buf;        /* Set pointer to start of array */
  39. X        }
  40. X    if (--nbchr >= 0)
  41. X        {
  42. X        *ch = *bufp++;
  43. X        return(0);
  44. X        }
  45. X    else
  46. X        {
  47. X        return(EOF);
  48. X        }
  49. X    }
  50. X
  51. X/*   CRC-16 constant array...
  52. X     from Usenet contribution by Mark G. Mendel, Network Systems Corp.
  53. X     (ihnp4!umn-cs!hyper!mark)
  54. X*/
  55. X
  56. X/* crctab as calculated by initcrctab() */
  57. Xunsigned short crctab[1<<B] = { 
  58. X    0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
  59. X    0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
  60. X    0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
  61. X    0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
  62. X    0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
  63. X    0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
  64. X    0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
  65. X    0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
  66. X    0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
  67. X    0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
  68. X    0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
  69. X    0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
  70. X    0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
  71. X    0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
  72. X    0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
  73. X    0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
  74. X    0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
  75. X    0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
  76. X    0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
  77. X    0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
  78. X    0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
  79. X    0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
  80. X    0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
  81. X    0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
  82. X    0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
  83. X    0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
  84. X    0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
  85. X    0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
  86. X    0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
  87. X    0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
  88. X    0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
  89. X    0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
  90. X    };
  91. X
  92. X/* get a byte from data stream -- timeout if "seconds" elapses */
  93. X/* This routine is VERY 4.2 specific */
  94. X
  95. Xint
  96. Xreadbyte(seconds)
  97. Xint seconds;
  98. X    {
  99. X    int readfd;
  100. X    char c;
  101. X    struct timeval tmout;
  102. X
  103. X    tmout.tv_sec = seconds;
  104. X    tmout.tv_usec = 0;
  105. X
  106. X    readfd = 1<<0;
  107. X
  108. X    if ((select(1, &readfd, (int *)0, (int *)0, &tmout)) == 0)
  109. X        return(TIMEOUT);
  110. X
  111. X    read(0, &c, 1);
  112. X
  113. X    if (DEBUG)
  114. X        fprintf(LOGFP, "DEBUG: readbyte %02xh\n", c & 0xff);
  115. X
  116. X    return(c & 0xff);  /* return the char */
  117. X    }
  118. X
  119. X/* 
  120. X get a buffer (length bufsize) from data stream -- timeout if "seconds" elapses.
  121. X Read bunches of characters to save system overhead;
  122. X Further process data while kernel is reading stream (calculating "checksum").
  123. X Try to nap long enough so kernel collects 100 characters or so until we wake up
  124. X unless TOOBUSY is set.
  125. X*/
  126. X
  127. X/* This routine is VERY 4.2 specific */
  128. X
  129. Xint
  130. Xreadbuf(bufsize, seconds, tmode, recvsectcnt, checksum, bufctr)
  131. X
  132. Xint bufsize,    /* number of chars to be read */
  133. Xseconds,     /* timeout period for each read */
  134. Xtmode,         /* transmission mode: TRUE if text, FALSE if binary */
  135. X*checksum,     /* pointer to checksum value */
  136. X*bufctr;    /* length of actual data string in buffer */
  137. Xlong recvsectcnt;    /* running sector count (128 byte sectors) */
  138. X
  139. X{
  140. X    int readfd;        /* mask for select call */
  141. X    struct timeval tmout;    /* timeout structure for select */
  142. X    int numread;        /* number of chars read */
  143. X    int left;        /* number of chars left to read */
  144. X    int recfin = FALSE;        /* flag that EOF read */
  145. X    char inbuf[BBUFSIZ];    /* buffer for incoming packet */
  146. X    register unsigned char c;    /* character being processed */
  147. X    register unsigned short chksm;    /* working copy of checksum */
  148. X    register int bfctr;    /* working copy of bufctr */
  149. X    int j;            /* loop index */
  150. X
  151. X    tmout.tv_sec = seconds;
  152. X    tmout.tv_usec = 0;
  153. X    readfd = 1<<0;
  154. X    chksm = 0;
  155. X    bfctr = 0;
  156. X
  157. X    for (left = bufsize; left > 0;) {
  158. X
  159. X        /* read however many chars are waiting */
  160. X
  161. X        if ((select(1, &readfd, (int *)0, (int *)0, &tmout)) == 0)
  162. X            return(TIMEOUT);
  163. X
  164. X        numread = read(0, inbuf, left);
  165. X        left -= numread;
  166. X
  167. X        if (DEBUG)
  168. X            fprintf(LOGFP, "DEBUG: readbuf--read %d characters\n", numread);
  169. X
  170. X        /* now process part of packet we just read */
  171. X
  172. X        for (j =  0; j < numread; j++) 
  173. X            {  
  174. X                buff[bfctr] = c = inbuf[j] & 0xff;
  175. X                fileread++;
  176. X
  177. X                if (CRCMODE)  /* CRC */
  178. X                    chksm = (chksm<<B) ^ crctab[(chksm>>(W-B)) ^ c];
  179. X
  180. X                else        /* checksum */
  181. X                           chksm = ((chksm+c) & 0xff);
  182. X
  183. X                if (CHECKLENGTH && fileread > filelength)    /* past EOF ? */
  184. X                    continue;
  185. X
  186. X                if (tmode)         /* text mode processing */
  187. X                    {
  188. X                    buff[bfctr] &= 0x7f;    /* nuke bit 8 */
  189. X                    if (c == CR || c == 0)    /* skip CRs and nulls */
  190. X                        continue;
  191. X                    if (c == CTRLZ)        /* CP/M EOF char */
  192. X                        {  
  193. X                        recfin = TRUE;
  194. X                               continue;
  195. X                               }
  196. X                           if (!recfin)    /* dont increment if past EOF */
  197. X                        bfctr++;
  198. X                    }
  199. X                else            /* binary */
  200. X                    bfctr++;
  201. X
  202. X                 }    
  203. X
  204. X        /* go to sleep to save uneeded system calls while kernel
  205. X           is reading data from serial line; 
  206. X           fudge constant from 10000 to 9000 to avoid sleeping too long.
  207. X        */
  208. X        if (left && !TOOBUSY)
  209. X            napms( (left<SLEEPNUM ? left:SLEEPNUM) * 9000/ttyspeed);
  210. X
  211. X    }
  212. X
  213. X    if (CHECKLENGTH && fileread >= filelength)
  214. X        logitarg("File end from YMODEM length found in sector %s\n",
  215. X          sectdisp(recvsectcnt,bufsize,1));
  216. X    *checksum = chksm;
  217. X    *bufctr = bfctr;
  218. X    return(0);
  219. X}
  220. X
  221. X/* send a byte to data stream */
  222. X
  223. Xsendbyte(data)
  224. Xchar data;
  225. X    {
  226. X    if (DEBUG)
  227. X        fprintf(LOGFP, "DEBUG: sendbyte %02xh\n", data & 0xff);
  228. X
  229. X    if (write(1, &data, 1) != 1)      /* write the byte (assume it goes NOW; no flushing needed) */
  230. X        error ("Write error on stream", TRUE);
  231. X    return;
  232. X    }
  233. X
  234. X/* send a buffer to data stream */
  235. X
  236. Xwritebuf(buffer, nbytes)
  237. Xchar *buffer;
  238. Xint  nbytes;
  239. X    {
  240. X    if (DEBUG)
  241. X        fprintf(LOGFP, "DEBUG: writebuf (%d bytes)\n", nbytes);
  242. X
  243. X    if (write(1, buffer, nbytes) != nbytes)        /* write the buffer (assume no TIOCFLUSH needed) */
  244. X        error ("Write error on stream", TRUE);
  245. X    return;
  246. X    }
  247. X
  248. X/*
  249. X * "nap" for specified time -- VERY 4.2BSD specific
  250. X */
  251. X
  252. Xnapms (milliseconds)
  253. Xint    milliseconds;
  254. X{
  255. X    struct    timeval    timeout;
  256. X    int readfd;
  257. X
  258. X    if (milliseconds == 0)
  259. X        return;
  260. X    if (DEBUG)
  261. X        fprintf (LOGFP, "DEBUG: napping for %d ms\n", milliseconds);
  262. X    timeout.tv_sec = 0;
  263. X    timeout.tv_usec = milliseconds * 1000;
  264. X    readfd = 0;
  265. X
  266. X    (void) select(1, &readfd, (int *)0, (int *)0, &timeout);
  267. X}
  268. X
  269. X/* set and restore tty modes for XMODEM transfers */
  270. X/* These routines are 4.2/v7(?) specific */
  271. X
  272. Xstruct sgttyb ttys, ttysnew;    /* for stty terminal mode calls */
  273. Xstruct stat statbuf;        /* for terminal message on/off control */
  274. X
  275. Xint wason;            /* holds status of tty read write/modes */
  276. Xchar *tty;            /* current tty name */
  277. X
  278. X
  279. Xsetmodes()
  280. X    {
  281. X    char *ttyname();
  282. X
  283. X    int n;
  284. X
  285. X    extern onintr();
  286. X
  287. X    sleep(2);            /* let the output appear */
  288. X    if (ioctl(0,TIOCGETP,&ttys)<0)  /* get tty params [V7] */
  289. X        error("Can't get TTY Parameters", TRUE);
  290. X
  291. X    tty = ttyname(0);  /* identify current tty */
  292. X    
  293. X    ttysnew.sg_ispeed = ttys.sg_ispeed;    /* copy input speed */
  294. X    ttysnew.sg_ospeed = ttys.sg_ospeed;    /* copy input speed */
  295. X    ttysnew.sg_flags |= RAW;    /* set for RAW Mode */
  296. X    ttysnew.sg_flags &= ~ECHO;    /* set for no echoing */
  297. X    ttysnew.sg_flags &= ~TANDEM;    /* turn off flow control */
  298. X
  299. X    /* set new paramters */
  300. X    if (ioctl(0,TIOCSETP,&ttysnew) < 0)
  301. X        error("Can't set new TTY Parameters", TRUE);
  302. X
  303. X    /* Flush characters waiting for read or write */
  304. X    n = 0;
  305. X    if (ioctl(0,TIOCFLUSH,&n) < 0)
  306. X        error("Can't flush terminal queue", TRUE);
  307. X
  308. X    /* get tty status */ 
  309. X    if (stat(tty, &statbuf) < 0)  
  310. X        error("Can't get your TTY Status", TRUE);
  311. X
  312. X    if (statbuf.st_mode & 022)    /* Need to turn messages off */
  313. X        if (chmod(tty, (int)statbuf.st_mode & ~022) < 0)
  314. X            error("Can't change  TTY mode", TRUE);
  315. X        else 
  316. X            wason = TRUE;
  317. X    else 
  318. X        wason = FALSE;
  319. X
  320. X    /* set up signal catcher to restore tty state if we are KILLed */
  321. X
  322. X    if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
  323. X        signal(SIGTERM, onintr);
  324. X    }
  325. X
  326. X/* restore normal tty modes */
  327. X
  328. Xrestoremodes(errcall)
  329. Xint errcall;
  330. X    {
  331. X    if (wason)
  332. X        if (chmod(tty, (int)statbuf.st_mode | 022) < 0)
  333. X            error("Can't change TTY mode", FALSE);
  334. X    if (ioctl(0,TIOCSETP,&ttys) < 0)
  335. X        { if (!errcall)
  336. X           error("RESET - Can't restore normal TTY Params", FALSE);
  337. X        else
  338. X             printf("RESET - Can't restore normal TTY Params\n");
  339. X        }
  340. X    if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
  341. X        signal(SIGTERM, SIG_DFL);
  342. X    return;
  343. X    }
  344. X
  345. X
  346. X
  347. X
  348. X/* signal catcher */
  349. Xonintr()
  350. X    {
  351. X    error("Kill signal; bailing out", TRUE);
  352. X    }
  353. X
  354. X/* create string with a timestamp for log file */
  355. X
  356. Xchar *stamptime()
  357. X{
  358. X    char *asctime();        /* stuff to get timestamp */
  359. X    struct tm *localtime(), *tp;
  360. X    struct timeval tv;
  361. X    struct timezone tz;
  362. X
  363. X    gettimeofday (&tv, &tz);        /* fill in timestamp */
  364. X    tp = localtime ((time_t *)&tv.tv_sec);
  365. X    return(asctime(tp));
  366. X}
  367. X
  368. X
  369. X
  370. X/* get tty speed for time estimates */
  371. X
  372. Xgetspeed()
  373. X    {
  374. X    static int speedtbl[] = {0, 50, 75, 110, 134, 150, 200, 300, 600, 
  375. X       1200, 1800, 2400, 4800, 9600, 19200, 0};
  376. X    if (ioctl(0,TIOCGETP,&ttys) < 0)    /* get tty structure */
  377. X        error("Can't get TTY parameters", FALSE);
  378. X
  379. X    if (ttys.sg_ispeed >= 0 && ttys.sg_ispeed <= 14)
  380. X        {
  381. X        ttyspeed = speedtbl[ttys.sg_ispeed];
  382. X        logitarg ("Line speed = %d bits per second\n", ttyspeed);
  383. X        }
  384. X    else
  385. X        {
  386. X        ttyspeed = 1200;
  387. X        logit ("Can't determine line speed; assuming 1200 bps\n");
  388. X        }
  389. X    }
  390. !Funky!Stuff!
  391. echo x - getput.sysv.c
  392. sed -e 's/^X//' > getput.sysv.c << '!Funky!Stuff!'
  393. X/*
  394. X * Contains system routines to get and put bytes, change tty modes, etc
  395. X * Sys V version.  UNTESTED!!!!!!
  396. X */
  397. X
  398. X#include "xmodem.h"
  399. X
  400. X/*
  401. X *
  402. X *    Get a byte from the specified file.  Buffer the read so we don't
  403. X *    have to use a system call for each character.
  404. X *
  405. X */
  406. Xgetbyte(fildes, ch)                /* Buffered disk read */
  407. Xint fildes;
  408. Xchar *ch;
  409. X
  410. X    {
  411. X    static char buf[BUFSIZ];    /* Remember buffer */
  412. X    static char *bufp = buf;    /* Remember where we are in buffer */
  413. X    
  414. X    if (nbchr == 0)            /* Buffer exausted; read some more */
  415. X        {
  416. X        if ((nbchr = read(fildes, buf, BUFSIZ)) < 0)
  417. X            error("File Read Error", TRUE);
  418. X        bufp = buf;        /* Set pointer to start of array */
  419. X        }
  420. X    if (--nbchr >= 0)
  421. X        {
  422. X        *ch = *bufp++;
  423. X        return(0);
  424. X        }
  425. X    else
  426. X        {
  427. X        return(EOF);
  428. X        }
  429. X    }
  430. X
  431. X/*   CRC-16 constant array...
  432. X     from Usenet contribution by Mark G. Mendel, Network Systems Corp.
  433. X     (ihnp4!umn-cs!hyper!mark)
  434. X*/
  435. X
  436. X/* crctab as calculated by initcrctab() */
  437. Xunsigned short crctab[1<<B] = { 
  438. X    0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
  439. X    0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
  440. X    0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
  441. X    0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
  442. X    0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
  443. X    0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
  444. X    0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
  445. X    0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
  446. X    0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
  447. X    0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
  448. X    0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
  449. X    0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
  450. X    0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
  451. X    0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
  452. X    0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
  453. X    0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
  454. X    0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
  455. X    0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
  456. X    0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
  457. X    0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
  458. X    0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
  459. X    0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
  460. X    0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
  461. X    0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
  462. X    0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
  463. X    0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
  464. X    0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
  465. X    0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
  466. X    0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
  467. X    0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
  468. X    0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
  469. X    0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
  470. X    };
  471. X
  472. X/* get a byte from data stream -- timeout if "seconds" elapses */
  473. X
  474. Xint timedout;
  475. Xint
  476. Xreadbyte(seconds)
  477. Xint seconds;
  478. X{
  479. X    int force_it();
  480. X    char c;
  481. X    signal(SIGALRM, force_it);
  482. X
  483. X    timedout = 0;
  484. X    alarm(seconds);
  485. X    read(0, &c, 1);
  486. X    alarm(0);
  487. X    if (timedout)
  488. X        return(TIMEOUT);
  489. X    if (DEBUG)
  490. X        fprintf(LOGFP, "DEBUG: readbyte %02xh\n", c & 0xff);
  491. X    return(c & 0xff);
  492. X}
  493. X
  494. Xint
  495. Xforce_it()
  496. X{
  497. X    timedout++;
  498. X    return;
  499. X}
  500. X
  501. X/* 
  502. X get a buffer (length bufsize) from data stream -- timeout if "seconds" elapses.
  503. X Read bunches of characters to save system overhead;
  504. X Further process data while kernel is reading stream (calculating "checksum").
  505. X Try to nap long enough so kernel collects 100 characters or so until we wake up
  506. X unless TOOBUSY is set.
  507. X*/
  508. X
  509. X
  510. Xint
  511. Xreadbuf(bufsize, seconds, tmode, recvsectcnt, checksum, bufctr)
  512. X
  513. Xint bufsize,    /* number of chars to be read */
  514. Xseconds,     /* timeout period for each read */
  515. Xtmode,         /* transmission mode: TRUE if text, FALSE if binary */
  516. X*checksum,     /* pointer to checksum value */
  517. X*bufctr;    /* length of actual data string in buffer */
  518. Xlong recvsectcnt;    /* running sector count (128 byte sectors) */
  519. X
  520. X{
  521. X    int force_it();
  522. X    int numread;        /* number of chars read */
  523. X    int left;        /* number of chars left to read */
  524. X    int recfin = 0;        /* flag that EOF read */
  525. X    char inbuf[BBUFSIZ];    /* buffer for incoming packet */
  526. X    register unsigned char c;    /* character being processed */
  527. X    register unsigned short chksm;    /* working copy of checksum */
  528. X    register int bfctr;    /* working copy of bufctr */
  529. X    int j;            /* loop index */
  530. X
  531. X    signal(SIGALRM, force_it);
  532. X    chksm = 0;
  533. X    bfctr = 0;
  534. X
  535. X    for (left = bufsize; left > 0;) {
  536. X
  537. X        /* read however many chars are waiting */
  538. X        timedout = 0;
  539. X        alarm(seconds);
  540. X        numread = read(0, inbuf, left);
  541. X        alarm(0);
  542. X        if (timedout)
  543. X            return(TIMEOUT);
  544. X        left -= numread;
  545. X
  546. X        if (DEBUG)
  547. X            fprintf(LOGFP, "DEBUG: readbuf--read %d characters\n", numread);
  548. X
  549. X        /* now process part of packet we just read */
  550. X
  551. X        for (j =  0; j < numread; j++) 
  552. X            {  
  553. X                buff[bfctr] = c = inbuf[j] & 0xff;
  554. X                fileread++;
  555. X
  556. X                if (CRCMODE)  /* CRC */
  557. X                    chksm = (chksm<<B) ^ crctab[(chksm>>(W-B)) ^ c];
  558. X
  559. X                else        /* checksum */
  560. X                           chksm = ((chksm+c) & 0xff);
  561. X
  562. X                if (CHECKLENGTH && fileread > filelength)    /* past EOF ? */
  563. X                    continue;
  564. X
  565. X                if (tmode)         /* text mode processing */
  566. X                    {
  567. X                    buff[bfctr] &= 0x7f;    /* nuke bit 8 */
  568. X                    if (c == CR || c == 0)    /* skip CRs and nulls */
  569. X                        continue;
  570. X                    if (c == CTRLZ)        /* CP/M EOF char */
  571. X                        {  
  572. X                        recfin = TRUE;
  573. X                               continue;
  574. X                               }
  575. X                           if (!recfin)    /* dont increment if past EOF */
  576. X                        bfctr++;
  577. X                    }
  578. X                else            /* binary */
  579. X                    bfctr++;
  580. X
  581. X                 }    
  582. X
  583. X        /* go to sleep to save uneeded system calls while kernel
  584. X           is reading data from serial line, fudge constant from 10 to
  585. X           9 to avoid sleeping too long
  586. X        */
  587. X        if (left && !TOOBUSY)
  588. X            sleep ((left<SLEEPNUM ? left:SLEEPNUM) * 9/ttyspeed);
  589. X    }
  590. X
  591. X    if (CHECKLENGTH && fileread >= filelength)
  592. X        logitarg("File end from YMODEM length found in sector %s\n",
  593. X          sectdisp(recvsectcnt,bufsize,1));
  594. X    *checksum = chksm;
  595. X    *bufctr = bfctr;
  596. X    return(0);
  597. X}
  598. X
  599. X/* send a byte to data stream */
  600. X
  601. Xsendbyte(data)
  602. Xchar data;
  603. X    {
  604. X    if (DEBUG)
  605. X        fprintf(LOGFP, "DEBUG: sendbyte %02xh\n", data & 0xff);
  606. X
  607. X    if (write(1, &data, 1) != 1)      /* write the byte (assume it goes NOW; no flushing needed) */
  608. X        error ("Write error on stream", TRUE);
  609. X    return;
  610. X    }
  611. X
  612. X/* send a buffer to data stream */
  613. X
  614. Xwritebuf(buffer, nbytes)
  615. Xchar *buffer;
  616. Xint  nbytes;
  617. X    {
  618. X    if (DEBUG)
  619. X        fprintf(LOGFP, "DEBUG: writebuf (%d bytes)\n", nbytes);
  620. X
  621. X    if (write(1, buffer, nbytes) != nbytes)        /* write the buffer (assume no TIOCFLUSH needed) */
  622. X        error ("Write error on stream", TRUE);
  623. X    return;
  624. X    }
  625. X
  626. X/* set and restore tty modes for XMODEM transfers */
  627. X
  628. Xstruct termio ttys;
  629. Xstruct stat statbuf;        /* for terminal message on/off control */
  630. X
  631. Xint wason;            /* holds status of tty read write/modes */
  632. Xchar *tty;            /* current tty name */
  633. X
  634. X
  635. Xsetmodes()
  636. X    {
  637. X    char *ttyname();
  638. X    struct termio ttysnew;
  639. X
  640. X    extern onintr();
  641. X
  642. X    sleep(2);            /* let the output appear */
  643. X    if (ioctl(0,TCGETA,&ttys)<0)  /* get tty params [V7] */
  644. X        error("Can't get TTY Parameters", TRUE);
  645. X
  646. X    tty = ttyname(0);  /* identify current tty */
  647. X    
  648. X    if (ioctl(0,TCGETA,&ttysnew)<0)  /* get tty params */
  649. X        error("Can't get TTY Parameters", TRUE);
  650. X    ttysnew.c_cc[4] = 1;        /* VMIN */
  651. X    ttysnew.c_cc[5] = 0;        /* VTIME */
  652. X    ttysnew.c_iflag = 0;
  653. X    ttysnew.c_oflag = 0;
  654. X    ttysnew.c_lflag = 0;
  655. X    ttysnew.c_cflag &= ~CSIZE;
  656. X    ttysnew.c_cflag |= CS8;
  657. X    ttysnew.c_cflag &= ~PARENB;
  658. X    if (ioctl(0,TCSETA,&ttysnew)<0)  /* set new paramters */
  659. X        error("Can't set new TTY Parameters", TRUE);
  660. X
  661. X    if (stat(tty, &statbuf) < 0)  /* get tty status */ 
  662. X        error("Can't get your TTY Status", TRUE);
  663. X
  664. X    if (statbuf.st_mode & 022)    /* Need to turn messages off */
  665. X        if (chmod(tty, (int)statbuf.st_mode & ~022) < 0)
  666. X            error("Can't change  TTY mode", TRUE);
  667. X        else 
  668. X            wason = TRUE;
  669. X    else 
  670. X        wason = FALSE;
  671. X
  672. X    /* set up signal catcher to restore tty state if we are KILLed */
  673. X
  674. X    if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
  675. X        signal(SIGTERM, onintr);
  676. X    }
  677. X
  678. X/* restore normal tty modes */
  679. X
  680. Xrestoremodes(errcall)
  681. Xint errcall;
  682. X    {
  683. X    if (wason)
  684. X        if (chmod(tty, (int)statbuf.st_mode | 022) < 0)
  685. X            error("Can't change TTY mode", FALSE);
  686. X    if (ioctl(0,TCSETA,&ttys) < 0)
  687. X        { if (!errcall)
  688. X           error("RESET - Can't restore normal TTY Params", FALSE);
  689. X        else
  690. X             printf("RESET - Can't restore normal TTY Params\n");
  691. X        }
  692. X    if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
  693. X        signal(SIGTERM, SIG_DFL);
  694. X    return;
  695. X    }
  696. X
  697. X
  698. X
  699. X
  700. X/* signal catcher */
  701. Xonintr()
  702. X    {
  703. X    error("Kill signal; bailing out", TRUE);
  704. X    }
  705. X
  706. X/* create string with a timestamp for log file */
  707. X
  708. Xchar *stamptime()
  709. X{
  710. X    char *asctime();        /* stuff to get timestamp */
  711. X    struct tm *localtime(), *tp;
  712. X    long now;
  713. X
  714. X    time(&now);
  715. X    tp = localtime(now);
  716. X    return(asctime(tp));
  717. X}
  718. X
  719. X
  720. X
  721. X/* get tty speed for time estimates */
  722. X
  723. Xgetspeed()
  724. X    {
  725. X    static int speedtbl[] = {0, 50, 75, 110, 134, 150, 200, 300, 600,
  726. X    1200, 1800, 2400, 4800, 9600, 19200, 0};
  727. X    struct termio ttystemp;
  728. X
  729. X    if (ioctl(0,TCGETA,&ttystemp) < 0)    /* get tty structure */
  730. X        error("Can't get TTY parameters", FALSE);
  731. X    if ((ttystemp.c_cflag & 017) >= 0 && (ttystemp.c_cflag && 017) <= 14)
  732. X        {
  733. X        ttyspeed = speedtbl[ttystemp.c_cflag & 017];
  734. X        logitarg ("Line speed = %d bits per second\n", ttyspeed);
  735. X        }
  736. X    else
  737. X        {
  738. X        ttyspeed = 1200;
  739. X        logit ("Can't determine line speed; assuming 1200 bps\n");
  740. X        }
  741. X    }
  742. !Funky!Stuff!
  743. echo x - send.c
  744. sed -e 's/^X//' > send.c << '!Funky!Stuff!'
  745. X/**  send a file  **/
  746. X
  747. X/*
  748. X * Operation of this routine depends on on MDM7BAT and YMDMBAT flags.
  749. X *
  750. X * If "name" is NULL; close out the BATCH send.
  751. X */
  752. X
  753. X#include "xmodem.h"
  754. X
  755. Xsfile(name)
  756. Xchar *name;
  757. X    {
  758. X
  759. X    char *sectdisp();
  760. X    time_t time();
  761. X    char *strcpy();
  762. X    char *unix_cpm();
  763. X
  764. X    extern unsigned short crctab[1<<B];    /* CRC-16 constant values, see getput.c */
  765. X
  766. X    register int bufctr,         /* array index for data buffer */
  767. X    sectnum;            /* packet number for packet header */
  768. X
  769. X    register unsigned short checksum;     /* checksum/crc */
  770. X
  771. X    char blockbuf[BBUFSIZ+6];    /* holds packet as it is constructed */
  772. X
  773. X    struct stat filestatbuf;    /* file status info */
  774. X
  775. X    int fd,         /* file descriptor for file being transmitted */
  776. X    attempts,        /* number of attempts made to transmit a packet */
  777. X    nlflag,         /* flag that we have to send a LF in next packet */
  778. X    sendfin,         /* flag that we are sending the last packet */
  779. X    closeout,        /* flag that we are closing out batch send */
  780. X    startup,        /* flag that we are starting batch send */
  781. X    tmode,            /* TRUE for text mode; FALSE for binary mode */
  782. X    bbufcnt,        /* array index for packet */
  783. X    firstchar,        /* first character in protocol transaction */
  784. X    bufsize,        /* packet size (128 or 1024) */
  785. X    sendresp,          /* response char to sent block received from remote*/
  786. X    extrachar;        /* count of extra LF characters added */
  787. X    long sentsect;        /* count of 128 byte sectors actually sent */
  788. X    long expsect;        /* count of 128 byte sectors expected to be sent */
  789. X    time_t start;        /* starting time of transfer */
  790. X    char c;
  791. X
  792. X    nbchr = 0;  /* clear buffered read char count */
  793. X
  794. X    CRCMODE = FALSE;    /* Receiver determines use of crc or checksum */
  795. X
  796. X    closeout = FALSE; startup = TRUE;    /* indicate state of batch transfer */
  797. X
  798. X    /* Check on NULL file name */
  799. X    if (strcmp(name,"") == 0)
  800. X        {
  801. X        if (BATCH)
  802. X            closeout = TRUE;
  803. X        else
  804. X            {
  805. X            sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
  806. X            error("NULL file name in send", TRUE);
  807. X            }
  808. X        }
  809. X
  810. X    if (!closeout)        /* Are we closing down batch? */
  811. X        {            /* no; let's send a file */
  812. X        if ((fd = open(name, 0)) < 0)    
  813. X            {  
  814. X            sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
  815. X                    error("Can't open file for send", TRUE);
  816. X            }
  817. X    
  818. X        stat(name, &filestatbuf);  /* get file status bytes */
  819. X        expsect = (filestatbuf.st_size/128) + 1;
  820. X    
  821. X        if (LOGFLAG)
  822. X            {   
  823. X            fprintf(LOGFP, "----\nXMODEM Send Function\n");
  824. X                fprintf(LOGFP, "File Name: %s\n", name);
  825. X              fprintf(LOGFP,"Estimated File Size %ldK, %ld Records, %ld Bytes\n",
  826. X                (filestatbuf.st_size/1024)+1, expsect, filestatbuf.st_size);
  827. X            projtime(expsect, LOGFP);
  828. X            }
  829. X        }
  830. X    else
  831. X        {
  832. X        logit("----\nXMODEM Send Function\n");
  833. X        logit("Closing down Batch Transmission\n");
  834. X        }
  835. X
  836. X
  837. X    tmode = (XMITTYPE == 't') ? TRUE : FALSE;    /* set text mode */
  838. X
  839. X    bufsize = LONGPACK ? 1024 : 128;        /* set sector size */
  840. X    if (LONGPACK && !closeout)
  841. X        logit("1K packet mode chosen\n");
  842. X
  843. X        sendfin = nlflag = FALSE;
  844. X      attempts = 0;
  845. X
  846. X    /* wait for and read startup character */
  847. Xrestart:
  848. X    do
  849. X        {
  850. X        while (((firstchar=readbyte(1)) != NAK) && (firstchar != CRCCHR) && (firstchar != CAN))
  851. X            if (++attempts > NAKMAX)
  852. X                {
  853. X                if (MDM7BAT && startup)
  854. X                    {
  855. X                    sendbyte(ACK); sendbyte(EOT);
  856. X                    }
  857. X                error("Remote System Not Responding", TRUE);
  858. X                }
  859. X
  860. X        if ((firstchar & 0x7f) == CAN)
  861. X            if (readbyte(3) == CAN)
  862. X                error("Send cancelled at user's request",TRUE);
  863. X
  864. X        if (firstchar == CRCCHR)
  865. X            {
  866. X            CRCMODE = TRUE;
  867. X            if (!closeout)
  868. X                logit("CRC mode requested\n");
  869. X            if (readbyte(1) == KCHR)
  870. X                {
  871. X                LONGPACK = TRUE;
  872. X                logit("Receiver invoked 1K packet mode\n");
  873. X                }
  874. X            }
  875. X        }
  876. X    while (firstchar != NAK && firstchar != CRCCHR);
  877. X
  878. X    if (MDM7BAT && closeout)    /* close out MODEM7 batch */
  879. X        {
  880. X        sendbyte(ACK); sendbyte (EOT);
  881. X        readbyte(2);            /* flush junk */
  882. X        return;
  883. X        }
  884. X
  885. X    if (MDM7BAT && startup)        /* send MODEM7 file name */
  886. X        {
  887. X        if (send_name(unix_cpm(name)) == -1)
  888. X            {
  889. X            attempts = 0;
  890. X            goto restart;
  891. X            }
  892. X        startup = FALSE;
  893. X        attempts = 0;
  894. X        goto restart;
  895. X        }
  896. X
  897. X    sectnum = 1;
  898. X
  899. X    if (YMDMBAT)    /* Fudge for YMODEM transfer (to send name packet) */
  900. X        {
  901. X        sectnum = 0;
  902. X        bufsize = 128;
  903. X        }
  904. X
  905. X    attempts = sentsect = extrachar = 0;
  906. X    start = time((time_t *) 0);
  907. X
  908. X        do             /* outer packet building/sending loop; loop till whole file is sent */
  909. X        {   
  910. X
  911. X        if (closeout && YMDMBAT && sectnum == 1)    /* close out YMODEM */
  912. X            return;
  913. X
  914. X        if (YMDMBAT && sectnum == 1)            /* get set to send YMODEM data packets */
  915. X            {
  916. X            bufsize = LONGPACK ? 1024 : 128;
  917. X            do
  918. X                {
  919. X                while (((firstchar=readbyte(3)) != CRCCHR) && (firstchar != CAN))
  920. X                    if (++attempts > STERRORMAX)
  921. X                        error("YMODEM protocol botch, C expected", TRUE);
  922. X                if ((firstchar&0x7f) == CAN)
  923. X                    if (readbyte(3) == CAN)
  924. X                        error("Send cancelled at User's request", TRUE);
  925. X                }
  926. X            while (firstchar != CRCCHR);
  927. X            attempts = 0;
  928. X            }
  929. X
  930. X        if (extrachar >= 128)    /* update expected sector count */
  931. X            {
  932. X            extrachar = 0;
  933. X            expsect++;
  934. X            }
  935. X
  936. X        if ((bufsize == 1024) && (attempts > KSWMAX))
  937. X            {
  938. X            logit("Reducing packet size to 128 due to excessive errors\n");
  939. X            bufsize = 128;
  940. X            }
  941. X
  942. X        if ((bufsize == 1024) && ((expsect - sentsect) < 8))
  943. X            {
  944. X            logit("Reducing packet size to 128 for tail end of file\n");
  945. X            bufsize = 128;
  946. X            }
  947. X
  948. X        if (sectnum > 0)    /* data packet */
  949. X            {
  950. X            for (bufctr=0; bufctr < bufsize;)
  951. X                    {
  952. X                if (nlflag)
  953. X                            {  
  954. X                    buff[bufctr++] = LF;  /* leftover newline */
  955. X                               nlflag = FALSE;
  956. X                        }
  957. X                if (getbyte(fd, &c) == EOF)
  958. X                    { 
  959. X                    sendfin = TRUE;  /* this is the last sector */
  960. X                       if (!bufctr)  /* if EOF on sector boundary */
  961. X                              break;  /* avoid sending extra sector */
  962. X                          buff[bufctr++] = CTRLZ;  /* pad with Ctrl-Z for CP/M EOF (even do for binary files) */
  963. X                       continue;
  964. X                          }
  965. X    
  966. X                if (tmode && c == LF)  /* text mode & Unix newline? */
  967. X                        {
  968. X                    extrachar++;
  969. X                    buff[bufctr++] = CR;  /* insert carriage return */
  970. X                         if (bufctr < bufsize)
  971. X                                buff[bufctr++] = LF;  /* insert LF */
  972. X                           else
  973. X                            nlflag = TRUE;  /* insert on next sector */
  974. X                       }    
  975. X                else
  976. X                    buff[bufctr++] = c;  /* copy the char without change */
  977. X                    }
  978. X
  979. X                if (!bufctr)  /* if EOF on sector boundary */
  980. X                          break;  /* avoid sending empty sector */
  981. X            }    
  982. X
  983. X        else        /* YMODEM filename packet */
  984. X            {
  985. X            for (bufctr=0; bufctr<bufsize; bufctr++)  /* zero packet */
  986. X                buff[bufctr]=0;
  987. X            if (!closeout)
  988. X                {
  989. X                cpmify(name);
  990. X                strcpy((char *)buff, name);
  991. X                if (!tmode)    /* put in file length etc. only if binary transfer */
  992. X                    {
  993. X                    register char *p;
  994. X                    p = (char *)buff + strlen(name) + 1;
  995. X                    sprintf(p, "%lu %lo %o", filestatbuf.st_size, 
  996. X                      filestatbuf.st_mtime, filestatbuf.st_mode);
  997. X                    logitarg("YMODEM header information: %s\n", p);
  998. X                    }
  999. X                buff[bufsize-2]    = (expsect & 0xff);        /* put in KMD kludge information */
  1000. X                buff[bufsize-1] = ((expsect >> 8) & 0xff);
  1001. X                }
  1002. X            }
  1003. X
  1004. X        bbufcnt = 0;        /* start building block to be sent */
  1005. X        blockbuf[bbufcnt++] = (bufsize == 1024) ? STX : SOH;    /* start of packet char */
  1006. X        blockbuf[bbufcnt++] = sectnum;        /* current sector # */
  1007. X        blockbuf[bbufcnt++] = ~sectnum;   /* and its complement */
  1008. X
  1009. X                   checksum = 0;  /* initialize checksum */
  1010. X                   for (bufctr=0; bufctr < bufsize; bufctr++)
  1011. X                   {
  1012. X            blockbuf[bbufcnt++] = buff[bufctr];
  1013. X
  1014. X            if (CRCMODE)
  1015. X                checksum = (checksum<<B) ^ crctab[(checksum>>(W-B)) ^ buff[bufctr]];
  1016. X
  1017. X            else
  1018. X                           checksum = ((checksum+buff[bufctr]) & 0xff);
  1019. X                 }
  1020. X
  1021. X        if (CRCMODE)        /* put in CRC */
  1022. X            {
  1023. X            checksum &= 0xffff;
  1024. X            blockbuf[bbufcnt++] = ((checksum >> 8) & 0xff);
  1025. X            blockbuf[bbufcnt++] = (checksum & 0xff);
  1026. X            }
  1027. X        else            /* put in checksum */
  1028. X            blockbuf[bbufcnt++] = checksum;
  1029. X
  1030. X                attempts = 0;
  1031. X    
  1032. X                do                /* inner packet loop */
  1033. X                    {
  1034. X
  1035. X            writebuf(blockbuf, bbufcnt);    /* write the block */
  1036. X
  1037. X            if (DEBUG)
  1038. X                fprintf (LOGFP, "DEBUG: %d byte Packet %02xh (%02xh) sent, checksum %02xh %02xh\n", 
  1039. X                bbufcnt, blockbuf[1]&0xff, blockbuf[2]&0xff, blockbuf[bufsize+3]&0xff, blockbuf[bufsize+4]&0xff);
  1040. X
  1041. X                    attempts++;
  1042. X            sendresp = readbyte(10);  /* get response from remote */
  1043. X
  1044. X            if (sendresp != ACK)
  1045. X                   {
  1046. X                if (sendresp == TIMEOUT)
  1047. X                    {
  1048. X                       logitarg("Timeout on sector %s\n",sectdisp(sentsect,bufsize,1));
  1049. X                    }
  1050. X                else if (sendresp == NAK)
  1051. X                    {
  1052. X                       logitarg("NAK on sector %s\n",sectdisp(sentsect,bufsize,1));
  1053. X                    }
  1054. X                else
  1055. X                    {
  1056. X                       logitarg("Non-ACK on sector %s\n",sectdisp(sentsect,bufsize,1));
  1057. X                    }
  1058. X                   }
  1059. X                    }
  1060. X            while((sendresp != ACK) && (attempts < ERRORMAX));    /* close of inner loop */
  1061. X
  1062. X               sectnum++;  /* increment to next sector number */
  1063. X        sentsect += (bufsize == 128) ? 1 : 8;
  1064. X            }
  1065. X        while (!sendfin && ( attempts < ERRORMAX));    /* end of outer loop */
  1066. X
  1067. X    if (attempts > ERRORMAX)
  1068. X        {
  1069. X        sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
  1070. X        error ("Too many errors in transmission", TRUE);
  1071. X        }
  1072. X
  1073. X        attempts = 0;
  1074. X        sendbyte(EOT);  /* send 1st EOT to close down transfer */
  1075. X    
  1076. X        while ((readbyte(15) != ACK) && (attempts++ < EOTMAX))     /* wait for ACK of EOT */
  1077. X        {
  1078. X        if (attempts > 1)
  1079. X            logitarg("EOT not ACKed, try %d\n", attempts);
  1080. X           sendbyte(EOT);
  1081. X        }
  1082. X
  1083. X        if (attempts >= RETRYMAX)
  1084. X           error("Remote System Not Responding on Completion", TRUE);
  1085. X
  1086. X        close(fd);
  1087. X
  1088. X        logit("Send Complete\n");
  1089. X    prtime(sentsect, time((time_t *) 0) - start);
  1090. X    }
  1091. !Funky!Stuff!
  1092. exit
  1093.  
  1094.