home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume32 / xbbs / part06 / ymod.c < prev   
C/C++ Source or Header  |  1992-09-08  |  10KB  |  488 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.  */
  10.  
  11. #define SV
  12. #undef  BSD
  13.  
  14. #include <stdio.h>
  15. #include <signal.h>
  16. #include <sys/types.h>
  17. #include <sys/stat.h>
  18. #ifdef SV
  19. #include <termio.h>
  20. #endif
  21. #ifdef BSD
  22. #include <sgtty.h>
  23. #endif
  24.  
  25. #define MAXERRORS 10            /* max number of times to retry */
  26. #define SECSIZE    1024            /* CP/M sector, transmission block */
  27. #define CPMEOF    26            /* End Of File (for CP/M) */
  28. #define SOH     1
  29. #define STX    2            /* Start Of Header */
  30. #define EOT    4            /* End Of Transmission */
  31. #define ACK    6            /* ACKnowledge */
  32. #define NAK    21            /* Negative AcKnowledge */
  33. #define CAN    24            /* CANcel */
  34.  
  35. int synchron;
  36. int exit_return;
  37. unsigned char crc1, crc2;
  38. #ifdef SV
  39. struct termio ttyhold;
  40. #endif
  41. #ifdef BSD
  42. struct sgttyb ttyhold;
  43. #endif
  44.  
  45. main(argc, argv)
  46. int argc;
  47. char *argv[];
  48. {
  49.     int msgstat;
  50.     char *tty, *ttyname();
  51.     struct stat stbuf;
  52.     exit_return=0;
  53.     if (argc != 3) {
  54.         usage();
  55.         exit(1);
  56.     }
  57.     tty = ttyname(1);
  58.     stat(tty, &stbuf); 
  59.     msgstat = (stbuf.st_mode & 0777);
  60.     chmod(tty, 0600);            /* mesg n */
  61. #ifdef SV
  62.     ioctl(0, TCGETA, &ttyhold);        /* get current settings */
  63. #endif
  64. #ifdef BSD
  65.     ioctl(0, TIOCGETP, &ttyhold);
  66. #endif
  67.     switch (*argv[1]) {
  68.         case 'r':
  69.             recvfile(argv[2]);
  70.             break;
  71.         case 's':
  72.             sendfile(argv[2]);
  73.             break;
  74.         default:
  75.             usage();
  76.     }
  77. #ifdef SV
  78.     ioctl(0, TCSETAF, &ttyhold);        /* restore settings */
  79. #endif
  80. #ifdef BSD
  81.     ioctl(0, TIOCSETP, &ttyhold);
  82. #endif
  83.     chmod(tty, msgstat);            /* restore mesg status */
  84.     exit(exit_return);
  85. }
  86.  
  87. /* send a file to the remote */
  88. sendfile(tfile)
  89. char *tfile;
  90. {
  91.     FILE *fp;
  92.     unsigned char chr, checksum, block, sector[SECSIZE];
  93.     int i, mode, nbytes, errcount, size, speed;
  94.     long min, sec;
  95.     static int baud[15] = {0, 50, 75, 110, 134, 150, 200,
  96.     300, 600, 1200, 1800, 2400, 4800, 9600, 19200};
  97.     struct stat sbuf;
  98.  
  99.     if (!(fp = fopen(tfile, "r"))) {
  100.         fprintf(stderr, "xmodem: Can't open '%s' for read\r\n", tfile);
  101.         exit_return=1;
  102.         return;
  103.     }
  104.     stat(tfile, &sbuf);
  105.     size = (sbuf.st_size / 1024) + 1;
  106. #ifdef SV
  107.     speed = baud[ttyhold.c_cflag & 017];
  108. #endif
  109. #ifdef BSD
  110.     speed = baud[ttyhold.sg_ispeed];
  111. #endif
  112.     sec = size;
  113.     sec = sec * 1024L * 11L / speed;
  114.     min = sec / 60L;
  115.     sec = sec - min * 60L;
  116.     printf("File open: %d records\r\n", size);
  117.     printf("Send time: %ld min, %ld sec at %d baud\r\n", min, sec, speed);
  118.     printf("To cancel: use CTRL-X numerous times\r\n");
  119.     printf("Waiting ready signal\r\n");
  120.  
  121.     rawmode();
  122.     errcount = 0;
  123.     mode = 0;
  124.     block = 1;
  125.     while (errcount < MAXERRORS) {
  126.         chr = getchar_t();
  127.         if (chr == NAK)            /* checksum mode */
  128.             break;
  129.         if (chr == 'C') {        /* CRC mode */
  130.             mode = 1;
  131.             break;
  132.         }
  133.         errcount++;
  134.     }
  135.     if (errcount == MAXERRORS) {
  136.         sleep(3);
  137.         fprintf(stderr, "xmodem: Timed out on acknowledge\r\n");
  138.         exit_return=1;
  139.         return;
  140.     }
  141.     while (nbytes = fread(sector, sizeof(sector[0]), SECSIZE, fp)) {
  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.             putchar(STX);        /* the header */
  149.             putchar(block);        /* the block number */
  150.             chr = ~block;
  151.             putchar(chr);        /* it's complement */
  152.             checksum = 0;
  153.             crc1 = 0;
  154.             crc2 = 0;
  155.             for (i=0; i < SECSIZE; i++) {
  156.                 putchar(sector[i]);
  157.                 if (mode)
  158.                     update_crc(sector[i]);
  159.                 else
  160.                     checksum += sector[i];
  161.             }
  162.             if (mode) {
  163.                 update_crc(0);
  164.                 update_crc(0);
  165.                 putchar(crc1);
  166.                 putchar(crc2);
  167.             }
  168.             else
  169.                 putchar(checksum);
  170. rec_loop:
  171.             chr = getchar_t();
  172.             if (chr == CAN) {
  173.                 sleep(3);
  174.                 fprintf(stderr,"\r\nxmodem: Abort request received\r\n");
  175.                 exit_return=1;
  176.                 return;
  177.             }
  178.             if (chr == ACK)
  179.                 break;        /* got it! */
  180.             if (chr != NAK ) goto rec_loop;   /* noise on line? */
  181.             errcount++;
  182.         }
  183.         if (errcount == MAXERRORS) {
  184.             error();
  185.             exit_return=1;
  186.             return;
  187.         }
  188.         block++;
  189.     }
  190.     errcount = 0;
  191.     exit_return=1;
  192.     while (errcount < MAXERRORS) {
  193.         putchar(EOT);
  194.         if (getchar_t() == ACK)
  195.             {
  196.             exit_return=0;
  197.             break;
  198.             }
  199.         errcount++;
  200.     }
  201.     return;
  202. }
  203.  
  204. /* receive a file from the remote */
  205. recvfile(tfile)
  206. char *tfile;
  207. {
  208.     FILE *fp;
  209.     unsigned char hdr, blk, cblk, tmp, cksum;
  210.     unsigned char c1, c2, sum, block, sector[SECSIZE];
  211.     int i, stop = 0, mode, errcount, resync();
  212.     long true_end;
  213.     char ans[40];
  214.  
  215.     if (!access(tfile, 00)) {
  216.         while (1) {
  217.             printf("File already exists \r\n");
  218.                 return;
  219.         }
  220.     }
  221.  
  222.     if (!(fp = fopen(tfile, "w"))) {
  223.         fprintf(stderr, "xmodem: Can't open '%s' for write\r\n", tfile);
  224.         return;
  225.     }
  226.     printf("File open - ready to receive\r\n");
  227.     rawmode();
  228.     errcount = 0;
  229.     block = 1;
  230.     
  231.     sleep(10);
  232.     while (errcount < MAXERRORS) {
  233.         if (errcount < (MAXERRORS / 2)) {
  234.             putchar('C');        /* try CRC mode first */
  235.             mode = 1;
  236.         }
  237.         else {
  238.             putchar(NAK);        /* then checksum */
  239.             mode = 0;
  240.         }
  241.         if ((hdr = getchar_t()) == SOH) {
  242.             ungetc(SOH, stdin);
  243.             break;
  244.         }
  245.         if ( hdr == STX ) {
  246.             ungetc(STX, stdin);
  247.             break;
  248.         }
  249.         errcount++;
  250.     }
  251.     if (errcount == MAXERRORS) {
  252.         sleep(3);
  253.         fprintf(stderr, "\r\nxmodem: Timed out on acknowledge\r\n");
  254.         return;
  255.     }
  256.     errcount = 0;
  257.  
  258.     while (errcount < MAXERRORS) {
  259.         hdr = getchar_t();
  260.         if (hdr == CAN) {
  261.             sleep(3);
  262.             fprintf(stderr, "\r\nxmodem: Abort request received\r\n");
  263.             return;
  264.         }
  265.         if (hdr == EOT)            /* done! */
  266.             break;
  267.         if (hdr != STX && hdr != SOH) {        /* read in junk for 6 seconds */
  268.             synchron = 0;        /*  to re-synchronized block */
  269.             signal(SIGALRM, resync);
  270.             alarm(6);
  271.             while(synchron == 0)
  272.                 hdr = getchar();
  273.             goto nak;
  274.         }
  275.         blk = getchar_t();
  276.         cblk = getchar_t();
  277.         crc1 = 0;
  278.         crc2 = 0;
  279.         sum = 0;
  280.         for (i=0; i < SECSIZE; i++) {
  281.             sector[i] = getchar_t();
  282.             if (mode)
  283.                 update_crc(sector[i]);
  284.             else
  285.                 sum += sector[i];
  286.         }
  287.         if (mode) {
  288.             c1 = getchar_t();
  289.             c2 = getchar_t();
  290.         }
  291.         else
  292.             cksum = getchar_t();
  293.         if (blk != block && blk != (block - 1))
  294.             goto nak;
  295.         tmp = ~blk;
  296.         if (cblk != tmp)
  297.             goto nak;
  298.         if (mode) {
  299.             update_crc(0);
  300.             update_crc(0);
  301.             if (c1 != crc1 || c2 != crc2)
  302.                 goto nak;
  303.         }
  304.         else {
  305.             if (cksum != sum)
  306.                 goto nak;
  307.         }
  308.         if (block == blk) {
  309.             fflush(fp);
  310.             fwrite(sector, sizeof(sector[0]), SECSIZE, fp);
  311.         }
  312.         block = blk + 1;
  313.         putchar(ACK);            /* got it! */
  314.         errcount = 0;
  315.         continue;
  316.  
  317.     nak:    putchar(NAK);            /* do it over */
  318.         errcount++;
  319.     }
  320.     if (errcount == MAXERRORS) {
  321.         error();
  322.         return;
  323.     }
  324.     putchar(ACK);
  325.     for (i = SECSIZE -1; i >= 0; i--) {    /* find true EOF */
  326.         if (sector[i] != CPMEOF) {
  327.             stop = i;
  328.             break;
  329.         }
  330.     }
  331. /*
  332.  * Some CPM systems don't pad the end of the file with ^Z's so the file may
  333.  * have junk at the end.  A conservative approach had to be taken in order
  334.  * for Unix object code (where ^Z's may be valid data) to transfer properly.
  335.  */
  336.     true_end = ftell(fp) - SECSIZE + stop +1;
  337.     fclose(fp);
  338.     truncate(tfile, true_end);
  339.     return;
  340. }
  341.  
  342. /* give minimal usage message */
  343. usage()
  344. {
  345.     fprintf(stderr, "Usage: xmodem [ s | r ] filename\r\n");
  346.     fprintf(stderr, "       options are 's' for send or 'r' for receive\r\n");
  347.     return;
  348. }
  349.  
  350. /* exceeded the maximum number of retry's */
  351. error()
  352. {
  353.     putchar(CAN);
  354.     putchar(CAN);
  355.     putchar(CAN);
  356.     putchar(CAN);
  357.     sleep(3);
  358.     fprintf(stderr, "\r\nxmodem: Exceeded error limit...aborting\r\n");
  359.     return;
  360. }
  361.  
  362. /* update the CRC bytes */
  363. update_crc(c)
  364. unsigned char c;
  365. {
  366.     int i, temp;
  367.     unsigned char carry, c_crc1, c_crc2;
  368.     for (i=0; i < 8; i++) {
  369.         temp = c * 2;
  370.         c = temp;            /* rotate left */
  371.         carry = ((temp > 255) ? 1 : 0);
  372.         temp = crc2 * 2;
  373.         crc2 = temp;
  374.         crc2 |= carry;            /* rotate with carry */
  375.         c_crc2 = ((temp > 255) ? 1 : 0);
  376.         temp = crc1 * 2;
  377.         crc1 = temp;
  378.         crc1 |= c_crc2;
  379.         c_crc1 = ((temp > 255) ? 1 : 0);
  380.         if (c_crc1) {
  381.             crc2 ^= 0x21;
  382.             crc1 ^= 0x10;
  383.         }
  384.     }
  385.     return;
  386. }
  387.  
  388. /* getchar with a 10 sec time out */
  389. getchar_t()
  390. {
  391.     int force_it();
  392.     unsigned char c;
  393.     signal(SIGALRM, force_it);
  394.     alarm(10);                /* only have 10 sec... */
  395.     c = getchar();
  396.     alarm(0);
  397.     return(c);
  398. }
  399.  
  400. /*
  401.  * This code (and the resync() below) is the most machine dependent part
  402.  * of the program.  The action of the signal SIGALRM during a read system
  403.  * call is not well defined.  Some systems return the stack to the point
  404.  * outside the system call, others inside the call itself.  Have fun...
  405.  */
  406. force_it()
  407. {
  408.     unsigned char c;
  409.     c = CPMEOF;                /* arbitrary default char */
  410. #ifdef SV
  411.     ungetc(c, stdin);
  412. #endif
  413. #ifdef BSD
  414.     ioctl(0, TIOCSTI, &c);
  415. #endif
  416.     return;
  417. }
  418.  
  419. /* truncate file to given length */
  420. truncate(path, length)
  421. char *path;
  422. long length;
  423. {
  424.     FILE *fp, *tempfp;
  425.     long i;
  426.     char c, string[80], *tempfile, *mktemp();
  427.     if (!(fp = fopen(path, "r"))) {
  428.         fprintf(stderr, "xmodem: Can't open '%s' for read\r\n", path);
  429.         return;
  430.     }
  431.     tempfile = mktemp("/tmp/trunXXXXXX");
  432.     if (!(tempfp = fopen(tempfile, "w"))) {
  433.         fprintf(stderr, "xmodem: Can't open temporary file\r\n");
  434.         return;
  435.     }
  436.     for (i=0; i < length; i++) {
  437.         c = fgetc(fp);
  438.         fputc(c, tempfp);
  439.     }
  440.     fclose(fp);
  441.     fclose(tempfp);
  442.     sprintf(string, "mv %s %s", tempfile, path);
  443.     system(string);
  444.     return;
  445. }
  446.  
  447. /* put the stdin/stdout in the "raw" mode */
  448. rawmode()
  449. {
  450. #ifdef SV
  451.     struct termio tbuf;
  452.     ioctl(0, TCGETA, &tbuf);
  453.     tbuf.c_cc[4] = 1;            /* VMIN */
  454.     tbuf.c_cc[5] = 0;            /* VTIME */
  455.     tbuf.c_iflag = 0;
  456.     tbuf.c_oflag = 0;
  457.     tbuf.c_lflag = 0;
  458.     tbuf.c_cflag &= ~CSIZE;
  459.     tbuf.c_cflag |= CS8;
  460.     tbuf.c_cflag &= ~PARENB;
  461.     ioctl(0, TCSETAF, &tbuf);
  462.     return;
  463. #endif
  464. #ifdef BSD
  465.     struct sgttyb sgbuf;
  466.     ioctl(0, TIOCGETP, &sgbuf);
  467.     sgbuf.sg_flags |= RAW;
  468.     sgbuf.sg_flags &= ~ECHO;
  469.     ioctl(0, TIOCSETP, &sgbuf);
  470.     return;
  471. #endif
  472. }
  473.  
  474. /*  after 6 seconds of reading junk data... */
  475. resync()
  476. {
  477.     char c;
  478.     synchron = 1;                /* set the flag */
  479.     c = SOH;
  480. #ifdef SV
  481.     ungetc(c, stdin);
  482. #endif
  483. #ifdef BSD
  484.     ioctl(0, TIOCSTI, &c);
  485. #endif
  486.     return;
  487. }
  488.