home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 2 BBS / 02-BBS.zip / lora299s.zip / ZMODEM.CPP < prev   
C/C++ Source or Header  |  1998-05-12  |  34KB  |  1,287 lines

  1.  
  2. // LoraBBS Version 2.99 Free Edition
  3. // Copyright (C) 1987-98 Marco Maccaferri
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation; either version 2 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19. #include "_ldefs.h"
  20. #include "ftrans.h"
  21.  
  22. TZModem::TZModem (void)
  23. {
  24.    Com = NULL;
  25.    Log = NULL;
  26.    Progress = NULL;
  27.    EndRun = Hangup = FALSE;
  28.  
  29.    TxBuffer = RxBuffer;
  30.    FileSent = 0;
  31.    Wantfcs32 = TRUE;
  32.    Txfcs32 = FALSE;
  33.    ZCtlesc = FALSE;
  34.    Znulls = 0;
  35.    lastsent = -1;
  36.    Rxtimeout = 200;
  37.    Tframlen = 1024;
  38.    TryZHdrType = ZRINIT;
  39.    Maxblklen = 1024;
  40.    RxTempSize = 0;
  41.    Telnet = FALSE;
  42. }
  43.  
  44. TZModem::~TZModem (void)
  45. {
  46. }
  47.  
  48. USHORT TZModem::AbortSession (VOID)
  49. {
  50.    USHORT RetVal = FALSE;
  51.  
  52.    if (EndRun == TRUE || Hangup == TRUE)
  53.       RetVal = TRUE;
  54.    else if (Com != NULL && Com->Carrier () == FALSE)
  55.       RetVal = TRUE;
  56.  
  57.    return (RetVal);
  58. }
  59.  
  60. /*
  61. SHORT TZModem::TimedRead (LONG hSec)
  62. {
  63.    SHORT RetVal = -1;
  64.    ULONG tout;
  65.  
  66.    if (RxTempSize == 0) {
  67.       if (Com->BytesReady () == FALSE) {
  68.          tout = TimerSet (hSec);
  69.          do {
  70.             if (Com->BytesReady () == TRUE)
  71.                break;
  72.          } while (!TimeUp (tout) && AbortSession () == FALSE);
  73.       }
  74.       if (Com->BytesReady () == TRUE) {
  75.          RxTempSize = (SHORT)Com->ReadBytes ((UCHAR *)RxTemp, sizeof (RxTemp));
  76.          RxTempPos = RxTemp;
  77.       }
  78.    }
  79.  
  80.    if (RxTempSize > 0) {
  81.       RetVal = *RxTempPos++;
  82.       RxTempSize--;
  83.    }
  84.  
  85.    return (RetVal);
  86. }
  87. */
  88.  
  89. SHORT TZModem::TimedRead (LONG hSec)
  90. {
  91.    SHORT RetVal = -1;
  92.    ULONG tout;
  93.  
  94.    if (Com->BytesReady () == FALSE) {
  95.       tout = TimerSet (hSec);
  96.       do {
  97.          if (Com->BytesReady () == TRUE) {
  98.             RetVal = Com->ReadByte ();
  99.             break;
  100.          }
  101.       } while (!TimeUp (tout) && AbortSession () == FALSE);
  102.    }
  103.    else
  104.       RetVal = Com->ReadByte ();
  105.  
  106.    return (RetVal);
  107. }
  108.  
  109. VOID TZModem::ZAckBiBi (VOID)
  110. {
  111.    int n;
  112.  
  113.    ZPutLong (Txhdr, 0L);
  114.  
  115.    for (n = 4; --n >= 0 && AbortSession () == FALSE; ) {
  116.       ZSendHexHeader (ZFIN, Txhdr);
  117.       switch (TimedRead (100)) {
  118.          case 'O':
  119.             TimedRead (1);
  120.          /* ***** FALL THRU TO ***** */
  121.          case TIMEOUT:
  122.          case RCDO:
  123.             return;
  124.       }
  125.    }
  126. }
  127.  
  128. short TZModem::ZDLRead (void)
  129. {
  130.    short c;
  131.  
  132.    if ((c = TimedRead ((SHORT)Rxtimeout)) != ZDLE)
  133.       return (c);
  134.    if ((c = TimedRead ((SHORT)Rxtimeout)) < 0)
  135.       return (c);
  136.    if (c == CAN) {
  137.       if ((c = TimedRead ((SHORT)Rxtimeout)) < 0)
  138.          return (c);
  139.    }
  140.    if (c == CAN) {
  141.       if ((c = TimedRead ((SHORT)Rxtimeout)) < 0)
  142.          return (c);
  143.    }
  144.    if (c == CAN) {
  145.       if ((c = TimedRead ((SHORT)Rxtimeout)) < 0)
  146.          return (c);
  147.    }
  148.    switch (c) {
  149.       case CAN:
  150.          return (GOTCAN);
  151.       case ZCRCE:
  152.       case ZCRCG:
  153.       case ZCRCQ:
  154.       case ZCRCW:
  155.          return ((short)(c | GOTOR));
  156.       case ZRUB0:
  157.          return (0177);
  158.       case ZRUB1:
  159.          return (0377);
  160.       default:
  161.          if ((c & 0140) ==  0100)
  162.             return ((short)(c ^ 0100));
  163.          break;
  164.    }
  165.    return (ZERROR);
  166. }
  167.  
  168. LONG TZModem::ZGetLong (char *hdr)
  169. {
  170.    long l;
  171.  
  172.    l = (hdr[ZP3] & 0377);
  173.    l = (l << 8) | (hdr[ZP2] & 0377);
  174.    l = (l << 8) | (hdr[ZP1] & 0377);
  175.    l = (l << 8) | (hdr[ZP0] & 0377);
  176.  
  177.    return (l);
  178. }
  179.  
  180. SHORT TZModem::ZReceiveData (char *buf, short length)
  181. {
  182.    short d, c;
  183.    char *endpos;
  184.    unsigned short crc;
  185.    unsigned long ulCrc;
  186.  
  187.    Rxcount = 0;
  188.    endpos = buf + length;
  189.  
  190.    if (Rxframeind == ZBIN32) {
  191.       ulCrc = 0xFFFFFFFFL;
  192.       while (buf <= endpos) {
  193.          if ((c = ZDLRead()) & ~0377) {
  194. crcfoo2:
  195.             switch (c) {
  196.                case GOTCRCE:
  197.                case GOTCRCG:
  198.                case GOTCRCQ:
  199.                case GOTCRCW:
  200.                   d = c;
  201.                   ulCrc = Crc32 ((UCHAR)(c & 0377), ulCrc);
  202.                   if ((c = ZDLRead ()) & ~0377)
  203.                      goto crcfoo2;
  204.                   ulCrc = Crc32 ((UCHAR)c, ulCrc);
  205.                   if ((c = ZDLRead ()) & ~0377)
  206.                      goto crcfoo2;
  207.                   ulCrc = Crc32 ((UCHAR)c, ulCrc);
  208.                   if ((c = ZDLRead ()) & ~0377)
  209.                      goto crcfoo2;
  210.                   ulCrc = Crc32 ((UCHAR)c, ulCrc);
  211.                   if ((c = ZDLRead ()) & ~0377)
  212.                      goto crcfoo2;
  213.                   ulCrc = Crc32 ((UCHAR)c, ulCrc);
  214.                   if (ulCrc != 0xDEBB20E3L)
  215.                      return (ZERROR);
  216.                   return (d);
  217.                case GOTCAN:
  218.                   return (ZCAN);
  219.                case RCDO:
  220.                case TIMEOUT:
  221.                   return (c);
  222.                default:
  223.                   return (c);
  224.             }
  225.          }
  226.          ++Rxcount;
  227.          if (buf < endpos)
  228.             *buf++ = (char)c;
  229.          ulCrc = Crc32 ((UCHAR)c, ulCrc);
  230.       }
  231.    }
  232.    else {
  233.       crc = 0;
  234.       while (buf <= endpos) {
  235.          if ((c = ZDLRead()) & ~0377) {
  236. crcfoo1:
  237.             switch (c) {
  238.                case GOTCRCE:
  239.                case GOTCRCG:
  240.                case GOTCRCQ:
  241.                case GOTCRCW:
  242.                   d = c;
  243.                   crc = Crc16 ((UCHAR)(c & 0377), crc);
  244.                   if ((c = ZDLRead ()) & ~0377)
  245.                      goto crcfoo1;
  246.                   crc = Crc16 ((UCHAR)c, crc);
  247.                   if ((c = ZDLRead ()) & ~0377)
  248.                      goto crcfoo1;
  249.                   crc = Crc16 ((UCHAR)c, crc);
  250.                   if (crc & 0xFFFF)
  251.                      return (ZERROR);
  252.                   return (d);
  253.                case GOTCAN:
  254.                   return (ZCAN);
  255.                case RCDO:
  256.                case TIMEOUT:
  257.                   return (c);
  258.                default:
  259.                   return (c);
  260.             }
  261.          }
  262.          ++Rxcount;
  263.          if (buf < endpos)
  264.             *buf++ = (char)c;
  265.          crc = Crc16 ((UCHAR)c, crc);
  266.       }
  267.    }
  268.  
  269.    return (ZERROR);
  270. }
  271.  
  272. void TZModem::ZSendLine (unsigned char c)
  273. {
  274.    switch (c) {
  275.       case 0177:
  276.          if (Telnet == TRUE) {
  277.             Com->BufferByte (ZDLE);
  278.             Com->BufferByte ((UCHAR)(lastsent = ZRUB0));
  279.          }
  280.          else
  281.             Com->BufferByte ((UCHAR)(lastsent = c));
  282.          break;
  283.       case 0377:
  284.          if (Telnet == TRUE) {
  285.             Com->BufferByte (ZDLE);
  286.             Com->BufferByte ((UCHAR)(lastsent = ZRUB1));
  287.          }
  288.          else
  289.             Com->BufferByte ((UCHAR)(lastsent = c));
  290.          break;
  291.       case 015:
  292.       case 0215:
  293.          if (!ZCtlesc && (lastsent & 0177) != '@')
  294.             goto sendit;
  295.       /* **** FALL THRU TO **** */
  296.       case 020:
  297.       case 021:
  298.       case 023:
  299.       case 0220:
  300.       case 0221:
  301.       case 0223:
  302.       case ZDLE:
  303.          Com->BufferByte (ZDLE);
  304.          c ^= 0x40;
  305.       default:
  306. sendit:
  307.          Com->BufferByte ((UCHAR)(lastsent = c));
  308.          break;
  309.    }
  310. }
  311.  
  312. // Invia un header binario
  313. void TZModem::ZSendBinaryHeader (short type, char *hdr)
  314. {
  315.    short n;
  316.    unsigned short crc;
  317.    unsigned long  ulCrc;
  318.  
  319.    if (AbortSession () == FALSE) {
  320.       if (type == ZDATA) {
  321.          for (n = Znulls; --n >= 0; )
  322.             Com->BufferByte ((char)0);
  323.       }
  324.  
  325.       Com->BufferByte (ZPAD);
  326.       Com->BufferByte (ZDLE);
  327.  
  328.       if (Txfcs32 == TRUE) {
  329.          Com->BufferByte (ZBIN32);
  330.          ZSendLine ((unsigned char)type);
  331.          ulCrc = Crc32 ((unsigned char)type, 0xFFFFFFFFL);
  332.  
  333.          for (n = 4; --n >= 0; hdr++) {
  334.             ZSendLine ((unsigned char)*hdr);
  335.             ulCrc = Crc32 ((unsigned char)*hdr, ulCrc);
  336.          }
  337.          ulCrc = ~ulCrc;
  338.          for (n = 4; --n >= 0;) {
  339.             ZSendLine ((unsigned char)ulCrc);
  340.             ulCrc >>= 8;
  341.          }
  342.       }
  343.       else {
  344.          Com->BufferByte (ZBIN);
  345.          ZSendLine ((unsigned char)type);
  346.          crc = Crc16 ((unsigned char)type, 0);
  347.  
  348.          for (n = 4; --n >= 0; hdr++) {
  349.             ZSendLine ((unsigned char)*hdr);
  350.             crc = Crc16 ((unsigned char)*hdr, crc);
  351.          }
  352.          ZSendLine ((unsigned char)(crc >> 8));
  353.          ZSendLine ((unsigned char)crc);
  354.       }
  355.  
  356.       Com->UnbufferBytes ();
  357.    }
  358. }
  359.  
  360. void TZModem::ZSendData (char *buf, short length, short frameend)
  361. {
  362.    short n;
  363.    unsigned short crc;
  364.    unsigned long  ulCrc;
  365.  
  366.    if (AbortSession () == FALSE) {
  367.       if (Txfcs32 == TRUE) {
  368.          ulCrc = 0xFFFFFFFFL;
  369.          for ( ; --length >= 0; buf++) {
  370.             ZSendLine ((unsigned char)*buf);
  371.             ulCrc = Crc32 ((unsigned char)*buf, ulCrc);
  372.          }
  373.          Com->BufferByte (ZDLE);
  374.          Com->BufferByte ((unsigned char)frameend);
  375.          ulCrc = Crc32 ((unsigned char)frameend, ulCrc);
  376.          ulCrc = ~ulCrc;
  377.          for (n = 4; --n >= 0;) {
  378.             ZSendLine ((unsigned char)ulCrc);
  379.             ulCrc >>= 8;
  380.          }
  381.  
  382.          Com->UnbufferBytes ();
  383.       }
  384.       else {
  385.          crc = 0;
  386.          for ( ; --length >= 0; buf++) {
  387.             ZSendLine ((unsigned char)*buf);
  388.             crc = Crc16 ((unsigned char)*buf, crc);
  389.          }
  390.          Com->BufferByte (ZDLE);
  391.          Com->BufferByte ((unsigned char)frameend);
  392.          crc = Crc16 ((unsigned char)frameend, crc);
  393.  
  394.          ZSendLine ((unsigned char)(crc >> 8));
  395.          ZSendLine ((unsigned char)(crc & 0xFF));
  396.  
  397.          Com->UnbufferBytes ();
  398.  
  399. //         if (frameend == ZCRCW)
  400. //            Com->SendByte (XON);
  401.       }
  402.    }
  403. }
  404.  
  405. short TZModem::ZGetByte (void)
  406. {
  407.    short c;
  408.  
  409.    while (AbortSession () == FALSE) {
  410.       if ((c = TimedRead ((SHORT)Rxtimeout)) < 0)
  411.          return (TIMEOUT);
  412.       switch (c &= 0177) {
  413.          case XON:
  414.          case XOFF:
  415.             continue;
  416.          default:
  417.             return (c);
  418.       }
  419.    }
  420.  
  421.    return (RCDO);
  422. }
  423.  
  424. short TZModem::ZGetHex (void)
  425. {
  426.    short c, n;
  427.  
  428.    if ((c = ZGetByte ()) < 0)
  429.       return (c);
  430.    n = (short)(c - '0');
  431.    if (n > 9)
  432.       n -= ('a' - ':');
  433.    if (n & ~0xF)
  434.       return (ZERROR);
  435.    if ((c = ZGetByte ()) < 0)
  436.       return (c);
  437.    c -= '0';
  438.    if (c > 9)
  439.       c -= ('a' - ':');
  440.    if (c & ~0xF)
  441.       return (ZERROR);
  442.    c += (n << 4);
  443.    return (c);
  444. }
  445.  
  446. short TZModem::ZReceiveHexHeader (char *hdr)
  447. {
  448.    short n, c;
  449.    unsigned short crc;
  450.  
  451.    if ((c = ZGetHex ()) < 0)
  452.       return (c);
  453.    Rxtype = c;
  454.    crc = Crc16 ((char)c, 0);
  455.  
  456.    for (n = 4; --n >= 0;) {
  457.       if ((c = ZGetHex ()) < 0)
  458.          return (c);
  459.       crc = Crc16 ((char)c, crc);
  460.       *hdr++ = (char)c;
  461.    }
  462.    if ((c = ZGetHex ()) < 0)
  463.       return (c);
  464.    crc = Crc16 ((char)c, crc);
  465.    if ((c = ZGetHex ()) < 0)
  466.       return (c);
  467.    crc = Crc16 ((char)c, crc);
  468.    if (crc & 0xFFFF)
  469.       return (ZERROR);
  470.    if (TimedRead (20) == '\r')        /* Throw away possible cr/lf */
  471.       TimedRead (20);
  472.    return (Rxtype);
  473. }
  474.  
  475. short TZModem::ZReceiveBinaryHeader (char *hdr)
  476. {
  477.    short c, n;
  478.    unsigned short crc;
  479.  
  480.    if ((c = ZDLRead ()) & ~0377)
  481.       return (c);
  482.    Rxtype = c;
  483.    crc = Crc16 ((char)c, 0);
  484.  
  485.    for (n = 4; --n >= 0; ) {
  486.       if ((c = ZDLRead ()) & ~0377)
  487.          return (c);
  488.       crc = Crc16 ((char)c, crc);
  489.       *hdr++ = (char)c;
  490.    }
  491.    if ((c = ZDLRead ()) & ~0377)
  492.       return (c);
  493.    crc = Crc16 ((char)c, crc);
  494.    if ((c = ZDLRead ()) & ~0377)
  495.       return (c);
  496.    crc = Crc16 ((char)c, crc);
  497.    if (crc & 0xFFFF)
  498.       return (ZERROR);
  499.    return (Rxtype);
  500. }
  501.  
  502. short TZModem::ZReceiveBinaryHeader32 (char *hdr)
  503. {
  504.    short c, n;
  505.    unsigned long crc;
  506.  
  507.    if ((c = ZDLRead ()) & ~0377)
  508.       return (c);
  509.    Rxtype = c;
  510.    crc = Crc32 ((char)c, 0xFFFFFFFFL);
  511.  
  512.    for (n = 4; --n >= 0; ) {
  513.       if ((c = ZDLRead ()) & ~0377)
  514.          return (c);
  515.       crc = Crc32 ((UCHAR)c, crc);
  516.       *hdr++ = (char)c;
  517.    }
  518.    for (n = 4; --n >= 0;) {
  519.       if ((c = ZDLRead ()) & ~0377)
  520.          return (c);
  521.       crc = Crc32 ((UCHAR)c, crc);
  522.    }
  523.    if (crc != 0xDEBB20E3L)
  524.       return(ZERROR);
  525.  
  526.    return (Rxtype);
  527. }
  528.  
  529. short TZModem::ZGetHeader (char *hdr)
  530. {
  531.    short c, n, cancount;
  532.  
  533.    n = 2400;                     /* Max characters before start of frame */
  534.    cancount = 5;
  535.  
  536. again:
  537.    Rxframeind = Rxtype = 0;
  538.    switch (c = ZGetByte ()) {
  539.       case RCDO:
  540.       case TIMEOUT:
  541.          goto fifi;
  542.       case CAN:
  543.          if (--cancount <= 0) {
  544.             c = ZCAN;
  545.             goto fifi;
  546.          }
  547.       /* **** FALL THRU TO **** */
  548.       default:
  549. agn2:
  550.          if ( --n == 0)
  551.             return (ZERROR);
  552.          if (c != CAN)
  553.             cancount = 5;
  554.          goto again;
  555.       case ZPAD:              /* This is what we want. */
  556.          break;
  557.    }
  558.    cancount = 5;
  559. splat:
  560.    switch (c = ZGetByte ()) {
  561.       case ZPAD:
  562.          goto splat;
  563.       case RCDO:
  564.       case TIMEOUT:
  565.          goto fifi;
  566.       default:
  567.          goto agn2;
  568.       case ZDLE:              /* This is what we want. */
  569.          break;
  570.    }
  571.  
  572.    switch (c = ZGetByte ()) {
  573.       case RCDO:
  574.       case TIMEOUT:
  575.          goto fifi;
  576.       case ZBIN:
  577.          Rxframeind = ZBIN;
  578.          c = ZReceiveBinaryHeader (hdr);
  579.          break;
  580.       case ZBIN32:
  581.          Rxframeind = ZBIN32;
  582.          c = ZReceiveBinaryHeader32 (hdr);
  583.          break;
  584.       case ZHEX:
  585.          Rxframeind = ZHEX;
  586.          c = ZReceiveHexHeader (hdr);
  587.          break;
  588.       case CAN:
  589.          if (--cancount <= 0) {
  590.             c = ZCAN;
  591.             goto fifi;
  592.          }
  593.          goto agn2;
  594.       default:
  595.          goto agn2;
  596.    }
  597.  
  598.    Rxpos = hdr[ZP3] & 0377;
  599.    Rxpos = (Rxpos << 8) + (hdr[ZP2] & 0377);
  600.    Rxpos = (Rxpos << 8) + (hdr[ZP1] & 0377);
  601.    Rxpos = (Rxpos << 8) + (hdr[ZP0] & 0377);
  602.  
  603. fifi:
  604.    if (c == GOTCAN)
  605.       c = ZCAN;
  606.  
  607.    return (c);
  608. }
  609.  
  610. void TZModem::ZPutHex (short c)
  611. {
  612.    char digits[] = "0123456789abcdef";
  613.  
  614.    Com->BufferByte (digits[(c & 0xF0) >> 4]);
  615.    Com->BufferByte (digits[(c) & 0xF]);
  616. }
  617.  
  618. void TZModem::ZSendHexHeader (short type, char *hdr)
  619. {
  620.    short n;
  621.    unsigned short crc;
  622.  
  623.    if (AbortSession () == FALSE) {
  624.       Com->BufferByte (ZPAD);
  625.       Com->BufferByte (ZPAD);
  626.       Com->BufferByte (ZDLE);
  627.       Com->BufferByte (ZHEX);
  628.       ZPutHex (type);
  629.  
  630.       crc = Crc16 ((char)type, 0);
  631.       for (n = 4; --n >= 0; ) {
  632.          ZPutHex (*hdr);
  633.          crc = Crc16 ((char)((0377& *hdr++)), crc);
  634.       }
  635.       ZPutHex ((unsigned char)(crc >> 8));
  636.       ZPutHex (crc);
  637.  
  638.       Com->BufferByte (015);
  639.       Com->BufferByte (012);
  640.  
  641.       if (type != ZFIN)
  642.          Com->BufferByte (021);
  643.  
  644.       Com->UnbufferBytes ();
  645.    }
  646. }
  647.  
  648. void TZModem::ZPutLong (char *hdr, long pos)
  649. {
  650.    hdr[ZP0] = (char)pos;
  651.    hdr[ZP1] = (char)(pos >> 8);
  652.    hdr[ZP2] = (char)(pos >> 16);
  653.    hdr[ZP3] = (char)(pos >> 24);
  654. }
  655.  
  656. SHORT TZModem::ZInitReceiver (VOID)
  657. {
  658.    short n, errors;
  659.  
  660.    FileSent = 0;
  661.    Txfcs32 = TRUE;
  662.    errors = 0;
  663.    Com->ClearInbound ();
  664.    RxTempSize = 0;
  665.  
  666.    for (n = 10; --n >= 0 && AbortSession () == FALSE; ) {
  667.       ZPutLong (Txhdr, 0L);
  668.       Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
  669.       ZSendHexHeader (TryZHdrType, Txhdr);
  670.  
  671. again:
  672.       switch (ZGetHeader (Rxhdr)) {
  673.          case ZRQINIT:
  674.             break;
  675.  
  676.          case ZFILE:
  677.             TryZHdrType = ZRINIT;
  678.             if (ZReceiveData (RxBuffer, KSIZE) == GOTCRCW)
  679.                return (ZFILE);
  680.             ZSendHexHeader (ZNAK, Txhdr);
  681.             goto again;
  682.  
  683.          case ZSINIT:
  684.             if (ZReceiveData (Attn, ZATTNLEN) == GOTCRCW) {
  685.                ZPutLong (Txhdr, 1L);
  686.                ZSendHexHeader (ZACK, Txhdr);
  687.             }
  688.             else
  689.                ZSendHexHeader (ZNAK, Txhdr);
  690.             goto again;
  691.  
  692.          case ZFREECNT:
  693.             ZPutLong (Txhdr, 0xFFFFFFFFL);
  694.             ZSendHexHeader (ZACK, Txhdr);
  695.             goto again;
  696.  
  697.          case ZCOMMAND:
  698. //            cmdzack1flg = Rxhdr[ZF0];
  699.             if (ZReceiveData (RxBuffer, KSIZE) == GOTCRCW) {
  700.                ZPutLong (Txhdr, 0L);
  701.                do {
  702.                   ZSendHexHeader (ZCOMPL, Txhdr);
  703.                } while (++errors < 10 && ZGetHeader (Rxhdr) != ZFIN);
  704.                ZAckBiBi();
  705.                return (ZCOMPL);
  706.             }
  707.             else
  708.                ZSendHexHeader (ZNAK, Txhdr);
  709.             goto again;
  710.  
  711.          case ZCOMPL:
  712.             goto again;
  713.  
  714.          case ZFIN:
  715.             ZAckBiBi();
  716.             return (ZCOMPL);
  717.  
  718.          case RCDO:
  719.          case ZCAN:
  720.             return (ZERROR);
  721.  
  722.          default:
  723.             break;
  724.       }
  725.    }
  726.  
  727.    return (OK);
  728. }
  729.  
  730. short TZModem::ZInitSender (short nothing_to_do)
  731. {
  732.    short i;
  733.  
  734.    if (nothing_to_do == FALSE && FileSent == 0) {
  735.       Com->SendBytes ((unsigned char *)"rz\r", 3);
  736.       ZPutLong (Txhdr, 0L);
  737.       ZSendHexHeader (ZRQINIT, Txhdr);
  738.    }
  739.  
  740.    if (nothing_to_do == TRUE || (nothing_to_do == FALSE && FileSent == 0)) {
  741.       for (i = 0; i < 10 && AbortSession () == FALSE; i++) {
  742.          switch (ZGetHeader (Rxhdr)) {
  743.             case ZCHALLENGE:                 /* Echo receiver's challenge numbr */
  744.                ZPutLong (Txhdr, Rxpos);
  745.                ZSendHexHeader (ZACK, Txhdr);
  746.                break;
  747.  
  748.             case ZCOMMAND:                   /* They didn't see out ZRQINIT */
  749.                ZPutLong (Txhdr, 0L);
  750.                ZSendHexHeader (ZRQINIT, Txhdr);
  751.                break;
  752.  
  753.             case ZRINIT:
  754.                Rxflags = (short)(0377 & Rxhdr[ZF0]);
  755.                if (Wantfcs32 && (Rxflags & CANFC32))
  756.                   Txfcs32 = TRUE;
  757.                Rxbuflen = (short)((0377 & Rxhdr[ZP0]) + ((0377 & Rxhdr[ZP1]) << 8));
  758.                /* Use 1024 byte frames if no sample/interrupt */
  759.                if (Rxbuflen < 32 || Rxbuflen > 1024)
  760.                   Rxbuflen = 1024;
  761.                /* Override to force shorter frame length */
  762.                if (Rxbuflen && (Rxbuflen > Tframlen) && (Tframlen >= 32))
  763.                   Rxbuflen = Tframlen;
  764.                if (!Rxbuflen && (Tframlen >= 32) && (Tframlen <= 1024))
  765.                   Rxbuflen = Tframlen;
  766.                return (OK);
  767.  
  768.             case RCDO:
  769.             case ZCAN:
  770.             case TIMEOUT:
  771.                return (ZERROR);
  772.  
  773.             case ZRQINIT:
  774.                if (Rxhdr[ZF0] == ZCOMMAND)
  775.                   break;
  776.  
  777.             default:
  778.                ZSendHexHeader (ZNAK, Txhdr);
  779.                break;
  780.          }
  781.       }
  782.  
  783.       return (ZERROR);
  784.    }
  785.  
  786.    return (OK);
  787. }
  788.  
  789. SHORT TZModem::ZReceiveFile (PSZ pszPath)
  790. {
  791.    FILE *fout;
  792.    SHORT c, n, gota;
  793.    CHAR *p, *q, *fileinfo, *name;
  794.    long length, filesize, filetime;
  795.    struct utimbuf utimes;
  796.    struct stat f;
  797.  
  798.    for (p = RxBuffer, q = RxBuffer; *p; p++) {
  799.       if (*p == '/' || *p == '\\' || *p == ':')
  800.          q = p + 1;
  801.    }
  802.  
  803.    name = q;
  804.    sprintf (Pathname, "%s%s", pszPath, q);
  805.    strlwr (Pathname);
  806.  
  807.    filesize = filetime = 0L;
  808.    fileinfo = RxBuffer + strlen (RxBuffer) + 1;
  809.    if (*fileinfo)
  810.       sscanf (fileinfo, "%ld %lo", &filesize, &filetime);
  811.  
  812.    Log->Write (" Receiving %s; %ldb, %d min.", q, filesize, (int)((filesize * 10 / Speed + 53) / 54));
  813.  
  814.    Rxbytes = 0L;
  815.    if ((fout = _fsopen (Pathname, "rb", SH_DENYNO)) != NULL) {
  816.       // If the file already exists, it's date and size are verified in order to
  817.       // prevent other end to send us a file that we have already received.
  818.       fstat (fileno (fout), &f);
  819.       fclose (fout);
  820.       if (filesize == f.st_size && filetime == f.st_mtime) {
  821.          Log->Write ("+Already have %s", Pathname);
  822.          ZSendHexHeader (ZSKIP, Txhdr);
  823.          return (ZEOF);
  824.       }
  825.       else if (filesize > f.st_size) {
  826.          Rxbytes = f.st_size;
  827.          Log->Write ("+Synchronizing to offset %lu", Rxbytes);
  828.       }
  829.       else {
  830.          if ((p = strchr (Pathname, '\0')) != NULL) {
  831.             p--;
  832.             gota = FALSE;
  833.             do {
  834.                if (isdigit (*p) || gota == TRUE) {
  835.                   if (*p == '9') {
  836.                      gota = TRUE;
  837.                      *p = 'A';
  838.                   }
  839.                   else
  840.                      *p = (char)(*p + 1);
  841.                }
  842.                else
  843.                   *p = '0';
  844.                if ((fout = _fsopen (Pathname, "rb", SH_DENYNO)) != NULL)
  845.                   fclose (fout);
  846.             } while (fout != NULL);
  847.             Log->Write ("+Renaming dupe file %s", Pathname);
  848.          }
  849.       }
  850.    }
  851.  
  852.    if (Progress != NULL) {
  853.       Progress->Type = FILE_RECEIVING;
  854.       strcpy (Progress->RxFileName, name);
  855.       Progress->RxBlockSize = 0;
  856.       Progress->RxSize = filesize;
  857.       Progress->Begin ();
  858.       Progress->RxPosition = Rxbytes;
  859.       Progress->Update ();
  860.    }
  861.  
  862.    n = 10;
  863.    length = time (NULL);
  864.  
  865.    if ((fout = _fsopen (Pathname, "ab", SH_DENYNO)) == NULL) {
  866.       if (Progress != NULL)
  867.          Progress->End ();
  868.       return (ZERROR);
  869.    }
  870.  
  871.    while (AbortSession () == FALSE) {
  872.       ZPutLong (Txhdr, Rxbytes);
  873.       ZSendBinaryHeader (ZRPOS, Txhdr);
  874.  
  875. nxthdr:
  876.       switch (c = ZGetHeader (Rxhdr)) {
  877.          case ZNAK:
  878.          case TIMEOUT:
  879.             if ( --n < 0) {
  880.                if (fout != NULL) {
  881.                   fclose (fout);
  882.                   fout = NULL;
  883.                }
  884.                if (Progress != NULL)
  885.                   Progress->End ();
  886.                return (ZERROR);
  887.             }
  888.             break;
  889.  
  890.          case ZFILE:
  891.             ZReceiveData (RxBuffer, KSIZE);
  892.             continue;
  893.  
  894.          case ZEOF:
  895.             if (ZGetLong (Rxhdr) != Rxbytes)
  896.                continue;
  897.             if (Progress != NULL)
  898.                Progress->End ();
  899.             if (fout != NULL) {
  900.                fclose (fout);
  901.                fout = NULL;
  902.                if ((length = time (NULL) - length) == 0L)
  903.                   length++;
  904.                Log->Write ("+CPS: %lu (%lu bytes)  Efficiency: %d%%", Rxbytes / length, Rxbytes, ((Rxbytes / length) * 100L) / (Speed / 10));
  905.                Log->Write ("+Received-Z%s %s", (Txfcs32 == TRUE) ? "/32" : "", strupr (Pathname));
  906.                if (filetime) {
  907.                   utimes.actime = filetime;
  908.                   utimes.modtime = filetime;
  909.                   utime (Pathname, &utimes);
  910.                }
  911.             }
  912.             return (c);
  913.  
  914.          case ZERROR:     /* Too much garbage in header search error */
  915.             if (--n < 0) {
  916.                if (fout != NULL) {
  917.                   fclose (fout);
  918.                   fout = NULL;
  919.                   if (filetime) {
  920.                      utimes.actime = filetime;
  921.                      utimes.modtime = filetime;
  922.                      utime (Pathname, &utimes);
  923.                   }
  924.                }
  925.                if (Progress != NULL)
  926.                   Progress->End ();
  927.                return (ZERROR);
  928.             }
  929.             Com->SendBytes ((unsigned char *)Attn, (USHORT)strlen (Attn));
  930.             continue;
  931.  
  932.          case ZDATA:
  933.             if (ZGetLong (Rxhdr) != Rxbytes) {
  934.                if (--n < 0) {
  935.                   if (fout != NULL) {
  936.                      fclose (fout);
  937.                      fout = NULL;
  938.                      if (filetime) {
  939.                         utimes.actime = filetime;
  940.                         utimes.modtime = filetime;
  941.                         utime (Pathname, &utimes);
  942.                      }
  943.                   }
  944.                   if (Progress != NULL)
  945.                      Progress->End ();
  946.                   return (ZERROR);
  947.                }
  948.                Com->SendBytes ((unsigned char *)Attn, (USHORT)strlen (Attn));
  949.                continue;
  950.             }
  951.  
  952. moredata:
  953.             switch (c = ZReceiveData (RxBuffer, KSIZE)) {
  954.                case ZCAN:
  955.                   if (fout != NULL) {
  956.                      fclose (fout);
  957.                      fout = NULL;
  958.                      if (filetime) {
  959.                         utimes.actime = filetime;
  960.                         utimes.modtime = filetime;
  961.                         utime (Pathname, &utimes);
  962.                      }
  963.                   }
  964.                   if (Progress != NULL)
  965.                      Progress->End ();
  966.                   return (ZERROR);
  967.  
  968.                case ZERROR:     /* CRC error */
  969.                   if (--n < 0) {
  970.                      if (fout != NULL) {
  971.                         fclose (fout);
  972.                         fout = NULL;
  973.                         if (filetime) {
  974.                            utimes.actime = filetime;
  975.                            utimes.modtime = filetime;
  976.                            utime (Pathname, &utimes);
  977.                         }
  978.                      }
  979.                      if (Progress != NULL)
  980.                         Progress->End ();
  981.                      return (ZERROR);
  982.                   }
  983.                   Com->SendBytes ((unsigned char *)Attn, (USHORT)strlen (Attn));
  984.                   continue;
  985.  
  986.                case TIMEOUT:
  987.                   if (--n < 0) {
  988.                      if (fout != NULL) {
  989.                         fclose (fout);
  990.                         fout = NULL;
  991.                         if (filetime) {
  992.                            utimes.actime = filetime;
  993.                            utimes.modtime = filetime;
  994.                            utime (Pathname, &utimes);
  995.                         }
  996.                      }
  997.                      if (Progress != NULL)
  998.                         Progress->End ();
  999.                      return (ZERROR);
  1000.                   }
  1001.                   continue;
  1002.  
  1003.                case GOTCRCW:
  1004.                   n = 10;
  1005.                   fwrite (RxBuffer, Rxcount, 1, fout);
  1006.                   Rxbytes += Rxcount;
  1007.                   ZPutLong (Txhdr, Rxbytes);
  1008.                   ZSendBinaryHeader (ZACK, Txhdr);
  1009.                   if (Progress != NULL) {
  1010.                      Progress->RxPosition = Rxbytes;
  1011.                      Progress->RxBlockSize = Rxcount;
  1012.                      Progress->Update ();
  1013.                   }
  1014.                   goto nxthdr;
  1015.  
  1016.                case GOTCRCQ:
  1017.                   n = 10;
  1018.                   fwrite (RxBuffer, Rxcount, 1, fout);
  1019.                   Rxbytes += Rxcount;
  1020.                   ZPutLong (Txhdr, Rxbytes);
  1021.                   ZSendBinaryHeader (ZACK, Txhdr);
  1022.                   if (Progress != NULL) {
  1023.                      Progress->RxPosition = Rxbytes;
  1024.                      Progress->RxBlockSize = Rxcount;
  1025.                      Progress->Update ();
  1026.                   }
  1027.                   goto moredata;
  1028.  
  1029.                case GOTCRCG:
  1030.                   n = 10;
  1031.                   fwrite (RxBuffer, Rxcount, 1, fout);
  1032.                   Rxbytes += Rxcount;
  1033.                   if (Progress != NULL) {
  1034.                      Progress->RxPosition = Rxbytes;
  1035.                      Progress->RxBlockSize = Rxcount;
  1036.                      Progress->Update ();
  1037.                   }
  1038.                   goto moredata;
  1039.  
  1040.                case GOTCRCE:
  1041.                   n = 10;
  1042.                   fwrite (RxBuffer, Rxcount, 1, fout);
  1043.                   Rxbytes += Rxcount;
  1044.                   if (Progress != NULL) {
  1045.                      Progress->RxPosition = Rxbytes;
  1046.                      Progress->RxBlockSize = Rxcount;
  1047.                      Progress->Update ();
  1048.                   }
  1049.                   goto nxthdr;
  1050.             }
  1051.             break;
  1052.       }
  1053.    }
  1054.  
  1055.    if (Progress != NULL)
  1056.       Progress->End ();
  1057.  
  1058.    if (fout != NULL) {
  1059.       fclose (fout);
  1060.       fout = NULL;
  1061.       if (filetime) {
  1062.          utimes.actime = filetime;
  1063.          utimes.modtime = filetime;
  1064.          utime (Pathname, &utimes);
  1065.       }
  1066.    }
  1067.  
  1068.    return (ZERROR);
  1069. }
  1070.  
  1071. short TZModem::ZSendFile (char *file, char *name)
  1072. {
  1073.    int fd;
  1074.    short c, filedone, len, goodneeded, goodblks;
  1075.    char buf[64], *p, *q;
  1076.    unsigned long length;
  1077.    struct stat f;
  1078.  
  1079.    AdjustPath (file);
  1080.    if ((fd = sopen (file, O_RDONLY|O_BINARY, SH_DENYNO, S_IREAD|S_IWRITE)) == -1)
  1081.       return (ZERROR);
  1082.  
  1083.    if (name == NULL) {
  1084.       for (p = file, q = buf; *p; p++) {
  1085.          if ((*q++ = *p) == '/' || *p == '\\' || *p == ':')
  1086.             q = buf;
  1087.       }
  1088.    }
  1089.    else {
  1090.       strcpy (buf, name);
  1091.       q = strchr (buf, '\0');
  1092.    }
  1093.    *q++ = '\0';
  1094.  
  1095.    fstat (fd, &f);
  1096.    sprintf (q, "%lu %lo %o", f.st_size, f.st_mtime, f.st_mode);
  1097.    length = time (NULL);
  1098.  
  1099.    Txpos = Rxpos = 0L;
  1100.    Log->Write (" Sending %s; %ldb, %d min.", file, f.st_size, (int)((f.st_size * 10 / Speed + 53) / 54));
  1101.  
  1102.    if (Progress != NULL) {
  1103.       Progress->Type = FILE_SENDING;
  1104.       if (name != NULL)
  1105.          strcpy (Progress->TxFileName, name);
  1106.       else
  1107.          strcpy (Progress->TxFileName, file);
  1108.       Progress->TxBlockSize = 0;
  1109.       Progress->TxSize = f.st_size;
  1110.       Progress->Begin ();
  1111.       Progress->Update ();
  1112.    }
  1113.  
  1114.    while (TimedRead (50) != -1 && AbortSession () == FALSE)
  1115.       ;
  1116.  
  1117.    do {
  1118.       Txhdr[ZF0] = LZCONV;    /* file conversion request */
  1119.       Txhdr[ZF1] = LZMANAG;   /* file management request */
  1120.       Txhdr[ZF2] = LZTRANS;   /* file transport request */
  1121.       Txhdr[ZF3] = 0;
  1122.       ZSendBinaryHeader (ZFILE, Txhdr);
  1123.       ZSendData (buf, (short)(strlen (buf) + 1 + strlen (q)), ZCRCW);
  1124.  
  1125.       switch (c = ZGetHeader (Rxhdr)) {
  1126.          case ZRINIT:
  1127.             continue;
  1128.  
  1129.          case ZCAN:
  1130.          case TIMEOUT:
  1131.          case ZABORT:
  1132.          case ZFIN:
  1133.          case RCDO:
  1134.             close (fd);
  1135.             if (Progress != NULL)
  1136.                Progress->End ();
  1137.             Log->Write ("!Aborted by remote");
  1138.             return (ZERROR);
  1139.  
  1140.          case ZSKIP:
  1141.             close (fd);
  1142.             if (Progress != NULL)
  1143.                Progress->End ();
  1144.             Log->Write ("+Remote refused %s", buf);
  1145.             return (c);
  1146.  
  1147.          case ZRPOS:
  1148.             break;
  1149.  
  1150.          case ZERROR:
  1151.          default:
  1152.             continue;
  1153.       }
  1154.    } while (c != ZRPOS && AbortSession () == FALSE);
  1155.  
  1156.    lseek (fd, Rxpos, SEEK_SET);
  1157.    Txpos = Rxpos;
  1158.    filedone = FALSE;
  1159.    goodblks = 0;
  1160.    goodneeded = 4;
  1161. //   if (Rxbuflen == 0)
  1162.    Rxbuflen = 1024;
  1163.  
  1164.    if (Progress != NULL) {
  1165.       Progress->TxPosition = Txpos;
  1166.       Progress->TxBlockSize = 0;
  1167.       Progress->Update ();
  1168.    }
  1169.  
  1170.    if (Txpos < f.st_size) {
  1171.       ZPutLong (Txhdr, Txpos);
  1172.       ZSendBinaryHeader (ZDATA, Txhdr);
  1173.    }
  1174.  
  1175.    while (AbortSession () == FALSE) {
  1176.       if (filedone == FALSE) {
  1177.          if ((len = (short)read (fd, TxBuffer, Rxbuflen)) > 0) {
  1178.             if (len < Rxbuflen)
  1179.                ZSendData (TxBuffer, len, ZCRCE);
  1180.             else
  1181.                ZSendData (TxBuffer, len, ZCRCG);
  1182.             Txpos += len;
  1183.             if (Progress != NULL) {
  1184.                Progress->TxPosition += len;
  1185.                Progress->TxBlockSize = len;
  1186.                Progress->Update ();
  1187.             }
  1188.          }
  1189.          else {
  1190.             filedone = TRUE;
  1191.             ZPutLong (Txhdr, Txpos);
  1192.             ZSendBinaryHeader (ZEOF, Txhdr);
  1193.          }
  1194.       }
  1195.  
  1196.       if (Rxbuflen < Maxblklen && ++goodblks > goodneeded) {
  1197.          Rxbuflen = (SHORT)(((Rxbuflen << 1) < Maxblklen) ? Rxbuflen << 1 : Maxblklen);
  1198.          goodblks = 0;
  1199.       }
  1200.  
  1201.       while (Com->BytesReady () == TRUE && AbortSession () == FALSE) {
  1202.          c = Com->ReadByte ();
  1203.          if (c == CAN || c == ZPAD) {
  1204.             switch (c = ZGetHeader (Rxhdr)) {
  1205.                case ZACK:
  1206.                   continue;
  1207.  
  1208.                case ZRINIT:
  1209.                   close (fd);
  1210.                   if (Progress != NULL)
  1211.                      Progress->End ();
  1212.                   if ((length = time (NULL) - length) == 0L)
  1213.                      length++;
  1214.                   Log->Write ("+CPS: %lu (%lu bytes)  Efficiency: %d%%", f.st_size / length, f.st_size, ((f.st_size / length) * 100L) / (Speed / 10));
  1215.                   Log->Write ("+Sent-Z%s %s", (Txfcs32 == TRUE) ? "/32" : "", strupr (file));
  1216.                   return (OK);
  1217.  
  1218.                case ZRPOS:
  1219.                   Txpos = Rxpos;
  1220.                   lseek (fd, Txpos, SEEK_SET);
  1221.                   filedone = FALSE;
  1222.                   Com->ClearOutbound ();
  1223.                   if (Txpos < f.st_size) {
  1224.                      ZPutLong (Txhdr, Txpos);
  1225.                      ZSendBinaryHeader (ZDATA, Txhdr);
  1226.                   }
  1227.                   if (Rxpos > 0L) {
  1228.                      Rxbuflen = (SHORT)(((Rxbuflen >> 2) > 64) ? Rxbuflen >> 2 : 64);
  1229.                      goodblks = 0;
  1230.                      goodneeded = (SHORT)(((goodneeded << 1) > 16) ? 16 : goodneeded << 1);
  1231.                   }
  1232.                   if (Progress != NULL) {
  1233.                      Progress->TxPosition = Rxpos;
  1234.                      Progress->TxBlockSize = Rxbuflen;
  1235.                      Progress->Update ();
  1236.                   }
  1237.                   break;
  1238.  
  1239.                case ZSKIP:
  1240.                   close (fd);
  1241.                   if (Progress != NULL)
  1242.                      Progress->End ();
  1243.                   Log->Write ("+Remote refused %s", buf);
  1244.                   return (c);
  1245.             }
  1246.          }
  1247.       }
  1248.    }
  1249.  
  1250.    if (Progress != NULL)
  1251.       Progress->End ();
  1252.  
  1253.    close (fd);
  1254.    return (ZERROR);
  1255. }
  1256.  
  1257. void TZModem::ZEndSender (void)
  1258. {
  1259.    ULONG TimeOut;
  1260.  
  1261.    FileSent = 0;
  1262.  
  1263. //   ZPutLong (Txhdr, 0L);
  1264. //   ZSendBinaryHeader (ZFIN, Txhdr);
  1265.  
  1266.    TimeOut = TimerSet (200L);
  1267.    while (AbortSession () == FALSE && !TimeUp (TimeOut)) {
  1268.       ZPutLong (Txhdr, 0L);
  1269.       ZSendBinaryHeader (ZFIN, Txhdr);
  1270.  
  1271.       switch (ZGetHeader (Rxhdr)) {
  1272.          case ZFIN:
  1273.             Com->SendByte ('O');
  1274.             Com->SendByte ('O');
  1275.  
  1276.          case ZCAN:
  1277.          case TIMEOUT:
  1278.          case RCDO:
  1279.             return;
  1280.       }
  1281.    }
  1282.  
  1283. //   Pause (2);
  1284.    Com->ClearInbound ();
  1285. }
  1286.  
  1287.