home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume14 / pcomm / part06 / x_send.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-05-18  |  10.2 KB  |  484 lines

  1. /*
  2.  * Send a list of files using a version of Ward Christensen's file
  3.  * transfer protocol.  A non-zero return code means an error must be
  4.  * acknowledged by the user.
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <curses.h>
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include "dial_dir.h"
  12. #include "status.h"
  13. #include "misc.h"
  14. #include "xmodem.h"
  15.  
  16. int tot_err, err_method;
  17.  
  18. int
  19. send_xmodem(win, list, type, fast)
  20. WINDOW *win;
  21. char *list;
  22. int type, fast;
  23. {
  24.     FILE *fp;
  25.     int i, block_size, file_count, secs, mins, hours, size, xmit_size;
  26.     int big_blocks, small_blocks, err_count, got_it, num, block, sent;
  27.     int crc, is_batch, code, max_block, default_err;
  28.     char *file, *strtok(), *name, *strrchr();
  29.     unsigned char buf[1029], blk, calc_sum();
  30.     unsigned int packet, sleep();
  31.     float performance, percent;
  32.     struct stat sbuf;
  33.  
  34.     /*
  35.      * What type of xmodem?  The default_err means: 0=checksum only,
  36.      * 1=checksum or CRC, 2=CRC only, and 3=none.
  37.      */
  38.     switch(type) {
  39.         case XMODEM:
  40.             mvwaddstr(win, 2, 24, "xmodem");
  41.             is_batch = 0;
  42.             default_err = 1;
  43.             max_block = 128;
  44.             performance = 1.36;
  45.             break;
  46.         case XMODEM_1k:
  47.             mvwaddstr(win, 2, 24, "xmodem-1k");
  48.             is_batch = 0;
  49.             default_err = 1;
  50.             max_block = 1024;
  51.             performance = 1.09;
  52.             break;
  53.         case MODEM7:
  54.             mvwaddstr(win, 2, 24, "modem7");
  55.             is_batch = 1;
  56.             default_err = 0;
  57.             max_block = 128;
  58.             performance = 1.36;
  59.             break;
  60.         case YMODEM:
  61.             mvwaddstr(win, 2, 24, "ymodem");
  62.             is_batch = 1;
  63.             default_err = 2;
  64.             max_block = 1024;
  65.             performance = 1.09;
  66.             break;
  67.         case YMODEM_G:
  68.             mvwaddstr(win, 2, 24, "ymodem-g");
  69.             is_batch = 1;
  70.             default_err = 3;
  71.             max_block = 1024;
  72.             performance = 1.02;
  73.             break;
  74.     }
  75.  
  76.     tot_err = 0;
  77.     file_count = 0;
  78.     mvwaddstr(win, 11, 24, "0  ");
  79.  
  80.                     /* each one in the list */
  81.     file = strtok(list, "     ");
  82.     do {
  83.                     /* is it a batch type ? */
  84.         file_count++;
  85.         if (file_count > 1 && !is_batch)
  86.             break;
  87.                     /* display the name */
  88.         clear_line(win, 3, 24, 1);
  89.         if ((name = strrchr(file, '/')))
  90.             name++;
  91.         else
  92.             name = file;
  93.         waddstr(win, name);
  94.         wrefresh(win);
  95.                     /* get the file size */    
  96.         if (stat(file, &sbuf) < 0) {
  97.             beep();
  98.             clear_line(win, 12, 24, 1);
  99.             wattrstr(win, A_BOLD, "CAN'T FIND FILE");
  100.             wrefresh(win);
  101.             sleep(3);
  102.             continue;
  103.         }
  104.  
  105.         size = sbuf.st_size;
  106.         mvwprintw(win, 4, 24, "%-10d", size);
  107.         clear_line(win, 5, 24, 1);
  108.  
  109.         if (access(file, 4)) {
  110.             beep();
  111.             clear_line(win, 12, 24, 1);
  112.             wattrstr(win, A_BOLD, "PERMISSION DENIED");
  113.             wrefresh(win);
  114.             sleep(3);
  115.             continue;
  116.         }
  117.         if (!(fp = fopen(file, "r"))) {
  118.             beep();
  119.             clear_line(win, 12, 24, 1);
  120.             wattrstr(win, A_BOLD, "CAN'T OPEN FILE");
  121.             wrefresh(win);
  122.             sleep(3);
  123.             continue;
  124.         }
  125.                     /* get the xmit size */
  126.         block_size = max_block;
  127.         big_blocks = 0;
  128.         small_blocks = 0;
  129.         if (block_size == 128) {
  130.             small_blocks = size / 128;
  131.             if (size % 128)
  132.                 small_blocks++;
  133.         }
  134.         else {
  135.             big_blocks = size / 1024;
  136.             small_blocks = (size % 1024) / 128;
  137.             if (size % 128)
  138.                 small_blocks++;
  139.  
  140.             if (small_blocks == 8 && !big_blocks) {
  141.                 big_blocks++;
  142.                 small_blocks = 0;
  143.             }
  144.                     /* if tiny file */
  145.             if (big_blocks == 0)
  146.                 block_size = 128;
  147.         }
  148.  
  149.         xmit_size = (big_blocks * 1024) + (small_blocks * 128);
  150.                     /* add block 0 to the size */
  151.         if (type == YMODEM || type == YMODEM_G)
  152.             xmit_size += 128;
  153.  
  154.         secs = (xmit_size * 10.0 / dir->baud[dir->d_cur]) * performance;
  155.         hours = secs / 3600;
  156.         mins = (secs % 3600) / 60;
  157.         secs = (secs % 3600) % 60;
  158.  
  159.         mvwprintw(win, 6, 24, "%d:%02d:%02d", hours, mins, secs);
  160.  
  161.                     /* some starting numbers */
  162.         mvwaddstr(win, 7, 24, "     ");
  163.         mvwaddstr(win, 8, 24, "0%  ");
  164.         mvwaddstr(win, 9, 24, "0          ");
  165.         mvwaddstr(win, 10, 24, "0 ");
  166.         clear_line(win, 12, 24, 1);
  167.         waddstr(win, "NONE");
  168.         wrefresh(win);
  169.                     /* send the batch stuff */
  170.         switch (type) {
  171.             case MODEM7:
  172.                 if (code = rcv_first(win, default_err)) {
  173.                     fclose(fp);
  174.                     return(code +1);
  175.                 }
  176.  
  177.                 if (send_modem7(win, name)) {
  178.                     fclose(fp);
  179.                     return(1);
  180.                 }
  181.                 break;
  182.             case YMODEM:
  183.             case YMODEM_G:
  184.                 if (code = rcv_first(win, default_err)) {
  185.                     fclose(fp);
  186.                     return(code +1);
  187.                 }
  188.  
  189.                 if (code = send_ymodem(win, name, size)) {
  190.                     fclose(fp);
  191.                     /*
  192.                      * CANCEL now means that the other
  193.                      * end can't open that file.
  194.                      */
  195.                     if (code == CANCEL)
  196.                         break;
  197.                     return(code +1);
  198.                 }
  199.                 xmit_size -= 128;
  200.                 break;
  201.             default:
  202.                 code = 0;
  203.                 break;
  204.         }
  205.                     /* remote can't receive that file ? */
  206.         if (code == CANCEL)
  207.             break;
  208.                     /* wait for first character */
  209.         if (code = rcv_first(win, default_err)) {
  210.             fclose(fp);
  211.             return(code +1);
  212.         }
  213.                     /* here we go... */
  214.         sent = 0;
  215.         block = 1;
  216.         blk = 1;
  217.         while (num = fread((char *) &buf[3], sizeof(buf[0]), block_size, fp)) {
  218.  
  219.                     /* fill short block */
  220.             if (num < block_size) {
  221.                 for (i=num; i<block_size; i++)
  222.                     buf[i+3] = CTRLZ;
  223.             }
  224.  
  225.                     /* show current stats */
  226.             mvwprintw(win, 7, 24, "%-5d", block);
  227.             if (fast) {
  228.                 percent = sent * 100.0 / xmit_size;
  229.                 mvwprintw(win, 8, 24, "%0.1f%%", percent);
  230.                 mvwprintw(win, 9, 24, "%-10d", sent);
  231.             }
  232.             wrefresh(win);
  233.  
  234.                     /* build the header */
  235.             if (block_size == 128)
  236.                 buf[0] = SOH;
  237.             else
  238.                 buf[0] = STX;
  239.  
  240.             buf[1] = blk;
  241.             buf[2] = ~blk;
  242.  
  243.                     /* build the error detection stuff */
  244.             switch (err_method) {
  245.                 case 0:        /* checksum */
  246.                     buf[block_size+3] = calc_sum(&buf[3], block_size);
  247.                     packet = block_size +4;
  248.                     break;
  249.                 case 1:        /* CRC */
  250.                     crc = calc_crc(&buf[3], block_size);
  251.                     buf[block_size+3] = crc >> 8;
  252.                     buf[block_size+4] = crc;
  253.                     packet = block_size +5;
  254.                     break;
  255.                 case 2:        /* none */
  256.                     buf[block_size+3] = 0;
  257.                     buf[block_size+4] = 0;
  258.                     packet = block_size +5;
  259.                     break;
  260.             }
  261.  
  262.                     /* send the block */
  263.             if (code = send_block(win, buf, packet)) {
  264.                 fclose(fp);
  265.                 return(code +1);
  266.             }
  267.             block++;
  268.             blk++;
  269.             sent += block_size;
  270.  
  271.                     /* change block size ? */
  272.             if (xmit_size - sent < 1024)
  273.                 block_size = 128;
  274.         }
  275.         mvwaddstr(win, 8, 24, "100%  ");
  276.         mvwprintw(win, 9, 24, "%-10d", sent);
  277.                     /* at the end of the file */
  278.         err_count = 0;
  279.         got_it = 0;
  280.         while (err_count < MAX_ERRORS) {
  281.             putc_line(EOT);
  282.             if (getc_line(10) == ACK) {
  283.                 got_it++;
  284.                 break;
  285.             }
  286.             err_count++;
  287.         }
  288.         clear_line(win, 12, 24, 1);
  289.         if (!got_it) {
  290.             /*
  291.              * So what???  We don't do anything if there is
  292.              * no acknowledge from the host!!
  293.              */
  294.             waddstr(win, "NO ACKNOWLEDGE");
  295.         }
  296.         else
  297.             waddstr(win, "TRANSFER COMPLETE");
  298.         if (!is_batch)
  299.             beep();
  300.         wrefresh(win);
  301.         sleep(2);
  302.                     /* prepare to start again */
  303.         fclose(fp);
  304.     } while (file = strtok((char *) NULL, "     "));
  305.  
  306.     /*
  307.      * The end of batch markers... For modem7 it's an ACK and EOT, for
  308.      * ymodem, it's an empty block 0.
  309.      */
  310.     switch (type) {
  311.         case MODEM7:
  312.             if (code = rcv_first(win, default_err))
  313.                 return(code +1);
  314.             putc_line(ACK);
  315.             putc_line(EOT);
  316.             beep();
  317.             wrefresh(win);
  318.             break;
  319.         case YMODEM:
  320.         case YMODEM_G:
  321.             if (code = rcv_first(win, default_err))
  322.                 return(code +1);
  323.  
  324.             if (code = send_ymodem(win, NULL, 0))
  325.                 return(code +1);
  326.             beep();
  327.             wrefresh(win);
  328.             break;
  329.         default:
  330.             break;
  331.     }
  332.     return(0);
  333. }
  334.  
  335. /*
  336.  * Wait for the first character to start the transmission.  This first
  337.  * character also sets the crc/checksum method.  Returns the standard
  338.  * error codes, or 0 on success.  The variable err_method is global.
  339.  */
  340.  
  341. int
  342. rcv_first(win, default_err)
  343. WINDOW *win;
  344. int default_err;
  345. {
  346.     int err_count;
  347.     unsigned int sleep();
  348.  
  349.     err_count = 0;
  350.     while (err_count < MAX_ERRORS) {
  351.  
  352.                     /* scan the keyboard for abort */
  353.         if (wgetch(win) == 27) {
  354.             beep();
  355.             clear_line(win, 12, 24, 1);
  356.             waddstr(win, "ABORTED");
  357.             wrefresh(win);
  358.             sleep(3);
  359.             return(ABORT);
  360.         }
  361.  
  362.                     /* scan the tty line */
  363.         switch(getc_line(10)) {
  364.             case NAK:    /* checksum marker */
  365.                 if (default_err < 2) {
  366.                     mvwaddstr(win, 5, 24, "CHECKSUM");
  367.                     err_method = 0;
  368.                     return(0);
  369.                 }
  370.                 err_count++;
  371.                 break;
  372.             case 'C':    /* CRC marker */
  373.                 if (default_err == 1 || default_err == 2) {
  374.                     mvwaddstr(win, 5, 24, "CRC");
  375.                     err_method = 1;
  376.                     return(0);
  377.                 }
  378.                 err_count++;
  379.                 break;
  380.             case 'G':    /* ymodem-g marker */
  381.                 if (default_err == 3) {
  382.                     mvwaddstr(win, 5, 24, "NONE");
  383.                     err_method = 2;
  384.                     return(0);
  385.                 }
  386.                 err_count++;
  387.                 break;
  388.             case CAN:    /* two CAN's and you're out! */
  389.                 if (getc_line(2) == CAN) {
  390.                     beep();
  391.                     clear_line(win, 12, 24, 1);
  392.                     wattrstr(win, A_BOLD, "REMOTE ABORTED");
  393.                     wrefresh(win);
  394.                     return(CANCEL);
  395.                 }
  396.                 /* fall thru... */
  397.             default:
  398.                 err_count++;
  399.                 break;
  400.         }
  401.         clear_line(win, 12, 24, 1);
  402.         waddstr(win, "BAD HEADER");
  403.         mvwprintw(win, 10, 24, "%-2d", err_count);
  404.         wrefresh(win);
  405.     }
  406.                     /* failed to get it right ? */
  407.     beep();
  408.     clear_line(win, 12, 24, 1);
  409.     wattrstr(win, A_BOLD, "TIMED OUT");
  410.     wrefresh(win);
  411.     return(ERROR);
  412. }
  413.  
  414. /*
  415.  * Send a block of data, scan the keyboard for a user abort, and check
  416.  * the return codes from the host.  Returns standard error codes or 0
  417.  * on success.
  418.  */
  419.  
  420. int
  421. send_block(win, blk, packet)
  422. WINDOW *win;
  423. unsigned char *blk;
  424. unsigned int packet;
  425. {
  426.     int err_count;
  427.  
  428.     err_count = 0;
  429.     while (err_count < MAX_ERRORS) {
  430.                     /* write the block */
  431.         write(status->fd, (char *) blk, packet);
  432.                     /* scan the keyboard */
  433.         if (wgetch(win) == 27) {
  434.             beep();
  435.             clear_line(win, 12, 24, 1);
  436.             waddstr(win, "ABORTED");
  437.             wrefresh(win);
  438.             sleep(3);
  439.             return(ABORT);
  440.         }
  441.                     /* ymodem-g doesn't need ACKs */
  442.         if (err_method == 2)
  443.             return(0);
  444.                     /* wait for acknowledge */
  445.         switch(getc_line(10)) {
  446.             case ACK:    /* Hooray!! we got it */
  447.                 return(0);
  448.             case NAK:    /* show our disappointment... */
  449.                 clear_line(win, 12, 24, 1);
  450.                 if (err_method)
  451.                     waddstr(win, "CRC FAILED");
  452.                 else
  453.                     waddstr(win, "CHECKSUM FAILED");
  454.                 err_count++;
  455.                 tot_err++;
  456.                 break;
  457.             case CAN:    /* two CAN's and you're out! */
  458.                 if (getc_line(2) == CAN) {
  459.                     beep();
  460.                     clear_line(win, 12, 24, 1);
  461.                     wattrstr(win, A_BOLD, "REMOTE ABORTED");
  462.                     wrefresh(win);
  463.                     return(CANCEL);
  464.                 }
  465.                 /* fall thru... */
  466.             default:
  467.                 clear_line(win, 12, 24, 1);
  468.                 waddstr(win, "RESENDING");
  469.                 err_count++;
  470.                 tot_err++;
  471.                 break;
  472.         }
  473.         mvwprintw(win, 10, 24, "%-2d", err_count);
  474.         mvwprintw(win, 11, 24, "%-3d", tot_err);
  475.         wrefresh(win);
  476.     }
  477.                     /* failed to get it right */
  478.     beep();
  479.     clear_line(win, 12, 24, 1);
  480.     wattrstr(win, A_BOLD, "TOO MANY ERRORS");
  481.     wrefresh(win);
  482.     return(ERROR);
  483. }
  484.