home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / XMODEM.C < prev    next >
C/C++ Source or Header  |  1994-04-17  |  13KB  |  497 lines

  1. /*
  2.  * A version of Ward Christensen's file transfer protocol for
  3.  * Unix System V or 4.2 bsd.
  4.  *
  5.  *        Emmet P. Gray, ..!ihnp4!uiucuxc!fthood!egray, 16 Aug 85
  6.  *
  7.  * Modified by Sanford Zelkovitz   08/18/86
  8.  * Last modification date = 05/20/87
  9.  * Modified for KA9Q NOS BBS - WA3DSP 2/93
  10.  */
  11.   
  12. #ifndef LINUX
  13. #include <io.h>
  14. #endif
  15. #include <sys/types.h>
  16. #include <sys/stat.h>
  17. #include <stdarg.h>
  18. #include "global.h"
  19. #ifdef TIPSERVER
  20. #ifdef XMODEM
  21. #include "dirutil.h"
  22. #include "timer.h"
  23. #include "socket.h"
  24. #include "mailbox.h"
  25.   
  26.   
  27. #define SPEED 2400       /* Serial line Baudrate */
  28.   
  29. #define MAXERRORS 10     /* max number of times to retry */
  30. #define SECSIZE   128    /* CP/M sector, transmission block */
  31. #define CPMEOF    26     /* End Of File (for CP/M) */
  32. #define SOH       1      /* Start Of Header */
  33. #define STX       2      /* Start of 1K block */
  34. #define EOT       4      /* End Of Transmission */
  35. #define ACK       6      /* ACKnowledge */
  36. #define NAK       21     /* Negative AcKnowledge */
  37. #define CAN       24     /* CANcel */
  38. #define BS        8      /* Backspace */
  39.   
  40. static int recvfile(char*,struct mbx *m);
  41. static int sendfile(char*,struct mbx *m);
  42. static char getchar_t(int socket);
  43. static void update_crc(unsigned char c, unsigned char *crc1, unsigned char *crc2);
  44. static void error(struct mbx *m);
  45. static void print_text(struct mbx *m,char *fmt, ...);
  46. static void rawmode(struct mbx *);
  47. static void restoremode(struct mbx *);
  48.   
  49. int doxmodem(char mode,char *filename,void *p)
  50. {
  51.     int exit_return=0, oldflush;
  52.     struct mbx *m;
  53.   
  54.     m = (struct mbx *)p;
  55.     oldflush=setflush(m->user,-1);
  56.   
  57.     switch (mode) {
  58.         case 'r':
  59.         case 'R':
  60.             exit_return=recvfile(filename,m);
  61.             break;
  62.         case 's':
  63.         case 'S':
  64.             exit_return=sendfile(filename,m);
  65.             break;
  66.         default :
  67.             print_text(m,"Xmodem: Invalid Option\n");
  68.     }
  69.     restoremode(m);
  70.     usputc(m->user,'\n');
  71.     usflush(m->user);
  72.     setflush(m->user,oldflush);
  73.     return(exit_return);
  74. }
  75.   
  76. /* send a file to the remote */
  77. static int
  78. sendfile(char *tfile,struct mbx *m)
  79. {
  80.     FILE *fp;
  81.     unsigned char chr, checksum, block, sector[SECSIZE];
  82.     unsigned char crc1, crc2, mode, errcount, errcount2, two_can;
  83.     int i, nbytes, speed=SPEED;
  84.     long size, min, sec;
  85.   
  86.     if ((size=fsize(tfile))==-1){
  87.         print_text(m,"xmodem: Can't open '%s' for read\n", tfile);
  88.         return(1);
  89.     }
  90.   
  91.     if (!(fp = fopen(tfile, READ_BINARY))) {
  92.         print_text(m,"xmodem: Can't open '%s' for read\n", tfile);
  93.         return(1);
  94.     }
  95.   
  96.     size=(size/128L)+1L;
  97.     sec = size * 128L * 15L / speed;
  98.     min = sec / 60L;
  99.     sec = sec - min * 60L;
  100.     print_text(m,"\nFile open: %d records\n", size);
  101.     print_text(m,"Send time: %ld min, %ld sec at %d baud\n", min, sec, speed);
  102.     print_text(m,"To cancel: use CTRL-X numerous times\n");
  103.     print_text(m,"Waiting receive ready signal\n");
  104.   
  105.     pause(3000L);
  106.     rawmode(m);
  107.     errcount = 0;
  108.     mode = 0;
  109.     two_can=0;
  110.     block = 1;
  111.   
  112.     while (errcount < MAXERRORS) {
  113.         chr = getchar_t(m->user);
  114.         if (chr == NAK)                        /* checksum mode */
  115.             break;
  116.         if (chr == 'C') {                /* CRC mode */
  117.             mode = 1;
  118.             break;
  119.         }
  120.         if (chr == CAN) {
  121.             if (two_can)  {
  122.                 pause(3000L);
  123.                 print_text(m,"\nxmodem: Abort request received\n");
  124.                 fclose(fp);
  125.                 return(1);
  126.             }
  127.             two_can=1;
  128.         } else {
  129.             two_can=0;
  130.         }
  131.   
  132.         errcount++;
  133.     }
  134.     if (errcount >= MAXERRORS) {
  135.         pause(3000L);
  136.         print_text(m,"xmodem: Timed out on acknowledge\n");
  137.         fclose(fp);
  138.         return(1);
  139.     }
  140.     two_can=0;
  141.     while ((nbytes= fread(sector,1,128, fp))!=0) {
  142.         if (nbytes < SECSIZE) {              /* fill short sector */
  143.             for (i=nbytes; i < SECSIZE; i++)
  144.                 sector[i] = CPMEOF;
  145.         }
  146.         errcount = 0;
  147.         while (errcount < MAXERRORS) {
  148.             usputc(m->user,SOH);        /* the header */
  149.             usputc(m->user,block);      /* the block number */
  150.             chr = ~block;
  151.             usputc(m->user,chr);        /* it's complement */
  152.             checksum = 0;
  153.             crc1 = 0;
  154.             crc2 = 0;
  155.             for (i=0; i < SECSIZE; i++) {
  156.                 usputc(m->user,sector[i]);
  157.                 if (mode)
  158.                     update_crc(sector[i],&crc1,&crc2);
  159.                 else
  160.                     checksum += sector[i];
  161.             }
  162.             if (mode) {
  163.                 update_crc(0,&crc1,&crc2);
  164.                 update_crc(0,&crc1,&crc2);
  165.                 usputc(m->user,crc1);
  166.                 usputc(m->user,crc2);
  167.   
  168.             }
  169.             else
  170.                 usputc(m->user,checksum);
  171.   
  172.             usflush(m->user);
  173.             errcount2=0;
  174.             rec_loop:
  175.   
  176.             chr = getchar_t(m->user);
  177.             if (chr == CAN) {
  178.                 if (two_can)  {
  179.                     pause(3000L);
  180.                     print_text(m,"\nxmodem: Abort request received\n");
  181.                     fclose(fp);
  182.                     return(1);
  183.                 }
  184.                 two_can=1;
  185.             } else {
  186.                 two_can=0;
  187.             }
  188.   
  189.             if (chr == ACK)
  190.                 break;                /* got it! */
  191.                          /* noise on line? */
  192.             if (chr != NAK ) {
  193.                 ++errcount2;
  194.                 if (errcount2>=MAXERRORS) {
  195.                     error(m);
  196.                     fclose(fp);
  197.                     return 1;
  198.                 }
  199.                 goto rec_loop;
  200.             }
  201.             errcount++;
  202.         }
  203.         if (errcount >= MAXERRORS) {
  204.             error(m);
  205.             fclose(fp);
  206.             return(1);
  207.         }
  208.         block++;
  209.     }
  210.     errcount = 0;
  211.     while (errcount < MAXERRORS) {
  212.         usputc(m->user,EOT);
  213.         usflush(m->user);
  214.         if (getchar_t(m->user) == ACK)
  215.         {
  216.             fclose(fp);
  217.             pause(6000L);
  218.             log(m->user,"Xmodem: Download - %s",tfile);
  219.             print_text(m,"Xmodem: File sent OK\n");
  220.             return(0);
  221.         }
  222.         errcount++;
  223.     }
  224.     fclose(fp);
  225.     pause(3000L);
  226.     error(m);
  227.     return(1);
  228. }
  229.   
  230. /* receive a file from the remote */
  231. static int
  232. recvfile(char *tfile,struct mbx *m)
  233. {
  234.     FILE *fp;
  235.     unsigned char hdr, blk, cblk, tmp, cksum, crc1, crc2;
  236.     unsigned char c1, c2, sum, block, sector[SECSIZE];
  237.     unsigned char first, mode, errcount, two_can;
  238.     int i;
  239.   
  240.     if (!access(tfile, 00)) {
  241.         print_text(m,"xmodem: File %s already exists\n",tfile);
  242.         return(1);
  243.     }
  244.   
  245.     if (!(fp = fopen(tfile, WRITE_BINARY))) {
  246.         print_text(m,"xmodem: Can't open '%s' for write\n", tfile);
  247.         return(1);
  248.     }
  249.     print_text(m,"File open - ready to receive\n");
  250.     print_text(m,"To cancel: use CTRL-X numerous times\n");
  251.     pause(3000L);
  252.     rawmode(m);
  253.     errcount = 0;
  254.     block = 1;
  255.     first=0;
  256.     two_can=0;
  257.   
  258.     pause(3000L);
  259.     while (errcount < MAXERRORS) {
  260.         if (errcount < (MAXERRORS / 2)) {
  261.             usputc(m->user,'C');                /* try CRC mode first */
  262.             usflush(m->user);
  263.             mode = 1;
  264.         }
  265.         else {
  266.             usputc(m->user,NAK);                /* then checksum */
  267.             usflush(m->user);
  268.             mode = 0;
  269.         }
  270.         if ((hdr = getchar_t(m->user)) == SOH) {
  271.             first=1;
  272.             break;
  273.         }
  274.         if (hdr == CAN) {
  275.             if (two_can){
  276.                 pause(3000L);
  277.                 print_text(m,"\nxmodem: Abort request received\n");
  278.                 fclose(fp);
  279.                 unlink(tfile);
  280.                 return(1);
  281.             }
  282.             two_can=1;
  283.         } else {
  284.             two_can=0;
  285.         }
  286.         errcount++;
  287.     }
  288.     if (errcount >= MAXERRORS) {
  289.         pause(3000L);
  290.         print_text(m,"\nxmodem: Timed out on acknowledge\n");
  291.         fclose(fp);
  292.         unlink(tfile);
  293.         return(1);
  294.     }
  295.     errcount = 0;
  296.     two_can=0;
  297.     while (errcount < MAXERRORS) {
  298.   
  299.         if (first) {
  300.             hdr=SOH;
  301.             first=0;
  302.         } else
  303.             hdr = getchar_t(m->user);
  304.   
  305.         if (hdr == CAN) {
  306.             if (two_can){
  307.                 pause(3000L);
  308.                 print_text(m,"\nxmodem: Abort request received\n");
  309.                 fclose(fp);
  310.                 unlink(tfile);
  311.                 return(1);
  312.             }
  313.             two_can=1;
  314.             continue;
  315.         } else {
  316.             two_can=0;
  317.         }
  318.   
  319.         if (hdr == EOT)                        /* done! */
  320.             break;
  321.   
  322.         if (hdr != SOH) {             /* read in junk for 6 seconds */
  323.             alarm(6000L);
  324.             while(errno != EALARM)
  325.                 rrecvchar(m->user);
  326.             alarm(0L);   /* cancel alarm */
  327.             first=0;
  328.             goto nak;
  329.         }
  330.         blk = getchar_t(m->user);
  331.         cblk = getchar_t(m->user);
  332.         crc1 = 0;
  333.         crc2 = 0;
  334.         sum = 0;
  335.         for (i=0; i < SECSIZE; i++) {
  336.             sector[i] = getchar_t(m->user);
  337.             if (mode)
  338.                 update_crc(sector[i],&crc1,&crc2);
  339.             else
  340.                 sum += sector[i];
  341.         }
  342.         if (mode) {
  343.             c1 = getchar_t(m->user);
  344.             c2 = getchar_t(m->user);
  345.         }
  346.         else
  347.             cksum = getchar_t(m->user);
  348.         if (blk != block && blk != (block - 1))
  349.             goto nak;
  350.         tmp = ~blk;
  351.         if (cblk != tmp)
  352.             goto nak;
  353.         if (mode) {
  354.             update_crc(0,&crc1,&crc2);
  355.             update_crc(0,&crc1,&crc2);
  356.             if (c1 != crc1 || c2 != crc2)
  357.                 goto nak;
  358.         }
  359.         else {
  360.             if (cksum != sum)
  361.                 goto nak;
  362.         }
  363.         if (block == blk) {
  364.             fflush(fp);
  365.             if (fwrite(sector, sizeof(sector[0]), SECSIZE, fp)!=SECSIZE){
  366.                 error(m);
  367.                 print_text(m,"         File write error - Partial file deleted\n");
  368.                 fclose(fp);
  369.                 unlink(tfile);
  370.                 return (1);
  371.             }
  372.         }
  373.         block = blk + 1;
  374.         usputc(m->user,ACK);                        /* got it! */
  375.         usflush(m->user);
  376.         errcount = 0;
  377.         continue;
  378.   
  379.         nak:        usputc(m->user,NAK);                    /* do it over */
  380.         usflush(m->user);
  381.         errcount++;
  382.     }
  383.     if (errcount == MAXERRORS) {
  384.         error(m);
  385.         fclose(fp);
  386.         unlink(tfile);
  387.         return(1);
  388.     }
  389.     usputc(m->user,ACK);
  390.     usflush(m->user);
  391.     pause(3000L);
  392.     fclose(fp);
  393.     log(m->user,"Xmodem: Upload - %s",tfile);
  394.     print_text(m,"Xmodem: File received OK\n");
  395.     return(0);
  396. }
  397.   
  398. /* exceeded the maximum number of retry's */
  399. static void
  400. error(struct mbx *m)
  401. {
  402.     int i;
  403.   
  404.     for(i=0;i<9;i++) {
  405.         usputc(m->user,CAN);
  406.     }
  407.     usflush(m->user);
  408.     pause(1000L);
  409.     for(i=0;i<9;i++) {
  410.         usputc(m->user,BS);
  411.     }
  412.     usflush(m->user);
  413.     pause(3000L);
  414.     print_text(m,"\nxmodem: Exceeded error limit...aborting\n");
  415.     return;
  416. }
  417.   
  418. /* update the CRC bytes */
  419. static void
  420. update_crc(unsigned char c ,unsigned char *crc1 ,unsigned char *crc2)
  421. {
  422.     register int i, temp;
  423.     register unsigned char carry, c_crc1, c_crc2;
  424.   
  425.     for (i=0; i < 8; i++) {
  426.         temp = c * 2;
  427.         c = temp;                        /* rotate left */
  428.         carry = ((temp > 255) ? 1 : 0);
  429.         temp = *crc2 * 2;
  430.         *crc2 = temp;
  431.         *crc2 |= carry;                        /* rotate with carry */
  432.         c_crc2 = ((temp > 255) ? 1 : 0);
  433.         temp = *crc1 * 2;
  434.         *crc1 = temp;
  435.         *crc1 |= c_crc2;
  436.         c_crc1 = ((temp > 255) ? 1 : 0);
  437.         if (c_crc1) {
  438.             *crc2 ^= 0x21;
  439.             *crc1 ^= 0x10;
  440.         }
  441.     }
  442.     return;
  443. }
  444.   
  445. /* getchar with a 5 sec time out */
  446. static char
  447. getchar_t(int s)
  448. {
  449.     char c;
  450.         /* only have 5 sec... */
  451.     alarm(5000L);
  452.         /* Wait for something to happen */
  453.     c=rrecvchar(s);
  454.     alarm(0L);
  455.     return(c);
  456. }
  457.   
  458. /* put the stdin/stdout in the "raw" mode */
  459. static void
  460. rawmode(struct mbx *m)
  461. {
  462.     seteol(m->user,0);
  463.     seteol(m->tip->s,0);
  464.     sockmode(m->tip->s,SOCK_BINARY);
  465.     sockmode(m->user,SOCK_BINARY);
  466.     m->tip->raw=1;
  467. }
  468.   
  469. static void
  470. restoremode(struct mbx *m)
  471. {
  472.     while(socklen(m->user,0) != 0)
  473.         recv_mbuf(m->user,NULL,0,NULLCHAR,0);
  474.     seteol(m->user,"\n");
  475.     seteol(m->tip->s,"\n");
  476.     sockmode(m->user,SOCK_ASCII);
  477.     sockmode(m->tip->s,SOCK_ASCII);
  478.     m->tip->raw=0;
  479. }
  480.   
  481. void
  482. print_text(struct mbx *m,char *fmt, ...)
  483. {
  484.     va_list ap;
  485.     char buf[80];
  486.   
  487.     restoremode(m);
  488.     va_start(ap,fmt);
  489.     vsprintf(buf,fmt,ap);
  490.     va_end(ap);
  491.     usputs(m->user,buf);
  492.     usflush(m->user);
  493. }
  494.   
  495. #endif
  496. #endif
  497.