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