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