home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Pascal / Applications / ircle 1.5.1 / source / ircle sources / DCC.p < prev    next >
Encoding:
Text File  |  1993-10-12  |  16.4 KB  |  737 lines  |  [TEXT/PJMM]

  1. {    ircle - Internet Relay Chat client    }
  2. {    File: DCC    }
  3. {    Copyright © 1992 Olaf Titz (s_titz@ira.uka.de)    }
  4.  
  5. {    This program is free software; you can redistribute it and/or modify    }
  6. {    it under the terms of the GNU General Public License as published by    }
  7. {    the Free Software Foundation; either version 2 of the License, or    }
  8. {    (at your option) any later version.    }
  9.  
  10. {    This program is distributed in the hope that it will be useful,    }
  11. {    but WITHOUT ANY WARRANTY; without even the implied warranty of    }
  12. {    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    }
  13. {    GNU General Public License for more details.    }
  14.  
  15. {    You should have received a copy of the GNU General Public License    }
  16. {    along with this program; if not, write to the Free Software    }
  17. {    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.    }
  18.  
  19. unit DCC;
  20. { Handles DCC connections }
  21.  
  22. interface
  23. uses
  24.     TCPTypes, TCPStuff, TCPConnections, ApplBase, MiscGlue, MsgWindows, {}
  25.     IRCGlobals, IRCaux, IRCChannels;
  26.  
  27. procedure InitDCC;
  28. { startup }
  29.  
  30. procedure DCCRequest (var fr, s: string);
  31. { Request for DCC from outside }
  32.  
  33. procedure DCCcommand (var s: string);
  34. { user DCC command }
  35.  
  36. procedure DCCChatSend (var s: string);
  37. { send line over DCC CHAT }
  38.  
  39. implementation
  40. { Largely an adaption of the IRCII DCC code by Troy Rollo }
  41.  
  42. {$SETC DCCenable=true}
  43. {$SETC DEBUG=false}
  44.  
  45. {$IFC DISTRIBUTION }
  46. {$SETC DEBUG=FALSE }
  47. {$ENDC}
  48.  
  49. const
  50.     BUFSIZ = 4096;
  51.  
  52. {$IFC DCCenable}
  53. type
  54.     DCCType = (CHAT, SEND, GET);
  55.     DCCFlagsType = (CLOSED, WAITING, OFFERED, OPENING, OPEN);
  56.     DCCPtr = ^DCCrec;
  57.     DCCrec = record
  58.             next: DCCPtr;            { Link }
  59.             flag: DCCFlagsType;    { status }
  60.             peer: string[16];        { peer (nick) }
  61.             host, port: longint;        { TCP host/port }
  62.             sock: ConnectionIndex;    { socket }
  63.             case typ : DCCType of
  64.                 CHAT: (
  65.                         win: MWHndl;    { window for DCC CHAT messages }
  66.                 );
  67.                 SEND: (
  68.                         sfil: SFReply;    { contains file parameters }
  69.                         sfref: integer;    { file refnum }
  70.                         stext: boolean;    { textfile conversion }
  71.                         sendbuf: CharsPtr;{ Buffer pointer }
  72.                         sent: longint;    { Bytes already sent }
  73.                         sendmax: longint;    { Bytes to send }
  74.                 );
  75.                 GET: (
  76.                         gfil: SFReply;    { contains file parameters }
  77.                         gfref: integer;    { file refnum }
  78.                         gtext: boolean;    { textfile conversion }
  79.                         getbuf: CharsPtr;    { Buffer pointer }
  80.                         gotten: longint;    { Bytes received }
  81.                 );
  82.         end;
  83.  
  84. var
  85.     FDCC: DCCPtr;
  86.  
  87. { The following is really not beautiful, but DCC protocol requires IP addresses }
  88. { to be given as unsigned long in ASCII, while this compiler has only signed longint. Sigh. }
  89. {$V-}
  90. function ulongval (var s: string): longint;
  91.     var
  92.         l: longint;
  93.         i, j: integer;
  94.     begin
  95.         l := 0;
  96.         i := 1;
  97.         repeat
  98.             if i > length(s) then
  99.                 leave;
  100.             j := ord(s[i]) - 48;
  101.             if (j < 0) or (j > 9) then
  102.                 leave;
  103.             l := 10 * l + j;
  104.             i := succ(i);
  105.         until false;
  106.         ulongval := l;
  107.     end;
  108.  
  109. procedure str10neg (var s: string);
  110. { Given s as a 10-digit ASCII number, this will compute 2^32-s, i.e. the }
  111. { 32-bit twos complement of s. }
  112.     var
  113.         y: string[10];
  114.         i, x, c: integer;
  115.     begin
  116.         y := '4294967296'; { 2^32 }
  117.         c := 0;
  118.         for i := 10 downto 1 do begin
  119.             x := ord(y[i]) - ord(s[i]) - c;
  120.             if x < 0 then begin
  121.                 c := 1;
  122.                 x := x + 10
  123.             end
  124.             else
  125.                 c := 0;
  126.             s[i] := chr(x + 48)
  127.         end
  128.     end;
  129.  
  130. procedure ulongstr (l: longint; var s: string);
  131.     var
  132.         i: integer;
  133.         n: boolean;
  134.     begin
  135.         if l = 0 then
  136.             debugstr('Bogus IP/port number 0'); { here it is guaranteed to be nonzero! }
  137.         n := (l < 0);
  138.         l := abs(l);
  139.         for i := 10 downto 1 do begin
  140.             s[i] := chr((l mod 10) + 48);
  141.             l := l div 10
  142.         end;
  143.         s[0] := chr(10);
  144.         if n then
  145.             str10neg(s);
  146.         while s[1] = '0' do
  147.             delete(s, 1, 1);
  148.     end;
  149.  
  150.  
  151. { U*X open/create substitutes }
  152.  
  153. function openoldfile (x: DCCPtr): OSErr;
  154.     begin
  155.         openoldfile := FSOpen(x^.sfil.fName, x^.sfil.vRefNum, x^.sfref)
  156.     end;
  157.  
  158. function opennewfile (x: DCCPtr): OSErr;
  159.     var
  160.         e: OSErr;
  161.         b1, b2: OSType;
  162.     begin
  163.         if x^.gtext then begin
  164.             b1 := 'EDIT';
  165.             b2 := 'TEXT';
  166.         end
  167.         else begin
  168.             b1[0] := chr(0);
  169.             b1[1] := chr(0);
  170.             b1[2] := chr(0);
  171.             b1[3] := chr(0);
  172.             b2 := b1
  173.         end;
  174.         e := create(x^.gfil.fName, x^.gfil.vRefNum, b1, b2);
  175.         if (e = noErr) or (e = dupFNErr) then
  176.             e := openoldfile(x); { XX: assumes sfil==gfil }
  177.         opennewfile := e
  178.     end;
  179.  
  180. function getDCC (ty: DCCType; var from: string; var f: DCCPtr): boolean;
  181. { will return true if dcc already existed, allocate it otherwise }
  182.     begin
  183.         getDCC := true;
  184.         f := FDCC;
  185.         while f <> nil do
  186.             with f^ do begin
  187.                 if (typ = ty) and (peer = from) then
  188.                     exit(getDCC);
  189.                 f := f^.next;
  190.             end;
  191.         new(f);
  192.         if f = nil then
  193.             exit(getDCC); { error condition, will lead to collision msg }
  194.         with f^ do begin
  195.             next := FDCC;
  196.             typ := ty;
  197.             flag := CLOSED;
  198.             peer := from;
  199.             host := 0;
  200.             port := 0;
  201.             sock := 0;
  202.             win := nil;
  203.             sfref := 0;
  204.             if (ty = SEND) or (ty = GET) then { XX: assume sendbuf==getbuf }
  205.                 begin
  206.                 sendbuf := CharsPtr(NewPtr(BUFSIZ));
  207.                 if MemError <> 0 then
  208.                     exit(getDCC);
  209.             end;
  210.         end;
  211.         FDCC := f;
  212.         getDCC := false;
  213.     end;
  214.  
  215. procedure killDCC (x: DCCPtr);
  216.     var
  217.         p: DCCPtr;
  218.         t: string[12];
  219.         i: integer;
  220.     begin
  221.         if x^.sock <> 0 then    { Forcibly close connection }
  222.             AbortConnection(x^.sock);
  223.         if x^.win <> nil then begin    { inactivate chat window }
  224.             t := concat(DCC_CHAT_PREFIX, x^.peer, DCC_CHAT_POSTFIX);
  225.             Inactive(t);
  226.             x^.win := nil
  227.         end;
  228.         if x^.sfref <> 0 then    { close file }
  229.             i := FSClose(x^.sfref);
  230.         if (x^.typ = SEND) or (x^.typ = GET) then begin
  231.             DisposPtr(Ptr(x^.sendbuf));
  232.             if x^.flag = OPEN then begin    { sync FT counter }
  233.                 NFT := pred(NFT);
  234.                 UpdateStatusLine
  235.             end
  236.         end;
  237.         if x = FDCC then
  238.             FDCC := x^.next
  239.         else begin
  240.             p := FDCC;
  241.             while p^.next <> x do begin
  242.                 if p^.next = nil then
  243.                     debugstr('Error in DCC chain');
  244.                 p := p^.next
  245.             end;
  246.             p^.next := x^.next;
  247.         end;
  248.         dispose(x);
  249.     end;
  250.  
  251. { Cleanly close DCC }
  252. procedure closeDCC (x: DCCPtr);
  253.     begin
  254.         if x^.sock <> 0 then begin
  255.             CloseConnection(x^.sock);
  256.             x^.sock := 0;
  257.         end;
  258.         killDCC(x)
  259.     end;
  260.  
  261. { Give message for failed DCC and close }
  262. procedure failedDCC (x: DCCPtr; e: string);
  263.     var
  264.         s: string[120];
  265.     begin
  266.         s := stringof('*** ', e, ' DCC ', x^.typ, ' connection to ', x^.peer);
  267.         Message(s);
  268.         killDCC(x)
  269.     end;
  270.  
  271. { This gets called on user closing active DCC CHAT window }
  272. procedure closeDChat (w: WindowPtr);
  273.     var
  274.         x: DCCPtr;
  275.         t: str255;
  276.         inac: boolean;
  277.     begin
  278.         GetWTitle(w, t);
  279.         DoPart(t);
  280.         delete(t, 1, 1);
  281.         t[0] := pred(t[0]);
  282.         if not inac then begin
  283.             if not getDCC(CHAT, t, x) then
  284.                 debugstr(concat('Bogus DCC CHAT window ', t));
  285.             x^.win := nil; { window is already closed }
  286.             CloseDCC(x);
  287.         end;
  288.     end;
  289.  
  290. { Send a portion of BUFSIZ bytes over DCC. }
  291. { XX: DCC SEND protocol assumes that receiver sends acknowledge as }
  292. { four byte high-endian integer (htonl format). Mac is high-endian so no conversion is needed. }
  293. procedure DCCsendfile (p: DCCPtr; c: TCPConnectionPtr);
  294.     var
  295.         nn: longint;
  296.         i, e: integer;
  297.         s: string[80];
  298.     begin
  299.         nn := p^.sendmax;
  300.         if nn = 0 then begin
  301.             s := stringof('*** Completed DCC SEND to ', p^.peer);
  302.             Message(s);
  303.             CloseDCC(p);
  304.             exit(DCCSendfile)
  305.         end;
  306.         if nn > BUFSIZ then
  307.             nn := BUFSIZ;
  308.         if FSRead(p^.sfref, nn, Ptr(p^.sendbuf)) = 0 then begin
  309.             if p^.stext then
  310.                 for i := 0 to nn - 1 do
  311.                     p^.sendbuf^[i] := ISOEncode^^[p^.sendbuf^[i]];
  312.             p^.sendmax := p^.sendmax - nn;
  313.             p^.sent := p^.sent + nn;
  314. {$IFC DEBUG}
  315.             s := stringof('* Sending ', nn : 1, ' bytes');
  316.             Message(s);
  317. {$ENDC}
  318.             e := 0;
  319.             i := TCPSendAsync(c, Ptr(p^.sendbuf), nn, false, @e);
  320.             if i = 0 then begin
  321.                 repeat
  322.                     ApplRun
  323.                 until i <> inProgress;
  324.             end;
  325.             if (i <> 0) or (e <> 0) then
  326.                 failedDCC(p, 'Lost (send error)');
  327.         end
  328.         else
  329.             failedDCC(p, 'Lost (file read error)');
  330.     end;
  331.  
  332.  
  333. procedure DCCgotline (p: DCCPtr; c: CEPtr);
  334.     var
  335.         s: string;
  336.         nn: longint;
  337.         b: boolean;
  338.         i, j: integer;
  339.     begin
  340.         case p^.typ of
  341.             CHAT: 
  342.                 begin
  343.                 nn := 1;
  344.                 if TCPReceiveUpTo(c^.tcpc, 10, readTimeout, @s[0], 250, nn, b) = 0 then begin
  345.                     j := nn - 1;
  346.                     while (j > 0) and ((s[j] = chr(10)) or (s[j] = chr(13))) do
  347.                         j := pred(j);
  348.                     s[0] := chr(j);
  349.                     for i := 1 to j do
  350.                         s[i] := ISODecode^^[s[i]];
  351.                     MWMessage(p^.win, s);
  352.                 end
  353.             end;
  354.             SEND: 
  355.                 begin
  356.                 if TCPReceiveChars(c^.tcpc, @nn, sizeof(nn)) = 0 then begin
  357.  {$IFC DEBUG}
  358.                     s := stringof('* Acknowledged ', nn : 1, ' bytes');
  359.                     Message(s);
  360. {$ENDC}
  361.                     if nn = p^.sent then
  362.                         DCCsendfile(p, c^.tcpc)
  363.                     else if nn > p^.sent then
  364.                         failedDCC(p, 'Lost (bogus acknowledge)')
  365.                 end
  366.                 else
  367.                     failedDCC(p, 'Lost (no acknowledge)');
  368.             end;
  369.             GET: 
  370.                 begin
  371.                 nn := TCPCharsAvailable(c^.tcpc);
  372.                 if nn > BUFSIZ then
  373.                     nn := BUFSIZ;
  374.                 if TCPReceiveChars(c^.tcpc, Ptr(p^.getbuf), nn) = 0 then begin
  375.                     if p^.gtext then begin
  376.                         for i := 0 to nn - 1 do
  377.                             p^.getbuf^[i] := ISODecode^^[p^.getbuf^[i]];
  378.                     end;
  379.                     if FSWrite(p^.gfref, nn, Ptr(p^.getbuf)) = 0 then begin
  380.                         p^.gotten := p^.gotten + nn;
  381. {$IFC DEBUG}
  382.                         s := stringof('* Received ', p^.gotten : 1, ' bytes');
  383.                         Message(s);
  384. {$ENDC}
  385.                         if TCPSend(c^.tcpc, @p^.gotten, sizeof(longint), true) <> 0 then
  386.                             failedDCC(p, 'Lost');
  387.                     end
  388.                     else
  389.                         failedDCC(p, 'Lost (file write error)');
  390.                 end
  391.                 else
  392.                     failedDCC(p, 'Lost (receive error)');
  393.             end;
  394.         end;
  395.     end;
  396.  
  397. procedure DCCConnOpened (p: DCCPtr; c: CEPtr);
  398.     var
  399.         t: string[16];
  400.     begin
  401.         p^.flag := OPEN;
  402.         case p^.typ of
  403.             CHAT: 
  404.                 begin
  405.                 t := concat(DCC_CHAT_PREFIX, p^.peer, DCC_CHAT_POSTFIX);
  406.                 p^.win := DoJoin(t);
  407.                 if p^.win <> nil then
  408.                     p^.win^^.whenDone := @closeDChat; { XX }
  409.             end;
  410.             SEND: 
  411.                 begin
  412.                 NFT := succ(NFT);
  413.                 UpdateStatusLine;
  414.                 if openoldfile(p) = 0 then begin
  415.                     if getEOF(p^.sfref, p^.sendmax) = 0 then begin
  416.                         p^.sent := 0;
  417.                         DCCsendfile(p, c^.tcpc);
  418.                         exit(DCCConnOpened)
  419.                     end;
  420.                 end;
  421.                 killDCC(p);
  422.             end;
  423.             GET: 
  424.                 begin
  425.                 if opennewfile(p) = 0 then begin
  426.                     NFT := succ(NFT);
  427.                     UpdateStatusLine;
  428.                     p^.gotten := 0;
  429.                 end
  430.                 else
  431.                     killDCC(p)
  432.             end;
  433.         end;
  434.     end;
  435.  
  436.  
  437. function netEvent (var e: EventRecord): boolean;
  438.     var
  439.         p: DCCPtr;
  440.         c: CEPtr;
  441.     begin
  442.         c := CEPtr(e.message);
  443.         p := FDCC;
  444.         while p <> nil do begin
  445.             if p^.sock = c^.connection then begin
  446.                 case c^.event of
  447.                     C_Established: 
  448.                         DCCConnOpened(p, c);
  449.                     C_FailedToOpen: 
  450.                         failedDCC(p, 'Failed to open');
  451.                     C_Closing: 
  452.                         failedDCC(p, 'Closing');
  453.                     C_Closed: 
  454.                         failedDCC(p, 'Closed');
  455.                     C_CharsAvailable: 
  456.                         DCCgotline(p, c)
  457.                 end;
  458.                 netEvent := true;
  459.                 exit(netEvent)
  460.             end;
  461.             p := p^.next;
  462.         end;
  463.         netEvent := false;
  464.     end;
  465.  
  466. procedure openDCC (x: DCCPtr);
  467.     var
  468.         t: TCPConnectionPtr;
  469.         ipa, pn: string[12];
  470.         des: string[64];
  471.         s: string[150];
  472.         i: integer;
  473.     begin
  474.         if x^.flag = CLOSED then begin
  475.             if TCPGetMyIPAddr(x^.host) = 0 then
  476.                 if NewPassiveConnection(x^.sock, 8192, 0, 0, 0, nil) = 0 then begin
  477.                     GetConnectionTCPC(x^.sock, t);
  478.                     x^.port := TCPLocalPort(t);
  479.                     ulongstr(x^.host, ipa);
  480.                     if x^.port < 0 then
  481.                         x^.port := x^.port + 65536;
  482.                     ulongstr(x^.port, pn);
  483.                     if x^.typ = CHAT then
  484.                         des := 'chat'
  485.                     else
  486.                         des := x^.sfil.fName;
  487.                     repeat
  488.                         i := pos(' ', des);
  489.                         if i = 0 then
  490.                             leave;
  491.                         des[i] := '_'
  492.                     until false;
  493.                     s := stringof('PRIVMSG ', x^.peer, ' :', chr(1), 'DCC ', x^.typ, ' ', des, ' ', ipa, ' ', pn, chr(1));
  494.                     PutLine(s);
  495.                     s := stringof('Requesting DCC ', x^.typ, ' connection with ', x^.peer);
  496.                     Message(s);
  497.                     x^.flag := WAITING;
  498.                     exit(openDCC)
  499.                 end;
  500.             failedDCC(x, 'Failed to create');
  501.         end
  502.         else if x^.flag = OFFERED then begin
  503.             if NewActiveConnection(x^.sock, 8192, x^.host, x^.port, nil) = 0 then
  504.                 x^.flag := OPENING
  505.             else
  506.                 failedDCC(x, 'Failed to open');
  507.         end;
  508.     end;
  509.  
  510. {$ENDC}
  511.  
  512. { Process incoming DCC request }
  513. procedure DCCRequest (var fr, s: string);
  514.     var
  515.         c: str255;
  516. {$IFC DCCenable}
  517.         x: DCCPtr;
  518.         t: DCCType;
  519.         i: integer;
  520.         des: string[64];
  521. {$ENDC}
  522.     begin
  523.         NextArg(s, c);
  524.         uprString(c, false);
  525. {$IFC DCCenable}
  526.         if c = 'CHAT' then
  527.             t := CHAT
  528.         else if c = 'SEND' then
  529.             t := SEND
  530.         else begin
  531. {$ENDC}
  532.             c := concat('NOTICE ', fr, ' :', chr(1), 'ERRMSG DCC ', c, ' :Unsupported request', chr(1));
  533.             if serverStatus = S_CONN then
  534.                 PutLine(c);
  535.             exit(DCCRequest);
  536. {$IFC DCCenable}
  537.         end;
  538.         if getDCC(t, fr, x) then begin
  539.             c := stringof('*** DCC collision for ', t, ' request from ', fr);
  540.             Message(c);
  541.             killDCC(x)
  542.         end
  543.         else begin { request from peer }
  544.             NextArg(s, des);
  545.             repeat
  546.                 i := pos('/', des);
  547.                 if i = 0 then
  548.                     leave;
  549.                 delete(des, 1, i)
  550.             until false;
  551.             repeat
  552.                 i := pos(':', des);
  553.                 if i = 0 then
  554.                     leave;
  555.                 des[i] := '_'
  556.             until false;
  557.             NextArg(s, c);
  558.             x^.host := ulongval(c);
  559.             StringtoNum(s, x^.port);
  560.             x^.flag := OFFERED;
  561.             if x^.typ = SEND then begin
  562.                 x^.typ := GET;
  563.                 x^.gfil.fName := des;
  564.             end;
  565.             c := stringof('*** DCC ', t, ' request from ', fr, ' (', des, ')');
  566.             Message(c);
  567.         end
  568. {$ENDC}
  569.     end;
  570.  
  571. procedure DCCcommand (var s: string);
  572.     label
  573.         39;
  574.     var
  575.         c: str255;
  576. {$IFC DCCenable}
  577.         des: string[64];
  578.         x: DCCPtr;
  579.         t: DCCType;
  580.         b: boolean;
  581.         p: Point;
  582.         ty: SFTypeList;
  583. {$ENDC}
  584.     begin
  585.         NextArg(s, c);
  586.         UprString(c, false);
  587. {$IFC DCCenable}
  588.         if IsChannel(s) then
  589.             c := '*** Target of DCC must be client'
  590.         else if c = 'CHAT' then
  591.             if s = '' then
  592.                 c := '*** Nickname needed for DCC CHAT'
  593.             else begin
  594.                 b := getDCC(CHAT, s, x);
  595.                 c := '';
  596.                 if (x^.flag = WAITING) or (x^.flag = OPENING) or (x^.flag = OPEN) then
  597.                     c := concat('*** DCC CHAT connection with ', s, ' exists already')
  598.                 else
  599.                     openDCC(x);
  600.             end
  601.         else if c = 'CLOSE' then begin
  602.             NextArg(s, c);
  603.             UprString(c, false);
  604.             if c = 'CHAT' then
  605.                 t := CHAT
  606.             else if c = 'SEND' then
  607.                 t := SEND
  608.             else if c = 'GET' then
  609.                 t := GET
  610.             else
  611.                 goto 39;
  612.             NextArg(s, c);
  613.             if c <> '' then begin
  614.                 if not getDCC(t, c, x) then
  615.                     c := stringof('*** No DCC ', t, ' connection to ', c)
  616.                 else
  617.                     c := stringof('*** DCC ', t, ' to ', c, ' closed');
  618.                 killDCC(x);
  619.             end
  620.             else
  621. 39: { Oh yes I know this is spaghetti code ;-) }
  622.                 c := '*** You must supply type and nick for DCC CLOSE';
  623.         end
  624.         else if (c = '') or (c = 'LIST') then begin
  625.             x := FDCC;
  626.             while x <> nil do begin
  627.                 if x^.typ = CHAT then
  628.                     des := 'chat'
  629.                 else
  630.                     des := x^.sfil.fName;
  631.                 c := stringof(x^.typ : 5, x^.peer : 11, x^.flag : 10, ' ', des);
  632.                 Message(c);
  633.                 x := x^.next
  634.             end;
  635.             c := ''
  636.         end
  637.         else if (c = 'TSEND') or (c = 'SEND') then begin
  638.             if s = '' then
  639.                 c := '*** You must supply a nick for DCC SEND'
  640.             else begin
  641.                 b := getDCC(SEND, s, x);
  642.                 if (x^.flag = WAITING) or (x^.flag = OPENING) or (x^.flag = OPEN) then
  643.                     c := concat('*** DCC SEND connection with ', s, ' exists already')
  644.                 else begin
  645.                     x^.stext := (c[1] = 'T');
  646.                     SetPt(p, 80, 30);
  647.                     ty[0] := 'TEXT';
  648.                     c := '';
  649.                     if x^.stext then
  650.                         SFGetFile(p, '', nil, 1, ty, nil, x^.sfil)
  651.                     else
  652.                         SFGetFile(p, '', nil, -1, ty, nil, x^.sfil);
  653.                     if x^.sfil.good then
  654.                         openDCC(x)
  655.                     else
  656.                         killDCC(x);
  657.                 end
  658.             end
  659.         end
  660.         else if (c = 'TGET') or (c = 'GET') then begin
  661.             if s = '' then
  662.                 c := '*** You must supply a nick for DCC GET'
  663.             else begin
  664.                 b := getDCC(GET, s, x);
  665.                 if x^.flag = OFFERED then begin
  666.                     x^.gtext := (c[1] = 'T');
  667.                     c := '';
  668.                     SetPt(p, 80, 30);
  669.                     if x^.gtext then
  670.                         SFPutFile(p, 'Save TEXT file as:', x^.gfil.fName, nil, x^.gfil)
  671.                     else
  672.                         SFPutFile(p, 'Save file as:', x^.gfil.fName, nil, x^.gfil);
  673.                     if x^.gfil.good then
  674.                         openDCC(x);
  675.                 end
  676.                 else begin
  677.                     c := concat('*** No DCC SEND offered from ', s);
  678.                     killDCC(x)
  679.                 end
  680.             end
  681.         end
  682.         else
  683.             c := concat('*** Unknown DCC command: ', c);
  684. {$ELSEC}
  685.         c := '*** DCC not implemented';
  686. {$ENDC}
  687.         if c <> '' then
  688.             Message(c);
  689.     end;
  690.  
  691.  
  692. procedure DCCChatSend (var s: string);
  693. {$IFC DCCEnable}
  694.     var
  695.         i, n, oe: integer;
  696.         p: TCPConnectionPtr;
  697.         x: DCCPtr;
  698.         t: string[12];
  699. {$ENDC}
  700.     begin
  701. {$IFC DCCEnable}
  702.         t := CurrentTarget;
  703.         delete(t, 1, 1);
  704.         t[0] := pred(t[0]);
  705.         if not getDCC(CHAT, t, x) then
  706.             debugstr(concat('Bogus DCC CHAT target ', CurrentTarget));
  707.         insert('> ', s, 1);
  708.         ChannelMsg(CurrentTarget, s);
  709.         n := length(s);
  710.         for i := 1 to n do
  711.             s[i] := ISOEncode^^[s[i]];
  712.         s[n + 1] := chr(10);
  713.         GetConnectionTCPC(x^.sock, p);
  714.         i := TCPSendAsync(p, @s[3], n - 1, false, @oe);
  715.         if i <> 0 then
  716.             killDCC(x)
  717.         else begin
  718.             repeat
  719.                 ApplRun
  720.             until oe <> inProgress;
  721.             if oe <> 0 then
  722.                 killDCC(x);
  723.         end;
  724. {$ENDC}
  725.     end;
  726.  
  727. procedure InitDCC;
  728.     var
  729.         i: integer;
  730.     begin
  731. {$IFC DCCenable}
  732.         FDCC := nil;
  733.         i := ApplTask(@netEvent, TCPMsg);
  734. {$ENDC}
  735.     end;
  736.  
  737. end.