home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_200 / 277_01 / xmodem.c < prev    next >
Text File  |  1988-11-15  |  7KB  |  388 lines

  1. /*
  2.  * xmodem.c - xmodem functions for Xenix or Unix
  3.  * copyright 1986, 1988 Ronald Florence
  4.  * 
  5.  * modified 3/88 to do crc by packet instead of by byte
  6.  */
  7.  
  8. #include <signal.h>
  9. #include <stdio.h>
  10.  
  11. #ifdef CU
  12.  
  13. extern int    rlfd;                /* the open line in cu */
  14. #define    WFD    rlfd
  15. #define RFD    rlfd
  16. #define    errf    stderr
  17.  
  18. #else
  19.  
  20. extern    FILE    *errf;                /* error file for remote */
  21. #define    WFD    1                /* stdout */
  22. #define RFD    0                /* stdin */
  23.  
  24. #endif
  25.  
  26. #define    BSIZE        128
  27. #define    DEBUG        01
  28. #define LF        02
  29. #define CRC        04
  30. #define NOREAD(x, c)    (rchar(x, &c) == -1)
  31. #define TX(c)        write(WFD, &c, 1)    
  32. #define ever        (;;)
  33.  
  34. static    char    soh = 0x01,
  35.         eot = 0x04,
  36.         ack = 0x06,
  37.         nak = 0x15,
  38.         can = 0x18,
  39.         crcinit = 'C';
  40.  
  41. static    int    debug,
  42.         crc;
  43.  
  44. unsigned short    do_crc();
  45.  
  46. int    kleenex(),
  47.     onalarm(); 
  48.  
  49. xget(fp, opts)
  50. FILE    *fp;
  51. int    opts;
  52. {
  53.     char     buf[BSIZE]; 
  54.     unsigned char    inch, b= 1, crchi;
  55.     int    iput = BSIZE, i; 
  56.  
  57.     debug = (opts & DEBUG);
  58.     crc = (opts & CRC);
  59.     signal(SIGALRM, onalarm);
  60. #ifdef CU
  61.     signal(SIGINT, kleenex);
  62. #else
  63.     sleep(10);
  64. #endif
  65.     (crc) ? TX(crcinit) : TX(nak);
  66.     for ever {
  67.         if NOREAD(10, inch) {
  68.             err("Timeout during SOH");
  69.             cksend(crc ? crcinit : nak);
  70.             continue;
  71.         }
  72.         if (inch == eot) 
  73.             break;
  74.         if (inch == can) {
  75.             err("CAN block %u", b);
  76.             kleenex(-1);
  77.         }
  78.         if (inch != soh) {
  79.             err("Bad SOH block %u: %#x", b, inch);
  80.             cksend(nak);
  81.             continue;
  82.         }
  83.         if NOREAD(2, inch) {
  84.             err("Timeout block %u during blocknum", b);
  85.             cksend(nak);
  86.             continue;
  87.         }
  88.         if (inch != b) {
  89.             err("Expected blocknum %u, got %u", b, inch);
  90.             cksend(nak);
  91.             continue;
  92.         }
  93.         if NOREAD(2, inch) {
  94.             err("Timeout block %u during ~blocknum", b);
  95.             cksend(nak);
  96.             continue;
  97.         }
  98.         if (inch != ~b) {
  99.             err("Expected ~blocknum %u, got %u", ~b, inch);
  100.             cksend(nak);
  101.             continue;
  102.         }
  103.             /* Read in the block of 128 bytes without
  104.              * taking time for checksums or crc.
  105.              */
  106.         for (i = 0; i < BSIZE; i++)
  107.             if NOREAD(2, buf[i]) 
  108.                 break;
  109.         if (i < BSIZE) {
  110.             err("Timeout data recv, char #%d", i);
  111.             cksend(nak);
  112.             continue;
  113.         }
  114.                 if (crc && NOREAD(2, crchi)) {
  115.             err("Timeout crc hibyte");
  116.             cksend(nak);
  117.             continue;
  118.         }
  119.                 if NOREAD(2, inch) {
  120.             err("Timeout %s", (crc) ? "crc lobyte" : "checksum");
  121.             cksend(nak);
  122.             continue;
  123.         }
  124.             /* Now, when we have the whole packet,
  125.              * do the checksum or crc.
  126.              */
  127.         if (crc) {
  128.             unsigned short    crcsum;
  129.  
  130.             crcsum = do_crc(buf);
  131.             if (inch + (crchi << 8) != crcsum) {
  132.                 err("Expected crc %u, got %u", 
  133.                     crcsum, inch + (crchi << 8));
  134.                 cksend(nak);
  135.                 continue;
  136.             }
  137.         }
  138.         else {
  139.             unsigned char    cksum;
  140.  
  141.             for (cksum = 0, i = 0; i < BSIZE; i++) 
  142.                 cksum += buf[i];
  143.             cksum %= 256;
  144.             if (cksum != inch) {
  145.                 err("Expected checksum %u, got %u", cksum,inch);
  146.                 cksend(nak);
  147.                 continue;
  148.             }
  149.         }
  150.         TX(ack);
  151. #ifdef CU
  152.         putc('.', stderr);
  153. #endif
  154.         if (opts & LF) 
  155.             for (i=0, iput=0; i < BSIZE; i++) {
  156.                 if (buf[i] == 0x1a)    /* old ms-dos eof */
  157.                     break;
  158.                 if (buf[i] != '\r')
  159.                     buf[iput++] = buf[i];
  160.             }
  161.         fwrite(buf, iput, 1, fp);
  162.         b++;
  163.         b %= 256;
  164.     }
  165.     TX(ack);
  166.     kleenex(0);
  167. }
  168.  
  169.  
  170. xput(fp, opts)
  171. FILE    *fp;
  172. int    opts;
  173. {
  174.     char    buf[BSIZE];
  175.     unsigned char    b = 1, cb, inch;
  176.     int     cread, i;
  177.  
  178.  
  179. #ifdef CU
  180.     signal(SIGINT, kleenex);
  181. #endif
  182.     signal(SIGALRM, onalarm);
  183.     debug = (opts & DEBUG);
  184.     rchar(60, &cb);
  185.     if (cb == crcinit)
  186.         crc = 1;
  187.     else if (cb == nak)
  188.         crc = 0;
  189.     else  {
  190.         err("No startup %s", (crc) ? "'C'" : "NAK");
  191.         kleenex(-1);
  192.     }
  193.     cread = fillbuf(fp, buf, (opts & LF));
  194.     while (cread) {
  195.         for (i = cread; i < BSIZE; i++) 
  196.             buf[i] = 0;
  197.         TX(soh);
  198.         TX(b);
  199.         cb = ~b;
  200.         TX(cb);
  201.         write(WFD, buf, BSIZE);
  202.         if (crc) {
  203.             unsigned short    crcsum;
  204.             unsigned char    crclo, crchi;
  205.  
  206.             crcsum = do_crc(buf);
  207.             crclo = (crcsum & 0xff);
  208.             crchi = (crcsum >> 8);
  209.             TX(crchi);
  210.             TX(crclo);
  211.         }
  212.         else {
  213.             unsigned char    cksum;
  214.  
  215.             for (cksum = 0, i = 0; i < BSIZE; i++) 
  216.                 cksum += buf[i];
  217.             cksum %= 256;
  218.             TX(cksum);
  219.         }
  220.         if NOREAD(15, inch) {
  221.             err("Timeout after block %u", b);
  222.             continue;
  223.         }
  224.         if (inch == can) {
  225.             err("CAN after block %u", b);
  226.             kleenex(-1);
  227.         }
  228.         if (inch != ack) {
  229.             err("Non-ACK after block %u: %#x", b, inch);
  230.             continue;
  231.         }
  232. #ifdef CU
  233.         putc('.', stderr);
  234. #else
  235.         if (debug) 
  236.             fprintf(errf, "Validated block %u\n", b);
  237. #endif
  238.         cread = fillbuf(fp, buf, (opts & LF));
  239.         b++;
  240.         b %= 256;
  241.     }
  242.     for ever {
  243.         TX(eot);
  244.         if NOREAD(15, inch) {
  245.             err("Timeout during EOT");
  246.             continue;
  247.         }
  248.         if (inch == can) {
  249.             err("CAN during EOT");
  250.             kleenex(-1);
  251.         }
  252.         if (inch != ack) {
  253.             err("Non-ACK during EOT: %#x", inch);
  254.             continue;
  255.         }
  256.         break;
  257.     }
  258.     kleenex(0);
  259. }
  260.  
  261.  
  262. fillbuf(fp, buf, lf)
  263. FILE    *fp;
  264. char    *buf;
  265. int    lf;
  266. {
  267.     int    i = 0, c; 
  268.     static    int    cr_held; 
  269.  
  270.     if (cr_held) {
  271.         buf[i] = '\n';
  272.         i++;
  273.         cr_held--;
  274.     }
  275.     for (; i < BSIZE; i++) {
  276.         if ((c = getc(fp)) == EOF)
  277.             break;
  278.         if (c == '\n' && lf) {
  279.             buf[i] = '\r';
  280.             if (i == 127) {
  281.                 cr_held++;
  282.                 return BSIZE;
  283.             }
  284.             buf[i+1] = '\n';
  285.             i++;
  286.         }
  287.         else
  288.             buf[i] = c;
  289.     }
  290.     return i;
  291. }
  292.  
  293.  
  294. unsigned short do_crc(b)
  295. char    *b;
  296. {
  297.     unsigned short    shift, flag, crcsum;
  298.     char    c;
  299.     int    i;
  300.  
  301.     for (i = 0, crcsum = 0; i < (BSIZE + 2); i++) {
  302.         c = (i < BSIZE) ? b[i] : 0;
  303.         for (shift = 0x80; shift; shift >>= 1)  {
  304.             flag = (crcsum & 0x8000);
  305.             crcsum <<= 1;
  306.             crcsum |= ((shift & c) ? 1 : 0);
  307.             if (flag)
  308.                 crcsum ^= 0x1021;
  309.         }
  310.     }
  311.     return (crcsum);
  312. }
  313.  
  314.  
  315. /* The timeout in rchar() works by deliberately 
  316.  * interrupting the read() system call.  We know 
  317.  * errno=EINTR, so there is no reason for a 
  318.  * perror() autopsy. 
  319.  */
  320. rchar(timeout, cp)
  321. unsigned    timeout;
  322. char    *cp;
  323. {
  324.     int    c; 
  325.  
  326.     alarm(timeout);
  327.     if ((c = read(RFD, cp, 1)) == -1)
  328.         return -1;
  329.     alarm(0);
  330.     return c;
  331. }
  332.  
  333.  
  334. onalarm()
  335. {
  336.     signal(SIGALRM, onalarm);
  337. }
  338.  
  339.  
  340. kleenex(sig)
  341. int sig;
  342. {
  343. #ifdef CU
  344.     if (sig > 0)
  345.         cksend(can);
  346.     else 
  347.         fprintf(stderr, "\r\nFile transfer %s.",
  348.             (sig) ? "cancelled" : "complete");
  349.     fprintf(stderr, "\r\n");
  350. #else
  351.     printf("File transfer %s.\r\n", (sig) ? "cancelled" : "complete");
  352.     resetline();
  353. #endif
  354.     exit(sig);
  355. }
  356.  
  357.  
  358. cksend(ch)
  359. char    ch;
  360. {
  361.     int    j;
  362.     char    cp;
  363.  
  364.     do {
  365.         j = rchar(2, &cp);
  366.     } while (j != -1);
  367.     TX(ch);
  368. }
  369.  
  370.  
  371. /* VARARGS1 */
  372. err(s, i, j)
  373. char    *s;
  374. int    i, j;
  375. {
  376.     if (debug) {
  377.         fprintf(errf, s, i, j);
  378. #ifndef CU
  379.         fprintf(errf, "\n");
  380.     }
  381. #else
  382.         fprintf(errf, "\r\n");
  383.     }
  384.     else
  385.         putc('%', stderr);
  386. #endif
  387. }
  388.