home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / TELECOM / xyz.lzh / ftxy.c < prev    next >
Text File  |  1995-08-18  |  40KB  |  1,448 lines

  1. /*
  2.    Printed form of this source is Copyright (C) 1995 Coriolis
  3.    Group, Inc.  All rights reserved.  Individual users may
  4.    make printed copies for their own personal use.
  5.  
  6.    All other forms are Copyright (C) 1995 Tim Kientzle. All
  7.    rights reserved.
  8.  
  9. Redistribution in source or binary form is permitted only under
  10. the following conditions:
  11. 1. If you own a copy of `The Working Programmer's Guide To Serial
  12.    Protocols,' then you may redistribute this code as part of
  13.    a complete application program under the conditions
  14.    described in that book.  (See pages xiv, xv.)  In any case,
  15.    you must abide by terms 4-7 below.
  16. 2. Otherwise, if you have received this code as a part of an
  17.    application program, it may only be redistributed with the
  18.    complete source of that program, under whatever conditions
  19.    apply to redistribution of that program as a whole.
  20. 3. If you have received this source code by some other means,
  21.    you may not redistribute it without explicit written
  22.    permission from Tim Kientzle.
  23. 4. All advertising materials mentioning features or use of this
  24.    software must prominently display the following acknowledgement:
  25.       This product is partially based on source code appearing in
  26.       `The Working Programmer's Guide to Serial Protocols,'
  27.       Copyright (C) 1995 Coriolis Group, Inc. and Tim Kientzle.
  28. 5. All programs using this source code must display the above
  29.    acknowledgement prominently in the program documentation
  30.    and user interface.
  31. 6. Neither the name of the Tim Kientzle nor the Coriolis Group, Inc.,
  32.    may be used to endorse or promote products derived from this
  33.    software without specific prior written permission.
  34. 7. Any redistribution in source form must retain the above copyright
  35.    notice, this list of conditions, and the disclaimer below.
  36.  
  37. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  38. WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  39. OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  40. IN NO EVENT SHALL TIM KIENTZLE OR THE CORIOLIS GROUP BE LIABLE FOR
  41. ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  42. DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  43. GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  44. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  45. IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  46. OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  47. IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  48.  
  49. */
  50.  
  51. #define SOH (0x01)
  52. #define STX (0x02)
  53. #define EOT (0x04)
  54. #define ACK (0x06)
  55. #define NAK (0x15)
  56. #define CAN (0x18)
  57. #define SUB (0x1A)
  58. #define StsRet(expr) \
  59. do{ \
  60. int tmpErrorVal= (expr); \
  61. if(tmpErrorVal!=xyOK)return StsWarn(tmpErrorVal); \
  62. }while(FALSE)
  63. #define debugWarn (1)
  64. #define debugPacket (2)
  65. #define debugAttr (32)
  66. #define debugInit (64)
  67. #define StsWarn(s)((pXY->debug)?XYDebugWarn(pXY,(s),__FILE__,__LINE__):(s))
  68. #define ChooseLetter(f,ec,eu,dc,du) \
  69. ((f).enabled?((f).certain?ec:eu):((f).certain?dc:du))
  70. #include <stddef.h>
  71. #include <stdio.h>
  72. #ifdef _UCC
  73. #include <stdlib.h>
  74. #include <string.h>
  75. #else
  76. int     sprintf ();
  77. #endif
  78.  
  79. #include <time.h>
  80. #include "ftdebug.h"
  81. #include "ftprog.h"
  82. #include "ftdisk.h"
  83. #include "ftserial.h"
  84. #include "ftxy.h"
  85. #ifndef TRUE
  86. #define TRUE (1)
  87. #endif
  88. #ifndef FALSE
  89. #define FALSE (0)
  90. #endif
  91. #ifndef NULL
  92. #define NULL ((void *)0)
  93. #endif
  94. #define STATIC
  95. typedef unsigned char BYTE;
  96. typedef struct {
  97.    int     enabled;
  98.    int     certain;
  99. } CAPABILITY;
  100. enum {
  101.    stsNegotiating = progNegotiating,
  102.    stsSending = progSending,
  103.    stsReceiving = progReceiving,
  104.    stsEnding = progEnding,
  105.    stsDone = progDone,
  106.    stsEOF = progEOF,
  107.    stsNewFile = progNewFile,
  108.    stsFailed = progFailed,
  109.    stsCancelled = progCancelled
  110. };
  111. typedef struct {
  112.    int     timeout;
  113.    int     retries;
  114.    volatile int userCancel;
  115.    int     packetNumber;
  116.    unsigned long transferred;
  117.    long    fileSize;
  118.    CAPABILITY crc, longPacket, batch, G;
  119.    DEBUG   debug;
  120.    SERIAL_PORT port;
  121.    DISKFILE f;
  122.    const char **filenames;
  123.    int     currentFileName;
  124.    int     numFileNames;
  125.    int     fileType;
  126.    PROGRESS progress;
  127. } XYMODEM_PRIVATE;
  128. STATIC void 
  129. XYNewFile (XYMODEM_PRIVATE *pXY)
  130. {
  131.    pXY->fileSize = 0;
  132.    pXY->transferred = 0;
  133. }
  134.  
  135. enum {
  136.    xyOK = 0,
  137.    xyFail,
  138.    xyFailed,
  139.    xyBadPacket,
  140.    xyEOT,
  141.    xyEndOfSession,
  142.    xyEOF,
  143.    xyTimeout
  144. };
  145. STATIC int XYDebugWarn
  146.         (XYMODEM_PRIVATE *pXY, const int s, const char *file, const int line) {
  147.    const char *msg;
  148.  
  149.    if (s == xyOK)
  150.       return s;
  151.    DebugBeginInternal (pXY->debug, debugWarn, file, line);
  152.    DebugString (pXY->debug, "!?!?!?:");
  153.    switch (s) {
  154.    case xyFail:
  155.       msg = "xyFail";
  156.       break;
  157.    case xyFailed:
  158.       msg = "xyFailed";
  159.       break;
  160.    case xyBadPacket:
  161.       msg = "xyBadPacket";
  162.       break;
  163.    case xyEOT:
  164.       msg = "xyEOT";
  165.       break;
  166.    case xyEndOfSession:
  167.       msg = "xyEndOfSession";
  168.       break;
  169.    case xyEOF:
  170.       msg = "xyEOF";
  171.       break;
  172.    case xyTimeout:
  173.       msg = "xyTimeout";
  174.       break;
  175.    default:
  176.       DebugString (pXY->debug, "Error ");
  177.       DebugInt (pXY->debug, s);
  178.       msg = "";
  179.    }
  180.    DebugString (pXY->debug, msg);
  181.    DebugEnd (pXY->debug);
  182.    return s;
  183. }
  184. STATIC unsigned int xyCrcTable[256];
  185. STATIC void 
  186. XYInitCrc16 (void)
  187. {
  188.    static int crcDone = 0;
  189.    unsigned i, j, crc;
  190.  
  191.    if (crcDone)
  192.       return;
  193.    for (i = 0; i < 256; i++) {
  194.       crc = (i << 8);
  195.       for (j = 0; j < 8; j++)
  196.          crc = (crc << 1) ^ ((crc & 0x8000) ? 0x1021 : 0);
  197.       xyCrcTable[i] = crc & 0xffff;
  198.    }
  199.    crcDone = 1;
  200. }
  201. STATIC unsigned 
  202. XYCrc16 (void *buff, unsigned int length,
  203.          unsigned short crc)
  204. {
  205.    unsigned char *p = buff;
  206.  
  207.    while (length-- > 0)
  208.       crc = xyCrcTable[((crc >> 8) ^ *p++) & 0xFF] ^ (crc << 8);
  209.    return crc & 0xFFFF;
  210. }
  211. STATIC unsigned XYCrc16Constant
  212.         (unsigned char c, unsigned int length, unsigned short crc) {
  213.    while (length-- > 0)
  214.       crc = xyCrcTable[((crc >> 8) ^ c) & 0xFF] ^ (crc << 8);
  215.    return crc & 0xFFFF;
  216. }
  217. STATIC void XYTimeToTm
  218.         (long s, struct tm *pT) {
  219.    long    m, h;
  220.    int     d, M, y;
  221.  
  222.    if (s <= 0) {
  223.       time_t  t = time (NULL);
  224.  
  225.       *pT = *localtime (&t);
  226.       return;
  227.    }
  228.    m = s / 60;
  229.    h = m / 60;
  230.    d = h / 24;
  231.    y = d / 365;
  232.    s %= 60;
  233.    m %= 60;
  234.    h %= 24;
  235.    d %= 365;
  236.    d -= (y + 1) / 4;
  237.    if (d < 0) {
  238.       y--;
  239.       d += 365;
  240.    }
  241.    pT->tm_sec = s;
  242.    pT->tm_min = m;
  243.    pT->tm_hour = h;
  244.    pT->tm_yday = d;
  245.    if (((y - 2) % 4 != 0) && (d >= 59))
  246.       d++;
  247.    if (d >= 60)
  248.       d++;
  249.    M = (d > 214) ? 7 : 0 + ((d % 214) / 61) * 2 + ((d % 214) % 61) / 31;
  250.    d = ((d % 214) % 61) % 31 + 1;
  251.    pT->tm_mday = d;
  252.    pT->tm_mon = M;
  253.    pT->tm_year = y + 70;
  254.    pT->tm_isdst = -1;
  255.    pT->tm_wday = -1;
  256. }
  257. STATIC long XYTime
  258.         (struct tm *pT) {
  259.    static const int mon[] =
  260.    {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335};
  261.    int     y = pT->tm_year - 70, M = pT->tm_mon;
  262.    int     d = pT->tm_mday - 1 + mon[M];
  263.  
  264.    if (((y + 2) % 4 != 0) & (M > 1))
  265.       d--;
  266.    d += (y + 1) / 4;
  267.    return (((((long) y) * 365 + d) * 24 + pT->tm_hour) * 60 + pT->tm_min) * 60
  268.          + pT->tm_sec;
  269. }
  270. STATIC int XYSerialReadWithTimeout
  271.         (XYMODEM_PRIVATE *pXY, int timeout, BYTE *pBuffer, unsigned long length) {
  272.    int     s, returnVal;
  273.  
  274.    if (pXY->userCancel)
  275.       return StsWarn (xyFail);
  276.    s = SerialReadWithTimeout (pXY->port, timeout, pBuffer, &length);
  277.    switch (s) {
  278.    case serialOK:
  279.       returnVal = xyOK;
  280.       break;
  281.    case serialTimeout:
  282.       returnVal = xyTimeout;
  283.       break;
  284.    case serialUserCancel:
  285.       pXY->userCancel = TRUE;
  286.       returnVal = xyFail;
  287.       break;
  288.    case serialFrame:
  289.       returnVal = xyBadPacket;
  290.       break;
  291.    default:
  292.       return StsWarn (xyFailed);
  293.    }
  294.    if (pXY->userCancel)
  295.       return StsWarn (xyFail);
  296.    return returnVal;
  297. }
  298. STATIC int XYSerialSend
  299.         (XYMODEM_PRIVATE *pXY, const BYTE *pBuffer, unsigned int length) {
  300.    int     s, returnVal;
  301.  
  302.    if (pXY->userCancel)
  303.       return StsWarn (xyFail);
  304.    s = SerialSend (pXY->port, pBuffer, length);
  305.    switch (s) {
  306.    case serialOK:
  307.       returnVal = xyOK;
  308.       break;
  309.    case serialUserCancel:
  310.       pXY->userCancel = TRUE;
  311.       returnVal = xyFail;
  312.       break;
  313.    default:
  314.       return StsWarn (xyFailed);
  315.    }
  316.    if (pXY->userCancel)
  317.       return StsWarn (xyFail);
  318.    return StsWarn (returnVal);
  319. }
  320. STATIC int XYSerialWaitForSentBytes
  321.         (XYMODEM_PRIVATE *pXY) {
  322.    int     s, returnVal;
  323.  
  324.    if (pXY->userCancel)
  325.       return StsWarn (xyFail);
  326.    s = SerialWaitForSentBytes (pXY->port);
  327.    switch (s) {
  328.    case serialOK:
  329.       returnVal = xyOK;
  330.       break;
  331.    case serialUserCancel:
  332.       pXY->userCancel = TRUE;
  333.       returnVal = xyFail;
  334.       break;
  335.    default:
  336.       return StsWarn (xyFailed);
  337.    }
  338.    if (pXY->userCancel)
  339.       return StsWarn (xyFail);
  340.    return StsWarn (returnVal);
  341. }
  342. STATIC int XYSendByte
  343.         (XYMODEM_PRIVATE *pXY, BYTE b) {
  344.    return StsWarn (XYSerialSend (pXY, &b, 1));
  345. }
  346. STATIC int XYSerialReadByte
  347.         (XYMODEM_PRIVATE *pXY, int timeout, BYTE *pByte) {
  348.    return StsWarn (XYSerialReadWithTimeout (pXY, timeout, pByte, 1));
  349. }
  350. STATIC int 
  351. XYGobble (XYMODEM_PRIVATE *pXY, int timeout)
  352. {
  353.    int     err;
  354.    BYTE    junk[50];
  355.  
  356.    do {
  357.       err = XYSerialReadWithTimeout (pXY, timeout, junk, sizeof (junk));
  358.       if (err == xyBadPacket)
  359.          err = xyOK;
  360.    } while (err == xyOK);
  361.    if (err == xyTimeout)
  362.       return xyOK;
  363.    return StsWarn (err);
  364. }
  365. STATIC int XYFileReadOpenNext
  366.         (XYMODEM_PRIVATE *pXY) {
  367.    int     err;
  368.  
  369.    while (1) {
  370.       if (pXY->currentFileName == pXY->numFileNames)
  371.          return xyEndOfSession;
  372.       err = DiskReadOpen (&pXY->f, pXY->filenames[pXY->currentFileName++],
  373.                           pXY->fileType);
  374.       switch (err) {
  375.       case diskOK:
  376.          DiskFileSize (pXY->f, &(pXY->fileSize));
  377.          return xyOK;
  378.       case diskCantRead:
  379.          break;
  380.       case diskNoSuchFile:
  381.          break;
  382.       default:
  383.          return xyFail;
  384.       }
  385.    }
  386. }
  387. STATIC int 
  388. XYFileRead (XYMODEM_PRIVATE *pXY,
  389.             BYTE *pBuffer, unsigned long *pLength)
  390. {
  391.    int     returnVal;
  392.  
  393.    switch (DiskRead (pXY->f, pBuffer, *pLength, pLength)) {
  394.    case diskOK:
  395.       returnVal = xyOK;
  396.       break;
  397.    case diskEOF:
  398.       returnVal = xyEOF;
  399.       break;
  400.    default:
  401.       returnVal = xyFail;
  402.       break;
  403.    }
  404.    return returnVal;
  405. }
  406. STATIC int 
  407. XYFileReadClose (XYMODEM_PRIVATE *pXY)
  408. {
  409.    int     returnVal;
  410.  
  411.    switch (DiskReadClose (pXY->f)) {
  412.    case diskOK:
  413.       returnVal = xyOK;
  414.       break;
  415.    default:
  416.       returnVal = xyFail;
  417.       break;
  418.    }
  419.    pXY->f = NULL;
  420.    return returnVal;
  421. }
  422. STATIC int XYFileWriteOpen
  423.         (XYMODEM_PRIVATE *pXY, BYTE *pBuffer, unsigned length) {
  424.    const char *fileName = (char *) pBuffer;
  425.    long    fileMode = -1;
  426.    struct tm fileDate;
  427.  
  428.    ((void) length);
  429.    if (fileName == NULL)
  430.       fileName = "xymodem.000\0\0";
  431.    {
  432.       time_t  t = time (NULL);
  433.  
  434.       fileDate = *localtime (&t);
  435.    }
  436.    {
  437.       const char *p = fileName;
  438.  
  439.       p += strlen (p) + 1;
  440.       pXY->fileSize = -1;
  441.       if (*p) {
  442.          pXY->fileSize = atoi (p);
  443.          while ((*p) && (*p != ' '))
  444.             p++;
  445.          while (*p == ' ')
  446.             p++;
  447.       }
  448.       if (*p) {
  449.          long    fileDateSeconds = 0;
  450.  
  451.          while ((*p) && (*p >= '0') && (*p <= '7')) {
  452.             fileDateSeconds = fileDateSeconds * 8 + (*p) - '0';
  453.             p++;
  454.          }
  455.          XYTimeToTm (fileDateSeconds, &fileDate);
  456.          while ((*p) && (*p != ' '))
  457.             p++;
  458.          while (*p == ' ')
  459.             p++;
  460.       }
  461.       if (*p) {
  462.          fileMode = 0;
  463.          while ((*p) && (*p >= '0') && (*p <= '7')) {
  464.             fileMode = fileMode * 8 + (*p) - '0';
  465.             p++;
  466.          }
  467.          while ((*p) && (*p != ' '))
  468.             p++;
  469.          while (*p == ' ')
  470.             p++;
  471.       }
  472.    }
  473.    if (DiskWriteInit (&pXY->f, pXY->debug))
  474.       return StsWarn (xyFail);
  475.    if (DiskWriteName (pXY->f, fileName))
  476.       return StsWarn (xyFail);
  477.    if (pXY->fileSize >= 0)
  478.       if (DiskWriteSize (pXY->f, pXY->fileSize))
  479.          return StsWarn (xyFail);
  480.    if (DiskWriteDate (pXY->f, &fileDate))
  481.       return StsWarn (xyFail);
  482.    if (DiskWriteMode (pXY->f, fileMode))
  483.       return StsWarn (xyFail);
  484.    if (DiskWriteType (pXY->f, diskFileUnknown))
  485.       return StsWarn (xyFail);
  486.    if (DiskWriteOpen (pXY->f))
  487.       return StsWarn (xyFail);
  488.    return xyOK;
  489. }
  490. STATIC int XYFileWrite
  491.         (XYMODEM_PRIVATE *pXY, const BYTE *pBuffer, unsigned length) {
  492.    switch (DiskWrite (pXY->f, pBuffer, length)) {
  493.    case diskOK:
  494.       return xyOK;
  495.    default:
  496.       return xyFail;
  497.    }
  498. }
  499. STATIC int 
  500. XYFileWriteClose (XYMODEM_PRIVATE *pXY)
  501. {
  502.    int     returnVal;
  503.  
  504.    switch (DiskWriteClose (pXY->f)) {
  505.    case diskOK:
  506.       returnVal = xyOK;
  507.       break;
  508.    default:
  509.       returnVal = xyFail;
  510.       break;
  511.    }
  512.    pXY->f = NULL;
  513.    return returnVal;
  514. }
  515. STATIC void 
  516. XYProgress (XYMODEM_PRIVATE *pXY, int status)
  517. {
  518.    const char *protocol;
  519.    char    protoName[15];
  520.  
  521.    if (pXY->debug) {
  522.       protoName[0] = ChooseLetter (pXY->crc, 'C', 'c', '-', ' ');
  523.       protoName[1] = ChooseLetter (pXY->longPacket, 'K', 'k', '-', ' ');
  524.       protoName[2] = ChooseLetter (pXY->batch, 'B', 'b', '-', ' ');
  525.       protoName[3] = ChooseLetter (pXY->G, 'G', 'g', '-', ' ');
  526.       protoName[4] = 0;
  527.       protocol = protoName;
  528.    } else {
  529.       if (pXY->batch.enabled) {
  530.          if (pXY->G.enabled)
  531.             protocol = "YModem-G";
  532.          else
  533.             protocol = "YModem";
  534.       } else {
  535.          if (pXY->longPacket.enabled)
  536.             protocol = "XModem-K";
  537.          else if (pXY->crc.enabled)
  538.             protocol = "XModem-CRC";
  539.          else
  540.             protocol = "XModem";
  541.       }
  542.    }
  543.    ProgressProtocol (pXY->progress, protocol);
  544.    if (pXY->f) {
  545.       const char *fileName = NULL;
  546.       int     fileType = 0;
  547.  
  548.       DiskFileName (pXY->f, &fileName);
  549.       ProgressFileName (pXY->progress, fileName);
  550.       DiskFileType (pXY->f, &fileType);
  551.       ProgressFileType (pXY->progress, fileType);
  552.    } else {
  553.       ProgressFileName (pXY->progress, NULL);
  554.    }
  555.    ProgressFileSize (pXY->progress, pXY->fileSize);
  556.    ProgressFilePosition (pXY->progress, pXY->transferred);
  557.    ProgressReport (pXY->progress, status);
  558. }
  559. STATIC int 
  560. XYSendCAN (XYMODEM_PRIVATE *pXY)
  561. {
  562.    static const BYTE cancel[] =
  563.    {CAN, CAN, CAN, CAN, CAN, 8, 8, 8, 8, 8};
  564.  
  565.    XYSerialSend (pXY, cancel, sizeof (cancel) / sizeof (cancel[0]));
  566.    if (pXY->debug) {
  567.       DebugBegin (pXY->debug, debugWarn | debugPacket);
  568.       DebugString (pXY->debug, "Sent CAN CAN to cancel transfer.");
  569.       DebugEnd (pXY->debug);
  570.    }
  571.    return xyOK;
  572. }
  573. STATIC int 
  574. XYSendPacket (XYMODEM_PRIVATE *pXY,
  575.               BYTE *pBuffer, unsigned length)
  576. {
  577.    int     i;
  578.  
  579.    if (length <= 128)
  580.       StsRet (XYSendByte (pXY, SOH));
  581.    else
  582.       StsRet (XYSendByte (pXY, STX));
  583.    StsRet (XYSendByte (pXY, pXY->packetNumber));
  584.    StsRet (XYSendByte (pXY, ~pXY->packetNumber));
  585.    StsRet (XYSerialSend (pXY, pBuffer, length));
  586.    for (i = length; i < 128; i++)
  587.       StsRet (XYSendByte (pXY, SUB));
  588.    if (i > 128)
  589.       for (; i < 1024; i++)
  590.          StsRet (XYSendByte (pXY, SUB));
  591.    if (pXY->crc.enabled) {
  592.       int     crc = 0;
  593.  
  594.       crc = XYCrc16 (pBuffer, length, 0);
  595.       if (length < 128)
  596.          crc = XYCrc16Constant (SUB, 128 - length, crc);
  597.       else if (length > 128)
  598.          crc = XYCrc16Constant (SUB, 1024 - length, crc);
  599.       StsRet (XYSendByte (pXY, crc >> 8));
  600.       StsRet (XYSerialWaitForSentBytes (pXY));
  601.       StsRet (XYGobble (pXY, 0));
  602.       StsRet (XYSendByte (pXY, crc));
  603.    } else {
  604.       int     checksum = 0;
  605.  
  606.       for (i = 0; i < length; i++)
  607.          checksum += pBuffer[i];
  608.       if (i > 128)
  609.          checksum += (1024 - i) * SUB;
  610.       else
  611.          checksum += (128 - i) * SUB;
  612.       StsRet (XYSerialWaitForSentBytes (pXY));
  613.       StsRet (XYGobble (pXY, 0));
  614.       StsRet (XYSendByte (pXY, checksum));
  615.    }
  616.    if (pXY->debug) {
  617.       DebugBegin (pXY->debug, debugPacket);
  618.       DebugString (pXY->debug, "Sent packet: Number:");
  619.       DebugInt (pXY->debug, pXY->packetNumber);
  620.       DebugString (pXY->debug, " Length:");
  621.       DebugUInt (pXY->debug, length);
  622.       DebugString (pXY->debug, " ``");
  623.       if (length < 40) {
  624.          DebugStringCount (pXY->debug, (const char *) pBuffer, length);
  625.          DebugString (pXY->debug, "''");
  626.       } else {
  627.          DebugStringCount (pXY->debug, (const char *) pBuffer, 39);
  628.          DebugString (pXY->debug, "...");
  629.       }
  630.       DebugEnd (pXY->debug);
  631.    }
  632.    return xyOK;
  633. }
  634. STATIC int 
  635. XYSendReadAckNak (XYMODEM_PRIVATE *pXY, BYTE *pResponse)
  636. {
  637.    int     err;
  638.    int     canCount = 0;
  639.  
  640.    do {
  641.       err = XYSerialReadByte (pXY, pXY->timeout * 5, pResponse);
  642.       switch (err) {
  643.       case xyOK:
  644.          if (*pResponse == CAN) {
  645.             DebugBegin (pXY->debug, debugWarn);
  646.             DebugString (pXY->debug,
  647.                     "Received CAN CAN while waiting on response to packet");
  648.             DebugEnd (pXY->debug);
  649.             if (++canCount >= 2)
  650.                return StsWarn (xyFailed);
  651.          } else
  652.             canCount = 0;
  653.          break;
  654.       case xyBadPacket:
  655.          *pResponse = 0;
  656.          break;
  657.       default:
  658.          return StsWarn (err);
  659.       }
  660.    } while ((*pResponse != ACK) && (*pResponse != NAK));
  661.    if (pXY->debug) {
  662.       DebugBegin (pXY->debug, debugPacket);
  663.       if (*pResponse == ACK)
  664.          DebugString (pXY->debug, "Received ACK for packet ");
  665.       else
  666.          DebugString (pXY->debug, "Received NAK for packet ");
  667.       DebugInt (pXY->debug, pXY->packetNumber);
  668.       DebugEnd (pXY->debug);
  669.    }
  670.    return StsWarn (err);
  671. }
  672. STATIC int 
  673. XYReceivePacket (XYMODEM_PRIVATE *pXY,
  674.                  int *pPacketNumber, BYTE *pBuffer, unsigned *pLength)
  675. {
  676.    BYTE    startOfPacket = 0;
  677.    BYTE    packet = 0;
  678.    BYTE    packetCheck = 0;
  679.    int     err;
  680.  
  681.    do {
  682.       err = XYSerialReadByte (pXY, pXY->timeout, &packetCheck);
  683.       if (err != xyBadPacket)
  684.          StsRet (err);
  685.    } while (err == xyBadPacket);
  686.    if (packetCheck == EOT)
  687.       return xyEOT;
  688.    do {
  689.       startOfPacket = packet;
  690.       packet = packetCheck;
  691.       err = XYSerialReadByte (pXY, pXY->timeout, &packetCheck);
  692.       if (err == xyBadPacket) {
  693.          startOfPacket = packet = packetCheck = 0;
  694.       } else
  695.          StsRet (err);
  696.       if ((packetCheck == CAN) && (packet == CAN)) {
  697.          DebugBegin (pXY->debug, debugWarn | debugPacket);
  698.          DebugString (pXY->debug, "Received CAN CAN while waiting for packet");
  699.          DebugEnd (pXY->debug);
  700.          return StsWarn (xyFailed);
  701.       }
  702.    } while (((startOfPacket != SOH) && (startOfPacket != STX))
  703.             || (((packet ^ packetCheck) & 0xFF) != 0xFF));
  704.    if (startOfPacket == SOH)
  705.       *pLength = 128;
  706.    else
  707.       *pLength = 1024;
  708.    StsRet (XYSerialReadWithTimeout (pXY, 2, pBuffer, *pLength));
  709.    if (pXY->crc.enabled) {
  710.       unsigned crc = XYCrc16 (pBuffer, *pLength, 0);
  711.       BYTE    crcByte;
  712.       int     receivedCrc;
  713.  
  714.       StsRet (XYSerialReadByte (pXY, 2, &crcByte));
  715.       receivedCrc = (crcByte & 0xFF) << 8;
  716.       StsRet (XYSerialReadByte (pXY, 2, &crcByte));
  717.       receivedCrc |= (crcByte & 0xFF);
  718.       if (crc != receivedCrc)
  719.          return StsWarn (xyBadPacket);
  720.    } else {
  721.       unsigned checksum = 0;
  722.       BYTE    receivedChecksum;
  723.       int     length = *pLength;
  724.  
  725.       while (length-- > 0)
  726.          checksum += *pBuffer++;
  727.       checksum &= 0xFF;
  728.       StsRet (XYSerialReadByte (pXY, 2, &receivedChecksum));
  729.       if (checksum != receivedChecksum)
  730.          return StsWarn (xyBadPacket);
  731.    }
  732.    if (pXY->debug) {
  733.       DebugBegin (pXY->debug, debugPacket);
  734.       DebugString (pXY->debug, "Received packet #");
  735.       DebugInt (pXY->debug, packet);
  736.       DebugString (pXY->debug, " length:");
  737.       DebugUInt (pXY->debug, *pLength);
  738.       DebugEnd (pXY->debug);
  739.    }
  740.    *pPacketNumber = packet;
  741.    pXY->crc.certain = TRUE;
  742.    if (*pLength > 128) {
  743.       pXY->longPacket.enabled = TRUE;
  744.       pXY->longPacket.certain = TRUE;
  745.    }
  746.    return xyOK;
  747. }
  748. STATIC int XYSendPacketReliable
  749.         (XYMODEM_PRIVATE *pXY, BYTE *pBuffer, unsigned int length) {
  750.    int     err;
  751.    BYTE    response = ACK;
  752.  
  753.    do {
  754.       StsRet (XYSendPacket (pXY, pBuffer, length));
  755.       if (pXY->G.enabled)
  756.          return xyOK;
  757.       err = XYSendReadAckNak (pXY, &response);
  758.       if (err == xyTimeout)
  759.          return StsWarn (xyFail);
  760.       StsRet (err);
  761.    } while (response != ACK);
  762.    pXY->crc.certain = TRUE;
  763.    if (length > 128) {
  764.       pXY->longPacket.enabled = TRUE;
  765.       pXY->longPacket.certain = TRUE;
  766.    }
  767.    return xyOK;
  768. }
  769. STATIC int 
  770. XYSendEOTReliable (XYMODEM_PRIVATE *pXY)
  771. {
  772.    BYTE    b;
  773.    int     retries = pXY->retries;
  774.    int     err;
  775.  
  776.    do {
  777.       StsRet (XYSendByte (pXY, EOT));
  778.       err = XYSerialReadByte (pXY, pXY->timeout, &b);
  779.       switch (err) {
  780.       case xyOK:
  781.          if (pXY->debug) {
  782.             DebugBegin (pXY->debug, debugPacket);
  783.             DebugString (pXY->debug, "Response to EOT: ");
  784.             switch (b) {
  785.             case ACK:
  786.                DebugString (pXY->debug, "ACK");
  787.                break;
  788.             case NAK:
  789.                DebugString (pXY->debug, "NAK");
  790.                break;
  791.             default:
  792.                DebugChar (pXY->debug, b);
  793.                break;
  794.             }
  795.             DebugEnd (pXY->debug);
  796.          }
  797.          if (b == ACK)
  798.             return xyOK;
  799.          else
  800.             StsRet (XYGobble (pXY, 3));
  801.          break;
  802.       case xyTimeout:
  803.       case xyBadPacket:
  804.          break;
  805.       default:
  806.          return StsWarn (err);
  807.       }
  808.       if (retries-- == 0)
  809.          return StsWarn (xyFail);
  810.    } while (TRUE);
  811. }
  812. STATIC int XYReceivePacketReliable
  813.         (XYMODEM_PRIVATE *pXY, int *pPacket, BYTE *pBuffer, unsigned *pLength) {
  814.    int     err;
  815.    int     eotCount = 0;
  816.    int     retries = pXY->retries;
  817.  
  818.    do {
  819.       err = XYReceivePacket (pXY, pPacket, pBuffer, pLength);
  820.       if (err == xyEOT) {
  821.          if (pXY->G.enabled)
  822.             return xyEOT;
  823.          eotCount += 3;
  824.       } else if (err == xyTimeout) {
  825.          if (eotCount > 0)
  826.             eotCount++;
  827.          else if (pXY->G.enabled)
  828.             return StsWarn (xyFail);
  829.       } else if (err == xyBadPacket) {
  830.          eotCount = 0;
  831.          if (pXY->G.enabled)
  832.             return StsWarn (xyFail);
  833.       } else
  834.          return StsWarn (err);
  835.       if (eotCount >= 6)
  836.          return StsWarn (xyEOT);
  837.       StsRet (XYSendByte (pXY, NAK));
  838.    } while (retries-- > 0);
  839.    return StsWarn (xyFail);
  840. }
  841. STATIC int 
  842. XYSendPacketZero (XYMODEM_PRIVATE *pXY)
  843. {
  844.    const char *fileName = NULL;
  845.    long    fileSize = -1;
  846.    int     fileType = diskFileUnknown;
  847.    long    fileMode = -1;
  848.    struct tm fileDate;
  849.    BYTE    data[1024];
  850.    unsigned length = 128;
  851.    char   *p;
  852.  
  853.    if (pXY->f) {
  854.       DiskFileName (pXY->f, &fileName);
  855.       fileSize = pXY->fileSize;
  856.       DiskFileType (pXY->f, &fileType);
  857.       DiskFileMode (pXY->f, &fileMode);
  858.       DiskFileDate (pXY->f, &fileDate);
  859.    }
  860.    memset (data, 0, sizeof (data));
  861.    p = (char *) data;
  862.    if (fileName && fileName[0]) {
  863.       strcpy (p, fileName);
  864.       p += strlen (p) + 1;
  865.       if ((fileSize >= 0) && (fileType == diskFileBinary)) {
  866.          sprintf (p, "%ld", fileSize);
  867.          p += strlen (p);
  868.          sprintf (p, " %lo", XYTime (&fileDate));
  869.          p += strlen (p);
  870.          if (fileMode >= 0) {
  871.             sprintf (p, " %lo", fileMode);
  872.             p += strlen (p);
  873.          }
  874.       }
  875.    }
  876.    if (p >= ((char *) data) + 128)
  877.       length = 1024;
  878.    pXY->packetNumber = 0;
  879.    return StsWarn (XYSendPacket (pXY, data, length));
  880. }
  881. STATIC int XYSendReadHandshake
  882.         (XYMODEM_PRIVATE *pXY, int timeout, BYTE *pResponse) {
  883.    int     err;
  884.    int     canCount = 0;
  885.  
  886.    while (TRUE) {
  887.       err = XYSerialReadByte (pXY, timeout, pResponse);
  888.       if (err == xyBadPacket)
  889.          continue;
  890.       if (err != xyOK)
  891.          return StsWarn (err);
  892.       if (*pResponse == CAN) {
  893.          if (++canCount >= 2) {
  894.             DebugBegin (pXY->debug, debugWarn | debugPacket);
  895.             DebugString (pXY->debug,
  896.                     "Received CAN CAN while waiting for startup handshake");
  897.             DebugEnd (pXY->debug);
  898.             return StsWarn (xyFailed);
  899.          }
  900.       } else
  901.          canCount = 0;
  902.       switch (*pResponse) {
  903.       case 'G':
  904.          if ((pXY->crc.certain) && (!pXY->crc.enabled))
  905.             break;
  906.          if ((pXY->batch.certain) && (!pXY->batch.enabled))
  907.             break;
  908.          if ((pXY->G.certain) && (!pXY->G.enabled))
  909.             break;
  910.          pXY->crc.enabled = TRUE;
  911.          pXY->batch.enabled = TRUE;
  912.          pXY->G.enabled = TRUE;
  913.          return xyOK;
  914.       case 'C':
  915.          if (!pXY->G.certain)
  916.             pXY->G.enabled = FALSE;
  917.          if (pXY->G.enabled)
  918.             break;
  919.          if (pXY->crc.enabled)
  920.             return xyOK;
  921.          if (!pXY->crc.certain)
  922.             pXY->crc.enabled = TRUE;
  923.          if (!pXY->crc.enabled)
  924.             break;
  925.          if (!pXY->batch.certain)
  926.             pXY->batch.enabled = TRUE;
  927.          if (!pXY->longPacket.certain)
  928.             pXY->longPacket.enabled = pXY->batch.enabled;
  929.          return xyOK;
  930.       case NAK:
  931.          if (!pXY->G.certain)
  932.             pXY->G.enabled = FALSE;
  933.          if (pXY->G.enabled)
  934.             break;
  935.          if (!pXY->crc.enabled)
  936.             return xyOK;
  937.          if (!pXY->crc.certain)
  938.             pXY->crc.enabled = FALSE;
  939.          if (pXY->crc.enabled)
  940.             break;
  941.          if (!pXY->batch.certain)
  942.             pXY->batch.enabled = FALSE;
  943.          if (pXY->batch.enabled)
  944.             break;
  945.          if (!pXY->longPacket.certain)
  946.             pXY->longPacket.enabled = FALSE;
  947.          return xyOK;
  948.       case ACK:
  949.          return xyOK;
  950.       default:
  951.          break;
  952.       }
  953.    }
  954. }
  955. STATIC int XYSendFirstPacket
  956.         (XYMODEM_PRIVATE *pXY, BYTE *pBuffer, int bufferLength) {
  957.    int     totalRetries = pXY->retries;
  958.    int     retries = pXY->retries / 3 + 1;
  959.    BYTE    firstHandshake;
  960.    BYTE    acknowledge;
  961.    BYTE    handshake;
  962.    int     handshakeErr = xyOK;
  963.    unsigned long dataLength = 0;
  964.  
  965.    ((void) bufferLength);
  966.    do {
  967.       handshakeErr = XYSendReadHandshake (pXY, pXY->timeout * 5, &firstHandshake);
  968.       if (handshakeErr == xyTimeout)
  969.          return StsWarn (xyFail);
  970.       StsRet (handshakeErr);
  971.       DebugBegin (pXY->debug, debugPacket);
  972.       DebugString (pXY->debug, "Initial handshake ");
  973.       DebugChar (pXY->debug, firstHandshake);
  974.       DebugEnd (pXY->debug);
  975.    } while (firstHandshake == ACK);
  976.    do {
  977.       if (pXY->batch.enabled) {
  978.          StsRet (XYSendPacketZero (pXY));
  979.       } else {
  980.          if (dataLength == 0) {
  981.             dataLength = (pXY->longPacket.enabled) ? 1024 : 128;
  982.             StsRet (XYFileRead (pXY, pBuffer, &dataLength));
  983.          }
  984.          pXY->packetNumber = 1;
  985.          XYProgress (pXY, stsNewFile);
  986.          StsRet (XYSendPacket (pXY, pBuffer, dataLength));
  987.       }
  988.       StsRet (XYSendReadHandshake (pXY, pXY->timeout, &acknowledge));
  989.       if ((acknowledge == ACK) && (pXY->batch.enabled)) {
  990.          DebugBegin (pXY->debug, debugPacket);
  991.          DebugString (pXY->debug, "Received ACK for batch file header");
  992.          DebugEnd (pXY->debug);
  993.          do {
  994.             handshakeErr = XYSendReadHandshake (pXY, pXY->timeout, &handshake);
  995.             if (handshakeErr == xyOK) {
  996.                DebugBegin (pXY->debug, debugWarn);
  997.                DebugString (pXY->debug, "Second handshake ");
  998.                DebugChar (pXY->debug, handshake);
  999.                if (handshake != firstHandshake)
  1000.                   DebugString (pXY->debug, " doesn't match initial handshake");
  1001.                DebugEnd (pXY->debug);
  1002.             }
  1003.          } while ((handshakeErr == xyOK) && (handshake != firstHandshake));
  1004.          if ((handshakeErr != xyOK) && (handshakeErr != xyTimeout))
  1005.             return StsWarn (handshakeErr);
  1006.       } else if ((pXY->G.enabled) && (acknowledge == 'G')) {
  1007.          DebugBegin (pXY->debug, debugPacket);
  1008.          DebugString (pXY->debug, "Saw second 'G' handshake");
  1009.          DebugEnd (pXY->debug);
  1010.          acknowledge = ACK;
  1011.       } else {
  1012.          firstHandshake = acknowledge;
  1013.       }
  1014.       if ((acknowledge != ACK)
  1015.           || (pXY->batch.enabled && (handshakeErr != xyOK))
  1016.             ) {
  1017.          if (retries-- == 0) {
  1018.             if (!pXY->batch.certain)
  1019.                pXY->batch.enabled = !pXY->batch.enabled;
  1020.             if (!pXY->longPacket.certain)
  1021.                pXY->longPacket.enabled = pXY->batch.enabled;
  1022.             retries = 2;
  1023.          }
  1024.          if (totalRetries-- == 0)
  1025.             return StsWarn (xyFail);
  1026.       }
  1027.    } while ((acknowledge != ACK)
  1028.             || (pXY->batch.enabled && (handshakeErr != xyOK))
  1029.          );
  1030.    pXY->batch.certain = TRUE;
  1031.    pXY->G.certain = TRUE;
  1032.    if (pXY->packetNumber == 0)
  1033.       XYProgress (pXY, stsNewFile);
  1034.    if ((pXY->packetNumber == 0) && (dataLength > 0)) {
  1035.       pXY->packetNumber++;
  1036.       StsRet (XYSendPacketReliable (pXY, pBuffer, dataLength));
  1037.       pXY->transferred += dataLength;
  1038.    }
  1039.    return xyOK;
  1040. }
  1041. STATIC int 
  1042. XYSendFile (XYMODEM_PRIVATE *pXY)
  1043. {
  1044.    BYTE    data[1024];
  1045.    unsigned long dataLength;
  1046.    int     err = xyOK;
  1047.  
  1048.    XYProgress (pXY, stsNegotiating);
  1049.    StsRet (XYSendFirstPacket (pXY, data, sizeof (data) / sizeof (data[0])));
  1050.    while (err == xyOK) {
  1051.       unsigned packetLength;
  1052.       BYTE   *p = data;
  1053.  
  1054.       dataLength = (pXY->longPacket.enabled) ? 1024 : 128;
  1055.       err = XYFileRead (pXY, data, &dataLength);
  1056.       packetLength = (dataLength > 767) ? 1024 : 128;
  1057.       while ((err == xyOK) && (dataLength > 0)) {
  1058.          pXY->packetNumber++;
  1059.          XYProgress (pXY, stsSending);
  1060.          if (packetLength > dataLength)
  1061.             packetLength = dataLength;
  1062.          StsRet (XYSendPacketReliable (pXY, p, packetLength));
  1063.          pXY->transferred += packetLength;
  1064.          dataLength -= packetLength;
  1065.          p += packetLength;
  1066.       }
  1067.    }
  1068.    if (err == xyEOF) {
  1069.       err = XYSendEOTReliable (pXY);
  1070.       XYProgress (pXY, stsEOF);
  1071.    }
  1072.    return StsWarn (xyOK);
  1073. }
  1074. STATIC int 
  1075. XYReceiveFallback (XYMODEM_PRIVATE *pXY)
  1076. {
  1077.    if (pXY->G.enabled)
  1078.       pXY->G.enabled = FALSE;
  1079.    else if (pXY->crc.enabled)
  1080.       pXY->crc.enabled
  1081.             = pXY->batch.enabled
  1082.             = pXY->longPacket.enabled
  1083.             = FALSE;
  1084.    else
  1085.       pXY->G.enabled = pXY->batch.enabled
  1086.             = pXY->longPacket.enabled = pXY->crc.enabled = TRUE;
  1087.    return xyOK;
  1088. }
  1089. STATIC int 
  1090. XYReceiveSendHandshake (XYMODEM_PRIVATE *pXY)
  1091. {
  1092.    BYTE    handshake;
  1093.  
  1094.    if (pXY->G.enabled)
  1095.       handshake = 'G';
  1096.    else if (pXY->crc.enabled)
  1097.       handshake = 'C';
  1098.    else
  1099.       handshake = NAK;
  1100.    if (pXY->debug) {
  1101.       DebugBegin (pXY->debug, debugPacket);
  1102.       DebugString (pXY->debug, "Sending handshake ");
  1103.       DebugChar (pXY->debug, handshake);
  1104.       DebugEnd (pXY->debug);
  1105.    }
  1106.    return StsWarn (XYSendByte (pXY, handshake));
  1107. }
  1108. STATIC int 
  1109. XYReceiveFile (XYMODEM_PRIVATE *pXY)
  1110. {
  1111.    BYTE    data[1024];
  1112.    unsigned dataLength;
  1113.    int     err = xyOK;
  1114.    int     packetNumber;
  1115.    int     retries = pXY->retries / 2 + 1;
  1116.    int     totalRetries = (pXY->retries * 3) / 2 + 1;
  1117.  
  1118.    XYNewFile (pXY);
  1119.    XYProgress (pXY, stsNegotiating);
  1120.    do {
  1121.       if (--retries == 0) {
  1122.          XYReceiveFallback (pXY);
  1123.          XYProgress (pXY, stsNegotiating);
  1124.          retries = (pXY->retries / 3);
  1125.       }
  1126.       if (totalRetries-- == 0)
  1127.          return StsWarn (xyFail);
  1128.       StsRet (XYReceiveSendHandshake (pXY));
  1129.       XYProgress (pXY, stsNewFile);
  1130.       err = XYReceivePacket (pXY, &packetNumber, data, &dataLength);
  1131.       if (err == xyEOT) {
  1132.          StsRet (XYGobble (pXY, pXY->timeout / 2));
  1133.          err = xyTimeout;
  1134.       }
  1135.       if (err == xyBadPacket) {
  1136.          StsRet (XYGobble (pXY, pXY->timeout / 3));
  1137.       }
  1138.       if ((packetNumber != 0) && (packetNumber != 1)) {
  1139.          err = xyBadPacket;
  1140.       }
  1141.    } while ((err == xyTimeout) || (err == xyBadPacket));
  1142.    StsRet (err);
  1143.    if (packetNumber == 0) {
  1144.       pXY->batch.enabled = TRUE;
  1145.    } else {
  1146.       if (pXY->batch.certain && pXY->batch.enabled)
  1147.          return StsWarn (xyFail);
  1148.       pXY->batch.enabled = FALSE;
  1149.       pXY->G.enabled = FALSE;
  1150.    }
  1151.    pXY->batch.certain = TRUE;
  1152.    if (pXY->G.enabled || !pXY->batch.enabled)
  1153.       pXY->G.certain = TRUE;
  1154.    if (packetNumber == 0) {
  1155.       if (data[0] == 0) {
  1156.          if (!pXY->G.enabled)
  1157.             StsRet (XYSendByte (pXY, ACK));
  1158.          return xyEndOfSession;
  1159.       }
  1160.       StsRet (XYFileWriteOpen (pXY, data, dataLength));
  1161.       if (!pXY->G.enabled)
  1162.          StsRet (XYSendByte (pXY, ACK));
  1163.       StsRet (XYReceiveSendHandshake (pXY));
  1164.       err = XYReceivePacketReliable (pXY, &packetNumber, data, &dataLength);
  1165.    } else {
  1166.       StsRet (XYFileWriteOpen (pXY, NULL, 0));
  1167.    }
  1168.    pXY->packetNumber = 1;
  1169.    pXY->transferred = 0;
  1170.    XYProgress (pXY, stsReceiving);
  1171.    if ((err == xyOK) && (packetNumber == 1)) {
  1172.       if ((pXY->fileSize > 0)
  1173.           && (dataLength + pXY->transferred > pXY->fileSize))
  1174.          dataLength = pXY->fileSize - pXY->transferred;
  1175.       StsRet (XYFileWrite (pXY, data, dataLength));
  1176.       pXY->transferred += dataLength;
  1177.       pXY->packetNumber++;
  1178.       XYProgress (pXY, stsReceiving);
  1179.       if (pXY->batch.enabled && !pXY->G.enabled && !pXY->G.certain) {
  1180.          int     oldTimeout = pXY->timeout;
  1181.  
  1182.          pXY->timeout /= 3;
  1183.          err = XYReceivePacketReliable (pXY, &packetNumber, data, &dataLength);
  1184.          pXY->timeout = oldTimeout;
  1185.          if ((err == xyOK) && (packetNumber == 2)) {
  1186.             pXY->G.enabled = TRUE;
  1187.             if (pXY->debug) {
  1188.                DebugBegin (pXY->debug, debugInit);
  1189.                DebugString (pXY->debug, "Y-G sender detected");
  1190.                DebugEnd (pXY->debug);
  1191.             }
  1192.          } else if (err == xyTimeout) {
  1193.             StsRet (XYSendByte (pXY, ACK));
  1194.             err = XYReceivePacketReliable (pXY, &packetNumber, data, &dataLength);
  1195.          }
  1196.       } else
  1197.          err = XYReceivePacketReliable (pXY, &packetNumber, data, &dataLength);
  1198.    }
  1199.    while (err == xyOK) {
  1200.       if (packetNumber == (pXY->packetNumber & 0xFF)) {
  1201.          if ((pXY->fileSize > 0)
  1202.              && (dataLength + pXY->transferred > pXY->fileSize))
  1203.             dataLength = pXY->fileSize - pXY->transferred;
  1204.          StsRet (XYFileWrite (pXY, data, dataLength));
  1205.          pXY->transferred += dataLength;
  1206.          pXY->packetNumber++;
  1207.          XYProgress (pXY, stsReceiving);
  1208.          if (!pXY->G.enabled)
  1209.             StsRet (XYSendByte (pXY, ACK));
  1210.       } else if (packetNumber == (pXY->packetNumber - 1) & 0xFF)
  1211.          StsRet (XYSendByte (pXY, ACK));
  1212.       else
  1213.          return StsWarn (xyFail);
  1214.       err = XYReceivePacketReliable (pXY, &packetNumber, data, &dataLength);
  1215.    }
  1216.    if (err == xyEOT) {
  1217.       err = XYSendByte (pXY, ACK);
  1218.       DebugBegin (pXY->debug, debugPacket);
  1219.       DebugString (pXY->debug, "Acknowledging EOT");
  1220.       DebugEnd (pXY->debug);
  1221.       XYProgress (pXY, stsEOF);
  1222.    }
  1223.    StsRet (XYFileWriteClose (pXY));
  1224.    return StsWarn (err);
  1225. }
  1226. STATIC int 
  1227. XYSendSessionEnd (XYMODEM_PRIVATE *pXY)
  1228. {
  1229.    int     err;
  1230.    BYTE    response;
  1231.  
  1232.    XYNewFile (pXY);
  1233.    XYProgress (pXY, stsEnding);
  1234.    do {
  1235.       err = XYSendReadHandshake (pXY, pXY->timeout, &response);
  1236.       if (err == xyTimeout)
  1237.          return StsWarn (xyFail);
  1238.       StsRet (err);
  1239.       DebugBegin (pXY->debug, debugPacket);
  1240.       DebugString (pXY->debug, "Initial handshake ");
  1241.       DebugChar (pXY->debug, response);
  1242.       DebugEnd (pXY->debug);
  1243.    } while (response == ACK);
  1244.    do {
  1245.       StsRet (XYSendPacketZero (pXY));
  1246.       if (pXY->G.enabled)
  1247.          return xyOK;
  1248.       do {
  1249.          err = XYSendReadHandshake (pXY, pXY->timeout, &response);
  1250.          if (err == xyTimeout)
  1251.             return StsWarn (xyFail);
  1252.          StsRet (err);
  1253.       } while (err != xyOK);
  1254.       if (pXY->debug) {
  1255.          DebugBegin (pXY->debug, debugPacket);
  1256.          if (response == ACK)
  1257.             DebugString (pXY->debug, "Received ACK for final YModem header");
  1258.          else {
  1259.             DebugString (pXY->debug, "Received ");
  1260.             DebugChar (pXY->debug, response);
  1261.             DebugString (pXY->debug, " for final YModem header");
  1262.          }
  1263.          DebugEnd (pXY->debug);
  1264.       }
  1265.    } while (response != ACK);
  1266.    return xyOK;
  1267. }
  1268. STATIC int 
  1269. XYSend (XYMODEM_PRIVATE *pXY)
  1270. {
  1271.    int     err;
  1272.  
  1273.    XYNewFile (pXY);
  1274.    do {
  1275.       err = XYFileReadOpenNext (pXY);
  1276.       if (err == xyOK) {
  1277.          err = XYSendFile (pXY);
  1278.          XYFileReadClose (pXY);
  1279.          XYNewFile (pXY);
  1280.       }
  1281.    } while ((err == xyOK) && (pXY->batch.enabled));
  1282.    if (err == xyEndOfSession) {
  1283.       err = xyOK;
  1284.       if (pXY->batch.enabled)
  1285.          err = XYSendSessionEnd (pXY);
  1286.    }
  1287.    if (err == xyFail) {
  1288.       XYSendCAN (pXY);
  1289.       err = xyFailed;
  1290.    }
  1291.    if (err == xyOK)
  1292.       XYProgress (pXY, stsDone);
  1293.    else if (pXY->userCancel)
  1294.       XYProgress (pXY, stsCancelled);
  1295.    else
  1296.       XYProgress (pXY, stsFailed);
  1297.    return StsWarn (err);
  1298. }
  1299. STATIC int 
  1300. XYReceive (XYMODEM_PRIVATE *pXY)
  1301. {
  1302.    int     err;
  1303.  
  1304.    do {
  1305.       err = XYReceiveFile (pXY);
  1306.    } while ((err == xyOK) && (pXY->batch.enabled));
  1307.    if (err == xyEndOfSession)
  1308.       err = xyOK;
  1309.    if (err == xyFail) {
  1310.       XYSendCAN (pXY);
  1311.       err = xyFailed;
  1312.    }
  1313.    if (err == xyOK)
  1314.       XYProgress (pXY, stsDone);
  1315.    else if (pXY->userCancel)
  1316.       XYProgress (pXY, stsCancelled);
  1317.    else
  1318.       XYProgress (pXY, stsFailed);
  1319.    XYGobble (pXY, 2);
  1320.    return StsWarn (err);
  1321. }
  1322. int 
  1323. XYModemInit (XYMODEM *pXYPublic, SERIAL_PORT port)
  1324. {
  1325.    XYMODEM_PRIVATE *pXY;
  1326.  
  1327.    XYInitCrc16 ();
  1328.    pXY = malloc (sizeof (*pXY));
  1329.    if (pXY == NULL)
  1330.       return 1;
  1331.    memset (pXY, 0, sizeof (*pXY));
  1332.    pXY->timeout = 10;
  1333.    pXY->retries = 10;
  1334.    pXY->userCancel = 0;
  1335.    pXY->packetNumber = 0;
  1336.    pXY->transferred = 0;
  1337.    pXY->fileSize = 0;
  1338.    pXY->crc.enabled = TRUE;
  1339.    pXY->crc.certain = FALSE;
  1340.    pXY->longPacket.enabled = TRUE;
  1341.    pXY->longPacket.certain = FALSE;
  1342.    pXY->batch.enabled = TRUE;
  1343.    pXY->batch.certain = FALSE;
  1344.    pXY->G.enabled = FALSE;
  1345.    pXY->G.certain = FALSE;
  1346.    pXY->debug = NULL;
  1347.    pXY->port = NULL;
  1348.    pXY->f = NULL;
  1349.    pXY->filenames = NULL;
  1350.    pXY->currentFileName = 0;
  1351.    pXY->numFileNames = 0;
  1352.    pXY->fileType = diskFileUnknown;
  1353.    pXY->progress = NULL;
  1354.    pXY->port = port;
  1355.    *pXYPublic = pXY;
  1356.    return xyOK;
  1357. }
  1358. int 
  1359. XYModemDestroy (XYMODEM xyPublic)
  1360. {
  1361.    free (xyPublic);
  1362.    return xyOK;
  1363. }
  1364. int 
  1365. XYModemSetProtocol (XYMODEM xyPublic, int protocol)
  1366. {
  1367.    XYMODEM_PRIVATE *pXY = xyPublic;
  1368.  
  1369.    pXY->G.enabled = FALSE;
  1370.    pXY->crc.enabled = FALSE;
  1371.    pXY->batch.enabled = FALSE;
  1372.    pXY->longPacket.enabled = FALSE;
  1373.    switch (protocol) {
  1374.    case YMODEMG:
  1375.       pXY->G.enabled = TRUE;
  1376.    case YMODEM:
  1377.       pXY->batch.enabled = TRUE;
  1378.    case XMODEMK:
  1379.       pXY->longPacket.enabled = TRUE;
  1380.    case XMODEMCRC:
  1381.       pXY->crc.enabled = TRUE;
  1382.    case XMODEM:
  1383.       break;
  1384.    default:
  1385.       DebugBegin (pXY->debug, debugWarn);
  1386.       DebugString (pXY->debug, "XYModem initialized with illegal protocol");
  1387.       DebugEnd (pXY);
  1388.       return StsWarn (xyFailed);
  1389.    }
  1390.    return 0;
  1391. }
  1392. int 
  1393. XYModemSetDebug (XYMODEM xyPublic, DEBUG debug)
  1394. {
  1395.    XYMODEM_PRIVATE *pXY = (XYMODEM_PRIVATE *) xyPublic;
  1396.  
  1397.    pXY->debug = debug;
  1398.    return xyOK;
  1399. }
  1400. int 
  1401. XYModemSetProgress (XYMODEM xyPublic, PROGRESS progress)
  1402. {
  1403.    XYMODEM_PRIVATE *pXY = (XYMODEM_PRIVATE *) xyPublic;
  1404.  
  1405.    pXY->progress = progress;
  1406.    return xyOK;
  1407. }
  1408. int 
  1409. XYModemSetFileType (XYMODEM xyPublic, int fileType)
  1410. {
  1411.    XYMODEM_PRIVATE *pXY = (XYMODEM_PRIVATE *) xyPublic;
  1412.  
  1413.    pXY->fileType = fileType;
  1414.    return xyOK;
  1415. }
  1416. int 
  1417. XYModemCancel (XYMODEM xyPublic)
  1418. {
  1419.    XYMODEM_PRIVATE *pXY = (XYMODEM_PRIVATE *) xyPublic;
  1420.  
  1421.    pXY->userCancel = TRUE;
  1422.    return xyOK;
  1423. }
  1424. int     XYModemSend
  1425.         (XYMODEM xyPublic, const char *filenames[], int count) {
  1426.    XYMODEM_PRIVATE *pXY = (XYMODEM_PRIVATE *) xyPublic;
  1427.    int     returnVal = 0;
  1428.  
  1429.    pXY->currentFileName = 0;
  1430.    pXY->filenames = filenames;
  1431.    pXY->numFileNames = count;
  1432.    ProgressSending (pXY->progress);
  1433.    if (XYSend (pXY) != xyOK)
  1434.       returnVal = 1;
  1435.    return returnVal;
  1436. }
  1437. int 
  1438. XYModemReceive (XYMODEM xyPublic)
  1439. {
  1440.    XYMODEM_PRIVATE *pXY = (XYMODEM_PRIVATE *) xyPublic;
  1441.    int     returnVal = 0;
  1442.  
  1443.    ProgressReceiving (pXY->progress);
  1444.    if (XYReceive (pXY) != xyOK)
  1445.       returnVal = 1;
  1446.    return returnVal;
  1447. }
  1448.