home *** CD-ROM | disk | FTP | other *** search
/ The Devil's Doorknob BBS Capture (1996-2003) / devilsdoorknobbbscapture1996-2003.iso / Dloads / PROGRAMM / SERIAL.ZIP / PROTOCOL.C < prev    next >
C/C++ Source or Header  |  1992-01-29  |  25KB  |  942 lines

  1. /********************************************************************
  2. * protocol.c - Xmodem, Xmodem-1K, Ymodem, and Ymodem-G Protocols    *
  3. *              Copyright (c) 1992 By Mark D. Goodwin                *
  4. ********************************************************************/
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <time.h>
  9. #ifdef __TURBOC__
  10. #include <dir.h>
  11. #else
  12. #include <dos.h>
  13. #endif
  14. #include <stdarg.h>
  15. #include <io.h>
  16. #include "serial.h"
  17.  
  18. /* protocol constants */
  19. #define SOH 0x01
  20. #define STX 0x02
  21. #define EOT 0x04
  22. #define ACK 0x06
  23. #define NAK 0x15
  24. #define CAN 0x18
  25. #define CPMEOF 0x1A
  26. #define TIMED_OUT 3
  27. #define BAD_BLOCK 5
  28. #define CRC_ERROR 7
  29.  
  30. /* calculate elapsed time */
  31. #define elapsed ((clock() - start) / CLK_TCK)
  32.  
  33. /* buffer for data packets */
  34. unsigned char buffer[1024];
  35.  
  36. /* CRC table */
  37. unsigned short crctab[256] = {
  38.     0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
  39.     0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
  40.     0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
  41.     0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
  42.     0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
  43.     0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
  44.     0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
  45.     0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
  46.     0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
  47.     0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
  48.     0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
  49.     0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
  50.     0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
  51.     0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
  52.     0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
  53.     0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
  54.     0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
  55.     0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
  56.     0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
  57.     0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
  58.     0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
  59.     0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
  60.     0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
  61.     0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
  62.     0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
  63.     0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
  64.     0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
  65.     0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
  66.     0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
  67.     0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
  68.     0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
  69.     0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
  70. };
  71.  
  72. /* update CRC routine */
  73. #define updcrc(d, s) (crctab[((s >> 8) & 0xff)] ^ (s << 8) ^ d)
  74.  
  75. /* get a character, but time out after a specified time limit */
  76. static int timed_get(int n)
  77. {
  78.     clock_t start;
  79.  
  80.     start = clock();                    /* get current time */
  81.     while (TRUE) {
  82.         if (in_ready())                    /* char available? */
  83.             return get_serial();        /* return it if one is */
  84.         if (!carrier() || elapsed >= n) /* break out of loop if time out */
  85.             break;
  86.     }
  87.     return -1;                            /* return time out error */
  88. }
  89.  
  90. /* build a data packet */
  91. static int build_block(int l, FILE *file)
  92. {
  93.     int i, j;
  94.  
  95.     i = fread(buffer, 1, l, file);        /* read in the next block */
  96.     if (!i)                                /* return if EOF */
  97.         return FALSE;
  98.     for (j = i; j < l; j++)                /* save CPMEOF for rest of block */
  99.         buffer[j] = CPMEOF;
  100.     return TRUE;
  101. }
  102.  
  103. /* build Ymodem header block */
  104. static void header_block(char *fname, FILE *file)
  105. {
  106.     int i;
  107.     long length;
  108.     #ifdef __TURBOC__
  109.     struct ftime ft;
  110.     #else
  111.     unsigned fd, ft;
  112.     #endif
  113.     struct tm t;
  114.  
  115.     for (i = 0; i < 128; i++)            /* zero out the buffer */
  116.         buffer[i] = 0;
  117.     if (fname != NULL) {
  118.         sprintf(buffer, fname);            /* save the filename */
  119.         fseek(file, 0L, SEEK_END);        /* get the length */
  120.         length = ftell(file);
  121.         fseek(file, 0L, SEEK_SET);
  122.         #ifdef __TURBOC__
  123.         getftime(fileno(file), &ft);      /* figure the file mod date */
  124.         t.tm_year = ft.ft_year + 80;
  125.         t.tm_mon = ft.ft_month - 1;
  126.         t.tm_mday = ft.ft_day;
  127.         t.tm_hour = ft.ft_hour;
  128.         t.tm_min = ft.ft_min;
  129.         t.tm_sec = ft.ft_tsec * 2;
  130.         t.tm_isdst = FALSE;
  131.         #else
  132.         _dos_getftime(fileno(file), &fd, &ft);
  133.         t.tm_year = (fd >> 9) + 80;
  134.         t.tm_mon = ((fd >> 5) & 0xf) - 1;
  135.         t.tm_mday = (fd & 0x1f);
  136.         t.tm_hour = (ft >> 11);
  137.         t.tm_min = (ft >> 5) & 0x3f;
  138.         t.tm_sec = (ft & 0x1f) * 2;
  139.         t.tm_isdst = FALSE;
  140.         #endif
  141.         putenv("TZ=GMT0GMT");               /* adjust for time zones */
  142.         tzset();
  143.         /* save the length and mod date */
  144.         sprintf(buffer + strlen(buffer) + 1, "%ld %lo", length, mktime(&t));
  145.     }
  146. }
  147.  
  148. /* abort transfer routine */
  149. static void abort_transfer(void)
  150. {
  151.     int i;
  152.  
  153.     for (i = 0; i < 8; i++)             /* send 8 CANs */
  154.         put_serial(CAN);
  155. }
  156.  
  157. /* parse the filename */
  158. static void parse(char *p, char *f)
  159. {
  160.     int i;
  161.     char *s;
  162.  
  163.     if ((s = strrchr(p, ':')) != NULL)    /* bump past drive spec */
  164.         p = s + 1;
  165.     if ((s = strrchr(p, '\\')) != NULL)    /* bump past path spec */
  166.         p = s + 1;
  167.     *f = 0;                                /* save the filename */
  168.     for (i = 0; i < 12; i++) {
  169.         if (!*p)
  170.             break;
  171.         *f = *p;
  172.         f++;
  173.         *f = 0;
  174.         p++;
  175.     }
  176. }
  177.  
  178. /* file transmit routine */
  179. int xmit_file(int xtype, int (*error_handler)(int c, long p, char *s), char *files[])
  180. {
  181.     int i, tries, block = 0, bsize, cancel, retrans, crc, batch, nfiles = 0;
  182.     int obits, oparity, ostop, oxon;
  183.     unsigned int sum;
  184.     long length, bsent;
  185.     clock_t start;
  186.     char *fname;
  187.     FILE *file;
  188.     char path[13];
  189.  
  190.     switch (xtype) {                    /* set block size and batch flag */
  191.         case XMODEM:
  192.             bsize = 128;
  193.             batch = FALSE;
  194.             break;
  195.         case XMODEM1K:
  196.             bsize = 1024;
  197.             batch = FALSE;
  198.             break;
  199.         case YMODEM:
  200.             bsize = 1024;
  201.             batch = TRUE;
  202.             break;
  203.         case YMODEMG:
  204.             bsize = 1024;
  205.             batch = TRUE;
  206.             break;
  207.         default:
  208.             return FALSE;
  209.     }
  210.     obits = get_bits();                    /* save current settings */
  211.     oparity = get_parity();
  212.     ostop = get_stopbits();
  213.     oxon = get_tx_xon();
  214.     set_data_format(8, NO_PARITY, 1);    /* set for 8-N-1 */
  215.     set_tx_xon(FALSE);
  216.     while (TRUE) {
  217.         fname = files[nfiles];            /* get the next filename */
  218.         nfiles++;
  219.         /* return if none and if not a batch transfer */
  220.         if (fname == NULL && !batch) {
  221.             set_data_format(obits, oparity, ostop);
  222.             set_tx_xon(oxon);
  223.             return TRUE;
  224.         }
  225.         start = clock();                /* get clock */
  226.         cancel = FALSE;                    /* no CAN */
  227.         while (TRUE) {
  228.             /* abort if loss of carrier */
  229.             if (!carrier()) {
  230.                 (*error_handler)(ERROR, block, "Loss of Carrier Detected!");
  231.                 set_data_format(obits, oparity, ostop);
  232.                 set_tx_xon(oxon);
  233.                 return FALSE;
  234.             }
  235.             /* get a character from the receiver */
  236.             if (in_ready()) {
  237.                 switch (get_serial()) {
  238.                     case NAK:            /* Use no CRCs */
  239.                         crc = FALSE;
  240.                         break;
  241.                     case 'C':              /* Use CRCs */
  242.                         if (xtype == YMODEMG)
  243.                             xtype = YMODEM;
  244.                         crc = TRUE;
  245.                         break;
  246.                     case 'G':            /* Ymodem-G */
  247.                         if (xtype != YMODEMG)
  248.                             continue;
  249.                         crc = TRUE;
  250.                         break;
  251.                     case CAN:
  252.                         /* abort if second cancel */
  253.                         if (cancel) {
  254.                             (*error_handler)(ERROR, block, "Transfer Cancelled By Receiver");
  255.                             set_data_format(obits, oparity, ostop);
  256.                             set_tx_xon(oxon);
  257.                             return FALSE;
  258.                         }
  259.                         cancel = TRUE;
  260.                         continue;
  261.                     default:
  262.                         cancel = FALSE;
  263.                         continue;
  264.                 }
  265.                 break;
  266.             }
  267.             /* abort if time out */
  268.             if (elapsed >= 60) {
  269.                 set_data_format(obits, oparity, ostop);
  270.                 set_tx_xon(oxon);
  271.                 return FALSE;
  272.             }
  273.         }
  274.         if (fname != NULL) {
  275.             /* open the file */
  276.             if ((file = fopen(fname, "rb")) == NULL) {
  277.                 abort_transfer();
  278.                 set_data_format(obits, oparity, ostop);
  279.                 set_tx_xon(oxon);
  280.                 return FALSE;
  281.             }
  282.             /* parse filename */
  283.             parse(fname, path);
  284.             fseek(file, 0L, SEEK_END);
  285.             length = ftell(file);
  286.             fseek(file, 0L, SEEK_SET);
  287.             /* send filename and length to the error handler */
  288.             if (!(*error_handler)(SENDING, length, fname)) {
  289.                 abort_transfer();
  290.                 fclose(file);
  291.                 set_data_format(obits, oparity, ostop);
  292.                 set_tx_xon(oxon);
  293.                 return FALSE;
  294.             }
  295.             /* set number of bytes sent */
  296.             bsent = 0L;
  297.         }
  298.         /* send header if Ymodem or Ymodem-G */
  299.         if (batch) {
  300.             /* build header block */
  301.             header_block(fname, file);
  302.             while (TRUE) {
  303.                 /* figure CRC */
  304.                 for (i = sum = 0; i < 128; i++)
  305.                     sum = updcrc(buffer[i], sum);
  306.                 /* send the block */
  307.                 put_serial(SOH);
  308.                 put_serial(0);
  309.                 put_serial(0xff);
  310.                 for (i = 0; i < 128; i++)
  311.                     put_serial(buffer[i]);
  312.                 sum = updcrc(0, sum);
  313.                 sum = updcrc(0, sum);
  314.                 put_serial((unsigned char)((sum >> 8) & 0xff));
  315.                 put_serial((unsigned char)(sum & 0xff));
  316.                 cancel = retrans = FALSE;
  317.                 start = clock();
  318.                 while (TRUE) {
  319.                     /* abort if loss of carrier */
  320.                     if (!carrier()) {
  321.                         (*error_handler)(ERROR, block, "Loss of Carrier Detected!");
  322.                         if (fname != NULL)
  323.                             fclose(file);
  324.                         set_data_format(obits, oparity, ostop);
  325.                         set_tx_xon(oxon);
  326.                         return FALSE;
  327.                     }
  328.                     /* don't wait if Ymodem-G */
  329.                     if (xtype == YMODEMG)
  330.                         break;
  331.                     /* get ACK */
  332.                     if (in_ready()) {
  333.                         switch (get_serial()) {
  334.                             case NAK:    /* retransmit the block */
  335.                                 cancel = FALSE;
  336.                                 retrans = TRUE;
  337.                                 break;
  338.                             case ACK:    /* block received ok */
  339.                                 cancel = FALSE;
  340.                                 break;
  341.                             case CAN:
  342.                                 /* abort if second CAN */
  343.                                 if (cancel) {
  344.                                     if (fname != NULL)
  345.                                         fclose(file);
  346.                                     set_data_format(obits, oparity, ostop);
  347.                                     set_tx_xon(oxon);
  348.                                     return FALSE;
  349.                                 }
  350.                                 cancel = TRUE;
  351.                                 continue;
  352.                             default:
  353.                                 cancel = FALSE;
  354.                                 continue;
  355.                         }
  356.                         break;
  357.                     }
  358.                     /* abort if time out */
  359.                     if (elapsed >= 60) {
  360.                         if (fname != NULL)
  361.                             fclose(file);
  362.                         set_data_format(obits, oparity, ostop);
  363.                         set_tx_xon(oxon);
  364.                         return FALSE;
  365.                     }
  366.                 }
  367.                 /* do it again if NAK */
  368.                 if (retrans)
  369.                     continue;
  370.                 /* exit if end of batch transmission */
  371.                 if (fname == NULL) {
  372.                     timed_get(10);
  373.                     set_data_format(obits, oparity, ostop);
  374.                     set_tx_xon(oxon);
  375.                     return TRUE;
  376.                 }
  377.                 break;
  378.             }
  379.             start = clock();            /* get clock */
  380.             cancel = FALSE;                /* flag no CAN */
  381.             while (TRUE) {
  382.                 /* abort if loss of carrier */
  383.                 if (!carrier()) {
  384.                     (*error_handler)(ERROR, block, "Loss of Carrier Detected!");
  385.                     set_data_format(obits, oparity, ostop);
  386.                     set_tx_xon(oxon);
  387.                     fclose(file);
  388.                     return FALSE;
  389.                 }
  390.                 if (in_ready()) {
  391.                     switch (get_serial()) {
  392.                         case NAK:        /* no CRCs */
  393.                             crc = FALSE;
  394.                             break;
  395.                         case 'C':        /* use CRCs */
  396.                             if (xtype == YMODEMG)
  397.                                 xtype = YMODEM;
  398.                             crc = TRUE;
  399.                             break;
  400.                         case 'G':        /* Ymodem-G */
  401.                             if (xtype != YMODEMG)
  402.                                 continue;
  403.                             crc = TRUE;
  404.                             break;
  405.                         case CAN:
  406.                             /* abort if second CAN */
  407.                             if (cancel) {
  408.                                 (*error_handler)(ERROR, block, "Transfer Cancelled By Receiver");
  409.                                 set_data_format(obits, oparity, ostop);
  410.                                 set_tx_xon(oxon);
  411.                                 fclose(file);
  412.                                 return FALSE;
  413.                             }
  414.                             cancel = TRUE;
  415.                             continue;
  416.                         default:
  417.                             cancel = FALSE;
  418.                             continue;
  419.                     }
  420.                     break;
  421.                 }
  422.                 /* abort if time out */
  423.                 if (elapsed >= 60) {
  424.                     set_data_format(obits, oparity, ostop);
  425.                     set_tx_xon(oxon);
  426.                     fclose(file);
  427.                     return FALSE;
  428.                 }
  429.             }
  430.         }
  431.         block = 1;                        /* starting block number */
  432.         retrans = FALSE;
  433.         while (TRUE) {
  434.             /* build the new block if not rexmit */
  435.             if (!retrans) {
  436.                 if (bsize == 1024 && length - ftell(file) < 1024L)
  437.                     bsize = 128;
  438.                 if (!build_block(bsize, file))
  439.                     break;
  440.             }
  441.             /* figure CRC or checksum */
  442.             for (i = sum = 0; i < bsize; i++) {
  443.                 if (crc)
  444.                     sum = updcrc(buffer[i], sum);
  445.                 else
  446.                     sum += buffer[i];
  447.             }
  448.             /* send the block */
  449.             if (bsize == 128)
  450.                 put_serial(SOH);
  451.             else
  452.                 put_serial(STX);
  453.             put_serial((unsigned char)(block & 0xff));
  454.             put_serial((unsigned char)((255 - block) & 0xff));
  455.             for (i = 0; i < bsize; i++)
  456.                 put_serial(buffer[i]);
  457.             if (crc) {
  458.                 sum = updcrc(0, sum);
  459.                 sum = updcrc(0, sum);
  460.                 put_serial((unsigned char)((sum >> 8) & 0xff));
  461.                 put_serial((unsigned char)(sum & 0xff));
  462.             }
  463.             else
  464.                 put_serial((unsigned char)(sum & 0xff));
  465.             cancel = retrans = FALSE;
  466.             start = clock();
  467.             while (TRUE) {
  468.                 /* abort if loss of carrier */
  469.                 if (!carrier()) {
  470.                     (*error_handler)(ERROR, block, "Loss of Carrier Detected!");
  471.                     fclose(file);
  472.                     set_data_format(obits, oparity, ostop);
  473.                     set_tx_xon(oxon);
  474.                     return FALSE;
  475.                 }
  476.                 /* Ymodem-G */
  477.                 if (xtype == YMODEMG) {
  478.                     /* adjust no bytes sent */
  479.                     bsent += bsize;
  480.                     if (!(*error_handler)(SENT, bsent, "ACK")) {
  481.                         abort_transfer();
  482.                         fclose(file);
  483.                         set_data_format(obits, oparity, ostop);
  484.                         set_tx_xon(oxon);
  485.                         return FALSE;
  486.                     }
  487.                     /* abort if two CANs received */
  488.                     if (in_ready() && get_serial() == CAN &&
  489.                         in_ready() && get_serial() == CAN) {
  490.                         (*error_handler)(ERROR, block, "Transfer Cancelled By Receiver");
  491.                         fclose(file);
  492.                         set_data_format(obits, oparity, ostop);
  493.                         set_tx_xon(oxon);
  494.                         return FALSE;
  495.                     }
  496.                     break;
  497.                 }
  498.                 if (in_ready()) {
  499.                     switch (get_serial()) {
  500.                         case NAK:        /* retransmit */
  501.                             if (!(*error_handler)(ERROR, block, "NAK")) {
  502.                                 abort_transfer();
  503.                                 fclose(file);
  504.                                  set_data_format(obits, oparity, ostop);
  505.                                 set_tx_xon(oxon);
  506.                                 return FALSE;
  507.                             }
  508.                             cancel = FALSE;
  509.                             retrans = TRUE;
  510.                             break;
  511.                         case ACK:        /* block received ok */
  512.                             bsent += bsize;
  513.                             if (!(*error_handler)(SENT, bsent, "ACK")) {
  514.                                 abort_transfer();
  515.                                 fclose(file);
  516.                                 set_data_format(obits, oparity, ostop);
  517.                                 set_tx_xon(oxon);
  518.                                 return FALSE;
  519.                             }
  520.                             cancel = FALSE;
  521.                             break;
  522.                         case CAN:
  523.                             /* abort if second CAN */
  524.                             if (cancel) {
  525.                                 (*error_handler)(ERROR, block, "Transfer Cancelled By Receiver");
  526.                                 fclose(file);
  527.                                 set_data_format(obits, oparity, ostop);
  528.                                 set_tx_xon(oxon);
  529.                                 return FALSE;
  530.                             }
  531.                             cancel = TRUE;
  532.                             continue;
  533.                         default:
  534.                             cancel = FALSE;
  535.                             continue;
  536.                     }
  537.                     break;
  538.                 }
  539.                 /* abort if time out */
  540.                 if (elapsed >= 60) {
  541.                     fclose(file);
  542.                     set_data_format(obits, oparity, ostop);
  543.                     set_tx_xon(oxon);
  544.                     return FALSE;
  545.                 }
  546.             }
  547.             /* bump block number if not retransmit */
  548.             if (retrans)
  549.                 continue;
  550.             block = (block + 1) & 0xff;
  551.         }
  552.         /* close the file */
  553.         fclose(file);
  554.         start = clock();
  555.         /* flag end of transfer */
  556.         put_serial(EOT);
  557.         while (TRUE) {
  558.             /* abort if loss of carrier */
  559.             if (!carrier()) {
  560.                 (*error_handler)(ERROR, block, "Loss of Carrier Detected!");
  561.                 set_data_format(obits, oparity, ostop);
  562.                 set_tx_xon(oxon);
  563.                 return FALSE;
  564.             }
  565.             /* get ACK */
  566.             if (in_ready()) {
  567.                 if (get_serial() != ACK) {
  568.                     put_serial(EOT);
  569.                     continue;
  570.                 }
  571.                 break;
  572.             }
  573.             /* abort if time out */
  574.             if (elapsed >= 60) {
  575.                 set_data_format(obits, oparity, ostop);
  576.                 set_tx_xon(oxon);
  577.                 return FALSE;
  578.             }
  579.         }
  580.         (*error_handler)(COMPLETE, block, "Transfer Successfully Completed");
  581.         /* exit if not Ymodem or Ymodem-G */
  582.         if (!batch) {
  583.             set_data_format(obits, oparity, ostop);
  584.             set_tx_xon(oxon);
  585.             return TRUE;
  586.         }
  587.         /* adjust block size */
  588.         bsize = 1024;
  589.     }
  590. }
  591.  
  592. /* get a block from transmitter */
  593. static int getblock(int block, int crc)
  594. {
  595.     int c, l, i, sum;
  596.  
  597.     /* get a character */
  598.     if ((c = timed_get(10)) == -1)
  599.         return TIMED_OUT;
  600.     switch (c) {
  601.         case CAN:                        /* two CANs? */
  602.             if ((c = timed_get(1)) == CAN)
  603.                 return CAN;
  604.             return TIMED_OUT;
  605.         case SOH:                        /* 128 byte block header */
  606.             l = 128;
  607.             break;
  608.         case STX:                         /* 1024 byte block header */
  609.             l = 1024;
  610.             break;
  611.         case EOT:                          /* end of transfer */
  612.             return EOT;
  613.         default:
  614.             return TIMED_OUT;            /* return timed out */
  615.     }
  616.     if ((c = timed_get(1)) == -1)        /* get the block number */
  617.         return TIMED_OUT;
  618.     if (c != block)                      /* return if bad block number */
  619.         return BAD_BLOCK;
  620.     if ((c = timed_get(1)) == -1)        /* get complement */
  621.         return TIMED_OUT;
  622.     if (c != ((255 - block) & 0xff))    /* return if bad block number */
  623.         return BAD_BLOCK;
  624.     for (i = 0; i < l; i++)                /* get the block */
  625.         if ((int)(buffer[i] = (unsigned char)timed_get(1)) == -1)
  626.             return TIMED_OUT;
  627.     /* get checksum */
  628.     if (!crc) {
  629.         if ((c = timed_get(1)) == -1)
  630.             return TIMED_OUT;
  631.         for (i = sum = 0; i < l; i++)
  632.             sum += buffer[i];
  633.     }
  634.     /* get CRC */
  635.     else {
  636.         if ((sum = timed_get(1)) == -1)
  637.             return TIMED_OUT;
  638.         if ((c = timed_get(1)) == -1)
  639.             return TIMED_OUT;
  640.         c |= sum << 8;
  641.         for (i = sum = 0; i < l; i++)
  642.             sum = updcrc(buffer[i], sum);
  643.         sum = updcrc(0, sum);
  644.         sum = updcrc(0, sum);
  645.     }
  646.     /* check for checksum or CRC error */
  647.     if (c != sum)
  648.         return CRC_ERROR;
  649.     /* return block size */
  650.     if (l == 128)
  651.         return SOH;
  652.     return STX;
  653. }
  654.  
  655. /* receive files routine */
  656. int recv_file(int xtype, int(*error_handler)(int c, long p, char *s), char *path)
  657. {
  658.     int i, l, batch, block, crc;
  659.     int obits, oparity, ostop, oxon;
  660.     long length, received, moddate;
  661.     char *fname, line[80];
  662.     FILE *file;
  663.     #ifdef __TURBOC__
  664.     struct ftime ft;
  665.     #else
  666.     unsigned fd, ft;
  667.     #endif
  668.     struct tm *t;
  669.  
  670.     /* set batch flag */
  671.     switch (xtype) {
  672.         case XMODEM:
  673.         case XMODEM1K:
  674.             batch = FALSE;
  675.             break;
  676.         case YMODEM:
  677.         case YMODEMG:
  678.             batch = TRUE;
  679.             break;
  680.         default:
  681.             return FALSE;
  682.     }
  683.     obits = get_bits();                    /* save current settings */
  684.     oparity = get_parity();
  685.     ostop = get_stopbits();
  686.     oxon = get_tx_xon();
  687.     set_data_format(8, NO_PARITY, 1);    /* set to 8-N-1 */
  688.     set_tx_xon(FALSE);
  689.     while (TRUE) {
  690.         crc = TRUE;                        /* use CRCs */
  691.         /* get transmitter going */
  692.         if (xtype == YMODEMG)
  693.             put_serial('G');
  694.         else
  695.             put_serial('C');
  696.         block = batch ? 0 : 1;
  697.         for (i = 0; i < 10; i++) {
  698.             /* get a block */
  699.             l = getblock(block, crc);
  700.             /* abort if CAN or loss of carrier */
  701.             if (l == CAN || !carrier()) {
  702.                 set_data_format(obits, oparity, ostop);
  703.                 set_tx_xon(oxon);
  704.                 return FALSE;
  705.             }
  706.             /* get transmitter going again */
  707.             if (l != SOH && l != STX && l != EOT) {
  708.                 switch (xtype) {
  709.                     case XMODEM:
  710.                         if (i < 2)
  711.                             put_serial('C');    /* use CRCs */
  712.                         else {
  713.                             put_serial(NAK);     /* no CRCs after two tries */
  714.                             crc = FALSE;
  715.                         }
  716.                         continue;
  717.                     case XMODEM1K:
  718.                     case YMODEM:
  719.                         put_serial('C');        /* use CRCs */
  720.                         continue;
  721.                     case YMODEMG:
  722.                         put_serial('G');        /* Ymodem-G */
  723.                         continue;
  724.                 }
  725.             }
  726.             break;
  727.         }
  728.         /* abort if transmitter doesn't respond after 10 tries */
  729.         if (i == 10) {
  730.             set_data_format(obits, oparity, ostop);
  731.             set_tx_xon(oxon);
  732.             return FALSE;
  733.         }
  734.         /* set filename, length, and number of bytes received */
  735.         if (!batch) {
  736.             fname = path;
  737.             length = received = 0L;
  738.         }
  739.         else {
  740.             if (!*buffer) {
  741.                 set_data_format(obits, oparity, ostop);
  742.                 set_tx_xon(oxon);
  743.                 return TRUE;
  744.             }
  745.             sprintf(line, "%s\\%s", path, buffer);
  746.             fname = line;
  747.             if (!buffer[strlen(buffer) + 1]) {
  748.                 length = 0L;
  749.                 moddate = 0L;
  750.             }
  751.             else {
  752.                 sscanf(buffer + strlen(buffer) + 1, "%ld%lo", &length, &moddate);
  753.                 received = 0;
  754.             }
  755.         }
  756.         /* open the file */
  757.         if ((file = fopen(fname, "wb")) == NULL) {
  758.             abort_transfer();
  759.             set_data_format(obits, oparity, ostop);
  760.             set_tx_xon(oxon);
  761.             return FALSE;
  762.         }
  763.         /* send filename and length to the error handler */
  764.         if (!(*error_handler)(RECEIVING, length, fname)) {
  765.             abort_transfer();
  766.             fclose(file);
  767.             set_data_format(obits, oparity, ostop);
  768.             set_tx_xon(oxon);
  769.             return FALSE;
  770.         }
  771.         /* if batch signal get 1st block */
  772.         if (batch) {
  773.             crc = TRUE;
  774.             put_serial(ACK);            /* ACK block 0 */
  775.             /* tell tranmitter to send 1st block */
  776.             if (xtype == YMODEMG)
  777.                 put_serial('G');
  778.             else
  779.                 put_serial('C');
  780.             block = 1;
  781.             for (i = 0; i < 10; i++) {
  782.                 /* get a block */
  783.                 l = getblock(block, crc);
  784.                 /* abort if CAN or loss of carrier */
  785.                 if (l == CAN || !carrier()) {
  786.                     set_data_format(obits, oparity, ostop);
  787.                     set_tx_xon(oxon);
  788.                     fclose(file);
  789.                     return FALSE;
  790.                 }
  791.                 /* nudge transmitter again if no block */
  792.                 if (l != SOH && l != STX && l != EOT) {
  793.                     switch (xtype) {
  794.                         case YMODEM:
  795.                             put_serial('C');
  796.                             continue;
  797.                         case YMODEMG:
  798.                             put_serial('G');
  799.                             continue;
  800.                     }
  801.                 }
  802.                 break;
  803.             }
  804.             /* abort if failed after 10 attempts */
  805.             if (i == 10) {
  806.                 abort_transfer();
  807.                 set_data_format(obits, oparity, ostop);
  808.                 set_tx_xon(oxon);
  809.                 fclose(file);
  810.                 return FALSE;
  811.             }
  812.         }
  813.         /* get file */
  814.         while (TRUE) {
  815.             /* break out of loop if end of file */
  816.             if (l == EOT) {
  817.                 (*error_handler)(COMPLETE, 0, "Transfer Successfully Completed");
  818.                 break;
  819.             }
  820.             /* write the block to disk */
  821.             if (!batch || (batch && !length)) {
  822.                 fwrite(buffer, 1, l == SOH ? 128 : 1024, file);
  823.                 received += (l == SOH ? 128 : 1024);
  824.             }
  825.             else {
  826.                 if (length - received >= (l == SOH ? 128 : 1024)) {
  827.                     fwrite(buffer, 1, l == SOH ? 128 : 1024, file);
  828.                     received += (l == SOH ? 128 : 1024);
  829.                 }
  830.                 else {
  831.                     if (length - received) {
  832.                         fwrite(buffer, 1, (size_t)(length - received), file);
  833.                             received = length;
  834.                     }
  835.                 }
  836.             }
  837.             if (!(*error_handler)(RECEIVED, received, "Block Received")) {
  838.                 abort_transfer();
  839.                 set_data_format(obits, oparity, ostop);
  840.                 set_tx_xon(oxon);
  841.                 fclose(file);
  842.                 return FALSE;
  843.             }
  844.             /* increment block number */
  845.             block = (block + 1) & 255;
  846.             /* ACK if not Ymodem-G */
  847.             if (xtype != YMODEMG)
  848.                 put_serial(ACK);
  849.             for (i = 0; i < 10; i++) {
  850.                 /* get a block */
  851.                 l = getblock(block, crc);
  852.                 if (l == SOH || l == STX || l == EOT)
  853.                     break;
  854.                 /* abort if loss of carrier */
  855.                 if (!carrier()) {
  856.                     (*error_handler)(ERROR, block, "Loss of Carrier Detected!");
  857.                     set_data_format(obits, oparity, ostop);
  858.                     set_tx_xon(oxon);
  859.                     fclose(file);
  860.                     return FALSE;
  861.                 }
  862.                 switch (l) {
  863.                     case CAN:            /* abort if CAN */
  864.                         (*error_handler)(ERROR, block, "Cancelled by Sender");
  865.                         set_data_format(obits, oparity, ostop);
  866.                         set_tx_xon(oxon);
  867.                         fclose(file);
  868.                         return FALSE;
  869.                     case TIMED_OUT:        /* TIMED OUT */
  870.                         if (!(*error_handler)(ERROR, block, "Short Block")) {
  871.                             abort_transfer();
  872.                             set_data_format(obits, oparity, ostop);
  873.                             set_tx_xon(oxon);
  874.                             fclose(file);
  875.                             return FALSE;
  876.                         }
  877.                         break;
  878.                     case BAD_BLOCK:        /* bad block number */
  879.                         if (!(*error_handler)(ERROR, block, "Bad Block Number")) {
  880.                             abort_transfer();
  881.                             set_data_format(obits, oparity, ostop);
  882.                             set_tx_xon(oxon);
  883.                             fclose(file);
  884.                             return FALSE;
  885.                         }
  886.                         break;
  887.                     case CRC_ERROR:        /* CRC error */
  888.                         if (!(*error_handler)(ERROR, block, crc ? "CRC Error" : "Checksum Error") || xtype == YMODEMG) {
  889.                             abort_transfer();
  890.                             set_data_format(obits, oparity, ostop);
  891.                             set_tx_xon(oxon);
  892.                             fclose(file);
  893.                             return FALSE;
  894.                         }
  895.                         break;
  896.                 }
  897.                 /* send NAK if not Ymodem-G */
  898.                 if (xtype != YMODEMG)
  899.                     put_serial(NAK);
  900.             }
  901.             /* abort after 10 attempts */
  902.             if (i == 10) {
  903.                 abort_transfer();
  904.                 set_data_format(obits, oparity, ostop);
  905.                 set_tx_xon(oxon);
  906.                 return FALSE;
  907.             }
  908.         }
  909.         /* ACK EOT */
  910.         put_serial(ACK);
  911.         /* close the file */
  912.         fclose(file);
  913.         /* exit if not Ymodem or Ymodem-G */
  914.         if (!batch)
  915.             return TRUE;
  916.         /* adjust file mod date */
  917.         if (moddate && (file = fopen(fname, "rb")) != NULL) {
  918.             putenv("TZ=GMT0GMT");
  919.             tzset();
  920.             t = localtime(&moddate);
  921.             #ifdef __TURBOC__
  922.             ft.ft_year = t->tm_year - 80;
  923.             ft.ft_month = t->tm_mon + 1;
  924.             ft.ft_day = t->tm_mday;
  925.             ft.ft_hour = t->tm_hour;
  926.             ft.ft_min = t->tm_min;
  927.             ft.ft_tsec = t->tm_sec / 2;
  928.             setftime(fileno(file), &ft);
  929.             #else
  930.             fd = (t->tm_year - 80) << 9;
  931.             fd |= (t->tm_mon + 1) << 5;
  932.             fd |= t->tm_mday;
  933.             ft = t->tm_hour << 11;
  934.             ft |= t->tm_min << 5;
  935.             ft |= t->tm_sec / 2;
  936.             _dos_setftime(fileno(file), fd, ft);
  937.             #endif
  938.             fclose(file);
  939.         }
  940.     }
  941. }
  942.