home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / xc-4.1 / part02 / xcxmdm.c < prev   
Encoding:
C/C++ Source or Header  |  1993-04-13  |  10.5 KB  |  488 lines

  1. /*    xcxmdm.c -- XMODEM Protocol module for XC
  2.     This file uses 4-character tabstops
  3. */
  4.  
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9. #include <signal.h>
  10. #include <setjmp.h>
  11. #include "xc.h"
  12.  
  13. #define CPMEOF    032    /* ^Z */
  14. #define WANTCRC 'C'
  15. #define OK         0
  16. #define TIMEOUT    -1     /* -1 is returned by readbyte() upon timeout */
  17. #define ERROR    -2
  18. #define WCEOT    -3
  19. #define RETRYMAX 10
  20. #define SECSIZ  128
  21. #define Resume_Not_Allowed    1
  22.  
  23. /* crc_xmodem_tab calculated by Mark G. Mendel, Network Systems Corporation */
  24. ushort crc_xmodem_tab[256] = {
  25.      0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
  26.      0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
  27.      0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
  28.      0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
  29.      0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
  30.      0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
  31.      0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
  32.      0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
  33.      0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
  34.      0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
  35.      0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
  36.      0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
  37.      0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
  38.      0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
  39.      0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
  40.      0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
  41.      0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
  42.      0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
  43.      0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
  44.      0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
  45.      0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
  46.      0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
  47.      0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
  48.      0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
  49.      0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
  50.      0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
  51.      0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
  52.      0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
  53.      0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
  54.      0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
  55.      0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
  56.      0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
  57. };
  58.  
  59. short crcheck = TRUE;        /* CRC check enabled? */
  60. static FILE *xfp;            /* buffered file pointer */
  61. static short firstsec,        /* first sector of file or not? */
  62.             textmode,        /* Text translations enabled? */
  63.             save_crc;        /* Saved crcheck value */
  64. static char wcbuf[SECSIZ];    /* Ward Christensen sector buffer */
  65. static ushort Updcrc();
  66. static jmp_buf our_env;
  67. static void (*oldvec)();
  68.  
  69. /*    send 10 CAN's to try to get the other end to shut up */
  70. static void
  71. canit()
  72. {
  73.     int i;
  74.  
  75.     for(i = 0; i < 20; i++)
  76.         sendbyte(CAN);
  77. }
  78.  
  79. static void
  80. xmsigint(junk)
  81. int junk;
  82. {
  83.     show_abort();
  84.     signal(SIGINT, SIG_IGN);    /* Ignore subsequent DEL's */
  85.     canit();                    /* Abort the transmission */
  86.     longjmp(our_env,1);
  87. }
  88.  
  89. /*    fill the CP/M sector buffer from the UNIX file
  90.     do text adjustments if necessary
  91.     return 1 if more sectors are to be read, or 0 if this is the last
  92. */
  93. static
  94. getsec()
  95. {
  96.     int i;
  97.     register c;
  98.  
  99.     i = 0;
  100.     while(i < SECSIZ && (c = getc(xfp)) != EOF){
  101.         if (textmode && c == '\n'){
  102.             wcbuf[i++] = '\r';
  103.             if (i >= SECSIZ){         /* handle a newline on the last byte */
  104.                 ungetc(c, xfp);         /* of the sector */
  105.                 return(1);
  106.             }
  107.         }
  108.         wcbuf[i++] = c;
  109.     }
  110.     /* make sure that an extra blank sector is not sent */
  111.     if (c != EOF && (c = getc(xfp)) != EOF){
  112.         ungetc(c, xfp);
  113.         return(1);
  114.     }
  115.     /* fill up the last sector with ^Z's if text mode or 0's if binary mode */
  116.     while(i < SECSIZ)
  117.         wcbuf[i++] = textmode ? CPMEOF : '\0';
  118.     return(0);
  119. }
  120.  
  121. /*    wcgetsec() inputs an XMODEM "sector".
  122.     This routine returns the sector number encountered, or ERROR if a valid
  123.     sector is not received or CAN received; or WCEOT if EOT sector.
  124.  
  125.     Maxtime is the timeout for the first character, set to 6 seconds for
  126.     retries. No ACK is sent if the sector is received ok. This must be
  127.     done by the caller when it is ready to receive the next sector.
  128. */
  129. static
  130. wcgetsec(maxtime)
  131. unsigned maxtime;
  132. {
  133.     register ushort oldcrc;
  134.     register checksum, j, c;
  135.     int sectcurr, sectcomp, attempts;
  136.  
  137.     for(attempts = 0; attempts < RETRYMAX; attempts++){
  138.         do {
  139.             c = readbyte(maxtime);
  140.         } while(c != SOH && c != EOT && c != CAN && c != TIMEOUT);
  141.  
  142.         switch(c){
  143.         case SOH:
  144.             sectcurr = readbyte(3);
  145.             sectcomp = readbyte(3);
  146.             if ((sectcurr + sectcomp) == 0xff){
  147.                 oldcrc = checksum = 0;
  148.                 for(j = 0; j < SECSIZ; j++){
  149.                     if ((c = readbyte(3)) == TIMEOUT)
  150.                         goto timeout;
  151.                     wcbuf[j] = c;
  152.                     if (crcheck)
  153.                         oldcrc = Updcrc(c, oldcrc);
  154.                     else
  155.                         checksum += c;
  156.                 }
  157.                 if ((c = readbyte(3)) < 0)
  158.                     goto timeout;
  159.                 if (crcheck){
  160.                     oldcrc = Updcrc(c, oldcrc);
  161.                     if ((c = readbyte(3)) == TIMEOUT)
  162.                         goto timeout;
  163.                     if (Updcrc(c, oldcrc)){
  164.                         S2("CRC error");
  165.                         break;
  166.                     }
  167.                 }
  168.                 else if (((checksum - c) & 0xff) != 0){
  169.                     S2("Checksum error");
  170.                     break;
  171.                 }
  172.                 firstsec = FALSE;
  173.                 return(sectcurr);
  174.             }
  175.             else
  176.                 sprintf(Msg, "Sector number garbled 0%03o 0%03o",
  177.                     sectcurr, sectcomp);
  178.                 S2(Msg);
  179.             break;
  180.         case EOT:
  181.             if (readbyte(3) == TIMEOUT)
  182.                 return(WCEOT);
  183.             break;
  184.         case CAN:
  185.             S2("Sender CANcelled");
  186.             return(ERROR);
  187.         case TIMEOUT:
  188.             if (firstsec)
  189.             break;
  190. timeout:
  191.         S2("Timeout");
  192.         break;
  193.         }
  194.         S2("Trying again on this sector");
  195.         purge();
  196.         if (firstsec)
  197.             sendbyte(crcheck ? WANTCRC : NAK);
  198.         else
  199.             maxtime = 6,
  200.             sendbyte(NAK);
  201.     }
  202.     S2("Retry count exceeded");
  203.     canit();
  204.     return(ERROR);
  205. }
  206.  
  207. static
  208. putsec()
  209. {
  210.     int i;
  211.     register c;
  212.  
  213.     for(i = 0; i < SECSIZ; i++){
  214.         c = wcbuf[i];
  215.         if (textmode){
  216.             if (c == CPMEOF)
  217.                 return(1);
  218.             if (c == '\r')
  219.                 continue;
  220.         }
  221.         putc(c, xfp);
  222.     }
  223.     return(0);
  224. }
  225.  
  226. /* Receive a file using XMODEM protocol */
  227. static
  228. wcrx()
  229. {
  230.     register sendchar, sectnum, sectcurr;
  231.  
  232.     strcpy(Name, word);
  233.     if (!(xfp=QueryCreate(Resume_Not_Allowed)))
  234.         return(ERROR);
  235.  
  236.     firstsec = TRUE;
  237.     sectnum = 0;
  238.     sendchar = crcheck ? WANTCRC : NAK;
  239.     fputc('\r',tfp),
  240.     fputc('\n', tfp);
  241.     S1("Sync...");
  242.  
  243.     while(TRUE){
  244.         purge();
  245.         sendbyte(sendchar);
  246.         sectcurr = wcgetsec(6);
  247.         if (sectcurr == ((sectnum + 1) & 0xff)){
  248.             sectnum++;
  249.             putsec();
  250.             fprintf(tfp,"Received sector #%d\r", sectnum);
  251.             sendchar = ACK;
  252.             continue;
  253.         }
  254.  
  255.         if (sectcurr == (sectnum & 0xff)){
  256.             sprintf(Msg, "Received duplicate sector #%d", sectnum);
  257.             S2(Msg);
  258.             sendchar = ACK;
  259.             continue;
  260.         }
  261.  
  262.         fclose(xfp);
  263.  
  264.         if (sectcurr == WCEOT){
  265.             S1("File received OK");
  266.             sendbyte(ACK);
  267.             return(OK);
  268.         }
  269.  
  270.         if (sectcurr == ERROR)
  271.             return(ERROR);
  272.  
  273.         sprintf(Msg, "Sync error ... expected %d(%d), got %d",
  274.             (sectnum + 1) & 0xff, sectnum, sectcurr);
  275.         S;
  276.         return(ERROR);
  277.     }
  278. }
  279.  
  280. /*    wcputsec outputs a Ward Christensen type sector.
  281.     it returns OK or ERROR
  282. */
  283. static
  284. wcputsec(sectnum)
  285. int sectnum;
  286. {
  287.     register ushort oldcrc;
  288.     register checksum, j, c, attempts;
  289.  
  290.     oldcrc = checksum = 0;
  291.     for(j = 0; j < SECSIZ; j++)
  292.         c = wcbuf[j],
  293.         oldcrc = Updcrc(c, oldcrc),
  294.         checksum += c;
  295.     oldcrc = Updcrc(0, Updcrc(0, oldcrc));
  296.  
  297.     for(attempts = 0; attempts < RETRYMAX; attempts++){
  298.         sendbyte(SOH);
  299.         sendbyte(sectnum);
  300.         sendbyte(-sectnum - 1);
  301.         for(j = 0; j < SECSIZ; j++)
  302.             sendbyte(wcbuf[j]);
  303.         purge();
  304.         if (crcheck){
  305.             sendbyte((int) (oldcrc >> 8));
  306.             sendbyte((int) oldcrc);
  307.         }
  308.         else
  309.             sendbyte(checksum);
  310.         switch(c = readbyte(10)){
  311.         case CAN:
  312.         S2("Receiver CANcelled");
  313.             return(ERROR);
  314.         case ACK:
  315.             firstsec = FALSE;
  316.             return(OK);
  317.         case NAK:
  318.         S2("Got a NAK on sector acknowledge");
  319.             break;
  320.         case TIMEOUT:
  321.         S2("Timeout on sector acknowledge");
  322.             break;
  323.         default:
  324.             sprintf(Msg, "Got 0%03o for sector acknowledge", c);
  325.             S2(Msg);
  326.             do {
  327.                 if ((c = readbyte(3)) == CAN){
  328.                     S2("Receiver CANcelled");
  329.                     return(ERROR);
  330.                 }
  331.             } while(c != TIMEOUT);
  332.             if (firstsec)
  333.                 crcheck = (c == WANTCRC);
  334.             break;
  335.         }
  336.     }
  337.     S2("Retry count exceeded");
  338.     return(ERROR);
  339. }
  340.  
  341. /* Transmit a file using XMODEM protocol */
  342. static
  343. wctx()
  344. {
  345.     register sectnum, eoflg, c, attempts;
  346.  
  347.     if (!(xfp = fopen(word, "r"))){
  348.         sprintf(Msg, "Can't open '%s'", word);
  349.         S;
  350.         return(ERROR);
  351.     }
  352.     firstsec = TRUE;
  353.     attempts = 0;
  354.     S1("Sync...");
  355.  
  356.     while((c = readbyte(30)) != NAK && c != WANTCRC && c != CAN)
  357.         if (c == TIMEOUT && ++attempts > RETRYMAX){
  358.             S1("Receiver not responding");
  359.             fclose(xfp);
  360.             return(ERROR);
  361.         }
  362.     if (c == CAN){
  363.         S1("Receiver CANcelled");
  364.         fclose(xfp);
  365.         return(ERROR);
  366.     }
  367.     crcheck = (c == WANTCRC);
  368.     sprintf(Msg,"%s error checking requested", crcheck ? "CRC-16" : "Checksum");
  369.     S;
  370.     sectnum = 1;
  371.  
  372.     do {
  373.         eoflg = getsec();
  374.         fprintf(tfp,"Transmitting sector #%d\r", sectnum);
  375.  
  376.         if (wcputsec(sectnum) == ERROR){
  377.             fclose(xfp);
  378.             return(ERROR);
  379.         }
  380.         sectnum++;
  381.     } while(eoflg);
  382.  
  383.     fclose(xfp);
  384.     attempts = 0;
  385.     sendbyte(EOT);
  386.     while(readbyte(5) != ACK && attempts++ < RETRYMAX)
  387.         sendbyte(EOT);
  388.     if (attempts >= RETRYMAX){
  389.         S1("Receiver not responding to completion");
  390.         return(ERROR);
  391.     }
  392.  
  393.     S1("Transmission complete");
  394.     return(OK);
  395. }
  396.  
  397. /*    update the cyclic redundancy check value */
  398. static ushort
  399. Updcrc(c, crc)
  400. register c;
  401. register unsigned crc;
  402. {
  403.     int i;
  404.  
  405.     for(i = 0; i < 8; i++){
  406.         if (crc & 0x8000)
  407.             crc <<= 1,
  408.             crc += (((c <<= 1) & 0400) != 0),
  409.             crc ^= 0x1021;
  410.         else
  411.             crc <<= 1,
  412.             crc += (((c <<= 1) & 0400) != 0);
  413.     }
  414.     return(crc);
  415. }
  416.  
  417. static
  418. setmode(c)
  419. int c;
  420. {
  421.     switch(tolower(c)){
  422.     case 't':
  423.         textmode = TRUE;
  424.         break;
  425.     case 'b':
  426.         textmode = FALSE;
  427.     case ' ':
  428.         break;
  429.  
  430.     default:
  431.         return FAILURE;
  432.     }
  433.  
  434.     sprintf(Msg, "XMODEM %s file transfer mode", textmode ? "Text" : "Binary");
  435.     S;
  436.  
  437.     return SUCCESS;
  438. }
  439.  
  440. /*    Put received WC sector into a UNIX file
  441.     using text translations if neccesary.
  442. */
  443.  
  444. void
  445. xreceive(c)
  446. int c;
  447. {
  448.     save_crc = crcheck;
  449.     oldvec = signal(SIGINT, xmsigint);
  450.  
  451.     if (setmode(c)){
  452.         if (!setjmp(our_env)){
  453.             /* crcheck = 0xff; */
  454.  
  455.             sprintf(Msg, "Ready to receive single file %s", word);
  456.             S;
  457.             if (wcrx() == ERROR)
  458.                 canit();
  459.             return;
  460.         }
  461.     }
  462.  
  463.     signal(SIGINT, oldvec);
  464.     crcheck = save_crc;
  465. }
  466.  
  467. void
  468. xsend(c)
  469. int c;
  470. {
  471.     save_crc = crcheck;
  472.     oldvec = signal(SIGINT, xmsigint);
  473.  
  474.     if (setmode(c)){
  475.         if (!setjmp(our_env)){
  476.             /* crcheck = 0xff; */
  477.             if (wctx() == ERROR){
  478.                 sprintf(Msg, "Error transmitting file %s", word);
  479.                 S;
  480.                 return;
  481.             }
  482.         }
  483.     }
  484.  
  485.     signal(SIGINT, oldvec);
  486.     crcheck = save_crc;
  487. }
  488.