home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume16 / pcomm2 / part07 / x_batch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-09-14  |  8.3 KB  |  409 lines

  1. /*
  2.  * Routines to support the batch protocols.
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <ctype.h>
  7. #include <curses.h>
  8. #include "config.h"
  9. #include "misc.h"
  10. #include "xmodem.h"
  11.  
  12. /*
  13.  * Send the file name for the modem7 batch.  Only uses 11 characters
  14.  * of the filename.
  15.  */
  16.  
  17. int
  18. send_modem7(win, name)
  19. WINDOW *win;
  20. char *name;
  21. {
  22.     char *new_name, *fix_name();
  23.     unsigned char sum, calc_sum();
  24.  
  25.                     /* convert to 11 character name */
  26.     new_name = fix_name(name);
  27.     sum = calc_sum((unsigned char *) new_name, 12);
  28.  
  29.     putc_line(ACK);
  30.                     /* for each character in the name */
  31.     while (*new_name != CTRLZ) {
  32.         putc_line((unsigned char) *new_name);
  33.  
  34.         switch (getc_line(3)) {
  35.             case -1:    /* timed out */
  36.                 clear_line(win, 12, 24, 1);
  37.                 waddstr(win, "NO RESPONSE");
  38.                 wrefresh(win);
  39.                 return(ERROR);
  40.             case ACK:    /* got it! */
  41.                 break;
  42.             case CAN:    /* cancel transmission */
  43.                 if (getc_line(2) == CAN) {
  44.                     beep();
  45.                     clear_line(win, 12, 24, 1);
  46.                     wattrstr(win, A_BOLD, "REMOTE ABORTED");
  47.                     wrefresh(win);
  48.                     return(CANCEL);
  49.                 }
  50.                 /* fall thru... */
  51.             default:
  52.                 clear_line(win, 12, 24, 1);
  53.                 waddstr(win, "NAME FAILED");
  54.                 wrefresh(win);
  55.                 return(ERROR);
  56.         }
  57.         new_name++;
  58.     }
  59.     putc_line(CTRLZ);
  60.                     /* verify the checksum */
  61.     if (getc_line(10) != sum) {
  62.         putc_line('u');
  63.         clear_line(win, 12, 24, 1);
  64.         waddstr(win, "CHECKSUM FAILED");
  65.         wrefresh(win);
  66.         return(ERROR);
  67.     }
  68.     putc_line(ACK);
  69.     return(0);
  70. }
  71.  
  72. /*
  73.  * Receive a modem7 file name.  A return code of 1 means the end of the
  74.  * batch transfers.
  75.  */
  76.  
  77. int
  78. rcv_modem7(win, default_err)
  79. WINDOW *win;
  80. int default_err;
  81. {
  82.     extern char file_name[15];
  83.     int i, j, err_method, err_count, got_it;
  84.     unsigned char sum, calc_sum();
  85.     char temp_name[13];
  86.     void change_name(), unfix_name();
  87.  
  88.     err_method = default_err;
  89.     if (default_err == CRC_CHECKSUM)
  90.         err_method = CRC;
  91.  
  92.     err_count = 0;
  93.     got_it = 0;
  94.     while (err_count < MAX_ERRORS) {
  95.                     /* switch to checksum? */
  96.         if (default_err == CRC_CHECKSUM && err_count > MAX_ERRORS/2)
  97.             err_method = CHECKSUM;
  98.  
  99.         if (err_method == CRC)
  100.             putc_line('C');
  101.         else
  102.             putc_line(NAK);
  103.                     /* what'd we get? */
  104.         switch (getc_line(10)) {
  105.             case -1:    /* timed out */
  106.                 clear_line(win, 12, 24, 1);
  107.                 wattrstr(win, A_BOLD, "NO RESPONSE");
  108.                 wrefresh(win);
  109.                 err_count++;
  110.             case ACK:    /* ready to go... */
  111.                 got_it++;
  112.                 break;
  113.             default:    /* huh? */
  114.                 clear_line(win, 12, 24, 1);
  115.                 wattrstr(win, A_BOLD, "BAD HEADER");
  116.                 wrefresh(win);
  117.                 err_count++;
  118.         }
  119.     }
  120.     if (!got_it)
  121.         return(ERROR);
  122.                     /* get the name */
  123.     for (i=0; i<12; i++) {
  124.         j = getc_line(3);
  125.  
  126.         switch (j) {
  127.             case -1:    /* timed out */
  128.                 clear_line(win, 12, 24, 1);
  129.                 wattrstr(win, A_BOLD, "NO RESPONSE");
  130.                 wrefresh(win);
  131.                 return(ERROR);
  132.             case EOT:    /* end of batch? */
  133.                 return(-1);
  134.             case CAN:    /* cancel transmission */
  135.                 if (getc_line(2) == CAN) {
  136.                     beep();
  137.                     clear_line(win, 12, 24, 1);
  138.                     wattrstr(win, A_BOLD, "REMOTE ABORTED");
  139.                     wrefresh(win);
  140.                     return(CANCEL);
  141.                 }
  142.                 /* fall thru... */
  143.             case 'u':    /* bad name character */
  144.                 beep();
  145.                 clear_line(win, 12, 24, 1);
  146.                 wattrstr(win, A_BOLD, "BAD NAME");
  147.                 wrefresh(win);
  148.                 return(ERROR);
  149.             default:    /* the name... */
  150.                 temp_name[i] = j & 0xff;
  151.                 if (j != CTRLZ)
  152.                     putc_line(ACK);
  153.                 break;
  154.         }
  155.     }
  156.     temp_name[12] = NULL;
  157.                     /* send our checksum */
  158.     sum = calc_sum((unsigned char *) temp_name, 12);
  159.     putc_line(sum);
  160.                     /* do they agree? */
  161.     if (getc_line(10) != ACK) {
  162.         beep();
  163.         clear_line(win, 12, 24, 1);
  164.         wattrstr(win, A_BOLD, "BAD NAME");
  165.         wrefresh(win);
  166.         return(ERROR);
  167.     }
  168.                     /* load the file_name array */
  169.     unfix_name(temp_name);
  170.                     /* any name collisions? */
  171.     change_name(win, file_name);
  172.     return(0);
  173. }
  174.  
  175. /*
  176.  * Send the block 0 information for a ymodem batch transfer.  Uses only
  177.  * the name component of the path and the file size.
  178.  */
  179.  
  180. int
  181. send_ymodem(win, file, size)
  182. WINDOW *win;
  183. char *file;
  184. long size;
  185. {
  186.     register int i;
  187.     unsigned short crc, calc_crc();
  188.     char *strcpy();
  189.     unsigned char buf[133];
  190.                     /* start with a clean block */
  191.     for (i=0; i<132; i++)
  192.         buf[i] = NULL;
  193.                     /* the header */
  194.     buf[0] = SOH;
  195.     buf[1] = 0;
  196.     buf[2] = 255;
  197.  
  198.     /*
  199.      * The block zero consists of the file name (no path component),
  200.      * a NULL, and the file length (as a string).  The end of batch
  201.      * marker is an empty block.
  202.      */
  203.     if (*file != NULL) {
  204.         strcpy((char *) &buf[3], file);
  205.         sprintf((char *) &buf[strlen(file)+4], "%ld", size);
  206.     }
  207.                     /* the crc */
  208.     crc = calc_crc(&buf[3], 128);
  209.     buf[131] = crc >> 8;
  210.     buf[132] = crc;
  211.                     /* the block count */
  212.     mvwaddstr(win, 7, 24, "0   ");
  213.  
  214.     return(send_block(win, buf, 133));
  215. }
  216.  
  217. /*
  218.  * Receive the block 0 information for a ymodem batch transfer.  We
  219.  * only use the file name and the size (if present).  Currently doesn't
  220.  * support full path names.
  221.  */
  222.  
  223. int
  224. rcv_ymodem(win)
  225. WINDOW *win;
  226. {
  227.     extern unsigned char buf[1029];
  228.     extern long file_length;
  229.     extern char file_name[15];
  230.     int code, length_is_at;
  231.     long atol();
  232.  
  233.     file_length = 0L;
  234.     file_name[0] = NULL;
  235.                     /* read the zero block */
  236.     if (code = rcv_block(win, 1, 1024, 0))
  237.         return(code);
  238.                     /* at end of batch */
  239.     if (buf[3] == NULL)
  240.         return(0);
  241.                     /* get the file name */
  242.     change_name(win, (char *) &buf[3]);
  243.                     /* any trouble? */
  244.     if (file_name[0] == NULL) {
  245.         putc_line(CAN);
  246.         return(0);
  247.     }
  248.     /*
  249.      * The file length is placed after the NULL of the file name
  250.      * and is terminated by another NULL.  If the length is missing,
  251.      * atol() will see a NULL and return 0.
  252.      */
  253.     length_is_at = strlen((char *) &buf[3]) + 4;
  254.     file_length = atol((char *) &buf[length_is_at]);
  255.     return(0);
  256. }
  257.  
  258. /*
  259.  * Handle file name collisions.  Prepend an "X" to the name until you find
  260.  * a name that doesn't already exist.  Creates a NULL name on error.
  261.  * Loads the global character array "file_name".
  262.  */
  263.  
  264. void
  265. change_name(win, str)
  266. WINDOW *win;
  267. char *str;
  268. {
  269.     extern char file_name[15];
  270.     register int i;
  271.     int modified;
  272.     char temp[15], ans[15], *s, *strrchr(), *strcpy(), *strncat();
  273.     unsigned int sleep();
  274.                     /* dissect the name component */
  275.     if ((s = strrchr(str, '/')))
  276.         strcpy(temp, s++);
  277.     else
  278.         strcpy(temp, str);
  279.  
  280.     strcpy(ans, temp);
  281.     file_name[0] = NULL;
  282.                     /* write permission on directory? */
  283.     if (access(".", 2)) {
  284.         beep();
  285.         clear_line(win, 12, 24, 1);
  286.         wattrstr(win, A_BOLD, "NO WRITE ON DIRECTORY");
  287.         wrefresh(win);
  288.         return;
  289.     }
  290.                     /* prepend up to 13 "X"s */
  291.     modified = 0;
  292.     for (i=1; i<14; i++) {
  293.         if (access(ans, 0)) {
  294.             if (modified) {
  295.                 beep();
  296.                 clear_line(win, 12, 24, 1);
  297.                 waddstr(win, "NAME COLLISION");
  298.                 wrefresh(win);
  299.                 sleep(1);
  300.             }
  301.             strcpy(file_name, ans);
  302.             return;
  303.         }
  304.  
  305.         modified++;
  306.         strcpy(temp, "X");
  307.         strncat(temp, ans, 13);
  308.         temp[14] = NULL;
  309.         strcpy(ans, temp);
  310.     }
  311.     beep();
  312.     clear_line(win, 12, 24, 1);
  313.     waddstr(win, "BAD NAME");
  314.     wrefresh(win);
  315.     return;
  316. }
  317.  
  318. /*
  319.  * Convert a perfectly good Unix file name to fit the CP/M file name
  320.  * rules.  Used for the modem7 batch file transfer.  Returns a pointer
  321.  * to the new name.
  322.  */
  323.  
  324. char *
  325. fix_name(path)
  326. char *path;
  327. {
  328.     int dot;
  329.     char *s, *name, temp[15], *ext, *strcpy(), *strrchr();
  330.     static char ans[13];
  331.                     /* ignore the path component */
  332.     if (s = strrchr(path, '/'))
  333.         strcpy(temp, s++);
  334.     else
  335.         strcpy(temp, path);
  336.     name = temp;
  337.  
  338.     ext = NULL;
  339.     dot = 0;
  340.     for (s=name; *s; ++s) {
  341.         if (*s == '.' && !dot) {
  342.             dot++;
  343.             *s = NULL;
  344.             ext = s + 1;
  345.         }
  346.         if (islower(*s))
  347.             *s = toupper(*s);
  348.     }
  349.                     /* if null name component */
  350.     if (*name == NULL)
  351.         name = "X";
  352.                     /* if name too long */
  353.     if (strlen(name) > 8)
  354.         *(name+8) = NULL;
  355.                     /* if extension too long */
  356.     if (strlen(ext) > 3)
  357.         *(ext+3) = NULL;
  358.  
  359.     sprintf(ans, "%-8.8s%-3.3s%c", temp, ext, CTRLZ);
  360.     return(ans);
  361. }
  362.  
  363. /*
  364.  * Convert a CP/M style filename into a legal Unix file name.  Loads the
  365.  * global character array "file_name".
  366.  */
  367.  
  368. void
  369. unfix_name(cpm_name)
  370. char *cpm_name;
  371. {
  372.     extern char file_name[15];
  373.     register int i, n;
  374.     int dot;
  375.     char temp[15];
  376.  
  377.     file_name[0] = NULL;
  378.     if (!*cpm_name)
  379.         return;
  380.  
  381.     strcpy(temp, cpm_name);
  382.                     /* 8 character of the name */
  383.     n = 0;
  384.     for (i=0; i<8; i++) {
  385.         if (temp[i] != ' ') {
  386.             if (isupper(temp[i]))
  387.                 file_name[n++] = tolower(temp[i]);
  388.             else
  389.                 file_name[n++] = temp[i];
  390.         }
  391.     }
  392.                     /* 3 character extension */
  393.     dot = 0;
  394.     for (i=8; i<11; i++) {
  395.         if (temp[i] != ' ') {
  396.             if (!dot) {
  397.                 dot++;
  398.                 file_name[n++] = '.';
  399.             }
  400.             if (isupper(temp[i]))
  401.                 file_name[n++] = tolower(temp[i]);
  402.             else
  403.                 file_name[n++] = temp[i];
  404.         }
  405.     }
  406.     file_name[n] = NULL;
  407.     return;
  408. }
  409.