home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3598 / xcxmdm.c < prev   
Encoding:
C/C++ Source or Header  |  1991-07-11  |  10.7 KB  |  453 lines

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