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