home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / PROTOCOL / TPHYD100.ZIP / HYDRA.PAS < prev    next >
Pascal/Delphi Source File  |  1993-09-03  |  81KB  |  2,256 lines

  1. {$A+,B-,D+,E-,F+,I-,L+,N-,O+,R-,S+,V-}
  2. {$UnDef H_DEBUG}
  3. (******************************************************************************)
  4. (*                      Hydra Bi-directional Protocol                         *)
  5. (*                        ─────────────────────────                           *)
  6. (*                                                                            *)
  7. (*                                                                            *)
  8. (* BY: Adam Blake                                      Wandoo Valley Software *)
  9. (*     Arjen Lentz                                         and Lentz Software *)
  10. (* VER: 1.00                                                      Development *)
  11. (* DATE: 5th August 1993                                   (c) Copyright 1993 *)
  12. (* LANGUAGE: Turbo Pascal v6.0                  All Rights Reserved Worldwide *)
  13. (******************************************************************************)
  14. Unit Hydra;
  15. Interface
  16.  
  17. uses
  18.   Dos, TpCrt, TpString,
  19.   h_Comms, h_Date, h_File, h_String, h_Timers, h_Win;
  20.  
  21. {$I Hydra.inc}
  22.  
  23. type
  24.   ByteArrayP = ^ByteArray;
  25.   ByteArray  = array[0..0] of byte;
  26.  
  27.   FuncType   = Procedure( var Data; Len : word );
  28.   DevString  = string[H_FLAGLEN];
  29.  
  30. const
  31.   Hydra_TxWindow : longint = 0;
  32.   Hydra_RxWindow : longint = 0;
  33.  
  34.   Originator     : boolean = true;                        (*Are we the orig side?*)
  35.   HdxSession     : boolean = false;
  36.  
  37.   Hydra_Speed    : longint = 2400;
  38.  
  39. var
  40.   LastTimer,
  41.   ChatTimer      : h_Timer;
  42.   ChatFill       : word;
  43.  
  44.  
  45.  
  46. Function  Hydra_Init( Want_Options : longint ) : boolean;
  47.  
  48. Procedure Hydra_DeInit( CloseWindow : boolean );
  49.  
  50. Function  Hydra_Send( TxPathName, TxAlias : string ) : integer;
  51.  
  52. Function  Hydra_DevFree : boolean;
  53.  
  54. Function  Hydra_DevSend( Dev : DevString; Buffer : ByteArrayP; Len : word ) : boolean;
  55.  
  56. Function  Hydra_DevFunc( Dev : DevString; Func : FuncType ) : boolean;
  57.  
  58. (******************************************************************************)
  59. Implementation
  60.  
  61. uses
  62.   Crc;
  63.  
  64. var
  65.   BatchesDone  : integer;                       (* No. HYDRA batches done    *)
  66.   HdxLink      : boolean;                       (* Hdx link & not orig side  *)
  67.   Options      : longint;                       (* INIT options hydra_init() *)
  68.   TimeOut      : word;                          (* General TimeOut in secs   *)
  69.  
  70. const
  71.   PROGNAME     : string[20] = 'TP-Hydra';
  72.   VERSION      : string[5]  = '1.00';
  73.   H_OS         : string[10] = 'PC';
  74.  
  75.   PktPrefix    : string[H_PKTPREFIX] = '';
  76.   HdxMsg       : string[60]          = 'Fallback to one-way xfer';
  77.  
  78.   AutoStr      : array[1..6] of char = ('h', 'y', 'd', 'r', 'a', #13);
  79.   AbortStr     : array[1..18] of byte = (24, 24, 24, 24, 24, 24, 24, 24,
  80.                                          8, 8, 8, 8, 8, 8, 8, 8, 8, 8);
  81.  
  82.  
  83. var
  84.   Crc16Tab     : Crc16Table;                    (* CRC-16 table, CCITT       *)
  85.   Crc32Tab     : Crc32Table;                    (* CRC-32 table              *)
  86.  
  87.   TxBuf,
  88.   RxBuf        : ByteArrayP;                    (* packet buffers            *)
  89.   TxOptions,
  90.   RxOptions    : longint;                       (* HYDRA options (INIT seq)  *)
  91.   TxPktPrefix  : string[H_PKTPREFIX];           (* pkt prefix str they want  *)
  92.   TxWindow,
  93.   RxWindow     : longint;                       (* window size (0=streaming) *)
  94.   BrainDead    : h_timer;                       (* BrainDead timer           *)
  95.   TxBufIn      : ByteArrayP;                    (* read data from disk here  *)
  96.   TxLastC,                                      (* last byte put in txbuf    *)
  97.   RxDLE,                                        (* count of received H_DLEs  *)
  98.   RxPktFormat  : byte;                          (* format of pkt receiving   *)
  99.   RxBufPtr,                                     (* current position in RxBuf *)
  100.   RxBufMax     : integer;                       (* highwatermark of RxBuf    *)
  101.   TxFName,
  102.   RxFName      : string[12];                    (* fname of current files    *)
  103.   RxPathName   : string;                        (* pointer to rx pathname    *)
  104.   TxFTime,
  105.   RxFTime,                                      (* file timestamp (UNIX)     *)
  106.   TxFSize,
  107.   RxFSize      : longint;                       (* file length               *)
  108.   TxFd,
  109.   RxFd         : file;                          (* file handles              *)
  110.   RxPktLen,                                     (* length of last packet     *)
  111.   RxBlkLen     : word;                          (* len of last good data blk *)
  112.   TxState,
  113.   RxState      : byte;                          (* xmit/recv states          *)
  114.   TxPos,
  115.   RxPos        : longint;                       (* current position in files *)
  116.   TxBlkLen,                                     (* length of last block sent *)
  117.   TxMaxBlkLen  : word;                          (* max block length allowed  *)
  118.   TxLastAck,                                    (* last dataack received     *)
  119.   TxStart,
  120.   RxStart,                                      (* time we started this file *)
  121.   TxOffset,
  122.   RxOffset     : longint;                       (* offset in file we begun   *)
  123.   TxTimer,
  124.   RxTimer      : h_timer;                       (* retry timers              *)
  125.   TxRetries,
  126.   RxRetries    : word;                          (* retry counters            *)
  127.   RxLastSync,                                   (* filepos last sync retry   *)
  128.   TxSyncID,
  129.   RxSyncID     : longint;                       (* id of last resync         *)
  130.   TxGoodNeeded,                                 (* to send before larger blk *)
  131.   TxGoodBytes  : word;                          (* no. sent at this blk size *)
  132.  
  133. type
  134.   _h_Flags = record
  135.                St  : DevString;
  136.                Val : longint;
  137.              end;
  138.  
  139. const
  140.   H_FLAGNUM = 10;
  141.   h_Flags : array[0..h_FlagNum] of _h_Flags = (( St : 'XON'; Val : HOPT_XONXOFF ),
  142.                                                ( St : 'TLN'; Val : HOPT_TELENET ),
  143.                                                ( St : 'CTL'; Val : HOPT_CTLCHRS ),
  144.                                                ( St : 'HIC'; Val : HOPT_HIGHCTL ),
  145.                                                ( St : 'HI8'; Val : HOPT_HIGHBIT ),
  146.                                                ( St : 'BRK'; Val : HOPT_CANBRK  ),
  147.                                                ( St : 'ASC'; Val : HOPT_CANASC  ),
  148.                                                ( St : 'UUE'; Val : HOPT_CANUUE  ),
  149.                                                ( St : 'C32'; Val : HOPT_CRC32   ),
  150.                                                ( St : 'DEV'; Val : HOPT_DEVICE  ),
  151.                                                ( St : 'FPT'; Val : HOPT_FPT     ));
  152.  
  153. (*---------------------------------------------------------------------------*)
  154. Procedure Hydra_MsgDev( var Data; Len : word ); (*hWin_Message Window*)
  155. var
  156.   St : string;
  157. begin
  158.   If Len > 255 then Len := 255;
  159.   Move(Data, St[1], Len);
  160.   St[0] := Chr(Len);
  161.   hWin_Message('REMOTE HYDRA: ' + St);
  162. end; (*Hydra_MsgDev*)
  163.  
  164.  
  165. Procedure Hydra_ConDev( var Data; Len : word ); (*Remote Chat Window*)
  166. begin
  167.   hWin_RemChat(Data, Len);
  168.     (*Strings can be up to 2kb in length, handled by hWin_RemChat*)
  169. end; (*Hydra_ConDev*)
  170.  
  171.  
  172. Procedure Hydra_NilDev( var Data; Len : word );
  173. begin
  174. end; (*Hydra_NilDev*)
  175.  
  176. (*---------------------------------------------------------------------------*)
  177. var
  178.   DevTxState   : word;                          (* dev xmit state            *)
  179.   DevTxTimer   : h_timer;                       (* dev xmit retry timer      *)
  180.   DevTxRetries : word;                          (* dev xmit retry counter    *)
  181.   DevTxID,
  182.   DevRxID      : longint;                       (* id of last devdata pkt    *)
  183.   DevTxDev     : DevString;                     (* xmit device ident flag    *)
  184.   DevTxBuf     : ByteArrayP;                    (* ptr to usersupplied dbuf  *)
  185.   DevTxLen     : word;                          (* len of data in xmit buf   *)
  186.  
  187. type
  188.   _h_Dev = record
  189.              Dev  : DevString;
  190.              Func : FuncType;
  191.            end;
  192.  
  193. const
  194.   H_DEVNUM = 3;
  195.   h_Dev : array[0..h_DevNum] of _h_Dev = (( Dev : 'MSG'; Func : Hydra_MsgDev ),
  196.                                           ( Dev : 'CON'; Func : Hydra_ConDev ),
  197.                                           ( Dev : 'PRN'; Func : Hydra_NilDev ),
  198.                                           ( Dev : 'ERR'; Func : Hydra_NilDev ));
  199.  
  200.                                           (* 0: Internal protocol msg   *)
  201.                                           (* 1: Text to console (chat)  *)
  202.                                           (* 2: Data to printer         *)
  203.                                           (* 3: Text to error output    *)
  204.  
  205.  
  206. {$I h_Crc.inc}
  207. {$I h_Long.inc}
  208. {$I h_Encode.inc}
  209.  
  210. (*---------------------------------------------------------------------------*)
  211. Function Hydra_DevFree : boolean;
  212. begin
  213.   If (DevTxState or not(TxOptions and HOPT_DEVICE) or TxState >= HTX_END) then
  214.      Hydra_DevFree := false                      (* busy or not allowed *)
  215.   else
  216.     Hydra_DevFree := true;                       (* allowed to send a new pkt *)
  217. end; (*Hydra_DevFree*)
  218.  
  219.  
  220. (*---------------------------------------------------------------------------*)
  221. Function Hydra_DevSend( Dev : DevString; Buffer : ByteArrayP; Len : word ) : boolean;
  222. begin
  223.   Hydra_DevSend := false;
  224.  
  225.   If (Len < 1) or (not Hydra_DevFree) then
  226.     Exit;
  227.  
  228.   DevTxDev := StUpCase(Dev);
  229.   DevTxBuf := Buffer;
  230.   If Len > H_MAXBLKLEN then DevTxLen := H_MAXBLKLEN
  231.     else DevTxLen := Len;
  232.  
  233.   Inc(DevTxID);
  234.   DevTxTimer   := h_Timer_Reset;
  235.   DevTxRetries := 0;
  236.   DevTxState   := HTD_DATA;
  237.  
  238.   (* Special for chat, only prolong life If our side keeps typing! *)
  239.   If (ChatTimer > 0) and (DevTxDev = 'CON') and (TxState = HTX_REND) then
  240.     BrainDead := h_Timer_Set(H_BRAINDEAD);
  241.  
  242.   Hydra_DevSend := true;
  243. end; (*Hydra_DevSend*)
  244.  
  245.  
  246. (*---------------------------------------------------------------------------*)
  247. Function Hydra_DevFunc( Dev : DevString; Func : FuncType ) : boolean;
  248. var
  249.   Count : integer;
  250. begin
  251.   Hydra_DevFunc := false;
  252.  
  253.   For Count := 0 to h_DevNum do
  254.     begin
  255.       If Dev = h_Dev[Count].Dev then
  256.         begin
  257.           h_Dev[Count].Func := Func;
  258.           Hydra_DevFunc := true;
  259.         end;
  260.     end;
  261. end; (*Hydra_DevFunc*)
  262.  
  263.  
  264. (*---------------------------------------------------------------------------*)
  265. Procedure Hydra_DevRecv;
  266. var
  267.   Len   : word;
  268.   Count : integer;
  269.   DevStr : DevString;
  270.   Buffer : ByteArrayP;
  271. begin
  272.   Len := RxPktLen;
  273.   Buffer := RxBuf;
  274.   Inc(Buffer,SizeOf(longint));                       (* Skip the ID longint  *)
  275.   Dec(Len,SizeOf(longint));
  276.  
  277.   Move(Buffer^[0], DevStr[1], H_FLAGLEN);
  278.   DevStr[0] := Chr(H_FLAGLEN);
  279.  
  280.   Dec(Len, NulSearch(Buffer^) + 1);            (* sub devstr len    *)
  281.   Inc(Buffer, NulSearch(Buffer^) + 1);         (* skip devtag       *)
  282.  
  283.   Count := 0;
  284.   Repeat                                                (* walk through devs *)
  285.     If h_Dev[Count].Dev = DevStr then
  286.       h_Dev[Count].Func(Buffer^, Len);                  (* call output func  *)
  287.     Inc(Count);
  288.   Until (Count > h_DevNum) or (h_Dev[Count - 1].Dev = DevStr);
  289. end; (*Hydra_DevRecv*)
  290.  
  291.  
  292. (*---------------------------------------------------------------------------*)
  293. Function Put_Flags( Buffer : ByteArrayP; Value : longint ) : integer;
  294. var
  295.   Count,
  296.   Counter : integer;
  297. begin
  298.   Count := 0;
  299.  
  300.   For Counter := 0 to H_FLAGNUM do
  301.     begin
  302.       If (Value and h_Flags[Counter].Val) <> 0 then
  303.         begin
  304.           If Count > 0 then
  305.             begin
  306.               Buffer^[Count] := byte(',');
  307.               Inc(Count);
  308.             end;
  309.           Move(h_Flags[Counter].St[1], Buffer^[Count], H_FLAGLEN);
  310.           Inc(Count,H_FLAGLEN);
  311.         end;
  312.     end;
  313.  
  314.   Buffer^[Count] := 0; (*Nul*)
  315.   Inc(Count);
  316.   Put_Flags := Count;
  317. end; (*Put_Flags*)
  318.  
  319.  
  320. (*---------------------------------------------------------------------------*)
  321. Function Get_Flags( Buffer : ByteArrayP ) : longint;
  322. var
  323.   Len,
  324.   Count : integer;
  325.   Value : longint;
  326.   St   : array[1..3] of char;
  327. begin
  328.   Value := 0;
  329.  
  330.   Len := NulSearch(Buffer^);
  331.   For Count := 0 to H_FLAGNUM do
  332.     begin
  333.       (***DEBUG***)
  334.       Move(h_Flags[Count].St[1], St, H_FLAGLEN);
  335.       If Search(Buffer^, Len, St, H_FLAGLEN) <> $FFFF then
  336.         Value := Value or h_Flags[Count].Val;
  337.     end;
  338.  
  339.   Get_Flags := Value;
  340. end; (*Get_Flags*)
  341.  
  342.  
  343. (*---------------------------------------------------------------------------*)
  344. Procedure Put_BinByte( var Index : word; Ch : byte );
  345. var
  346.   N : byte;
  347. begin
  348.   N := Ch;
  349.   If (TxOptions and HOPT_HIGHCTL) <> 0 then
  350.      N := N and $7f;
  351.  
  352.   If ((N = H_DLE) or
  353.      ((TxOptions and HOPT_XONXOFF <> 0) and ((N = XON) or (N = XOFF)) ) or
  354.      ((TxOptions and HOPT_TELENET <> 0) and (N = 13) and (TxLastC = byte('@'))) or
  355.      ((TxOptions and HOPT_CTLCHRS <> 0) and ((N < 32) or (n = 127)))) then
  356.     begin
  357.       TxBuf^[Index] := H_DLE;
  358.       Inc(Index);
  359.       Ch := Ch xor $40;
  360.     end;
  361.  
  362.   TxBuf^[Index] := Ch;
  363.   Inc(Index);
  364.   TxLastC := N;
  365. end; (*Put_BinByte*)
  366.  
  367.  
  368. (*---------------------------------------------------------------------------*)
  369. Procedure TxPkt( Len : word; PktType : char );
  370. var
  371.   Format   : byte;
  372.   C,
  373.   N,
  374.   CrcW,
  375.   IndexIn,
  376.   IndexOut : word;
  377.   CrcL     : longint;
  378.   Crc32    : boolean;
  379. begin
  380.   Crc32 := false;
  381.  
  382.   TxBufIn^[Len] := byte(PktType);
  383.   Inc(Len);
  384.  
  385.   Case PktType of
  386.     HPKT_START,
  387.     HPKT_INIT,
  388.     HPKT_INITACK,
  389.     HPKT_END,
  390.     HPKT_IDLE : Format := byte(HCHR_HEXPKT);
  391.   else
  392.     begin
  393.       (* COULD do smart format selection depending on data and options! *)
  394.       If (TxOptions and HOPT_HIGHBIT) <> 0 then
  395.         begin
  396.          If ((TxOptions and HOPT_CTLCHRS <> 0) and (TxOptions and HOPT_CANUUE <> 0)) then
  397.            Format := byte(HCHR_UUEPKT)
  398.          else If (TxOptions and HOPT_CANASC) <> 0 then
  399.            Format := byte(HCHR_ASCPKT)
  400.          else
  401.            Format := byte(HCHR_HEXPKT);
  402.         end
  403.       else
  404.         Format := byte(HCHR_BINPKT);
  405.     end;
  406.   end;
  407.  
  408.   If ((Format <> byte(HCHR_HEXPKT)) and (TxOptions and HOPT_CRC32 <> 0)) then
  409.     Crc32 := true;
  410.  
  411.  
  412. {$IfDef H_DEBUG}
  413. If (loglevel=0) {
  414.    char *s1, *s2, *s3, *s4;
  415.  
  416.    hWin_Message(0,' -> PKT (format='%c'  type='%c'  crc=%d  len=%d)',
  417.              format, type, crc32 ? 32 : 16, len - 1);
  418.  
  419.    switch (type) {
  420.           case HPKT_START:    hWin_Message(0,'    <autostr>START');
  421.                               break;
  422.           case HPKT_INIT:     s1 := ((char *) TxBufIn) + ((integer) strlen((char *) TxBufIn)) + 1;
  423.                               s2 := s1 + ((integer) strlen(s1)) + 1;
  424.                               s3 := s2 + ((integer) strlen(s2)) + 1;
  425.                               s4 := s3 + ((integer) strlen(s3)) + 1;
  426.                               hWin_Message(0,'    INIT (appinfo='%s'  can='%s'  want='%s'  options='%s'  pktprefix='%s')',
  427.                                       (char *) TxBufIn, s1, s2, s3, s4);
  428.                               break;
  429.           case HPKT_INITACK:  hWin_Message(0,'    INITACK');
  430.                               break;
  431.           case HPKT_FINFO:    hWin_Message(0,'    FINFO (%s)',TxBufIn);
  432.                               break;
  433.           case HPKT_FINFOACK: If (RxFd >= 0) {
  434.                                  If (RxPos > 0) s1 := 'Result';
  435.                                  else            s1 := 'BOF';
  436.                               }
  437.                               else If (RxPos = -1) s1 := 'HAVE';
  438.                               else If (RxPos = -2) s1 := 'SKIP';
  439.                               else                   s1 := 'EOB';
  440.                               hWin_Message(0,'    FINFOACK (pos=%ld %s  RxState=%d  RxFd=%d)',
  441.                                       RxPos,s1,RxState,RxFd);
  442.                               break;
  443.           case HPKT_DATA:     hWin_Message(0,'    DATA (ofs=%ld  len=%d)',
  444.                                       h_long1(TxBufIn), len - 5);
  445.                               break;
  446.           case HPKT_DATAACK:  hWin_Message(0,'    DATAACK (ofs=%ld)',
  447.                                       h_long1(TxBufIn));
  448.                               break;
  449.           case HPKT_RPOS:     hWin_Message(0,'    RPOS (pos=%ld%s  blklen=%ld  syncid=%ld)',
  450.                                       RxPos, RxPos < 0 ? ' SKIP' : '',
  451.                                       h_long2(TxBufIn), RxSyncID);
  452.                               break;
  453.           case HPKT_EOF:      hWin_Message(0,'    EOF (ofs=%ld%s)',
  454.                                       TxPos, TxPos < 0 ? ' SKIP' : '');
  455.                               break;
  456.           case HPKT_EOFACK:   hWin_Message(0,'    EOFACK');
  457.                               break;
  458.           case HPKT_IDLE:     hWin_Message(0,'    IDLE');
  459.                               break;
  460.           case HPKT_END:      hWin_Message(0,'    END');
  461.                               break;
  462.           case HPKT_DEVDATA:  hWin_Message(0,'    DEVDATA (id=%ld  dev='%s'  len=%u)',
  463.                                       DevTxID, devtxdev, devtxlen);
  464.                               break;
  465.           case HPKT_DEVDACK:  hWin_Message(0,'    DEVDACK (id=%ld)',
  466.                                       h_long1(RxBuf));
  467.                               break;
  468.           default:            (* This couldn't possibly happen! ;-) *)
  469.                               break;
  470.    }
  471. }
  472. {$EndIf}
  473.  
  474.   If Crc32 then
  475.     begin
  476.       CrcL := Crc32Post(Crc32Block(Crc32Tab,CRC32_INIT,TxBufIn,Len));
  477.       Move(CrcL, TxBufIn^[Len], SizeOf(longint));
  478.       Inc(Len,SizeOf(longint));
  479.     end
  480.   else
  481.     begin
  482.       CrcW := Crc16Post(Crc16Block(Crc16Tab,CRC16_INIT,TxBufIn,Len));
  483.       Move(CrcW, TxBufIn^[Len], SizeOf(word));
  484.       Inc(Len,SizeOf(word));
  485.     end;
  486.  
  487.   IndexIn  := 0;
  488.   IndexOut := 0;
  489.   TxLastC  := 0;
  490.  
  491.   TxBuf^[IndexOut] := H_DLE;
  492.   Inc(IndexOut);
  493.   TxBuf^[IndexOut] := Format;
  494.   Inc(IndexOut);
  495.  
  496.   Case char(Format) of
  497.     HCHR_HEXPKT :
  498.       begin
  499.         While (Len > 0) do
  500.           begin
  501.             If (TxBufIn^[IndexIn] and $80) <> 0 then
  502.               begin
  503.                 TxBuf^[IndexOut] := byte('\');
  504.                 Inc(IndexOut);
  505.                 TxBuf^[IndexOut] := Ord(HexDigit[(TxBufIn^[IndexIn] shr 4) and $0f]);
  506.                 Inc(IndexOut);
  507.                 TxBuf^[IndexOut] := Ord(HexDigit[TxBufIn^[IndexIn] and $0f]);
  508.                 Inc(IndexOut);
  509.               end
  510.             else If (TxBufIn^[IndexIn] < 32) or (TxBufIn^[IndexIn] = 127) then
  511.               begin
  512.                 TxBuf^[IndexOut] := H_DLE;
  513.                 Inc(IndexOut);
  514.                 TxBuf^[IndexOut] := TxBufIn^[IndexIn] xor $40;
  515.                 Inc(IndexOut);
  516.               end
  517.             else If TxBufIn^[IndexIn] = byte('\') then
  518.               begin
  519.                 TxBuf^[IndexOut] := byte('\');
  520.                 Inc(IndexOut);
  521.                 TxBuf^[IndexOut] := byte('\');
  522.                 Inc(IndexOut);
  523.               end
  524.             else
  525.               begin
  526.                 TxBuf^[IndexOut] := TxBufIn^[IndexIn];
  527.                 Inc(IndexOut);
  528.               end;
  529.  
  530.             Inc(IndexIn);
  531.             Dec(Len);
  532.           end;
  533.       end;
  534.  
  535.     HCHR_BINPKT:
  536.       begin
  537.         While (Len > 0) do
  538.           begin
  539.             Put_BinByte(IndexOut,TxBufIn^[IndexIn]);
  540.             Inc(IndexIn);
  541.             Dec(Len);
  542.           end;
  543.       end;
  544.  
  545.     HCHR_ASCPKT:
  546.       begin
  547.         N := 0;
  548.         C := 0;
  549.         While (Len > 0) do
  550.           begin
  551.             C := C or (TxBufIn^[IndexIn] shl N);
  552.             Put_BinByte(IndexOut,(byte(C) and $7f));
  553.             C := C shr 7;
  554.             Inc(N);
  555.             If (N >= 7) then
  556.               begin
  557.                 Put_BinByte(IndexOut,(byte(C) and $7f));
  558.                 N := 0;
  559.                 C := 0;
  560.               end;
  561.  
  562.             Inc(IndexIn);
  563.             Dec(Len);
  564.           end;
  565.         If (N > 0) then
  566.           Put_BinByte(IndexOut,(byte(C) and $7f));
  567.       end;
  568.  
  569.     HCHR_UUEPKT:
  570.       begin
  571.         While (Len >= 3) do
  572.           begin
  573.             TxBuf^[IndexOut]     := h_UUEnc(TxBufIn^[IndexIn] shr 2);
  574.             TxBuf^[IndexOut + 1] := h_UUEnc( ((TxBufIn^[IndexIn] shl 4) and $30) or
  575.                                              ((TxBufIn^[IndexIn + 1] shr 4) and $0f) );
  576.             TxBuf^[IndexOut + 2] := h_UUEnc( ((TxBufIn^[IndexIn + 1] shl 2) and $3c) or
  577.                                              ((TxBufIn^[IndexIn + 2] shr 6) and $03) );
  578.             TxBuf^[IndexOut + 3] := h_UUEnc(TxBufIn^[IndexIn + 2] and $3f);
  579.  
  580.             Inc(IndexOut,4);
  581.             Inc(IndexIn,3);
  582.             Dec(Len,3);
  583.           end;
  584.  
  585.         If (Len > 0) then
  586.           begin
  587.             TxBuf^[IndexOut]     := h_UUEnc(TxBufIn^[IndexIn] shr 2);
  588.             TxBuf^[IndexOut + 1] := h_UUEnc(((TxBufIn^[IndexIn] shl 4) and $30) or ((TxBufIn^[IndexIn + 1] shr 4) and $0f));
  589.             Inc(IndexOut,2);
  590.             If (Len = 2) then
  591.               begin
  592.                 TxBuf^[IndexOut] := h_UUEnc((TxBufIn^[IndexIn + 1] shl 2) and $3c);
  593.                 Inc(IndexOut);
  594.               end;
  595.           end;
  596.       end;
  597.   end;
  598.  
  599.   TxBuf^[IndexOut]     := H_DLE;
  600.   TxBuf^[IndexOut + 1] := byte(HCHR_PKTEND);
  601.   Inc(IndexOut,2);
  602.  
  603.   If (PktType <> HPKT_DATA) and (Format <> byte(HCHR_BINPKT)) then
  604.     begin
  605.       TxBuf^[IndexOut]     := 13; (*CR*)
  606.       TxBuf^[IndexOut + 1] := 10; (*LF*)
  607.       Inc(IndexOut,2);
  608.     end;
  609.  
  610.   If Length(TxPktPrefix) > 0 then
  611.     For N := 1 to Length(TxPktPrefix) do
  612.       begin
  613.         Case Ord(TxPktPrefix[N]) of
  614.           221 : Com_Break;           (* Transmit break signal for one second *)
  615.           222 : Delay(1000);
  616.           223 : Com_TxByte(0);
  617.         else
  618.           Com_TxByte(byte(TxPktPrefix[N]));
  619.         end;
  620.       end;
  621.  
  622.   Com_TxBlock(TxBuf^,IndexOut);
  623. end; (*TxPkt*)
  624.  
  625.  
  626. (*---------------------------------------------------------------------------*)
  627. Function RxPkt : integer;
  628. label
  629.   Continue;
  630. var
  631.   C,
  632.   N,
  633.   I,
  634.   Count,
  635.   Index : integer;
  636.   OK,
  637.   Done  : boolean;
  638.   P,
  639.   Q     : ByteArrayP;
  640. begin
  641.   If hWin_KeyCheck then
  642.     begin
  643.       RxPkt := H_SYSABORT;
  644.       Exit;
  645.     end;
  646.  
  647.   If not Com_Carrier then
  648.     begin
  649.       RxPkt := H_CARRIER;
  650.       Exit;
  651.     end;
  652.  
  653.   If (h_Timer_Running(BrainDead)) and (h_Timer_Expired(BrainDead)) then
  654.     begin
  655.       {$IfDef H_DEBUG}
  656.         If (LogLevel = 0) then
  657.           hWin_Message(0,' <- BrainDead (timer=%08lx  time=%08lx)', BrainDead,tnow);
  658.       {$EndIf}
  659.  
  660.       RxPkt := H_BRAINTIME;
  661.       Exit;
  662.     end;
  663.  
  664.   If (h_Timer_Running(TxTimer)) and (h_Timer_Expired(TxTimer)) then
  665.     begin
  666.       {$IfDef H_DEBUG}
  667.         If (LogLevel = 0) then
  668.           hWin_Message(0,' <- TxTimer (timer=%08lx  time=%08lx)', TxTimer,tnow);
  669.       {$EndIf}
  670.  
  671.       RxPkt := H_TXTIME;
  672.       Exit;
  673.     end;
  674.  
  675.   If (h_Timer_Running(DevTxTimer)) and (h_Timer_Expired(DevTxTimer)) then
  676.     begin
  677.       {$IfDef H_DEBUG}
  678.         If (LogLevel = 0) then
  679.           hWin_Message(0,' <- DevTxTimer (timer=%08lx  time=%08lx)', DevTxTimer,tnow);
  680.       {$EndIf}
  681.  
  682.       RxPkt := H_DEVTXTIME;
  683.       Exit;
  684.     end;
  685.  
  686.   While Com_RxReady do
  687.     begin
  688.       C := Com_RxByte;
  689.  
  690.       If (RxOptions and HOPT_HIGHBIT) <> 0 then
  691.         C := C and $7f;
  692.  
  693.       N := C;
  694.       If (RxOptions and HOPT_HIGHCTL) <> 0 then
  695.         N := N and $7f;
  696.  
  697.       If ((N <> H_DLE) and
  698.         (((RxOptions and HOPT_XONXOFF <> 0) and ((N = XON) or (N = XOFF)))  or
  699.          ((RxOptions and HOPT_CTLCHRS <> 0) and ((N < 32) or (N = 127))) )) then
  700.         Goto Continue;
  701.  
  702.       If (RxDLE > 0) or (C = H_DLE) then
  703.         begin
  704.           Case char(C) of
  705.             char(H_DLE) :
  706.               begin
  707.                 Inc(RxDLE);
  708.                 If RxDLE >= 5 then
  709.                   begin
  710.                     RxPkt := H_CANCEL;
  711.                     Exit;
  712.                   end;
  713.               end;
  714.  
  715.             HCHR_PKTEND :
  716.               begin
  717.                 Case char(RxPktFormat) of
  718.                   HCHR_BINPKT :
  719.                     begin
  720.                       Index := RxBufPtr;
  721.                     end;
  722.  
  723.                   HCHR_HEXPKT :
  724.                     begin
  725.                       Count := 0;
  726.                       Index := 0;
  727.                       Done  := false;
  728.                       While (Count < RxBufPtr) and (not Done) do
  729.                         begin
  730.                           If (RxBuf^[Count] = byte('\')) then
  731.                             begin
  732.                               Inc(Count);
  733.                               If (RxBuf^[Count] <> byte('\')) then
  734.                                 begin
  735.                                   I := RxBuf^[Count];
  736.                                   N := RxBuf^[Count + 1];
  737.                                   Inc(Count);
  738.                                   Dec(I,48);
  739.                                   If (I > 9) then Dec(I,39);
  740.                                   Dec(N,48);
  741.                                   If (N > 9) then Dec(N,39);
  742.                                   If (I and $FFF0 <> 0) or (N and $FFF0 <> 0) then
  743.                                     begin
  744.                                       C := H_NOPKT;
  745.                                       Done := true;
  746.                                     end;
  747.                                   RxBuf^[Index] := (I shl 4) or N;
  748.                                   Inc(Index);
  749.                                 end
  750.                               else
  751.                                 begin
  752.                                   RxBuf^[Index] := RxBuf^[Count];
  753.                                   Inc(Index);
  754.                                 end;
  755.                             end
  756.                           else
  757.                             begin
  758.                               RxBuf^[Index] := RxBuf^[Count];
  759.                               Inc(Index);
  760.                             end;
  761.                           Inc(Count);
  762.                         end;
  763.                       If Count > RxBufPtr then
  764.                         C := H_NOPKT;
  765.                     end;
  766.  
  767.                   HCHR_ASCPKT :
  768.                     begin
  769.                       N := 0;
  770.                       I := 0;
  771.                       Count := 0;
  772.                       Index := 0;
  773.                       While Count < RxBufPtr do
  774.                         begin
  775.                           I := I or ((RxBuf^[Count] and $7f) shl N);
  776.                           Inc(N,7);
  777.                           If N >= 8 then
  778.                             begin
  779.                               RxBuf^[Index] := byte(I) and $FF;
  780.                               Inc(Index);
  781.                               I := I shr 8;
  782.                               Dec(N,8);
  783.                             end;
  784.                           Inc(Count);
  785.                         end;
  786.                     end;
  787.  
  788.                   HCHR_UUEPKT :
  789.                     begin
  790.                       N     := RxBufPtr;
  791.                       Count := 0;
  792.                       Index := 0;
  793.                       Done  := false;
  794.                       While (N >= 4) and (not Done) do
  795.                         begin
  796.                           If ((RxBuf^[Count]     <= byte(' ')) or (RxBuf^[Count]     >= byte('a'))  or
  797.                               (RxBuf^[Count + 1] <= byte(' ')) or (RxBuf^[Count + 1] >= byte('a'))  or
  798.                               (RxBuf^[Count + 2] <= byte(' ')) or (RxBuf^[Count + 2] >= byte('a'))  or
  799.                               (RxBuf^[Count + 3] <= byte(' ')) or (RxBuf^[Count + 3] >= byte('a'))) then
  800.                             begin
  801.                               C := H_NOPKT;
  802.                               Done := true;
  803.                             end
  804.                           else
  805.                             begin
  806.                               RxBuf^[Index]     := (h_uudec(RxBuf^[Count]) shl 2) or (h_uudec(RxBuf^[Count + 1]) shr 4);
  807.                               RxBuf^[Index + 1] := (h_uudec(RxBuf^[Count + 1]) shl 4) or (h_uudec(RxBuf^[Count + 2]) shr 2);
  808.                               RxBuf^[Index + 2] := (h_uudec(RxBuf^[Count + 2]) shl 6) or h_uudec(RxBuf^[Count + 3]);
  809.  
  810.                               Inc(Count,4);
  811.                               Inc(Index,3);
  812.                               Dec(N,4);
  813.                             end;
  814.                         end;
  815.  
  816.                       If (n >= 2) and (not Done) then
  817.                         begin
  818.                           If (RxBuf^[Count]     <= byte(' ')) or (RxBuf^[Count]     >= byte('a')) or
  819.                              (RxBuf^[Count + 1] <= byte(' ')) or (RxBuf^[Count + 1] >= byte('a')) then
  820.                             C := H_NOPKT
  821.                           else
  822.                             begin
  823.                                RxBuf^[Index] := (h_uudec(RxBuf^[Count]) shl 2) or (h_uudec(RxBuf^[Count + 1]) shr 4);
  824.                                Inc(Index);
  825.                                If (N = 3) then
  826.                                  begin
  827.                                    If (RxBuf^[Count + 2] <= byte(' ')) or (RxBuf^[Count + 2] >= byte('a')) then
  828.                                      C := H_NOPKT
  829.                                    else
  830.                                      begin
  831.                                        RxBuf^[Index] := (h_uudec(RxBuf^[Count + 1]) shl 4) or
  832.                                                         (h_uudec(RxBuf^[Count + 2]) shr 2);
  833.                                        Inc(Index);
  834.                                      end;
  835.                                  end;
  836.                             end;
  837.                         end;
  838.                     end;
  839.  
  840.                 else (*CASE - This'd mean an internal fluke *)
  841.                   begin
  842.                     {$IfDef H_DEBUG}
  843.                       If (LogLevel = 0) then
  844.                         hWin_Message(0,' <- <PKTEND> (pktformat='%c' dec=%d hex=%02x) ??',
  845.                         RxPktFormat, RxPktFormat, RxPktFormat);
  846.                     {$EndIf}
  847.                     C := H_NOPKT;
  848.                   end;
  849.                 end; (*CASE RxPktFormat*)
  850.  
  851.                 RxBufPtr := -1;
  852.  
  853.                 If (c = H_NOPKT) then
  854.                   Goto Continue;
  855.  
  856.                 RxPktLen := Index;
  857.  
  858.                 If (RxPktFormat <> byte(HCHR_HEXPKT)) and (RxOptions and HOPT_CRC32 <> 0) then
  859.                   begin
  860.                     If (RxPktLen < 5) then
  861.                       begin
  862.                         C := H_NOPKT;
  863.                         Goto Continue;
  864.                       end;
  865.                     OK := h_Crc32Test(Crc32Block(Crc32Tab,CRC32_INIT,RxBuf,RxPktLen));
  866.                     Dec(RxPktLen, SizeOf(longint)); (*Remove CRC-32*)
  867.                   end
  868.                 else
  869.                   begin
  870.                     If (RxPktLen < 3) then
  871.                       begin
  872.                         C := H_NOPKT;
  873.                         Goto Continue;
  874.                       end;
  875.                     OK := h_Crc16Test(Crc16Block(Crc16Tab, CRC16_INIT, RxBuf, RxPktLen));
  876.                     Dec(RxPktLen, SizeOf(word));  (*Remove CRC-16*)
  877.                   end;
  878.  
  879.                 Dec(RxPktLen); (*Remove Pkt type*)
  880.  
  881.                 If OK then
  882.                   begin
  883.  
  884. {$IfDef H_DEBUG}
  885. If (loglevel=0) {
  886.   char *s1, *s2, *s3, *s4;
  887.  
  888.   hWin_Message(0,' <- PKT (format='%c'  type='%c'  len=%d)',
  889.           RxPktFormat, (integer) RxBuf[RxPktLen], RxPktLen);
  890.  
  891.    switch (RxBuf[RxPktLen]) {
  892.           case HPKT_START:    hWin_Message(0,'    START');
  893.                               break;
  894.           case HPKT_INIT:     s1 := ((char *) RxBuf) + ((integer) strlen((char *) RxBuf)) + 1;
  895.                               s2 := s1 + ((integer) strlen(s1)) + 1;
  896.                               s3 := s2 + ((integer) strlen(s2)) + 1;
  897.                               s4 := s3 + ((integer) strlen(s3)) + 1;
  898.                               hWin_Message(0,'    INIT (appinfo='%s'  can='%s'  want='%s'  options='%s'  pktprefix='%s')',
  899.                                       (char *) RxBuf, s1, s2, s3, s4);
  900.                               break;
  901.           case HPKT_INITACK:  hWin_Message(0,'    INITACK');
  902.                               break;
  903.           case HPKT_FINFO:    hWin_Message(0,'    FINFO ('%s'  RxState=%d)',RxBuf,RxState);
  904.                               break;
  905.           case HPKT_FINFOACK: hWin_Message(0,'    FINFOACK (pos=%ld  TxState=%d  TxFd=%d)',
  906.                                       h_long1(RxBuf), TxState, TxFd);
  907.                               break;
  908.           case HPKT_DATA:     hWin_Message(0,'    DATA (RxState=%d  pos=%ld  len=%u)',
  909.                                       RxState, h_long1(RxBuf),
  910.                                       (word) (RxPktLen - ((integer) sizeof (longint))));
  911.                               break;
  912.           case HPKT_DATAACK:  hWin_Message(0,'    DATAACK (RxState=%d  pos=%ld)',
  913.                                       RxState, h_long1(RxBuf));
  914.                               break;
  915.           case HPKT_RPOS:     hWin_Message(0,'    RPOS (pos=%ld%s  blklen=%u->%ld  syncid=%ld%s  TxState=%d  TxFd=%d)',
  916.                                       h_long1(RxBuf),
  917.                                       h_long1(RxBuf) < 0 ? ' SKIP' : '',
  918.                                       TxBlkLen, h_long2(RxBuf),
  919.                                       h_long3(RxBuf),
  920.                                       h_long3(RxBuf) = RxSyncID ? ' DUP' : '',
  921.                                       TxState, TxFd);
  922.                               break;
  923.           case HPKT_EOF:      hWin_Message(0,'    EOF (RxState=%d  pos=%ld%s)',
  924.                                       RxState, h_long1(RxBuf),
  925.                                       h_long1(RxBuf) < 0 ? ' SKIP' : '');
  926.                               break;
  927.           case HPKT_EOFACK:   hWin_Message(0,'    EOFACK (TxState=%d)', TxState);
  928.                               break;
  929.           case HPKT_IDLE:     hWin_Message(0,'    IDLE');
  930.                               break;
  931.           case HPKT_END:      hWin_Message(0,'    END');
  932.                               break;
  933.           case HPKT_DEVDATA:  s1 := ((char *) RxBuf) + ((integer) sizeof (longint));
  934.                               hWin_Message(0,'    DEVDATA (id=%ld  dev=%s  len=%u',
  935.                                       h_long1(RxBuf), s1,
  936.                                       RxPktLen - (((integer) sizeof (longint)) + ((integer) strlen(s1)) + 1));
  937.                               break;
  938.           case HPKT_DEVDACK:  hWin_Message(0,'    DEVDACK (DevTxState=%d  id=%ld)',
  939.                                       DevTxState, h_long1(RxBuf));
  940.                               break;
  941.           default:            hWin_Message(0,'    Unkown PktType %d (TxState=%d  RxState=%d)',
  942.                                       (integer) RxBuf[RxPktLen], TxState, RxState);
  943.                               break;
  944.    }
  945. }
  946. {$EndIf}
  947.                     RxPkt := integer(RxBuf^[RxPktLen]);
  948.                     Exit;
  949.                   end; (*Good Pkt*)
  950.  
  951. (*                {$IfDef H_DEBUG} *)
  952.                     hWin_Message('Bad CRC (format=' + Chr(RxPktFormat) +
  953.                                  '  type=' + Chr(RxBuf^[RxPktLen]) +
  954.                                  '  len=' + Long2Str(RxPktLen) + ')');
  955. (*                {$EndIf} *)
  956.  
  957.               end; (*HCHR_PKTEND*)
  958.  
  959.             HCHR_BINPKT,
  960.             HCHR_HEXPKT,
  961.             HCHR_ASCPKT,
  962.             HCHR_UUEPKT :
  963.               begin
  964.                 {$IfDef H_DEBUG}
  965.                     hWin_Message('<- <PKTSTART> (pktformat=' + Chr(C) + ')');
  966.                 {$EndIf} 
  967.  
  968.                 RxPktFormat := C;
  969.                 RxBufPtr    := 0;
  970.                 RxDLE       := 0;
  971.               end;
  972.           else
  973.             begin
  974.               If RxBufPtr >= 0 then
  975.                 begin
  976.                   If RxBufPtr < RxBufMax then
  977.                     begin
  978.                       RxBuf^[RxBufPtr] := byte(C) xor $40;
  979.                       Inc(RxBufPtr);
  980.                     end
  981.                   else
  982.                     begin
  983. (*                      {$IfDef H_DEBUG} *)
  984.                           hWin_Message('<- Pkt too long - discarded');
  985. (*                      {$EndIf} *)
  986.                       RxBufPtr := -1;
  987.                     end;
  988.                 end;
  989.               RxDLE := 0;
  990.             end;
  991.           end; (*CASE C*)
  992.         end (*If*)
  993.       else
  994.         begin
  995.           If RxBufPtr >= 0 then
  996.             begin
  997.               If (RxBufPtr < RxBufMax) then
  998.                 begin
  999.                   RxBuf^[RxBufPtr] := byte(C);
  1000.                   Inc(RxBufPtr);
  1001.                 end
  1002.               else
  1003.                 begin
  1004. (*                  {$IfDef H_DEBUG} *)
  1005.                       hWin_Message('<- Pkt too long - discarded');
  1006. (*                  {$EndIf} *)
  1007.                   RxBufPtr := -1;
  1008.                 end;
  1009.             end;
  1010.         end;
  1011. Continue:
  1012.     end;
  1013.  
  1014.   RxPkt := H_NOPKT;
  1015. end; (*RxPkt*)
  1016.  
  1017.  
  1018. (*---------------------------------------------------------------------------*)
  1019. Procedure Hydra_Status( Xmit : boolean );
  1020. begin
  1021.   If Xmit then
  1022.     hWin_ShowTxBytes(TxPos,TxStart)
  1023.   else
  1024.     hWin_ShowRxBytes(RxPos,RxStart);
  1025. end; (*Hydra_Status*)
  1026.  
  1027.  
  1028. (*---------------------------------------------------------------------------*)
  1029. Procedure Hydra_Pct( Xmit : boolean );
  1030. begin
  1031.   If Xmit then
  1032.     hWin_Complete(TxFName,TxFSize - TxOffset)
  1033.   else
  1034.     hWin_Complete(RxFName,RxFSize - RxOffset);
  1035. end; (*Hydra_Pct*)
  1036.  
  1037.  
  1038. (*---------------------------------------------------------------------------*)
  1039. Procedure Hydra_BadXfer;
  1040. begin
  1041.   If (FileRec(RxFd).Mode <> fmClosed) then
  1042.     begin
  1043.       Close(RxFd);
  1044.       FileRec(RxFd).Mode := fmClosed;
  1045.       If hFile_Bad(RxPathName,RxFSize) then
  1046.         hWin_Message('Bad transfer - Recovery info saved')
  1047.       else
  1048.         hWin_Message('Bad transfer - File deleted');
  1049.     end;
  1050. end; (*Hydra_BadXfer*)
  1051.  
  1052.  
  1053. (*---------------------------------------------------------------------------*)
  1054. Function Hydra_Init( Want_Options : longint ) : boolean;
  1055. begin
  1056.   Hydra_Init := false;
  1057.  
  1058.   TxBuf    := nil;
  1059.   RxBuf    := nil;
  1060.   Crc16Tab := nil;
  1061.   Crc32Tab := nil;
  1062.  
  1063.   GetMem(TxBuf,H_BUFLEN);
  1064.   GetMem(RxBuf,H_BUFLEN);
  1065.   New(Crc16Tab);
  1066.   New(Crc32Tab);
  1067.  
  1068.   If (TxBuf = nil) or (RxBuf = nil) or (Crc16Tab = nil) or (Crc32Tab = nil) then
  1069.     begin
  1070.       If TxBuf <> nil then FreeMem(TxBuf,H_BUFLEN);
  1071.       If RxBuf <> nil then FreeMem(RxBuf,H_BUFLEN);
  1072.       If Crc16Tab <> nil then Dispose(Crc16Tab);
  1073.       If Crc32Tab <> nil then Dispose(Crc32Tab);
  1074.       Exit;
  1075.     end;
  1076.  
  1077.   TxBufIn  := TxBuf;
  1078.   Inc(TxBufIn,(H_MAXBLKLEN + H_OVERHEAD + 5) * 2);
  1079.   RxBufMax := H_MAXPKTLEN;
  1080.  
  1081.   Crc16Init(Crc16Tab,CRC16_POLY);
  1082.   Crc32Init(Crc32Tab,CRC32_POLY);
  1083.  
  1084.   BatchesDone := 0;
  1085.  
  1086.   If Originator then
  1087.     HdxLink := false
  1088.   else If HdxSession then
  1089.     HdxLink := true;
  1090.  
  1091.   Options := (Want_Options and HCAN_OPTIONS) and (not HUNN_OPTIONS);
  1092.  
  1093.   TimeOut := Trunc(40960 / Hydra_Speed);
  1094.   If (TimeOut < H_MINTIMER) then
  1095.     TimeOut := H_MINTIMER
  1096.   else If (TimeOut > H_MAXTIMER) then
  1097.     TimeOut := H_MAXTIMER;
  1098.  
  1099.   TxMaxBlkLen := Trunc(Hydra_Speed / 300) * 128;
  1100.   If (TxMaxBlkLen < 256) then
  1101.     TxMaxBlkLen := 256
  1102.   else If (TxMaxBlkLen > H_MAXBLKLEN) then
  1103.     TxMaxBlkLen := H_MAXBLKLEN;
  1104.  
  1105.   If Hydra_Speed < 2400 then
  1106.     TxBlkLen := 256
  1107.   else
  1108.     TxBlkLen := 512;
  1109.   RxBlkLen := TxBlkLen;
  1110.  
  1111.   TxGoodBytes  := 0;
  1112.   TxGoodNeeded := TxMaxBlkLen;
  1113.  
  1114.   TxState := HTX_DONE;
  1115.  
  1116.   If HdxLink then
  1117.     hWin_OpenWindow
  1118.   else
  1119.     hWin_OpenWindow;
  1120.  
  1121.   ChatFill  := 0;
  1122.   ChatTimer := -1;
  1123.   LastTimer := 0;
  1124.  
  1125.   Hydra_Init := true;
  1126. end; (*Hydra_Init*)
  1127.  
  1128.  
  1129. (*---------------------------------------------------------------------------*)
  1130. Procedure Hydra_DeInit( CloseWindow : boolean );
  1131. begin
  1132.   If TxBuf <> nil then FreeMem(TxBuf,H_BUFLEN);
  1133.   If RxBuf <> nil then FreeMem(RxBuf,H_BUFLEN);
  1134.   If Crc16Tab <> nil then Dispose(Crc16Tab);
  1135.   If Crc32Tab <> nil then Dispose(Crc32Tab);
  1136.  
  1137.   If CloseWindow then hWin_CloseWindow;
  1138. end; (*Hydra_DeInit*)
  1139.  
  1140.  
  1141. (*---------------------------------------------------------------------------*)
  1142. Function Hydra_Send( TxPathName, TxAlias : string) : integer;
  1143. label
  1144.   Break;
  1145. var
  1146.   St       : string;
  1147.   Result,
  1148.   PktType,
  1149.   Counter,
  1150.   Count,
  1151.   Index    : integer;
  1152.   WorkPtr  : ByteArrayP;
  1153.   FileStat : SearchRec;
  1154. begin
  1155.   Hydra_Send := XFER_ABORT;
  1156.  
  1157.   hWin_ClearTxWindow;
  1158.  
  1159.   (*-------------------------------------------------------------------------*)
  1160.   If (TxState = HTX_DONE) then
  1161.     begin
  1162.       hWin_ShowTxFileName('-Initialising-');
  1163.       TxState     := HTX_START;
  1164.       TxOptions   := HTXI_OPTIONS;
  1165.       TxPktPrefix := '';
  1166.  
  1167.       hWin_ClearRxWindow;
  1168.       hWin_ShowRxFileName('-Initialising-');
  1169.       RxState   := HRX_INIT;
  1170.       RxOptions := HRXI_OPTIONS;
  1171.       FileRec(RxFd).Mode := fmClosed;
  1172.       RxDLE     := 0;
  1173.       RxBufPtr  := -1;
  1174.       RxTimer   := h_Timer_Reset;
  1175.  
  1176.       DevTxID    := 0;
  1177.       DevRxID    := 0;
  1178.       DevTxTimer := h_Timer_Reset;
  1179.       DevTxState := HTD_DONE;
  1180.  
  1181.       BrainDead := h_Timer_Set(H_BRAINDEAD);
  1182.     end
  1183.   else
  1184.     TxState := HTX_FINFO;
  1185.  
  1186.   TxTimer   := h_Timer_Reset;
  1187.   TxRetries := 0;
  1188.  
  1189.   (*-------------------------------------------------------------------------*)
  1190.   If TxPathName <> '' then
  1191.     begin
  1192.       TxPathName := StUpCase(TxPathName);
  1193.       TxAlias := StUpCase(TxAlias);
  1194.       TxFName := JustFilename(TxPathName);
  1195.  
  1196.       FindFirst(TxPathName,(ReadOnly and Archive),FileStat);
  1197.       TxFSize := FileStat.Size;
  1198.       TxFTime := h_ToUnixDate(FileStat.Time);
  1199.  
  1200.       FileMode := RO or DenyNone;
  1201.       Assign(TxFd, TxPathName);
  1202.       Reset(TxFd,1);
  1203.       If IOResult <> 0 then
  1204.         begin
  1205.           hWin_Message('Unable to open ' + TxFName);
  1206.           Hydra_Send := XFER_SKIP;
  1207.           Exit;
  1208.         end;
  1209.  
  1210. {
  1211.       If isatty(TxFd) then
  1212.         begin
  1213.           hWin_Message(TxFName + ' is a device name!');
  1214.           Close(TxFd);
  1215.           Hydra_Send := XFER_SKIP;
  1216.           Exit;
  1217.         end;
  1218. }
  1219.  
  1220.       TxStart  := 0;
  1221.       TxSyncID := 0;
  1222.     end
  1223.   else
  1224.     begin
  1225.       TxFName := '';
  1226.       FileRec(TxFd).Mode := fmClosed;
  1227.     end;
  1228.  
  1229.   (*-------------------------------------------------------------------------*)
  1230.   Repeat
  1231.     Case (DevTxState) of
  1232.       HTD_DATA : begin
  1233.                    If (TxState > HTX_RINIT) then
  1234.                      begin
  1235.                        Count := 0;
  1236.                        h_PutLong(1,DevTxID);
  1237.                        Inc(Count,SizeOf(longint));
  1238. (***DEBUG***)          Move(DevTxDev[1], TxBufIn^[Count], H_FLAGLEN);
  1239.                        TxBufIn^[Count + H_FLAGLEN] := 0;
  1240.                        Inc(Count, H_FLAGLEN + 1);
  1241.                        Move(DevTxBuf^[0], TxBufIn^[Count], DevTxLen);
  1242.                        Inc(Count,DevTxLen);
  1243.                        TxPkt(Count,HPKT_DEVDATA);
  1244.                        If (RxState = HRX_DONE) and (TxState = HTX_REND) then
  1245.                          DevTxTimer := h_Timer_Set(TimeOut shr 1)
  1246. {***DEBUG***              DevTxTimer := h_Timer_Set(Trunc(TimeOut / 2))}
  1247.                        else
  1248.                          DevTxTimer := h_Timer_Set(TimeOut);
  1249.                        DevTxState := HTD_DACK;
  1250.                      end;
  1251.                  end;
  1252.     end; (*CASE DevTxState*)
  1253.  
  1254.     (*-----------------------------------------------------------------------*)
  1255.     Case (TxState) of
  1256.       HTX_START :
  1257.         begin
  1258.           Com_TxBlock(AutoStr,SizeOf(AutoStr));
  1259.           TxPkt(0,HPKT_START);
  1260.           TxTimer := h_Timer_Set(H_START);
  1261.           TxState := HTX_SWAIT;
  1262.         end;
  1263.  
  1264.       (*---------------------------------------------------------------------*)
  1265.       HTX_INIT :
  1266.         begin
  1267.           Count := 0;
  1268.           h_PutHex(Count,H_REVSTAMP);
  1269.           Inc(Count,8);
  1270.           Move(PROGNAME[1], TxBufIn^[Count], Length(PROGNAME));
  1271.           Inc(Count,Length(PROGNAME));
  1272.           TxBufIn^[Count] := byte(',');
  1273.           Inc(Count);
  1274.           Move(VERSION[1], TxBufIn^[Count], Length(VERSION));
  1275.           Inc(Count,Length(VERSION));
  1276.           TxBufIn^[Count] := byte(' ');
  1277.           Inc(Count);
  1278.           Move(H_OS[1], TxBufIn^[Count], Length(H_OS));
  1279.           Inc(Count,Length(H_OS));
  1280.           TxBufIn^[Count] := 0;
  1281.           Inc(Count);
  1282.  
  1283.           WorkPtr := TxBufIn;
  1284.           Inc(WorkPtr,Count);
  1285.           Inc(Count,Put_Flags(WorkPtr,HCAN_OPTIONS));    (*What we CAN do*)
  1286.           WorkPtr := TxBufIn;
  1287.           Inc(WorkPtr,Count);
  1288.           Inc(Count,Put_Flags(WorkPtr,Options));    (*What we WANT*)
  1289.  
  1290.           h_PutHex(Count,Hydra_TxWindow);
  1291.           Inc(Count,8);
  1292.           h_PutHex(Count,Hydra_RxWindow);
  1293.           Inc(Count,8);
  1294.           TxBufIn^[Count] := 0;
  1295.           Inc(Count);
  1296.  
  1297.           Move(PktPrefix[1], TxBufIn^[Count], Length(PktPrefix));
  1298.           Inc(Count,Length(PktPrefix));
  1299.           TxBufIn^[Count] := 0;
  1300.           Inc(Count);
  1301.  
  1302.           TxOptions := HTXI_OPTIONS;
  1303.           TxPkt(Count, HPKT_INIT);
  1304.           TxOptions := RxOptions;
  1305.           TxTimer   := h_Timer_Set(TimeOut shr 1);
  1306. (*         TxTimer   := h_Timer_Set(Trunc(TimeOut / 2)); ***DEBUG***)
  1307.           TxState   := HTX_INITACK;
  1308.         end;
  1309.  
  1310.       (*---------------------------------------------------------------------*)
  1311.       HTX_FINFO :
  1312.         begin
  1313.           If (FileRec(TxFd).Mode <> fmClosed) then
  1314.             begin
  1315.               If (TxRetries = 0) then
  1316.                 begin
  1317.                   If (TxAlias <> '') then
  1318.                     hWin_ShowTxFileName(TxFName + '(' + TxAlias + ')')
  1319.                   else
  1320.                     hWin_ShowTxFileName(TxFName);
  1321.                   hWin_ShowTxFileSize(TxFSize);
  1322.                   TxFName := StLoCase(TxFName);
  1323.                 end;
  1324.  
  1325.               h_PutHex( 0,TxFTime);
  1326.               h_PutHex( 8,TxFSize);
  1327.               h_PutHex(16,0);
  1328.               h_PutHex(24,0);
  1329.               h_PutHex(32,0);
  1330.               Count := 5 * 8;
  1331.  
  1332.               If TxAlias <> '' then
  1333.                 begin
  1334.                   Move(TxAlias[1], TxBufIn^[Count], Length(TxAlias));
  1335.                   Inc(Count,Length(TxAlias));
  1336.                 end
  1337.               else
  1338.                 begin
  1339.                   Move(TxFName[1], TxBufIn^[Count], Length(TxFName));
  1340.                   Inc(Count,Length(TxFName));
  1341.                 end;
  1342.  
  1343.               TxBufIn^[Count] := 0;
  1344.               Inc(Count);
  1345.             end
  1346.           else
  1347.             begin
  1348.               If (TxRetries = 0) then
  1349.                 hWin_ShowTxFileName('-End Of Batch-');
  1350.               TxBufIn^[0] := 0;
  1351.               Count := 1;
  1352.             end;
  1353.  
  1354.           TxPkt(Count,HPKT_FINFO);
  1355.           If TxRetries <> 0 then
  1356.             TxTimer := h_Timer_Set(TimeOut shr 1)
  1357. (*            TxTimer := h_Timer_Set(Trunc(TimeOut / 2)) ***DEBUG***)
  1358.           else
  1359.             TxTimer := h_Timer_Set(TimeOut);
  1360.           TxState := HTX_FINFOACK;
  1361.         end; (*HTX_FINFO*)
  1362.  
  1363.       (*---------------------------------------------------------------------*)
  1364.       HTX_XDATA :
  1365.         begin
  1366.           If (Com_TxChars^ < TxMaxBlkLen) then
  1367.             begin
  1368.               If (TxPos < 0) then
  1369.                  Counter := -1 (*Skip*)
  1370.               else
  1371.                 begin
  1372.                   h_PutLong(1,TxPos);
  1373.                   Count := SizeOf(longint);
  1374.                   BlockRead(TxFd,TxBufIn^[Count],TxBlkLen,Counter);
  1375.                   Inc(Count,Counter);
  1376.                   If IOResult <> 0 then
  1377.                     begin
  1378.                      Counter := -1;
  1379.                      hWin_Message('File read error');
  1380.                      Close(TxFd);
  1381.                      FileRec(TxFd).Mode := fmClosed;
  1382.                      TxPos := -2; (*Skip*)
  1383.                    end;
  1384.                 end;
  1385.  
  1386.               If (Counter > 0) then
  1387.                 begin
  1388.                   Inc(TxPos,Counter);
  1389.  
  1390.                   TxPkt(Count,HPKT_DATA);
  1391.  
  1392.                   If (TxBlkLen < TxMaxBlkLen) then
  1393.                     begin
  1394.                       Inc(TxGoodBytes,Counter);
  1395.                       If (TxGoodBytes >= TxGoodNeeded) then
  1396.                         begin
  1397.                           TxBlkLen := TxBlkLen shl 1;
  1398.                           If (TxBlkLen >= TxMaxBlkLen) then
  1399.                             begin
  1400.                               TxBlkLen := TxMaxBlkLen;
  1401.                               TxGoodNeeded := 0;
  1402.                             end;
  1403.                           TxGoodBytes := 0;
  1404.                         end;
  1405.                     end;
  1406.  
  1407.                   If (TxWindow > 0) and (TxPos >= (TxLastAck + TxWindow)) then
  1408.                     begin
  1409.                       If TxRetries <> 0 then
  1410.                         TxTimer := h_Timer_Set(TimeOut shr 1)
  1411. (*                        TxTimer := h_Timer_Set(Trunc(TimeOut / 2)) ***DEBUG***)
  1412.                       else
  1413.                         TxTimer := h_Timer_Set(TimeOut);
  1414.                       TxState := HTX_DATAACK;
  1415.                     end;
  1416.  
  1417.                   If (TxStart = 0) then
  1418.                     TxStart := h_Timer_Get;
  1419.                   Hydra_Status(true);
  1420.                 end
  1421.               else
  1422.                begin
  1423.                  TxState := HTX_EOF; (*Fallthrough to HTX_EOF*)
  1424.                end;
  1425.             end;
  1426.         end; (*HTX_XDATA*)
  1427.  
  1428.       (*---------------------------------------------------------------------*)
  1429.       HTX_EOF :
  1430.         begin
  1431.           h_PutLong(1,TxPos);
  1432.           TxPkt(SizeOf(longint),HPKT_EOF);
  1433.           If TxRetries <> 0 then
  1434.             TxTimer := h_Timer_Set(TimeOut shr 1)
  1435. (*            TxTimer := h_Timer_Set(Trunc(TimeOut / 2)) ***DEBUG***)
  1436.           else
  1437.             TxTimer := h_Timer_Set(TimeOut);
  1438.           TxState := HTX_EOFACK;
  1439.         end;
  1440.  
  1441.       (*---------------------------------------------------------------------*)
  1442.       HTX_END :
  1443.         begin
  1444.           TxPkt(0,HPKT_END);
  1445.           TxPkt(0,HPKT_END);
  1446.           TxTimer := h_Timer_Set(TimeOut shr 1);
  1447. (*          TxTimer := h_Timer_Set(Trunc(TimeOut / 2)); ***DEBUG***)
  1448.           TxState := HTX_ENDACK;
  1449.         end;
  1450.  
  1451.     end; (*CASE TxState*)
  1452.  
  1453.     (*-----------------------------------------------------------------------*)
  1454.     PktType := RxPkt;
  1455.  
  1456.     (*-----------------------------------------------------------------------*)
  1457.     Case PktType of
  1458.       (*---------------------------------------------------------------------*)
  1459.       H_CARRIER,
  1460.       H_CANCEL,
  1461.       H_SYSABORT,
  1462.       H_BRAINTIME :
  1463.         begin
  1464.           Case PktType of
  1465.             H_CARRIER   : hWin_Message('Carrier lost');
  1466.             H_CANCEL    : hWin_Message('Transfer aborted by remote console');
  1467.             H_SYSABORT  : hWin_Message('Transfer aborted by local console');
  1468.             H_BRAINTIME : hWin_Message('Remote has expired');
  1469.           end;
  1470.  
  1471.           TxState := HTX_DONE;
  1472.           Result  := XFER_ABORT;
  1473.         end; (*H_BRAINTIME*)
  1474.  
  1475.       (*---------------------------------------------------------------------*)
  1476.       H_TXTIME :
  1477.         begin
  1478.           If (TxState = HTX_XWAIT) or (TxState = HTX_REND) then
  1479.             begin
  1480.               TxPkt(0,HPKT_IDLE);
  1481.               TxTimer := h_Timer_Set(H_IDLE);
  1482.             end
  1483.           else
  1484.             begin
  1485.               Inc(TxRetries);
  1486.               If (TxRetries > H_RETRIES) then  (***DEBUG***)
  1487. {              If (TxRetries > H_RETRIES) and (TxState <> HTX_SWAIT) then}
  1488.                 begin
  1489.                   hWin_Message('Aborting - Too many errors');
  1490.                   TxState := HTX_DONE;
  1491.                   Result  := XFER_ABORT;
  1492.                   Goto Break;
  1493.                 end;
  1494.  
  1495.               Str(TxRetries,St);
  1496.               hWin_Message('TimeOut - Retry ' + St);
  1497.               TxTimer := h_Timer_Reset;
  1498.  
  1499.               Case (TxState) of
  1500.                 HTX_SWAIT    : TxState := HTX_START;
  1501.                 HTX_INITACK  : TxState := HTX_INIT;
  1502.                 HTX_FINFOACK : TxState := HTX_FINFO;
  1503.                 HTX_DATAACK  : TxState := HTX_XDATA;
  1504.                 HTX_EOFACK   : TxState := HTX_EOF;
  1505.                 HTX_ENDACK   : TxState := HTX_END;
  1506.               end;
  1507.             end;
  1508.         end; (*H_TXTIME*)
  1509.  
  1510.       (*---------------------------------------------------------------------*)
  1511.       H_DEVTXTIME :
  1512.         begin
  1513.           Inc(DevTxRetries);
  1514.           If (DevTxRetries > H_RETRIES) then
  1515.             begin
  1516.               hWin_Message('Aborting - Too many errors');
  1517.               TxState := HTX_DONE;
  1518.               Result  := XFER_ABORT;
  1519.               Goto Break;
  1520.             end;
  1521.  
  1522.           Str(DevTxRetries,St);
  1523.           hWin_Message('TimeOut - Retry ' + St);
  1524.  
  1525.           DevTxTimer := h_Timer_Reset;
  1526.           DevTxState := HTD_DATA;
  1527.         end; (*H_DEVTXTIME*)
  1528.  
  1529.       (*---------------------------------------------------------------------*)
  1530.       integer(HPKT_START) :
  1531.         begin
  1532.           If (TxState = HTX_START) or (TxState = HTX_SWAIT) then
  1533.             begin
  1534.               TxTimer   := h_Timer_Reset;
  1535.               TxRetries := 0;
  1536.               TxState   := HTX_INIT;
  1537.               BrainDead := h_Timer_Set(H_BRAINDEAD);
  1538.             end;
  1539.         end; (*HPKT_START*)
  1540.  
  1541.       (*---------------------------------------------------------------------*)
  1542.       integer(HPKT_INIT) :
  1543.         begin
  1544.           If (RxState = HRX_INIT) then
  1545.             begin
  1546.               Count := NulSearch(RxBuf^) + 1;
  1547.               WorkPtr := RxBuf;
  1548.               Inc(WorkPtr,Count);
  1549.               Index := Count + NulSearch(WorkPtr^) + 1;
  1550.               RxOptions := Options or HUNN_OPTIONS;
  1551.               WorkPtr := RxBuf;
  1552.               Inc(WorkPtr,Index);
  1553.               RxOptions := RxOptions or Get_Flags(WorkPtr);
  1554.               WorkPtr := RxBuf;
  1555.               Inc(WorkPtr,Count);
  1556.               RxOptions := RxOptions and Get_Flags(WorkPtr);
  1557.               RxOptions := RxOptions and HCAN_OPTIONS;
  1558.               If RxOptions < (Options and HNEC_OPTIONS) then
  1559.                 begin
  1560.                   hWin_Message('Incompatible on this link');
  1561.                   TxState := HTX_DONE;
  1562.                   Result  := XFER_ABORT;
  1563.                   Goto Break;
  1564.                 end;
  1565.  
  1566.               WorkPtr := RxBuf;
  1567.               Inc(WorkPtr,Index);
  1568.               Count := Index + NulSearch(WorkPtr^) + 1;
  1569.               WorkPtr := RxBuf;
  1570.               Inc(WorkPtr,Count);
  1571.               If NulSearch(WorkPtr^) < 16 then
  1572.                 begin
  1573.                   TxWindow := 0;
  1574.                   RxWindow := 0;
  1575.                 end
  1576.               else
  1577.                 begin
  1578.                   TxWindow := h_GetHex(Count + 8);
  1579.                   RxWindow := h_GetHex(Count);
  1580.                 end;
  1581.  
  1582.               If (RxWindow < 0) then RxWindow := 0;
  1583.               If (Hydra_RxWindow <> 0) and ((RxWindow = 0) or (Hydra_RxWindow < RxWindow)) then
  1584.                 RxWindow := Hydra_RxWindow;
  1585.               If (TxWindow < 0) then TxWindow := 0;
  1586.               If (Hydra_TxWindow <> 0) and ((TxWindow = 0) or (Hydra_TxWindow < TxWindow)) then
  1587.                  TxWindow := Hydra_TxWindow;
  1588.  
  1589.  
  1590.               WorkPtr := RxBuf;
  1591.               Inc(WorkPtr,Count);
  1592.               Index := Count + NulSearch(WorkPtr^) + 1;
  1593.               WorkPtr := RxBuf;
  1594.               Inc(WorkPtr,Index);
  1595.               Count := NulSearch(WorkPtr^);
  1596.               If Count > H_PKTPREFIX then Count := H_PKTPREFIX;
  1597.               Move(RxBuf^[Index], TxPktPrefix[1], Count);
  1598.               TxPktPrefix[0] := Chr(Count);
  1599.  
  1600.               If (BatchesDone = 0) then
  1601.                 begin
  1602. {
  1603.                   longint revstamp;
  1604.  
  1605.                   p := (char *) RxBuf;
  1606.                   sscanf(p,'%08lx',&revstamp);
  1607.                   hWin_Message(0,'*HYDRA: Other's HydraRev=%s',
  1608.                                h_revdate(revstamp));
  1609.                   p += 8;
  1610.                   If ((q := strchr(p,',')) <> NULL) *q := ' ';
  1611.                   If ((q := strchr(p,',')) <> NULL) *q := '/';
  1612.                   hWin_Message(0,'*HYDRA: Other's App.Info '%s'',p);
  1613.                   put_flags((char *) RxBuf,h_flags,RxOptions);
  1614.                   hWin_Message(1,'*HYDRA: Using link options '%s'',RxBuf);
  1615.                   If (TxWindow or RxWindow)
  1616.                      hWin_Message(0,'*HYDRA: Window tx=%ld rx=%ld',
  1617.                                    TxWindow,RxWindow);
  1618. }
  1619.                 end;
  1620.  
  1621.               If (RxOptions and HOPT_DEVICE <> 0) then
  1622.                 ChatTimer := 0
  1623.               else
  1624.                 ChatTimer := -2;
  1625.  
  1626.               TxOptions := RxOptions;
  1627.               RxState   := HRX_FINFO;
  1628.             end;
  1629.  
  1630.           TxPkt(0,HPKT_INITACK);
  1631.         end; (*HPKT_INIT*)
  1632.  
  1633.       (*---------------------------------------------------------------------*)
  1634.       integer(HPKT_INITACK) :
  1635.         begin
  1636.           If (TxState = HTX_INIT) or (TxState = HTX_INITACK) then
  1637.             begin
  1638.               BrainDead := h_Timer_Set(H_BRAINDEAD);
  1639.               TxTimer   := h_Timer_Reset;
  1640.               TxRetries := 0;
  1641.               TxState   := HTX_RINIT;
  1642.             end;
  1643.         end; (*HPKT_INITACK*)
  1644.  
  1645.       (*---------------------------------------------------------------------*)
  1646.       integer(HPKT_FINFO) :
  1647.         begin
  1648.           If (RxState = HRX_FINFO) then
  1649.             begin
  1650.               BrainDead := h_Timer_Set(H_BRAINDEAD);
  1651.               If (RxBuf^[0] = 0) then
  1652.                 begin
  1653.                   hWin_ClearRxWindow;
  1654.                   hWin_ShowRxFileName('-End Of Batch-');
  1655.                   RxPos   := 0;
  1656.                   RxState := HRX_DONE;
  1657.                   Inc(BatchesDone);
  1658.                 end
  1659.               else
  1660.                 begin
  1661.                   RxFTime := h_GetHex(0);
  1662.                   RxFSize := h_GetHex(8);
  1663.                   Index   := 5 * 8;
  1664.                   WorkPtr := RxBuf;
  1665.                   Inc(WorkPtr,Index);
  1666.                   Count   := NulSearch(WorkPtr^);
  1667.                   Move(WorkPtr^[0], RxFName[1], Count);
  1668.                   RxFName[0] := Chr(Count);
  1669.                   RxFName := StUpCase(RxFName);
  1670.  
  1671.                   hWin_ClearRxWindow;
  1672.                   hWin_ShowRxFileName(RxFName);
  1673.  
  1674.                   RxPathName := hFile_Check(RxFName,RxFSize,RxFTime);
  1675.  
  1676.                   If (RxPathName = '') then   (* Already have file *)
  1677.                     begin
  1678.                       hWin_Message('Already have ' + RxFName + ', Skipping');
  1679.                       RxPos := -1;
  1680.                     end
  1681.                   else
  1682.                     begin
  1683.                       If FileCheck(RxPathName) then  (*Resuming?*)
  1684.                         begin
  1685.                           FileMode := RW or DenyAll;
  1686.                           Assign(RxFd,RxPathName);
  1687.                           Reset(RxFd,1);
  1688.                           If (IOResult <> 0) then
  1689.                             begin
  1690.                               hWin_Message('Unable to re-open ' + RxPathName + ', Skipping');
  1691.                               RxPos := -2;
  1692.                             end;
  1693.                         end
  1694.                       else
  1695.                         begin
  1696.                           FileMode := RW or DenyAll;
  1697.                           Assign(RxFd,RxPathName);
  1698.                           Rewrite(RxFd,1);
  1699.                           If (IOResult <> 0) then
  1700.                             begin
  1701.                               hWin_Message('Unable to create ' + RxPathName + ', Skipping');
  1702.                               RxPos := -2;
  1703.                             end;
  1704.                         end;
  1705.  
  1706.                       If (FileRec(RxFd).Mode <> fmClosed) then
  1707.                         begin
  1708.                           hWin_ShowRxFileSize(RxFSize);
  1709.                           Seek(RxFd,FileSize(RxFd));
  1710.                           If (IOResult <> 0) then
  1711.                             begin
  1712.                               hWin_Message('File seek error');
  1713.                               Hydra_BadXfer;
  1714.                               RxPos := -2;
  1715.                             end
  1716.                           else
  1717.                             begin
  1718.                               RxOffset := FilePos(RxFd);
  1719.                               RxPos := RxOffset;
  1720.                               If (IOResult <> 0) then
  1721.                                 begin
  1722.                                   hWin_Message('File positioning error');
  1723.                                   Hydra_BadXfer;
  1724.                                   RxPos := -2;
  1725.                                 end
  1726.                               else If ((RxFSize - RxOffset) + 10240) > DiskFree(0) then
  1727.                                 begin
  1728.                                   hWin_Message('Not enough diskspace for ' + RxFName);
  1729.                                   Hydra_BadXfer;
  1730.                                   RxPos := -2;
  1731.                                 end
  1732.                               else
  1733.                                 begin
  1734.                                   RxStart    := 0;
  1735.                                   RxTimer    := h_Timer_Reset;
  1736.                                   RxRetries  := 0;
  1737.                                   RxLastSync := 0;
  1738.                                   RxSyncID   := 0;
  1739.                                   Hydra_Status(false);
  1740.                                   If (RxPos > 0) then
  1741.                                     hWin_Message('Resuming file');
  1742.                                   RxState := HRX_DATA;
  1743.                                 end;
  1744.                             end;
  1745.                         end;
  1746.                     end;
  1747.                 end;
  1748.             end
  1749.           else If (RxState = HRX_DONE) then
  1750.             begin
  1751.               If RxBuf^[0] = 0 then
  1752.                 RxPos := 0
  1753.               else
  1754.                 RxPos := -2;
  1755.             end;
  1756.  
  1757.           h_PutLong(1,RxPos);
  1758.           TxPkt(SizeOf(longint),HPKT_FINFOACK);
  1759.         end; (*HPKT_FINFO*)
  1760.  
  1761.         (*-------------------------------------------------------------------*)
  1762.         integer(HPKT_FINFOACK) :
  1763.           begin
  1764.             If (TxState = HTX_FINFO) or (TxState = HTX_FINFOACK) then
  1765.               begin
  1766.                 BrainDead := h_Timer_Set(H_BRAINDEAD);
  1767.                 TxRetries := 0;
  1768.                 If TxFName = '' then
  1769.                   begin
  1770.                     TxTimer := h_Timer_Set(H_IDLE);
  1771.                     TxState := HTX_REND;
  1772.                   end
  1773.                 else
  1774.                   begin
  1775.                     TxTimer := h_Timer_Reset;
  1776.                     TxPos   := h_GetLong(1);
  1777.                     If (TxPos >= 0) then
  1778.                       begin
  1779.                         TxOffset  := TxPos;
  1780.                         TxLastAck := TxPos;
  1781.                         Hydra_Status(true);
  1782.                         If (TxPos > 0) then
  1783.                           begin
  1784.                             hWin_Message('Transmit resuming file');
  1785.                             Seek(TxFd,TxPos);
  1786.                             If (IOResult <> 0) then
  1787.                               begin
  1788.                                 hWin_Message('File seek error');
  1789.                                 Close(TxFd);
  1790.                                 FileRec(TxFd).Mode := fmClosed;
  1791.                                 TxPos   := -2;
  1792.                                 TxState := HTX_EOF;
  1793.                                 Goto Break;
  1794.                               end;
  1795.                           end;
  1796.                         TxState := HTX_XDATA;
  1797.                       end
  1798.                     else
  1799.                       begin
  1800.                         Close(TxFd);
  1801.                         If (TxPos = -1) then
  1802.                           begin
  1803.                             hWin_Message('Remote skipped file ' + TxFName);
  1804.                             Hydra_Send := XFER_OK;
  1805.                             Exit;
  1806.                           end
  1807.                         else
  1808.                           begin  (* (TxPos < -1) file not sent *)
  1809.                             hWin_Message('Remote temporarily skipped ' + TxFName);
  1810.                             Hydra_Send := XFER_SKIP;
  1811.                             Exit;
  1812.                           end;
  1813.                       end;
  1814.                 end;
  1815.               end;
  1816.           end; (*HPKT_FINFOACK*)
  1817.  
  1818.         (*-------------------------------------------------------------------*)
  1819.         integer(HPKT_DATA) :
  1820.           begin
  1821.             If (RxState = HRX_DATA) then
  1822.               begin
  1823.                 If (h_GetLong(1) <> RxPos) or (h_GetLong(1) < 0) then
  1824.                   begin
  1825.                     If (h_GetLong(1) <= RxLastSync) then
  1826.                       begin
  1827.                         RxTimer   := h_Timer_Reset;
  1828.                         RxRetries := 0;
  1829.                       end;
  1830.                     RxLastSync := h_GetLong(1);
  1831.  
  1832.                     If (not h_Timer_Running(RxTimer)) or (h_Timer_Expired(RxTimer)) then
  1833.                       begin
  1834.                         If (RxRetries > 4) then
  1835.                           begin
  1836.                             If (TxState < HTX_REND) and (not Originator) and (not HdxLink) then
  1837.                               begin
  1838.                                 HdxLink   := true;
  1839.                                 RxRetries := 0;
  1840.                               end;
  1841.                            end;
  1842.                         Inc(RxRetries);
  1843.                         If (RxRetries > H_RETRIES) then
  1844.                           begin
  1845.                             hWin_Message('Too many errors');
  1846.                             TxState := HTX_DONE;
  1847.                             Result  := XFER_ABORT;
  1848.                             Goto Break;
  1849.                           end;
  1850.                         If (RxRetries = 1) or (RxRetries = 4) then
  1851.                           Inc(RxSyncID);
  1852.  
  1853.                         RxBlkLen := (RxBlkLen shr 1);
  1854. (***DEBUG***            RxBlkLen := Trunc(RxBlkLen / 2); *)
  1855.                         Counter  := RxBlkLen;
  1856.                         If (Counter <= 64) then Counter := 64
  1857.                           else If (Counter <= 128) then Counter := 128
  1858.                           else If (Counter <= 256) then Counter := 256
  1859.                           else If (Counter <= 512) then Counter := 512
  1860.                           else Counter := 1024;
  1861.  
  1862.                         hWin_Message('Bad packet at ' + Long2Str(RxPos) + ' - Retry ' + Long2Str(RxRetries));
  1863.                         h_PutLong(1,RxPos);
  1864.                         h_PutLong(2,longint(Counter));
  1865.                         h_PutLong(3,RxSyncID);
  1866.                         TxPkt(3 * SizeOf(longint),HPKT_RPOS);
  1867.                         RxTimer := h_Timer_Set(TimeOut);
  1868.                       end;
  1869.                   end
  1870.                 else
  1871.                   begin
  1872.                     BrainDead := h_Timer_Set(H_BRAINDEAD);
  1873.                     Dec(RxPktLen,SizeOf(longint));
  1874.                     RxBlkLen := RxPktLen;
  1875.                     WorkPtr := RxBuf;
  1876.                     Inc(WorkPtr,SizeOf(longint));
  1877.                     BlockWrite(RxFd,WorkPtr^,RxBlkLen);
  1878.                     If (IOResult <> 0) then
  1879.                       begin
  1880.                         hWin_Message('File write error');
  1881.                         Hydra_BadXfer;
  1882.                         RxPos     := -2;
  1883.                         RxRetries := 1;
  1884.                         Inc(RxSyncID);
  1885.                         h_PutLong(1,RxPos);
  1886.                         h_PutLong(2,0);
  1887.                         h_PutLong(3,RxSyncID);
  1888.                         TxPkt(3 * SizeOf(longint),HPKT_RPOS);
  1889.                         RxTimer := h_Timer_Set(TimeOut);
  1890.                         Goto Break;
  1891.                       end;
  1892.  
  1893.                     RxRetries  := 0;
  1894.                     RxTimer    := h_Timer_Reset;
  1895.                     RxLastSync := RxPos;
  1896.                     Inc(RxPos,RxPktLen);
  1897.                     If (RxWindow > 0) then
  1898.                       begin
  1899.                         h_PutLong(1,RxPos);
  1900.                         TxPkt(SizeOf(longint),HPKT_DATAACK);
  1901.                       end;
  1902.                     If (RxStart = 0) then
  1903.                       RxStart := h_Timer_Get - Trunc((RxPktLen * 10) / Hydra_Speed);
  1904.                     Hydra_Status(false);
  1905.                   end;
  1906.               end; (*RxState=HRX_DATA*)
  1907.           end; (*HPKT_DATA*)
  1908.  
  1909.         (*-------------------------------------------------------------------*)
  1910.         integer(HPKT_DATAACK) :
  1911.           begin
  1912.             If (TxState = HTX_XDATA) or (TxState = HTX_DATAACK) or (TxState = HTX_XWAIT) or
  1913.                (TxState = HTX_EOF)   or (TxState = HTX_EOFACK) then
  1914.               begin
  1915.                 If (TxWindow > 0) and (h_GetLong(1) > TxLastAck) then
  1916.                   begin
  1917.                     TxLastAck := h_GetLong(1);
  1918.                     If (TxState = HTX_DATAACK) and (TxPos < (TxLastAck + TxWindow)) then
  1919.                       begin
  1920.                         TxState   := HTX_XDATA;
  1921.                         TxRetries := 0;
  1922.                         TxTimer   := h_Timer_Reset;
  1923.                       end;
  1924.                   end;
  1925.               end;
  1926.           end; (*HPKT_DATAACK*)
  1927.  
  1928.         (*-------------------------------------------------------------------*)
  1929.         integer(HPKT_RPOS) :
  1930.           begin
  1931.             If (TxState = HTX_XDATA) or (TxState = HTX_DATAACK) or (TxState = HTX_XWAIT) or
  1932.                (TxState = HTX_EOF)   or (TxState = HTX_EOFACK) then
  1933.               begin
  1934.                 If (h_GetLong(3) <> TxSyncID) then
  1935.                   begin
  1936.                     TxSyncID  := h_GetLong(3);
  1937.                     TxRetries := 1;
  1938.                   end
  1939.                 else
  1940.                   begin
  1941.                     Inc(TxRetries);
  1942.                     If (TxRetries > H_RETRIES) then
  1943.                       begin
  1944.                         hWin_Message('Too many errors');
  1945.                         TxState := HTX_DONE;
  1946.                         Result  := XFER_ABORT;
  1947.                         Goto Break;
  1948.                       end;
  1949.                     If (TxRetries <> 4) then Goto Break;
  1950.                   end;
  1951.  
  1952.                 TxTimer := h_Timer_Reset;
  1953.                 TxPos   := h_GetLong(1);
  1954.                 If (TxPos < 0) then
  1955.                   begin
  1956.                     If (FileRec(TxFd).Mode <> fmClosed) then
  1957.                       begin
  1958.                         hWin_Message('Skipping ' + TxFName);
  1959.                         Close(TxFd);
  1960.                         FileRec(TxFd).Mode := fmClosed;
  1961.                         TxState := HTX_EOF;
  1962.                       end;
  1963.                     TxPos := -2;
  1964.                     Goto Break;
  1965.                   end;
  1966.  
  1967.                 If (TxBlkLen > h_GetLong(2)) then
  1968.                   TxBlkLen := h_GetLong(2)
  1969.                 else
  1970.                   TxBlkLen := TxBlkLen shr 1;
  1971.                 If (TxBlkLen <= 64) then TxBlkLen := 64
  1972.                   else If (TxBlkLen <= 128) then TxBlkLen := 128
  1973.                   else If (TxBlkLen <= 256) then TxBlkLen := 256
  1974.                   else If (TxBlkLen <= 512) then TxBlkLen := 512
  1975.                   else TxBlkLen := 1024;
  1976.  
  1977.                 TxGoodBytes := 0;
  1978.                 Inc(TxGoodNeeded, TxMaxBlkLen * 2);
  1979.                 If (TxGoodNeeded > (TxMaxBlkLen * 8)) then
  1980.                   TxGoodNeeded := (TxMaxBlkLen * 8);
  1981.  
  1982.                 Hydra_Status(true);
  1983.                 hWin_Message('Resending from offset ' + Long2Str(TxPos));
  1984.                 Seek(TxFd,TxPos);
  1985.                 If (IOResult <> 0) then
  1986.                   begin
  1987.                     hWin_Message('File seek error');
  1988.                     Close(TxFd);
  1989.                     FileRec(TxFd).Mode := fmClosed;
  1990.                     TxPos   := -2;
  1991.                     TxState := HTX_EOF;
  1992.                     Goto Break;
  1993.                   end;
  1994.  
  1995.                 If (TxState <> HTX_XWAIT) then
  1996.                   TxState := HTX_XDATA;
  1997.               end;
  1998.           end; (*HPKT_RPOS*)
  1999.  
  2000.         (*-------------------------------------------------------------------*)
  2001.         integer(HPKT_EOF) :
  2002.           begin
  2003.             If (RxState = HRX_DATA) then
  2004.               begin
  2005.                 If (h_GetLong(1) < 0) then
  2006.                   begin
  2007.                     Hydra_BadXfer;
  2008.                     hWin_Message('Remote skipping ' + RxFName);
  2009.                     RxState   := HRX_FINFO;
  2010.                     BrainDead := h_Timer_Set(H_BRAINDEAD);
  2011.                   end
  2012.                 else If (h_GetLong(1) <> RxPos) then
  2013.                   begin
  2014.                     If (h_GetLong(1) <= RxLastSync) then
  2015.                       begin
  2016.                         RxTimer   := h_Timer_Reset;
  2017.                         RxRetries := 0;
  2018.                       end;
  2019.                     RxLastSync := h_GetLong(1);
  2020.  
  2021.                     If (not h_Timer_Running(RxTimer)) or (h_Timer_Expired(RxTimer)) then
  2022.                       begin
  2023.                         Inc(RxRetries);
  2024.                         If (RxRetries > H_RETRIES) then
  2025.                           begin
  2026.                             hWin_Message('Too many errors');
  2027.                             TxState := HTX_DONE;
  2028.                             Result  := XFER_ABORT;
  2029.                             Goto Break;
  2030.                           end;
  2031.                         If (RxRetries = 1) or (RxRetries = 4) then
  2032.                           Inc(RxSyncID);
  2033.  
  2034.                         RxBlkLen := (RxBlkLen shr 1);
  2035. (***DEBUG***            RxBlkLen := Trunc(RxBlkLen / 2); *)
  2036.                         Counter  := RxBlkLen;
  2037.                         If (Counter <= 64) then Counter := 64
  2038.                           else If (Counter <= 128) then Counter := 128
  2039.                           else If (Counter <= 256) then Counter := 256
  2040.                           else If (Counter <= 512) then Counter := 512
  2041.                           else Counter := 1024;
  2042.  
  2043.                         hWin_Message('Bad EOF at ' + Long2Str(RxPos) + ' - Retry ' + Long2Str(RxRetries));
  2044.                         h_PutLong(1,RxPos);
  2045.                         h_PutLong(2,Counter);
  2046.                         h_PutLong(3,RxSyncID);
  2047.                         TxPkt(3 * SizeOf(longint),HPKT_RPOS);
  2048.                         RxTimer := h_Timer_Set(TimeOut);
  2049.                       end;
  2050.                   end
  2051.                 else
  2052.                   begin
  2053.                     RxFSize := RxPos;
  2054.                     SetFTime(RxFd,h_FromUnixDate(RxFTime));
  2055.  
  2056.                     Close(RxFd);
  2057.                     FileRec(RxFd).Mode := fmClosed;
  2058.                     Hydra_Pct(false);
  2059.  
  2060.                     If hFile_Okay(RxPathName,RxFTime) then;
  2061.  
  2062.                     Hydra_Status(false);
  2063.                     hWin_Message('Received ' + RxFName);
  2064.                     RxState   := HRX_FINFO;
  2065.                     BrainDead := h_Timer_Set(H_BRAINDEAD);
  2066.                   end;
  2067.               end; (*RxState=HRX_DATA*)
  2068.  
  2069.             If (RxState = HRX_FINFO) then
  2070.               TxPkt(0,HPKT_EOFACK);
  2071.           end; (*HPKT_EOF*)
  2072.  
  2073.         (*-------------------------------------------------------------------*)
  2074.         integer(HPKT_EOFACK) :
  2075.           begin
  2076.             If (TxState = HTX_EOF) or (TxState = HTX_EOFACK) then
  2077.               begin
  2078.                 BrainDead := h_Timer_Set(H_BRAINDEAD);
  2079.                 If (FileRec(TxFd).Mode <> fmClosed) then
  2080.                   begin
  2081.                     TxFSize := TxPos;
  2082.                     Close(TxFd);
  2083.                     Hydra_Pct(true);
  2084.                     Hydra_Send := XFER_OK;
  2085.                     Exit;
  2086.                   end
  2087.                 else
  2088.                   begin
  2089.                     Hydra_Send := XFER_SKIP;
  2090.                     Exit
  2091.                   end;
  2092.               end;
  2093.           end; (*HPKT_EOFACK*)
  2094.  
  2095.         (*-------------------------------------------------------------------*)
  2096.         integer(HPKT_IDLE) :
  2097.           begin
  2098.             If (TxState = HTX_XWAIT) then
  2099.               begin
  2100.                 HdxLink   := false;
  2101.                 TxTimer   := h_Timer_Reset;
  2102.                 TxRetries := 0;
  2103.                 TxState   := HTX_XDATA;
  2104.               end
  2105.             else If (TxState >= HTX_FINFO) and (TxState < HTX_REND) then
  2106.               BrainDead := h_Timer_Set(H_BRAINDEAD);
  2107.           end; (*HPKT_IDLE*)
  2108.  
  2109.         (*-------------------------------------------------------------------*)
  2110.         integer(HPKT_END) :
  2111.           begin
  2112.             (* special for chat, other side wants to quit *)
  2113.             If (ChatTimer > 0) and (TxState = HTX_REND) then
  2114.               begin
  2115.                 ChatTimer := -3;
  2116.                 Goto Break;
  2117.               end;
  2118.  
  2119.             If (TxState = HTX_END) or (TxState = HTX_ENDACK) then
  2120.               begin
  2121.                 TxPkt(0,HPKT_END);
  2122.                 TxPkt(0,HPKT_END);
  2123.                 TxPkt(0,HPKT_END);
  2124.                 hWin_Message('Session completed');
  2125.                 TxState := HTX_DONE;
  2126.                 Result  := XFER_OK;
  2127.               end;
  2128.           end; (*HPKT_END*)
  2129.  
  2130.         (*-------------------------------------------------------------------*)
  2131.         integer(HPKT_DEVDATA) :
  2132.           begin
  2133.             If (DevRxID <> h_GetLong(1)) then
  2134.               begin
  2135.                 Hydra_DevRecv;
  2136.                 DevRxID := h_GetLong(1);
  2137.               end;
  2138.             h_PutLong(1,h_GetLong(1));
  2139.             TxPkt(SizeOf(longint),HPKT_DEVDACK);
  2140.           end; (*HPKT_DEVDATA*)
  2141.  
  2142.         (*-------------------------------------------------------------------*)
  2143.         integer(HPKT_DEVDACK) :
  2144.           begin
  2145.             If (DevTxState <> HTD_DONE) and (DevTxID = h_GetLong(1)) then
  2146.               begin
  2147.                 DevTxTimer := h_Timer_Reset;
  2148.                 DevTxState := HTD_DONE;
  2149.               end;
  2150.           end; (*HPKT_DEVDACK*)
  2151.  
  2152.     (*-----------------------------------------------------------------------*)
  2153.     (* ELSE: Unknown packet types: IGNORE, no error! *)
  2154.  
  2155.     end; (*CASE PktType*)
  2156.  
  2157. Break:
  2158.  
  2159.     (*-----------------------------------------------------------------------*)
  2160.     Case (TxState) of
  2161.       HTX_START,
  2162.       HTX_SWAIT :
  2163.         begin
  2164.           If (RxState = HRX_FINFO) then
  2165.             begin
  2166.               TxTimer   := h_Timer_Reset;
  2167.               TxRetries := 0;
  2168.               TxState   := HTX_INIT;
  2169.             end;
  2170.         end;
  2171.  
  2172.       (*---------------------------------------------------------------------*)
  2173.       HTX_RINIT :
  2174.         begin
  2175.           If (RxState = HRX_FINFO) then
  2176.             begin
  2177.               TxTimer   := h_Timer_Reset;
  2178.               TxRetries := 0;
  2179.               TxState   := HTX_FINFO;
  2180.             end;
  2181.         end;
  2182.  
  2183.       (*---------------------------------------------------------------------*)
  2184.       HTX_XDATA :
  2185.         begin
  2186.           If (RxState <> HRX_DONE) and (HdxLink) then
  2187.             begin
  2188.               hWin_Message(HdxMsg);
  2189.               WorkPtr := @HdxMsg;
  2190.               Inc(WorkPtr);
  2191.               If Hydra_DevSend('MSG', WorkPtr, Length(HdxMsg)) then;
  2192.  
  2193.               TxTimer := h_Timer_Set(H_IDLE);
  2194.               TxState := HTX_XWAIT;
  2195.             end;
  2196.         end;
  2197.  
  2198.       (*---------------------------------------------------------------------*)
  2199.       HTX_XWAIT :
  2200.         begin
  2201.           If (RxState = HRX_DONE) then
  2202.             begin
  2203.               TxTimer   := h_Timer_Reset;
  2204.               TxRetries := 0;
  2205.               TxState   := HTX_XDATA;
  2206.             end;
  2207.         end;
  2208.  
  2209.       (*---------------------------------------------------------------------*)
  2210.       HTX_REND :
  2211.         begin
  2212.           If (RxState = HRX_DONE) and (DevTxState = HTD_DONE) then
  2213.             begin
  2214.               (*Special for chat, BrainDead will protect*)
  2215.               If (ChatTimer <= 0) then
  2216.                 begin
  2217.                   If (ChatTimer = 0) Then ChatTimer := -3;
  2218.                   TxTimer   := h_Timer_Reset;
  2219.                   TxRetries := 0;
  2220.                   TxState   := HTX_END;
  2221.                 end;
  2222.             end;
  2223.         end;
  2224.     end; (*CASE TxState*)
  2225.  
  2226.   Until TxState = HTX_DONE;
  2227.  
  2228.   If FileRec(TxFd).Mode <> fmClosed then
  2229.     Close(TxFd);
  2230.   Hydra_BadXfer;
  2231.  
  2232.   If (Result = XFER_ABORT) then
  2233.     begin
  2234.       Com_TxFlush;
  2235.       If (Com_Carrier) then
  2236.         begin
  2237.           Com_TxBlock(AbortStr,SizeOf(AbortStr));
  2238.           Repeat
  2239.           Until (Com_TxEmpty) or (not Com_Carrier);
  2240.         end;
  2241.       Com_RxFlush;
  2242.     end
  2243.   else
  2244.     begin
  2245.       Repeat
  2246.       Until (Com_TxEmpty) or (not Com_Carrier);
  2247.     end;
  2248.  
  2249.   Hydra_Send := Result;
  2250. end; (*Hydra*)
  2251.  
  2252. (**********************************MAINLINE************************************)
  2253.  
  2254. end.
  2255.  
  2256.