home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume7 / xmodem / part02 < prev    next >
Encoding:
Internet Message Format  |  1987-01-18  |  29.7 KB

  1. Subject:  v07i093:  Full-featured XMODEM, Part02/02
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: seismo!noao!grandi (Steve Grandi)
  6. Mod.sources: Volume 7, Issue 93
  7. Archive-name: xmodem/Part02
  8.  
  9. [  I'll be at USENIX, if you want to come look for me with bats and clubs.
  10.     --r$  ]
  11.  
  12. : This is a shar archive.  Extract with sh, not csh.
  13. echo x - batch.c
  14. sed -e 's/^X//' > batch.c << '!Funky!Stuff!'
  15. X/*
  16. X *  Various routines for batch tranfer
  17. X */
  18. X
  19. X#include "xmodem.h"
  20. X
  21. X/* make sure filename sent or received in YMODEM batch is canonical */
  22. X/* Turn Unix '/' into CP/M ':' and translate to all lower case */
  23. X
  24. Xunixify (name)
  25. Xchar *name;
  26. X    {
  27. X    char *ptr;
  28. X    for (ptr=name; *ptr; ++ptr)
  29. X        {
  30. X        if (*ptr == '/')
  31. X            *ptr = ':';
  32. X        if (isupper (*ptr))
  33. X            *ptr |= 040;
  34. X        }
  35. X    }
  36. X
  37. Xcpmify (name)
  38. Xchar *name;
  39. X    {
  40. X    char *ptr;
  41. X    for (ptr=name; *ptr; ++ptr)
  42. X        {
  43. X        if (*ptr == ':')
  44. X            *ptr = '/';
  45. X        if (isupper (*ptr))
  46. X            *ptr |= 040;
  47. X        }
  48. X    }
  49. X
  50. X
  51. X/* convert a CP/M file name received in a MODEM7 batch transfer
  52. X * into a unix file name mapping '/' into ':', converting to all
  53. X * upper case and adding dot in proper place.  
  54. X * Use "filename" to hold name.
  55. X * Code stolen from D. Thompson's (IRTF) xmodem.c
  56. X */
  57. X
  58. Xchar *cpm_unix (string)
  59. Xunsigned char *string;
  60. X{
  61. X    register int i;
  62. X    unsigned char *iptr, temp;
  63. X    register char *optr;
  64. X
  65. X    if (*string == '\0')
  66. X        error("Null file name in MODEM7 batch receive", TRUE);
  67. X
  68. X    for (iptr=string; (temp = *iptr) ; ) {
  69. X        temp &= 0177;            /* strips bit 7 */
  70. X        if (isupper(temp))
  71. X            temp |= 040;        /* set bit 5 for lower case */
  72. X        if (temp == '/') 
  73. X            temp=':';        /* map / into : */
  74. X        *iptr++ = temp;
  75. X    }
  76. X
  77. X    /* put in main part of name */
  78. X    iptr=string;
  79. X    optr=filename;
  80. X    for (i=0; i<8; i++) {
  81. X        if (*iptr != ' ')
  82. X            *optr++ = *iptr++;
  83. X    }
  84. X
  85. X    /* add dot */
  86. X    *optr++ = '.';
  87. X
  88. X    /* put in extension */
  89. X    iptr = &string[8];
  90. X    for (i=0; i<3; i++) {
  91. X        if (*iptr != ' ')
  92. X            *optr++ = *iptr++;
  93. X    }
  94. X
  95. X    *optr++ = '\000';
  96. X    return (filename);
  97. X}
  98. X
  99. X/* Send 11 character CP/M filename for MODEM7 batch transmission
  100. X * Returns -1 for a protocol error; 0 if successful
  101. X * NOTE: we tromp a little on the argument string!
  102. X * code stolen from D. Thompson's (IRTF) xmodem.c
  103. X */
  104. X
  105. Xsend_name(name)
  106. Xchar *name;
  107. X{
  108. X    register int cksum;
  109. X    register char *ptr;
  110. X
  111. X    xmdebug("send_name");
  112. X
  113. X    /* append cp/m EOF */
  114. X    name[NAMSIZ] = CTRLZ;
  115. X    name[NAMSIZ+1] = '\000';
  116. X
  117. X    /* create checksum */
  118. X    ptr = name;
  119. X    cksum = 0;
  120. X    while (*ptr)
  121. X        cksum += *ptr++;
  122. X    cksum &= 0x00FF;
  123. X
  124. X    /* send filename */
  125. X
  126. X    sendbyte(ACK);
  127. X    ptr = name;
  128. X    sendbyte(*ptr++);
  129. X
  130. X    while (*ptr) {
  131. X
  132. Xchecknak:        switch (readbyte(6)) {
  133. X
  134. X            case CAN: {
  135. X                if (readbyte(3) == CAN)
  136. X                    error("Program Canceled by User",TRUE);
  137. X                else
  138. X                    goto checknak;
  139. X            }
  140. X
  141. X            case ACK: break;
  142. X
  143. X            case TIMEOUT: {
  144. X                logit("Timeout while sending filename\n");
  145. X                sendbyte(BAD_NAME);
  146. X                return (-1);
  147. X            }
  148. X
  149. X            default: {
  150. X                logit("Error while sending filename\n");
  151. X                sendbyte(BAD_NAME);
  152. X                return (-1);
  153. X            }
  154. X        }    
  155. X
  156. X        sendbyte (*ptr++);
  157. X    }
  158. X
  159. X    /* Check checksum returned by other side against my value */
  160. X    if (readbyte(10) != cksum) {
  161. X        logit("Bad checksum while sending filename\n");
  162. X        sendbyte(BAD_NAME);
  163. X        return (-1);
  164. X    }
  165. X
  166. X    sendbyte(ACK);
  167. X    return (0);
  168. X}
  169. X
  170. X/* Convert Unix filename to 11 character CP/M file name (8 char name,
  171. X * 3 char extension, dot in between is not included).
  172. X * map ':' into '/'; Use filename to hold name.
  173. X * code stolen from D. Thompson's (IRTF) xmodem.c
  174. X */
  175. X
  176. Xchar *unix_cpm(string)
  177. Xchar *string;
  178. X{
  179. X    register char *iptr, *optr, temp;
  180. X    int i;
  181. X
  182. X    char *rindex();
  183. X    char *strcpy();
  184. X
  185. X    /* blank 11 character name */
  186. X    (void) strcpy (filename,"           ");
  187. X
  188. X    /* strip off any path name */
  189. X    if ((iptr = rindex(string,'/')))
  190. X        iptr++;
  191. X    else
  192. X        iptr=string;
  193. X
  194. X    /* skip leading '.'s */
  195. X    while (*iptr == '.')
  196. X        iptr++;
  197. X
  198. X    /* copy main part of name */
  199. X    optr = filename;
  200. X    i = 8;
  201. X    while ((i--) && (*iptr) && (*iptr != '.'))
  202. X        *optr++ = *iptr++;
  203. X
  204. X    /* advance to unix extension, or end of unix name */
  205. X    while ((*iptr != '.') && (*iptr))
  206. X        iptr++;
  207. X
  208. X    /* skip over the  '.' */
  209. X    while (*iptr == '.')
  210. X        iptr++;
  211. X
  212. X    /* copy extension */
  213. X    optr = &filename[8];
  214. X    i=3;
  215. X    while ((i--) && (*iptr) && (*iptr != '.'))
  216. X        *optr++ = *iptr++;
  217. X
  218. X    filename[NAMSIZ] = '\000';
  219. X
  220. X    /* Fuss with name */
  221. X    for (iptr=filename; (temp = *iptr) ;) {
  222. X        temp &= 0177;            /* strip bit 7 (parity bit) */
  223. X        if (islower(temp))
  224. X            temp &= ~040;        /* make upper case */
  225. X        if (temp == ':')
  226. X            temp ='/';        /* map ':' into '/' */
  227. X        *iptr++ = temp;
  228. X    }
  229. X
  230. X    if (DEBUG)
  231. X        fprintf (LOGFP, "DEBUG: File %s sent as %s\n", string, filename);
  232. X
  233. X    return(filename);
  234. X}
  235. !Funky!Stuff!
  236. echo x - misc.c
  237. sed -e 's/^X//' > misc.c << '!Funky!Stuff!'
  238. X#include "xmodem.h"
  239. X
  240. X/*  Print Help Message  */
  241. Xhelp()
  242. X    {
  243. X    printf("\nUsage:  \n\txmodem ");
  244. X    printf("-[rb!rt!sb!st][options] filename\n");
  245. X    printf("\nMajor Commands --");
  246. X    printf("\n\trb <-- Receive Binary");
  247. X    printf("\n\trt <-- Receive Text");
  248. X    printf("\n\tsb <-- Send Binary");
  249. X    printf("\n\tst <-- Send Text");
  250. X    printf("\nOptions --");
  251. X    printf("\n\tY  <-- Use YMODEM Batch Mode on transmit");
  252. X    printf("\n\tB  <-- Use MODEM7 Batch Mode on transmit");
  253. X    printf("\n\tK  <-- Use 1K packets on transmit");
  254. X    printf("\n\tc  <-- Select CRC mode on receive");
  255. X    printf("\n\td  <-- Delete xmodem.log file before starting");
  256. X    printf("\n\tl  <-- (ell) Turn OFF Log File Entries");
  257. X    printf("\n\tx  <-- Include copious debugging information in log file");
  258. X    printf("\n");
  259. X    }
  260. X
  261. X/* get type of transmission requested (text or binary) */
  262. Xgettype(ichar)
  263. Xchar ichar;
  264. X    {
  265. X    if (ichar == 't') return(ichar);
  266. X    if (ichar == 'b') return(ichar);
  267. X    error("Invalid Send/Receive Parameter - not t or b", FALSE);
  268. X    return(0);
  269. X    }
  270. X
  271. X/* print error message and exit; if mode == TRUE, restore normal tty modes */
  272. Xerror(msg, mode)
  273. Xchar *msg;
  274. Xint mode;
  275. X    {
  276. X    if (mode)
  277. X        restoremodes(TRUE);  /* put back normal tty modes */
  278. X    printf("\r\n%s\n", msg);
  279. X    if ((LOGFLAG || DEBUG) && (LOGFP != NULL))
  280. X        {   
  281. X        fprintf(LOGFP, "XMODEM Fatal Error:  %s\n", msg);
  282. X            fclose(LOGFP);
  283. X        }
  284. X    exit(-1);
  285. X    }
  286. X
  287. X
  288. X/* Construct a proper (i.e. pretty) sector count for messages */
  289. X
  290. Xchar
  291. X*sectdisp(recvsectcnt, bufsize, plus1)
  292. Xlong recvsectcnt;
  293. Xint bufsize, plus1;
  294. X    {
  295. X    static char string[20];
  296. X    if (plus1)
  297. X        recvsectcnt += (bufsize == 128) ? 1 : 8;
  298. X    if (bufsize == 128 || recvsectcnt == 0)
  299. X        sprintf (string, "%d", recvsectcnt);
  300. X    else
  301. X        sprintf (string, "%d-%d", recvsectcnt-7, recvsectcnt);
  302. X    return(string);
  303. X    }
  304. X
  305. X/* type out debugging info */
  306. Xxmdebug(str)
  307. Xchar *str;
  308. X    {
  309. X    if (DEBUG && (LOGFP != NULL))
  310. X        fprintf(LOGFP,"DEBUG: '%s'\n",str);
  311. X    }
  312. X
  313. X/* print elapsed time and rate of transfer in logfile */
  314. X
  315. Xint quant[] = { 60, 60, 24};    
  316. Xchar *sep[] = { "second", "minute", "hour" };
  317. X
  318. Xprtime (numsect, seconds)
  319. Xlong numsect;
  320. Xtime_t seconds;
  321. X
  322. X{
  323. X    register int i;
  324. X    register int Seconds;
  325. X    int nums[3];
  326. X    int rate = 0;
  327. X
  328. X    if (!LOGFLAG)
  329. X        return(0);
  330. X
  331. X    Seconds = (int)seconds;
  332. X
  333. X    if (Seconds != 0)
  334. X        rate = 128 * numsect/Seconds;
  335. X
  336. X    for (i=0; i<3; i++) {
  337. X        nums[i] = (Seconds % quant[i]);
  338. X        Seconds /= quant[i];
  339. X    }
  340. X
  341. X    fprintf (LOGFP, "%ld CP/M Sectors Transfered in ", numsect);
  342. X    while (--i >= 0)
  343. X        if (nums[i])
  344. X            fprintf (LOGFP, "%d %s%c ", nums[i], sep[i],
  345. X                nums[i] == 1 ? '\0' : 's');
  346. X    fprintf (LOGFP, "\n");
  347. X
  348. X    if (rate != 0)
  349. X        fprintf (LOGFP, "Transfer Rate = %d Characters per Second\n", rate);
  350. X
  351. X    return(0);
  352. X}
  353. X
  354. X/* Print elapsed time estimate */
  355. X
  356. Xprojtime (numsect, fd)
  357. Xlong numsect;
  358. XFILE *fd;
  359. X    {
  360. X    register int i;
  361. X    register int seconds;
  362. X    int nums[3];
  363. X
  364. X    if (numsect == 0)
  365. X        return (0);
  366. X
  367. X/* constant below should really be 1280; reduced to 90% to account for time lost in overhead */
  368. X
  369. X    seconds = 1422 * numsect / ttyspeed + 1;
  370. X
  371. X    for (i=0; i<3; i++) {
  372. X        nums[i] = (seconds % quant[i]);
  373. X        seconds /= quant[i];
  374. X    }
  375. X
  376. X    fprintf (fd, "Estimated transmission time ");
  377. X    while (--i >= 0)
  378. X        if (nums[i])
  379. X            fprintf (fd, "%d %s%c ", nums[i], sep[i],
  380. X                nums[i] == 1 ? '\0' : 's');
  381. X    fprintf (fd, "\n");
  382. X    return (0);
  383. X    }
  384. !Funky!Stuff!
  385. echo x - receive.c
  386. sed -e 's/^X//' > receive.c << '!Funky!Stuff!'
  387. X#include "xmodem.h"
  388. X
  389. X/**  receive a file  **/
  390. X
  391. X/* returns TRUE if in the midst of a batch transfer */
  392. X/* returns FALSE if no more files are coming */
  393. X
  394. X/* This routine is one HUGE do-while loop with far to many indented levels.
  395. X * I chose this route to facilitate error processing and to avoid GOTOs.
  396. X * Given the troubles I've had keeping the nested IF statements straight,
  397. X * I was probably mistaken...
  398. X */
  399. X
  400. Xrfile(name)
  401. Xchar *name;
  402. X    {
  403. X
  404. X    char *sectdisp();
  405. X    char *cpm_unix();
  406. X    char *strcpy();
  407. X    time_t time();
  408. X
  409. X    int fd,     /* file descriptor for created file */
  410. X    checksum,   /* packet checksum */
  411. X    firstchar,  /* first character of a packet */
  412. X    sectnum,    /* number of last received packet (modulo 128) */
  413. X    sectcurr,   /* second byte of packet--should be packet number (mod 128) */
  414. X    sectcomp,   /* third byte of packet--should be complement of sectcurr */
  415. X    tmode,      /* text mode if true, binary mode if false */
  416. X    errors,     /* running count of errors (reset when 1st packet starts */
  417. X    errorflag,  /* set true when packet (or first char of putative packet) is invalid */
  418. X    fatalerror, /* set within main "read-packet" Do-While when bad error found */
  419. X    inchecksum, /* incoming checksum or CRC */
  420. X    expsect,    /* expected number of sectors (YMODEM batch) */
  421. X    bufsize;    /* packet size (128 or 1024) */
  422. X    long recvsectcnt;   /* running sector count (128 byte sectors) */
  423. X    int bufctr; /* number of real chars in read packet */
  424. X    unsigned char *nameptr; /* ptr in filename for MODEM7 protocol */
  425. X    time_t start;   /* starting time of transfer */
  426. X    int openflag = FALSE;   /* is file open for writing? */
  427. X
  428. X    logit("----\nXMODEM File Receive Function\n");
  429. X    if (CRCMODE)
  430. X        logit("CRC mode requested\n");
  431. X
  432. X    BATCH = FALSE;          /* don't know if really are in batch mode ! */
  433. X    fatalerror = FALSE;
  434. X    sectnum = errors = recvsectcnt = 0;
  435. X    bufsize = 128;
  436. X
  437. X    tmode = (XMITTYPE == 't') ? TRUE : FALSE;
  438. X
  439. X    sleep(1);       /* wait a second for other side to get ready */
  440. X    if (CRCMODE)        /* start up transfer */
  441. X        sendbyte(CRCCHR);
  442. X    else
  443. X        sendbyte(NAK);
  444. X
  445. X
  446. X    do                  /* start of MAIN Do-While loop to read packets */
  447. X        {   
  448. X        errorflag = FALSE;
  449. X        do              /* start by reading first byte in packet */
  450. X            {
  451. X            firstchar = readbyte(6);
  452. X            } 
  453. X            while ((firstchar != SOH) 
  454. X                && (firstchar != STX) 
  455. X                && (firstchar != EOT) 
  456. X                && (firstchar != ACK || recvsectcnt > 0) 
  457. X                && (firstchar != TIMEOUT) 
  458. X                && (firstchar != CAN));
  459. X
  460. X        if (firstchar == EOT)           /* check for REAL EOT */
  461. X            {
  462. X            if (readbyte(1) != TIMEOUT)
  463. X                {
  464. X                firstchar = TIMEOUT;
  465. X                errorflag = TRUE;
  466. X                logit ("EOT followed by characters; ignored\n");
  467. X                }
  468. X            }
  469. X
  470. X        if (firstchar == TIMEOUT)       /* timeout? */
  471. X            {  
  472. X            logitarg("Timeout on Sector %s\n", sectdisp(recvsectcnt,bufsize,1));
  473. X                errorflag = TRUE;
  474. X            }
  475. X
  476. X        if (firstchar == CAN)           /* bailing out? */
  477. X            {
  478. X            if ((readbyte(3) & 0x7f) == CAN)
  479. X                error("Reception canceled at user's request",TRUE);
  480. X            else
  481. X                {
  482. X                errorflag = TRUE;
  483. X                logit("Received single CAN character\n");
  484. X                }
  485. X            }
  486. X
  487. X        if (firstchar == ACK)           /* MODEM7 batch? */
  488. X            {
  489. X            int i,c; 
  490. X
  491. X            logit("MODEM7 Batch Protocol\n");
  492. X            nameptr = buff;
  493. X            checksum = 0;
  494. X
  495. X            for (i=0; i<NAMSIZ; i++)
  496. X                {
  497. X                c = readbyte(3);
  498. X
  499. X                if (c == CAN)
  500. X                    {
  501. X                    if (readbyte(3) == CAN)
  502. X                        error("Program Canceled by User", TRUE);
  503. X                    else
  504. X                        {
  505. X                        logit("Received single CAN character\n");
  506. X                        errorflag = TRUE;
  507. X                        break;
  508. X                        }
  509. X                    }
  510. X
  511. X                if (c == EOT && i == 0)
  512. X                    {
  513. X                    logit("MODEM7 Batch Receive Complete\n");
  514. X                    return (FALSE);
  515. X                    }
  516. X
  517. X                if (c == TIMEOUT)
  518. X                    {
  519. X                    logit("Timeout waiting for MODEM7 filename character\n");
  520. X                    errorflag = TRUE;
  521. X                    break;
  522. X                    }
  523. X
  524. X                if (c == BAD_NAME)
  525. X                    {
  526. X                    logit("Error during MODEM7 filename transfer\n");
  527. X                    errorflag = TRUE;
  528. X                    break;
  529. X                    }
  530. X
  531. X                *nameptr++ = c;
  532. X                checksum += c;
  533. X                sendbyte(ACK);
  534. X                }
  535. X
  536. X            if (!errorflag)
  537. X                {
  538. X                c = readbyte(3);
  539. X                if (c == CTRLZ)     /* OK; end of string found */
  540. X                    {
  541. X                    sendbyte(checksum + CTRLZ);
  542. X                    if (readbyte(3) == ACK)     /* file name found! */
  543. X                        {
  544. X                        xmdebug("MODEM7 file name OK");
  545. X                        *nameptr = '\000';
  546. X                        name = cpm_unix(buff);
  547. X                        BATCH = TRUE;
  548. X                        }
  549. X                    else
  550. X                        {
  551. X                        logit("Checksum error in MODEM7 filename\n");
  552. X                        errorflag = TRUE;
  553. X                        }
  554. X                    }
  555. X                else
  556. X                    {
  557. X                    logit("Length error in MODEM7 fielname\n");
  558. X                    errorflag = TRUE;
  559. X                    }
  560. X                }
  561. X            }
  562. X            
  563. X
  564. X        if (firstchar == SOH || firstchar == STX)  /* start reading packet */
  565. X            {
  566. X            bufsize = (firstchar == SOH) ? 128 : 1024;
  567. X
  568. X            if (recvsectcnt == 0)           /* 1st data packet, initialize */
  569. X                {
  570. X                if (bufsize == 1024)
  571. X                    logit("1K packet mode chosen\n");
  572. X                start = time((time_t *) 0);
  573. X                errors = 0;
  574. X                }
  575. X
  576. X        sectcurr = readbyte(3);
  577. X        sectcomp = readbyte(3);
  578. X        if ((sectcurr + sectcomp) == 0xff)  /* is packet number checksum correct? */
  579. X            {  
  580. X            if (sectcurr == ((sectnum+1) & 0xff))   /* is packet number correct? */
  581. X                {  
  582. X                if (DEBUG)
  583. X                    fprintf(LOGFP,"DEBUG: packet %d started\n", sectnum);
  584. X
  585. X            /* Read, process and calculate checksum for a buffer of data */
  586. X
  587. X                if (readbuf(bufsize, 3, tmode, &checksum, &bufctr) != TIMEOUT) 
  588. X                                {
  589. X
  590. X            /* verify checksum or CRC */
  591. X
  592. X                if (CRCMODE) 
  593. X                                    {
  594. X                    checksum &= 0xffff;
  595. X                    inchecksum = readbyte(3);  /* get 16-bit CRC */
  596. X                    inchecksum = (inchecksum<<8) | readbyte(3);
  597. X                    }
  598. X                        
  599. X                else
  600. X                    inchecksum = readbyte(3);  /* get simple 8-bit checksum */
  601. X
  602. X                if (inchecksum == checksum) /* good checksum, hence good packet */
  603. X                    {  
  604. X                    xmdebug("checksum ok");
  605. X                    errors = 0;
  606. X                    recvsectcnt += (bufsize == 128) ? 1 : 8;
  607. X                    sectnum = sectcurr; 
  608. X
  609. X                    if (!openflag)      /* open output file if necessary */
  610. X                    {
  611. X                    openflag = TRUE;
  612. X                    if ((fd = creat(name, CREATMODE)) < 0)
  613. X                        {
  614. X                        sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
  615. X                        error("Can't create file for receive", TRUE);
  616. X                        }
  617. X                    logitarg("File Name: %s\n", name);
  618. X                    }
  619. X
  620. X                    if (write(fd, (char *) buff, bufctr) < 0)
  621. X                    error("File Write Error", TRUE);
  622. X                    else
  623. X                    sendbyte(ACK);      /* ACK the received packet */
  624. X                    }
  625. X
  626. X            /* Start handling various errors and special conditions */
  627. X
  628. X                else        /* bad checksum */
  629. X                    {  
  630. X                    logitarg("Checksum Error on Sector %s\n", sectdisp(recvsectcnt,bufsize,1));
  631. X                    errorflag = TRUE;
  632. X                    }
  633. X                                }
  634. X
  635. X                else    /* read timeout */
  636. X                {
  637. X                logitarg("Timeout while reading sector %s\n",sectdisp(recvsectcnt,bufsize,1));
  638. X                errorflag = TRUE;
  639. X                }
  640. X                }
  641. X
  642. X                        else        /* sector number is wrong OR Ymodem filename */
  643. X                            { 
  644. X                if (sectcurr == 0 && recvsectcnt == 0)  /* Ymodem file-name packet */
  645. X                {
  646. X                logit("YMODEM Batch Protocol\n");
  647. X
  648. X                /* Read and process a file-name packet */
  649. X
  650. X                if (readbuf(bufsize, 3, FALSE, &checksum, &bufctr) != TIMEOUT) 
  651. X                                    {
  652. X
  653. X                    /* verify checksum or CRC */
  654. X
  655. X                    if (CRCMODE) 
  656. X                                        {
  657. X                    checksum &= 0xffff;
  658. X                    inchecksum = readbyte(3);  /* get 16-bit CRC */
  659. X                    inchecksum = (inchecksum<<8) | readbyte(3);
  660. X                        }
  661. X                        
  662. X                    else
  663. X                    inchecksum = readbyte(3);  /* get simple 8-bit checksum */
  664. X
  665. X                    if (inchecksum == checksum) /* good checksum, hence good filename */
  666. X                    {
  667. X                    xmdebug("checksum ok");
  668. X                    strcpy(name, (char *)buff);
  669. X                                        expsect = ((buff[bufsize-1]<<8) | buff[bufsize-2]);
  670. X                    sendbyte(ACK);      /* ACK the packet */
  671. X                    BATCH = TRUE;
  672. X                    if (strlen(name) == 0)  /* check for no more files */
  673. X                        {
  674. X                        logit("YMODEM Batch Receive Complete\n");
  675. X                        return (FALSE);
  676. X                        }
  677. X                                        unixify(name);       /* make filename canonical */
  678. X                    logitarg("YMODEM file name: %s\n", name);
  679. X                    logitarg("YMODEM estimated file length %d sectors\n", expsect);
  680. X                    logitarg("YMODEM header info: %s\n", (char *)buff + strlen(name) + 1);
  681. X                    }
  682. X
  683. X                    else                /* bad filename checksum */
  684. X                    {
  685. X                    logit("checksum error on filename sector\n");
  686. X                    errorflag = TRUE;
  687. X                    }
  688. X                    }
  689. X                else
  690. X                    {
  691. X                    logit("Timeout while reading filename packet\n");
  692. X                    errorflag = TRUE;
  693. X                                    }
  694. X                }
  695. X
  696. X                else if (sectcurr == sectnum)   /* duplicate sector? */
  697. X                {  
  698. X                logitarg("Duplicate sector %s flushed\n", sectdisp(recvsectcnt,bufsize,0));
  699. X                while(readbyte(3) != TIMEOUT)
  700. X                    ;
  701. X                sendbyte(ACK);
  702. X                }
  703. X                else                /* no, real phase error */
  704. X                {
  705. X                logitarg("Phase Error - Expected packet is %s\n", sectdisp(recvsectcnt,bufsize,1));
  706. X                errorflag = TRUE;
  707. X                fatalerror = TRUE;
  708. X                sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
  709. X                }
  710. X                }
  711. X            }
  712. X
  713. X        else        /* bad packet number checksum */
  714. X            {  
  715. X            logitarg("Header Sector Number Error on Sector %s\n", sectdisp(recvsectcnt, bufsize,1));
  716. X            errorflag = TRUE;
  717. X            }
  718. X
  719. X        }           /* END reading packet loop */
  720. X    
  721. X    if ((errorflag && !fatalerror) || recvsectcnt == 0) /* check on errors or batch transfers */
  722. X        {  
  723. X        if (errorflag)
  724. X            errors++;
  725. X        if (recvsectcnt != 0)
  726. X        while (readbyte(3) != TIMEOUT)  /* wait for line to settle if not beginning */
  727. X            ;
  728. X
  729. X        if (CRCMODE && recvsectcnt == 0 && errors == CRCSWMAX)
  730. X        {
  731. X        CRCMODE = FALSE;
  732. X        logit("Sender not accepting CRC request, changing to checksum\n");
  733. X        sendbyte(NAK);
  734. X        }
  735. X        else if (!CRCMODE && recvsectcnt == 0 && errors == CRCSWMAX)
  736. X        {
  737. X        CRCMODE = TRUE;
  738. X        logit("Sender not accepting checksum request, changing to CRC\n");
  739. X        sendbyte(CRCCHR);
  740. X        }
  741. X        else if (CRCMODE && recvsectcnt == 0)
  742. X        sendbyte(CRCCHR);
  743. X        else
  744. X        sendbyte(NAK);
  745. X        }
  746. X    }
  747. X        while ((firstchar != EOT) && (errors < ERRORMAX) && !fatalerror);   /* end of MAIN Do-While */
  748. X
  749. X    if ((firstchar == EOT) && (errors < ERRORMAX))  /* normal exit? */
  750. X        {
  751. X        close(fd);
  752. X        sendbyte(ACK);
  753. X        logit("Receive Complete\n");
  754. X        prtime (recvsectcnt, time((time_t *) 0) - start);
  755. X        
  756. X        if (BATCH)          /* send appropriate return code */
  757. X        return(TRUE);
  758. X        else
  759. X        return(FALSE);
  760. X        }
  761. X    else                /* no, error exit */
  762. X        { 
  763. X        if (recvsectcnt != 0)
  764. X        sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
  765. X        error("ABORTED -- Too Many Errors", TRUE);
  766. X        return (FALSE);
  767. X        }
  768. X    }
  769. !Funky!Stuff!
  770. echo x - send.c
  771. sed -e 's/^X//' > send.c << '!Funky!Stuff!'
  772. X/**  send a file  **/
  773. X
  774. X/*
  775. X * Operation of this routine depends on on MDM7BAT and YMDMBAT flags.
  776. X *
  777. X * If "name" is NULL; close out the BATCH send.
  778. X */
  779. X
  780. X#include "xmodem.h"
  781. X
  782. Xsfile(name)
  783. Xchar *name;
  784. X    {
  785. X
  786. X    char *sectdisp();
  787. X    time_t time();
  788. X    char *strcpy();
  789. X    char *unix_cpm();
  790. X
  791. X    extern unsigned short crctab[1<<B];    /* CRC-16 constant values, see getput.c */
  792. X
  793. X    register int bufctr,         /* array index for data buffer */
  794. X    sectnum;            /* packet number for packet header */
  795. X
  796. X    register unsigned short checksum;     /* checksum/crc */
  797. X
  798. X    char blockbuf[BBUFSIZ+6];    /* holds packet as it is constructed */
  799. X
  800. X    struct stat filestatbuf;    /* file status info */
  801. X
  802. X    int fd,         /* file descriptor for file being transmitted */
  803. X    errors,            /* cumulative count of errors */
  804. X    attempts,        /* number of attempts made to transmit a packet */
  805. X    nlflag,         /* flag that we have to send a LF in next packet */
  806. X    sendfin,         /* flag that we are sending the last packet */
  807. X    closeout,        /* flag that we are closing out batch send */
  808. X    tmode,            /* TRUE for text mode; FALSE for binary mode */
  809. X    bbufcnt,        /* array index for packet */
  810. X    firstchar,        /* first character in protocol transaction */
  811. X    bufsize,        /* packet size (128 or 1024) */
  812. X    sendresp,          /* response char to sent block received from remote*/
  813. X    extrachar;        /* count of extra LF characters added */
  814. X    long sentsect;        /* count of 128 byte sectors actually sent */
  815. X    long expsect;        /* count of 128 byte sectors expected to be sent */
  816. X    time_t start;        /* starting time of transfer */
  817. X    char c;
  818. X
  819. X    nbchr = 0;  /* clear buffered read char count */
  820. X
  821. X    CRCMODE = FALSE;    /* Receiver determines use of crc or checksum */
  822. X
  823. X    closeout = FALSE;    /* Check on NULL file name */
  824. X    if (strcmp(name,"") == 0)
  825. X        {
  826. X        if (BATCH)
  827. X            closeout = TRUE;
  828. X        else
  829. X            {
  830. X            sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
  831. X            error("NULL file name in send", TRUE);
  832. X            }
  833. X        }
  834. X
  835. X    if (!closeout)        /* Are we closing down batch? */
  836. X        {            /* no; let's send a file */
  837. X        if ((fd = open(name, 0)) < 0)    
  838. X            {  
  839. X            sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
  840. X                    error("Can't open file for send", TRUE);
  841. X            }
  842. X    
  843. X        stat(name, &filestatbuf);  /* get file status bytes */
  844. X        expsect = (filestatbuf.st_size/128) + 1;
  845. X    
  846. X        if (LOGFLAG)
  847. X            {   
  848. X            fprintf(LOGFP, "----\nXMODEM Send Function\n");
  849. X                fprintf(LOGFP, "File Name: %s\n", name);
  850. X              fprintf(LOGFP,"Estimated File Size %ldK, %ld Records, %ld Bytes\n",
  851. X                (filestatbuf.st_size/1024)+1, expsect, filestatbuf.st_size);
  852. X            projtime(expsect, LOGFP);
  853. X            }
  854. X        }
  855. X    else
  856. X        {
  857. X        logit("----\nXMODEM Send Function\n");
  858. X        logit("Closing down Batch Transmission\n");
  859. X        }
  860. X
  861. X
  862. X    tmode = (XMITTYPE == 't') ? TRUE : FALSE;    /* set text mode */
  863. X
  864. X    bufsize = LONGPACK ? 1024 : 128;        /* set sector size */
  865. X    if (LONGPACK && !closeout)
  866. X        logit("1K packet mode chosen\n");
  867. X
  868. X        sendfin = nlflag = FALSE;
  869. X      attempts = 0;
  870. X
  871. X    /* wait for and read startup character */
  872. X    do
  873. X        {
  874. X        while (((firstchar=readbyte(30)) != NAK) && (firstchar != CRCCHR) && (firstchar != CAN))
  875. X            if (++attempts > NAKMAX)
  876. X                error("Remote System Not Responding", TRUE);
  877. X
  878. X        if ((firstchar & 0x7f) == CAN)
  879. X            if (readbyte(3) == CAN)
  880. X                error("Send cancelled at user's request",TRUE);
  881. X
  882. X        if (firstchar == CRCCHR)
  883. X            {
  884. X            CRCMODE = TRUE;
  885. X            if (!closeout)
  886. X                logit("CRC mode requested\n");
  887. X            }
  888. X        }
  889. X    while (firstchar != NAK && firstchar != CRCCHR);
  890. X
  891. X    if (closeout && MDM7BAT)    /* close out MODEM7 batch */
  892. X        {
  893. X        sendbyte(ACK); sendbyte (EOT);
  894. X        readbyte(2);            /* flush junk */
  895. X        return;
  896. X        }
  897. X
  898. X    if (MDM7BAT)        /* send MODEM7 file name and resync for data packets */
  899. X        {
  900. X        if (send_name(unix_cpm(name)) == -1)        /* should do better job here!! */
  901. X            error("MODEM7-batch filename transfer botch", TRUE);
  902. X
  903. X        firstchar = readbyte(5);
  904. X        if (firstchar != CRCCHR  && firstchar != NAK)    /* Should do some better error handling!!! */
  905. X            error("MODEM7 protocol botch, NAK/C expected", TRUE);
  906. X
  907. X        CRCMODE = FALSE;
  908. X        if (firstchar == CRCCHR)
  909. X            {
  910. X            CRCMODE = TRUE;
  911. X            logit("CRC mode requested for MODEM7 batch transfer\n");
  912. X            }
  913. X        }
  914. X
  915. X    sectnum = 1;
  916. X
  917. X    if (YMDMBAT)    /* Fudge for YMODEM transfer (to send name packet) */
  918. X        {
  919. X        sectnum = 0;
  920. X        bufsize = 128;
  921. X        }
  922. X
  923. X    attempts = errors = sentsect = extrachar = 0;
  924. X    start = time((time_t *) 0);
  925. X
  926. X        do             /* outer packet building/sending loop; loop till whole file is sent */
  927. X        {   
  928. X
  929. X        if (closeout && YMDMBAT && sectnum == 1)    /* close out YMODEM */
  930. X            return;
  931. X
  932. X        if (YMDMBAT && sectnum == 1)            /* get set to send YMODEM data packets */
  933. X            {
  934. X            bufsize = LONGPACK ? 1024 : 128;
  935. X            do
  936. X                {
  937. X                while (((firstchar=readbyte(3)) != CRCCHR) && (firstchar != CAN))
  938. X                    if (++attempts > NAKMAX)
  939. X                        error("YMODEM protocol botch, C expected", TRUE);
  940. X                if ((firstchar&0x7f) == CAN)
  941. X                    if (readbyte(3) == CAN)
  942. X                        error("Send cancelled at User's request", TRUE);
  943. X                }
  944. X            while (firstchar != CRCCHR);
  945. X            attempts = 0;
  946. X            }
  947. X
  948. X        if (extrachar >= 128)    /* update expected sector count */
  949. X            {
  950. X            extrachar = 0;
  951. X            expsect++;
  952. X            }
  953. X
  954. X        if ((bufsize == 1024) && (errors > KSWMAX))
  955. X            {
  956. X            logit("Reducing packet size to 128 due to excessive errors\n");
  957. X            bufsize = 128;
  958. X            }
  959. X
  960. X        if ((bufsize == 1024) && ((expsect - sentsect) < 8))
  961. X            {
  962. X            logit("Reducing packet size to 128 for tail end of file\n");
  963. X            bufsize = 128;
  964. X            }
  965. X
  966. X        if (sectnum > 0)    /* data packet */
  967. X            {
  968. X            for (bufctr=0; bufctr < bufsize;)
  969. X                    {
  970. X                if (nlflag)
  971. X                            {  
  972. X                    buff[bufctr++] = LF;  /* leftover newline */
  973. X                               nlflag = FALSE;
  974. X                        }
  975. X                if (getbyte(fd, &c) == EOF)
  976. X                    { 
  977. X                    sendfin = TRUE;  /* this is the last sector */
  978. X                       if (!bufctr)  /* if EOF on sector boundary */
  979. X                              break;  /* avoid sending extra sector */
  980. X                          buff[bufctr++] = CTRLZ;  /* Control-Z for CP/M EOF (even do it for binary file) */
  981. X                       continue;
  982. X                          }
  983. X    
  984. X                if (tmode && c == LF)  /* text mode & Unix newline? */
  985. X                        {
  986. X                    extrachar++;
  987. X                    buff[bufctr++] = CR;  /* insert carriage return */
  988. X                         if (bufctr < bufsize)
  989. X                                buff[bufctr++] = LF;  /* insert LF */
  990. X                           else
  991. X                            nlflag = TRUE;  /* insert on next sector */
  992. X                       }    
  993. X                else
  994. X                    buff[bufctr++] = c;  /* copy the char without change */
  995. X                    }
  996. X
  997. X                if (!bufctr)  /* if EOF on sector boundary */
  998. X                          break;  /* avoid sending empty sector */
  999. X            }    
  1000. X
  1001. X        else        /* YMODEM filename packet */
  1002. X            {
  1003. X            for (bufctr=0; bufctr<bufsize; bufctr++)
  1004. X                buff[bufctr]=0;
  1005. X            if (!closeout)
  1006. X                {
  1007. X                cpmify(name);
  1008. X                strcpy((char *)buff, name);
  1009. X                buff[bufsize-2]    = (expsect & 0xff);
  1010. X                buff[bufsize-1] = ((expsect >> 8) & 0xff);
  1011. X                }
  1012. X            }
  1013. X
  1014. X        bbufcnt = 0;        /* start building block to be sent */
  1015. X        blockbuf[bbufcnt++] = (bufsize == 1024) ? STX : SOH;    /* start of packet char */
  1016. X        blockbuf[bbufcnt++] = sectnum;        /* current sector # */
  1017. X        blockbuf[bbufcnt++] = ~sectnum;   /* and its complement */
  1018. X
  1019. X                   checksum = 0;  /* initialize checksum */
  1020. X                   for (bufctr=0; bufctr < bufsize; bufctr++)
  1021. X                   {
  1022. X            blockbuf[bbufcnt++] = buff[bufctr];
  1023. X
  1024. X            if (CRCMODE)
  1025. X                checksum = (checksum<<B) ^ crctab[(checksum>>(W-B)) ^ buff[bufctr]];
  1026. X
  1027. X            else
  1028. X                           checksum = ((checksum+buff[bufctr]) & 0xff);
  1029. X                 }
  1030. X
  1031. X        if (CRCMODE)        /* put in CRC */
  1032. X            {
  1033. X            checksum &= 0xffff;
  1034. X            blockbuf[bbufcnt++] = ((checksum >> 8) & 0xff);
  1035. X            blockbuf[bbufcnt++] = (checksum & 0xff);
  1036. X            }
  1037. X        else            /* put in checksum */
  1038. X            blockbuf[bbufcnt++] = checksum;
  1039. X
  1040. X                attempts = 0;
  1041. X    
  1042. X                do                /* inner packet loop */
  1043. X                    {
  1044. X
  1045. X            writebuf(blockbuf, bbufcnt);    /* write the block */
  1046. X
  1047. X            if (DEBUG)
  1048. X                fprintf (LOGFP, "DEBUG: %d byte Packet %02xh (%02xh) sent, checksum %02xh %02xh\n", 
  1049. X                bbufcnt, blockbuf[1]&0xff, blockbuf[2]&0xff, blockbuf[bufsize+3]&0xff, blockbuf[bufsize+4]&0xff);
  1050. X
  1051. X                    attempts++;
  1052. X            sendresp = readbyte(10);  /* get response from remote */
  1053. X
  1054. X            if (sendresp != ACK)
  1055. X                   {
  1056. X                errors++;
  1057. X
  1058. X                if ((sendresp & 0x7f) == CAN)
  1059. X                    if ((readbyte(3) & 0x7f) == CAN)
  1060. X                        error("Send cancelled at user's request\n",TRUE);
  1061. X
  1062. X                if (sendresp == TIMEOUT)
  1063. X                    {
  1064. X                       logitarg("Timeout on sector %s\n",sectdisp(sentsect,bufsize,1));
  1065. X                    }
  1066. X                else
  1067. X                    {
  1068. X                       logitarg("Non-ACK on sector %s\n",sectdisp(sentsect,bufsize,1));
  1069. X                    }
  1070. X                   }
  1071. X                    }
  1072. X            while((sendresp != ACK) && (attempts < RETRYMAX) && (errors < ERRORMAX)); /* close of inner loop */
  1073. X
  1074. X               sectnum++;  /* increment to next sector number */
  1075. X        sentsect += (bufsize == 128) ? 1 : 8;
  1076. X            }
  1077. X        while (!sendfin && (attempts < RETRYMAX) && ( errors < ERRORMAX));  /* end of outer loop */
  1078. X
  1079. X        if (attempts >= RETRYMAX)
  1080. X        {
  1081. X        sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
  1082. X        error("Remote System Not Responding", TRUE);
  1083. X        }
  1084. X
  1085. X    if (attempts > ERRORMAX)
  1086. X        {
  1087. X        sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
  1088. X        error ("Too many errors in transmission", TRUE);
  1089. X        }
  1090. X
  1091. X        attempts = 0;
  1092. X        sendbyte(EOT);  /* send 1st EOT to close down transfer */
  1093. X    
  1094. X        while ((readbyte(15) != ACK) && (attempts++ < RETRYMAX))     /* wait for ACK of EOT */
  1095. X        {
  1096. X        logit("EOT not ACKed\n");
  1097. X           sendbyte(EOT);
  1098. X        }
  1099. X
  1100. X        if (attempts >= RETRYMAX)
  1101. X           error("Remote System Not Responding on Completion", TRUE);
  1102. X
  1103. X        close(fd);
  1104. X
  1105. X        logit("Send Complete\n");
  1106. X    prtime(sentsect, time((time_t *) 0) - start);
  1107. X    }
  1108. !Funky!Stuff!
  1109. exit
  1110.  
  1111.