Sock.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:44k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. unit Sock;
  2. // *****************************************************************************
  3. // Sock.Pas (TSock)
  4. // Freeware Windows Socket Component For Delphi & C++ Builder
  5. // Version 1.0k, tested with Delphi 2.0, 3.0 & 4.0
  6. // Written By Tom Bradford
  7. // Maintained By Ward van Wanrooij
  8. //   (ward@ward.nu, http://www.ward.nu)
  9. //
  10. // Copyright (C) 1997-2000, Beach Dog Software, Inc.
  11. // Copyright (C) 2000-2003, Ward van Wanrooij
  12. // All Rights Reserved
  13. // Latest version can be obtained at http://www.ward.nu/computer/tsock
  14. // *****************************************************************************
  15. interface
  16. uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  17.   WinSock, BaseClass;
  18. type
  19.   TSocketInfo = (siLookUp, siConnect, siClose, siListen, siReceive, siSend,
  20.     siAccept, siError);
  21.   TSocketType = (stStream, stDatagram);
  22.   TLineBreak = (lbCRLF, lbCR, lbLF, lbSmart);
  23. const
  24.   WM_SOCK = WM_USER + 75; // Hopefully, Your App Won't Use This Message
  25. type
  26.   TSock = class; // Forward Declared For Event Types
  27.   ESockException = class(Exception);
  28.   TNotifyReadEvent = procedure(Sender: TObject; Count: Integer) of object;
  29.   TNotifyAutoEvent = procedure(Sender: TObject; NewSock: TSock) of object;
  30.   TNotifyInfoEvent = procedure(sender: TObject; SocketInfo: TSocketInfo; Msg:
  31.     string) of object;
  32.   TSock = class(TCustomControl)
  33.   private
  34.     FSockAddrIn: TSockAddrIn; // Address Information Block
  35.     FRecvAddrIn: TSockAddrIn; // Address Information Block For RecvFrom
  36.     FLastChar: Char; // Last Character Read For Line-Input
  37.     FPicture: TBitmap; // Holder For Design-Time Image
  38.     FBmp_TCP: TBitmap; // TCP Bitmap
  39.     FBmp_UDP: TBitmap; // UDP Bitmap
  40.     FBmp_Listen: TBitmap; // Listening Bitmap
  41.     // Character Buffer (Most WINSOCK.DLLs Max At 32k)
  42.     //  FCharBuf    : Array[1..32768] Of Char;
  43.     FCharBuf: array[1..750] of Char; // small buffer works more stable
  44.     FSocketType: TSocketType; // Socket Type (Stream Or Datagram)
  45.     FLineBreak: TLineBreak; // Line Break Style For Line Input
  46.     FHostName: string; // Host Name Or IP Address
  47.     FPortName: string; // Port Name Or Well-Known Number
  48.     FLocalPortName: string;
  49.       // Local Port Name Or Well-Known Number, Defaults To 1 (=FPortName) For Backward Compatibility
  50.     FSocket: TSocket; // Socket Handle
  51.     FInBuffer: string; // Input Buffer
  52.     FOutBuffer: string; // Output Buffer For Non-Blocking
  53.     FListen: Boolean; // Socket Listens?
  54.     FBlocking: Boolean; // Do Blocking Calls?
  55.     FAutoAccept: Boolean; // Automatically Accept Incomings
  56.     FConnected: Boolean; // Are We Connected?
  57.     FBlockTime: Integer; // How Long To Wait For Blocking Operation
  58.     FStream: TStream; // Associated TSockStream Object
  59.     FFreeOnClose: Boolean;
  60.       // Free after closure of socket? (Non-blocking, auto-accepted sockets!)
  61.     FOnConnect: TNotifyEvent;
  62.     FOnDisconnect: TNotifyEvent;
  63.     FOnInfo: TNotifyInfoEvent;
  64.     FOnRead: TNotifyReadEvent;
  65.     FOnWrite: TNotifyEvent;
  66.     FOnAccept: TNotifyEvent;
  67.     FOnAutoAccept: TNotifyAutoEvent;
  68.     m_receiveForm: TForm;
  69.     m_lock: TBCCritSec;
  70.     // Property Set/Get Routines
  71.     procedure SetHostName(Value: string);
  72.     procedure SetPortName(Value: string);
  73.     procedure SetLocalPortName(Value: string);
  74.     function GetText: string;
  75.     procedure SetText(Value: string);
  76.     procedure SetListen(Value: Boolean);
  77.     procedure SetBlocking(Value: Boolean);
  78.     procedure SetAutoAccept(Value: Boolean);
  79.     procedure SetConnected(Value: Boolean);
  80.     function GetConnected: Boolean;
  81.     procedure SetSocket(Value: TSocket);
  82.     procedure SetSocketType(Value: TSocketType);
  83.     function GetRemoteHost: string;
  84.     function GetEOF: Boolean;
  85.     // Private Support Methods
  86.     procedure DoInfo(SocketInfo: TSocketInfo; Msg: string);
  87.     procedure SetBitmap;
  88.   protected
  89.     // Event Handlers
  90.     procedure WMSock(var Message: TMessage); message WM_SOCK;
  91.     procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  92.     procedure WMSize(var Message: TWMSize); message WM_SIZE;
  93.     // Loaded Handles Starting Listening Mode After Streaming The Properties
  94.     procedure Loaded; override;
  95.     // Protected Constructor Can Only Be Called By TSock Class
  96.     constructor CreateWithSocket(AOwner: TComponent; NewSocket: TSocket);
  97.       virtual;
  98.   public
  99.     constructor Create(AOwner: TComponent); override;
  100.     destructor Destroy; override;
  101.     function Open: Boolean;
  102.     function Close: Boolean;
  103.     function Send(Value: string): Boolean;
  104.     function SendLine(Value: string): Boolean;
  105.     function ReceiveCount(Count: Integer): string;
  106.     function Receive: string;
  107.     function ReceiveLine: string;
  108.     function SendDatagram(Value, HostName: string): Boolean;
  109.     function ReceiveDatagram(var HostName: string): string;
  110.     // The Accept Method Will Create NewSock, But User Must Free
  111.     function Accept(var NewSock: TSock): Boolean;
  112.     // Public Support Methods
  113.     function HostLookup(Value: string): TInAddr;
  114.     function PortLookup(Value: string): U_Short;
  115.     // StartListen And StopListen Are A Robust Form Of Setting Listen
  116.     function StartListen: Boolean;
  117.     function StopListen: Boolean;
  118.     property Text: string read GetText write SetText;
  119.     property Connected: Boolean read GetConnected write SetConnected;
  120.       // Used To Read FConnected
  121.     property EndOfFile: Boolean read GetEOF;
  122.     property Socket: TSocket read FSocket write SetSocket;
  123.     property Stream: TStream read FStream;
  124.     // RemoteHost Returns The Remote IP If SocketType=stStream
  125.     // And Will Return The Most Recent Incoming Datagram IP If
  126.     // SocketType=stDatagram
  127.     property RemoteHost: string read GetRemoteHost;
  128.     // RemoteHost = INet_NToA(RecvAddrIn.SIn_Addr); Provided as property for easy-of-use and backward compatibility
  129.     property RecvAddrIn: TSockAddrIn read FRecvAddrIn;
  130.   published
  131.     property SocketType: TSocketType read FSocketType write SetSocketType;
  132.     property HostName: string read FHostName write SetHostName;
  133.     property PortName: string read FPortName write SetPortName;
  134.     property LocalPortName: string read FLocalPortName write SetLocalPortName;
  135.     property Blocking: Boolean read FBlocking write SetBlocking;
  136.     property AutoAccept: Boolean read FAutoAccept write SetAutoAccept;
  137.     property Listen: Boolean read FListen write SetListen;
  138.     property LineBreak: TLineBreak read FLineBreak write FLineBreak;
  139.     property BlockingTimeout: Integer read FBlockTime write FBlockTime;
  140.     property OnConnect: TNotifyEvent read FOnConnect write FOnConnect;
  141.     property OnDisconnect: TNotifyEvent read FOnDisconnect write FOnDisconnect;
  142.     property OnInfo: TNotifyInfoEvent read FOnInfo write FOnInfo;
  143.     property OnRead: TNotifyReadEvent read FOnRead write FOnRead;
  144.     property OnWrite: TNotifyEvent read FOnWrite write FOnWrite;
  145.     property OnAccept: TNotifyEvent read FOnAccept write FOnAccept;
  146.     property OnAutoAccept: TNotifyAutoEvent read FOnAutoAccept write
  147.       FOnAutoAccept;
  148.   end;
  149.   // Global IP Caching Mechanism.  Uses A String List That Stores The 32-Bit IP
  150.   // Address Of It's Associated Hostname In The Object Property Of The List.  You
  151.   // Should Never Have To Manipulate This Object Directly, But It Is Made Public
  152.   // For The Purpose Of Calling The Clear Method To Empty It.
  153. var
  154.   IPCache: TStringList;
  155. function WSDescription: string; // Returns A Description Of The WinSock Driver
  156. function WSSystemStatus: string; // Returns System Status From The WinSock Driver
  157. function GetLocalHostname: string; // Return Local Hostname
  158. function SocketInfoText(Value: TSocketInfo): string;
  159.   // Converts TSocketInfo Values To Text
  160. function ErrToStr(Value: Integer): string; // Converts A WinSock Error To Text
  161. function Base64Encode(Value: string): string;
  162.   // Converts Passed Value To MIME Base64
  163. function Base64Decode(Value: string): string;
  164.   // Converts Passed Value From MIME Base64
  165. function URLEncode(Value: string): string;
  166.   // Converts String To A URLEncoded String
  167. function URLDecode(Value: string): string;
  168.   // Converts String From A URLEncoded String
  169. procedure Register;
  170. implementation
  171. uses config;
  172. const
  173.   Base64Table =
  174.     'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  175.   ValidURLChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$-_@.&+-!*"''(),;/#?:';
  176.   SocketInfoMsg: array[siLookUp..siError] of string = ('Lookup', 'Connect',
  177.     'Close', 'Listen', 'Receive', 'Send', 'Accept', 'Error');
  178. type
  179.   TSockStream = class(TStream)
  180.   private
  181.     Sock: TSock;
  182.   public
  183.     function Read(var Buffer; Count: Longint): Longint; override;
  184.     function Write(const Buffer; Count: Longint): Longint; override;
  185.     function Seek(Offset: Longint; Origin: Word): Longint; override;
  186.     constructor Create(Sock: TSock); virtual;
  187.   end;
  188. type
  189.   TSockThread = class(TThread)
  190.   private
  191.     ParentSock: TSock;
  192.     ClientSock: TSock;
  193.   public
  194.     procedure Execute; override;
  195.     procedure ThreadTerminate(Sender: TObject);
  196.     procedure RunThread(ParentSock, ClientSock: TSock);
  197.   end;
  198.   // WinSock Initialization Data
  199. var
  200.   WSAData: TWSAData;
  201.   //*** TSockStream Methods ******************************************************
  202. constructor TSockStream.Create(Sock: TSock);
  203. begin
  204.   Self.Sock := Sock;
  205. end;
  206. function TSockStream.Read(var Buffer; Count: Longint): Longint;
  207. var
  208.   Temp: string;
  209. begin
  210.   Temp := Sock.ReceiveCount(Count);
  211.   Move(Temp[1], Buffer, Length(Temp));
  212.   Result := Length(Temp);
  213. end;
  214. function TSockStream.Write(const Buffer; Count: Longint): Longint;
  215. var
  216.   Temp: string;
  217. begin
  218.   SetLength(Temp, Count);
  219.   Move(Buffer, Temp[1], Count);
  220.   Sock.Send(Temp);
  221.   Result := Count;
  222. end;
  223. function TSockStream.Seek(Offset: Longint; Origin: Word): Longint;
  224. begin
  225.   Result := 0;
  226. end;
  227. //*** TSockThread Methods ******************************************************
  228. procedure TSockThread.Execute;
  229. begin
  230.   FreeOnTerminate := True;
  231.   OnTerminate := ThreadTerminate;
  232.   ParentSock.OnAutoAccept(ParentSock, ClientSock);
  233.   Terminate;
  234. end;
  235. procedure TSockThread.ThreadTerminate(Sender: TObject);
  236. begin
  237.   ClientSock.Free;
  238. end;
  239. procedure TSockThread.RunThread(ParentSock, ClientSock: TSock);
  240. begin
  241.   Self.ParentSock := ParentSock;
  242.   Self.ClientSock := ClientSock;
  243.   Resume;
  244. end;
  245. //*** Property Set/Get Procedures **********************************************
  246. procedure TSock.SetHostName(Value: string);
  247. begin
  248.   if (FSocketType = stStream) and FConnected then
  249.     DoInfo(SiLookup, 'Setting HostName While Connected Has No Effect');
  250.   FHostName := Value;
  251.   if (FSocketType = stDatagram) and FConnected then
  252.     FSockAddrIn.SIn_Addr := HostLookup(Value);
  253. end;
  254. procedure TSock.SetPortName(Value: string);
  255. begin
  256.   if FConnected then
  257.     DoInfo(SiLookup, 'Setting PortName While Connected Has No Effect');
  258.   FPortName := Value;
  259. end;
  260. procedure TSock.SetLocalPortName(Value: string);
  261. begin
  262.   if FConnected then
  263.     DoInfo(SiLookup, 'Setting LocalPortName While Connected Has No Effect');
  264.   FLocalPortName := Value;
  265. end;
  266. function TSock.GetText: string;
  267. begin
  268.   // Just Call The Receive Method
  269.   Result := Receive;
  270. end;
  271. procedure TSock.SetText(Value: string);
  272. begin
  273.   // Just Call The Send Method And Ignore The Boolean Result
  274.   Send(Value);
  275. end;
  276. procedure TSock.SetListen(Value: Boolean);
  277. var
  278.   WasListen: Boolean;
  279.   Addr: TSockAddr;
  280.   Res: Integer;
  281. begin
  282.   if (csDesigning in ComponentState) then
  283.   begin
  284.     FListen := Value;
  285.     if Value and (FSocketType = stDatagram) then
  286.       // Listening Sockets Must Be Stream Sockets
  287.       SetSocketType(stStream)
  288.     else
  289.       SetBitmap;
  290.     Exit;
  291.   end
  292.   else if (csReading in ComponentState) then
  293.   begin
  294.     // If We Haven't Loaded Yet, Just Set The Value And Exit
  295.     FListen := Value;
  296.     Exit;
  297.   end;
  298.   WasListen := FListen;
  299.   if (FSocket <> INVALID_SOCKET) and (not WasListen) then
  300.   begin
  301.     FListen := False;
  302.     raise ESockException.Create('Listen - Socket Already In Use');
  303.   end;
  304.   if (FSocketType = stDatagram) and Value then
  305.   begin
  306.     FListen := False;
  307.     raise ESockException.Create('Listen - Cannot Listen On A Datagram Socket');
  308.   end;
  309.   FListen := Value;
  310.   if FListen then
  311.   begin
  312.     if not WasListen then
  313.     begin
  314.       // Have To Create A Socket Start Asynchronous Listening
  315.       FListen := True;
  316.       FSocket := WinSock.Socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
  317.       FillChar(Addr, SizeOf(Addr), #0);
  318.       Addr.SIn_Family := AF_INET;
  319.       Addr.SIn_Port := PortLookup(FPortName);
  320.       Addr.SIn_Addr.S_Addr := HToNL(INADDR_ANY);
  321.       // SetBlocking Will Set The Asynchronous Mode
  322.       SetBlocking(FBlocking);
  323.       FListen := False;
  324.       Res := WinSock.Bind(FSocket, Addr, SizeOf(Addr));
  325.       if Res <> 0 then
  326.         raise ESockException.Create('Listen - Error Binding Socket');
  327.       Res := WinSock.Listen(FSocket, 5);
  328.       if Res <> 0 then
  329.         raise ESockException.Create('Listen - Error Starting Listen');
  330.       FListen := True;
  331.       DoInfo(SiListen, 'Listening Started');
  332.     end
  333.     else
  334.       DoInfo(SiListen, 'Listening Already Running');
  335.   end
  336.   else
  337.   begin
  338.     Close;
  339.     DoInfo(SiListen, 'Listening Stopped');
  340.   end;
  341. end;
  342. procedure TSock.SetBlocking(Value: Boolean);
  343. var
  344.   Il: U_Long;
  345.   Ev: U_Long;
  346. begin
  347.   if (not (csDesigning in ComponentState)) and (csReading in ComponentState)
  348.     then
  349.   begin
  350.     // If We Haven't Fully Loaded Yet, Just Set The Value And Exit
  351.     FBlocking := Value;
  352.     Exit;
  353.   end;
  354.   if FSocket = INVALID_SOCKET then
  355.     FBlocking := Value
  356.   else
  357.   begin
  358.     Ev := 0;
  359.     FBlocking := Value;
  360.     if (Parent = nil) then
  361.     begin
  362.       // If The Component Has No Parent (Dynamically Created) We Adopt It
  363.       Parent := Screen.Forms[0];
  364.       HandleNeeded;
  365.     end;
  366.     if FBlocking and (not FListen) then
  367.     begin
  368.       Il := 0;
  369.       // Turn Off Async Checking And Set Blocking On
  370.       WinSock.WSAAsyncSelect(FSocket, Handle, WM_SOCK, Ev);
  371.       WinSock.IOCtlSocket(FSocket, FIONBIO, Il);
  372.     end
  373.     else
  374.     begin
  375.       if FListen then
  376.         // If We're Listening, We Only Care About Accept Messages
  377.         Ev := FD_ACCEPT
  378.       else
  379.       begin
  380.         Ev := FD_READ; // Datagram Sockets Only Care About Read Messages
  381.         if FSocketType = stStream then
  382.           Ev := Ev or FD_CLOSE or FD_CONNECT or FD_WRITE or FD_READ;
  383.       end;
  384.       WinSock.WSAAsyncSelect(FSocket, Handle, WM_SOCK, Ev);
  385.     end;
  386.   end;
  387. end;
  388. procedure TSock.SetAutoAccept(Value: Boolean);
  389. begin
  390.   FAutoAccept := Value;
  391. end;
  392. procedure TSock.SetConnected(Value: Boolean);
  393. begin
  394.   if Value then
  395.     Open
  396.   else
  397.     Close;
  398. end;
  399. function TSock.GetConnected: Boolean;
  400. begin
  401.   if FSocket = INVALID_SOCKET then
  402.     FConnected := False;
  403.   Result := FConnected;
  404. end;
  405. function TSock.GetEOF: Boolean;
  406. begin
  407.   Result := (FInBuffer = '') and (not FConnected);
  408. end;
  409. procedure TSock.SetSocket(Value: TSocket);
  410. var
  411.   Buf: array[1..10] of Char;
  412.   Len: Integer;
  413.   Res: Integer;
  414. begin
  415.   FSocket := Value;
  416.   if FSocket = INVALID_SOCKET then
  417.   begin
  418.     // If The Socket Is Unassigned Then Who Cares
  419.     FConnected := False;
  420.     FListen := False;
  421.   end
  422.   else
  423.   begin
  424.     // Otherwise, We Need To Check To See If It's Already Listening
  425.     Len := SizeOf(Buf);
  426.     Res := WinSock.GetSockOpt(FSocket, IPPROTO_TCP, SO_ACCEPTCONN, PChar(@Buf),
  427.       Len);
  428.     if (Res = 0) and (Buf[1] <> #0) then
  429.     begin
  430.       FSocket := INVALID_SOCKET;
  431.       raise ESockException.Create('Socket - Can''t Assign A Listening Socket');
  432.     end
  433.     else
  434.       FConnected := True;
  435.   end;
  436. end;
  437. procedure TSock.SetSocketType(Value: TSocketType);
  438. begin
  439.   if csDesigning in ComponentState then
  440.   begin
  441.     // At Design-Time, stDatagram And Listen Are Mutually Exclusive
  442.     if (Value = stDatagram) and FListen then
  443.       SetListen(False);
  444.     FSocketType := Value;
  445.     SetBitmap;
  446.   end
  447.   else
  448.   begin
  449.     if FListen then
  450.       raise
  451.         ESockException.Create('SocketType - Can''t Assign Socket Type While Listening');
  452.     if FConnected then
  453.       raise
  454.         ESockException.Create('SocketType - Can''t Assign Socket Type While Connected');
  455.     FSocketType := Value;
  456.   end
  457. end;
  458. function TSock.GetRemoteHost: string;
  459. begin
  460.   // Convert FRecvAddrIn To A String IP Address
  461.   Result := INet_NToA(FRecvAddrIn.SIn_Addr);
  462. end;
  463. procedure TSock.DoInfo(SocketInfo: TSocketInfo; Msg: string);
  464. begin
  465.   if Assigned(FOnInfo) then
  466.     FOnInfo(Self, SocketInfo, Msg);
  467. end;
  468. procedure TSock.SetBitmap;
  469. begin
  470.   // Determine The Design-Time Bitmap To Use
  471.   if FSocketType = stDatagram then
  472.     FPicture := FBmp_UDP
  473.   else if FListen then
  474.     FPicture := FBmp_Listen
  475.   else
  476.     FPicture := FBmp_TCP;
  477.   Invalidate;
  478. end;
  479. //*** Constructor/Destructor ***************************************************
  480. constructor TSock.Create(AOwner: TComponent);
  481. begin
  482.   m_receiveForm := TForm.Create(nil);
  483.   inherited Create(m_receiveForm);
  484.   m_lock := TBCCritSec.Create;
  485.   Parent := TWinControl(m_receiveForm);
  486.     // <<--- added by blacktrip, wild cast but
  487.   // prevent crashes !!!
  488.   if WinSock.WSAStartup($0101, WSAData) <> 0 then
  489.     raise ESockException.Create('WSAStartup - Could Not Initialize WinSock');
  490.   IPCache := TStringList.Create;
  491.   IPCache.Clear;
  492.   if (csDesigning in ComponentState) then
  493.   begin
  494.     // Get Bitmaps For Design-Time Image
  495.     FBmp_TCP := TBitmap.Create;
  496.     FBmp_UDP := TBitmap.Create;
  497.     FBmp_Listen := TBitmap.Create;
  498.     FBmp_TCP.Handle := LoadBitmap(hInstance, 'TCP');
  499.     FBmp_UDP.Handle := LoadBitmap(hInstance, 'UDP');
  500.     FBmp_Listen.Handle := LoadBitmap(hInstance, 'LISTEN');
  501.     FPicture := FBmp_TCP;
  502.     Width := FPicture.Width;
  503.     Height := FPicture.Height;
  504.     SetZOrder(True);
  505.   end
  506.   else
  507.   begin
  508.     Width := 0;
  509.     Height := 0;
  510.     SetZOrder(False);
  511.     Visible := False;
  512.   end;
  513.   FHostName := '';
  514.   FPortName := '';
  515.   FLocalPortName := '-1';
  516.   FSocket := INVALID_SOCKET;
  517.   FLineBreak := lbSmart;
  518.   FLastChar := #0;
  519.   FInBuffer := '';
  520.   FOutBuffer := '';
  521.   FListen := False;
  522.   FBlocking := False;
  523.   FAutoAccept := False;
  524.   FConnected := False;
  525.   FStream := TSockStream.Create(Self);
  526.   FFreeOnClose := False;
  527. end;
  528. // This Constructor Assumes NewSocket Is A Valid Socket Handle
  529. constructor TSock.CreateWithSocket(AOwner: TComponent; NewSocket: TSocket);
  530. begin
  531.   Create(AOwner);
  532.   FSocket := NewSocket;
  533.   SetBlocking(TSock(AOwner).Blocking);
  534.   FBlockTime := TSock(AOwner).BlockingTimeout;
  535.   FOnRead := TSock(AOwner).OnRead;
  536.   FOnWrite := TSock(AOwner).OnWrite;
  537.   FOnDisconnect := TSock(AOwner).OnDisconnect;
  538.   FOnInfo := TSock(AOwner).OnInfo;
  539.   FConnected := True;
  540.   FLineBreak := TSock(AOwner).LineBreak;
  541.   FRecvAddrIn := TSock(AOwner).RecvAddrIn;
  542.   FFreeOnClose := not FBlocking;
  543. end;
  544. destructor TSock.Destroy;
  545. begin
  546.   if FListen or FConnected then
  547.     Close;
  548.   if (csDesigning in ComponentState) then
  549.   begin
  550.     FBmp_TCP.Free;
  551.     FBmp_UDP.Free;
  552.     FBmp_Listen.Free;
  553.   end;
  554.   FStream.Free;
  555.   IPCache.Free;
  556.   WinSock.WSACleanup;
  557.   inherited Destroy;
  558. end;
  559. procedure TSock.Loaded;
  560. begin
  561.   if not (csDesigning in ComponentState) then
  562.   begin
  563.     // If Component Has Been Loaded At Run-Time And Listen Then Start Listening
  564.     SetBlocking(FBlocking);
  565.     if FListen then
  566.     begin
  567.       FListen := False;
  568.       SetListen(True);
  569.     end;
  570.   end;
  571. end;
  572. //*** Event Handling ***********************************************************
  573. procedure TSock.WMSock(var Message: TMessage);
  574. var
  575.   Event: Word;
  576.   Error: Word;
  577.   Res: Integer;
  578.   AcSck: TSocket;
  579.   Addr: TSockAddrIn;
  580.   AddrL: Integer;
  581.   CSock: TSock;
  582.   Spawn: TSockThread;
  583. begin
  584.   m_lock.Lock;
  585.   inherited;
  586.   // Message Handling For Non-Blocking Sockets
  587.   Event := WinSock.WSAGetSelectEvent(Message.LParam);
  588.   Error := WinSock.WSAGetSelectError(Message.LParam);
  589.   if (Error > WSABASEERR) then
  590.     DoInfo(SiError, 'Error #' + IntToStr(Error) + ' (' + ErrToStr(Error) + ')');
  591.   if (Error <= WSABASEERR) or (Event = FD_CLOSE) then
  592.     // Messages Mean Different Things Depending On Whether You're Listening Or Not
  593.     case Event of
  594.       FD_ACCEPT:
  595.         begin
  596.           // Incoming Socket
  597.           if FAutoAccept and Assigned(FOnAutoAccept) then
  598.           begin
  599.             // If AutoAccept Is Set To True And OnAutoAccept Is Set...
  600.             // Create A New Socket Based On The Accepted One And Begin
  601.             // AutoAccept As If It Were A Thread... The AutoAccept
  602.             // Routine Is Responsible For Destroying The New Socket
  603.             // Component.
  604.             AddrL := SizeOf(Addr);
  605.             FillChar(Addr, SizeOf(Addr), #0);
  606. {$IFDEF VER93}
  607.             AcSck := WinSock.Accept(FSocket, Addr, AddrL);
  608. {$ELSE}
  609. {$IFDEF WIN32}
  610.             AcSck := WinSock.Accept(FSocket, @Addr, @AddrL);
  611. {$ELSE}
  612.             AcSck := WinSock.Accept(FSocket, Addr, AddrL);
  613. {$ENDIF}
  614. {$ENDIF}
  615.             FRecvAddrIn := Addr;
  616.             CSock := TSock.CreateWithSocket(Self, AcSck);
  617.             CSock.PortName := FPortName;
  618.             CSock.LocalPortName := FLocalPortName;
  619.             CSock.HostName := INet_NToA(Addr.SIn_Addr);
  620.             if FBlocking then
  621.             begin
  622.               Spawn := TSockThread.Create(True);
  623.               Spawn.RunThread(Self, CSock);
  624.             end
  625.             else
  626.               FOnAutoAccept(Self, CSock);
  627.           end
  628.           else if Assigned(FOnAccept) then
  629.             FOnAccept(Self);
  630.         end;
  631.       FD_CONNECT:
  632.         begin
  633.           FConnected := True;
  634.           DoInfo(SiConnect, 'Non-Blocking Socket Connected');
  635.           if Assigned(FOnConnect) then
  636.             FOnConnect(Self);
  637.         end;
  638.       FD_CLOSE:
  639.         begin
  640.           if Assigned(FOnDisconnect) then
  641.             FOnDisconnect(Self);
  642.           Close;
  643.         end;
  644.       FD_READ:
  645.         begin
  646.           if FSocketType = stStream then
  647.           begin
  648.             Res := WinSock.Recv(FSocket, FCharBuf, SizeOf(FCharBuf), 0);
  649.             if Res > 0 then
  650.               FInBuffer := FInBuffer + Copy(FCharBuf, 1, Res);
  651.             DoInfo(SiReceive, 'Non-Blocking Incoming Data');
  652.             if Assigned(FOnRead) then
  653.             begin
  654.               FOnRead(Self, Length(FInBuffer));
  655.             end;
  656.           end
  657.           else if Assigned(FOnRead) then
  658.             FOnRead(Self, Length(FInBuffer));
  659.         end;
  660.       FD_WRITE:
  661.         begin
  662.           if FOutBuffer <> '' then
  663.             Send('');
  664.           DoInfo(SiSend, 'Non-Blocking Outgoing Data');
  665.           if Assigned(FOnWrite) then
  666.             FOnWrite(Self);
  667.         end;
  668.     end;
  669.   Message.Result := 0;
  670.   m_lock.UnLock;
  671. end;
  672. procedure TSock.WMPaint(var Message: TWMPaint);
  673. begin
  674.   inherited;
  675.   if (csDesigning in ComponentState) then
  676.     Canvas.Draw(0, 0, FPicture);
  677.   Message.Result := 0;
  678. end;
  679. procedure TSock.WMSize(var Message: TWMSize);
  680. begin
  681.   inherited;
  682.   if (csDesigning in ComponentState) then
  683.   begin
  684.     if Width <> FPicture.Width then
  685.       Width := FPicture.Width;
  686.     if Height <> FPicture.Height then
  687.       Height := FPicture.Height;
  688.   end;
  689.   Message.Result := 0;
  690. end;
  691. //*** Support Methods **********************************************************
  692. function TSock.Open: Boolean;
  693. var
  694.   Res: Integer;
  695.   ST: Integer;
  696.   LAddrIn: TSockAddrIn;
  697.   //optval: integer;
  698. begin
  699.   if FSocket = INVALID_SOCKET then
  700.   begin
  701.     if FSocketType = stStream then
  702.       ST := SOCK_STREAM
  703.     else
  704.       ST := SOCK_DGRAM;
  705.     // Create The Socket
  706.     FSocket := WinSock.Socket(AF_INET, ST, IPPROTO_IP);
  707.     SetBlocking(FBlocking);
  708.     // Set local options
  709.     LAddrIn.SIn_Family := AF_INET;
  710.     if FLocalPortName = '-1' then
  711.       LAddrIn.SIn_Port := PortLookup(FPortName)
  712.         // Default behaviour for backward compatibility
  713.     else
  714.       LAddrIn.SIn_Port := PortLookup(FLocalPortName);
  715.     LAddrIn.SIn_Addr.S_Addr := HToNL(INADDR_ANY);
  716.       // No HostLookup(...) Because INADDR_ANY Is A Windows Constant
  717.     // Set Up The Remote Address And Port
  718.     FSockAddrIn.SIn_Family := AF_INET;
  719.     FSockAddrIn.SIn_Port := PortLookup(FPortName);
  720.     FSockAddrIn.SIn_Addr := HostLookup(FHostName);
  721.     if FSocketType = stStream then
  722.     begin
  723.       // Stream Sockets Require A Connect
  724.       Res := WinSock.Bind(FSocket, LAddrIn, SizeOf(LAddrIn)) +
  725.         WinSock.Connect(FSocket, FSockAddrIn, SizeOf(TSockAddrIn));
  726.       if FBlocking then
  727.       begin
  728.         if Res = 0 then
  729.         begin
  730.           FConnected := True;
  731.           DoInfo(SiConnect, 'Blocking Socket Connected');
  732.           if Assigned(FOnConnect) then
  733.             FOnConnect(Self);
  734.         end
  735.         else
  736.         begin
  737.           DoInfo(SiClose, 'Blocking Socket Can''t Connect');
  738.           Close;
  739.         end;
  740.       end;
  741.     end
  742.     else
  743.     begin
  744.       //Datagram Sockets are connectionless, so they don't get connected.
  745.       //It is possible to call WinSock.Connect, but it would produce extra overhead
  746.       //as it only sets the default destination.
  747.       Res := WinSock.Bind(FSocket, LAddrIn, SizeOf(LAddrIn));
  748.       if Res = 0 then
  749.       begin
  750.         FConnected := True;
  751.         DoInfo(SiConnect, 'Datagram Socket Connected');
  752.         if Assigned(FOnConnect) then
  753.           FOnConnect(Self);
  754.       end
  755.       else
  756.       begin
  757.         DoInfo(SiClose, 'Datagram Socket Can''t Connect');
  758.         Close;
  759.       end;
  760.     end;
  761.   end;
  762.   Result := FConnected;
  763. end;
  764. function TSock.Close: Boolean;
  765. begin
  766.   Result := (WinSock.CloseSocket(FSocket) = 0);
  767.   FSocket := INVALID_SOCKET;
  768.   FConnected := False;
  769.   if not FListen then
  770.     DoInfo(SiClose, 'Socket Closed');
  771.   FListen := False;
  772.   if FFreeOnClose then
  773.     Free;
  774. end;
  775. function TSock.Send(Value: string): Boolean;
  776. var
  777.   Remain: Integer;
  778. begin
  779.   Result := True;
  780.   if FSocket = INVALID_SOCKET then
  781.     raise ESockException.Create('Send - Socket Not Connected');
  782.   if FListen then
  783.     raise ESockException.Create('Send - Cannot Send On A Listener Socket');
  784.   if FSocketType = stStream then
  785.   begin
  786.     FOutBuffer := FOutBuffer + Value;
  787.     if FOutBuffer = '' then
  788.       Exit;
  789.     if FBlocking then
  790.     begin
  791.       Remain := Length(FOutBuffer);
  792.       // While Any Content Remains Or No Errors Have Happened, Then Loop
  793.       while Remain > 0 do
  794.       begin
  795.         Remain := WinSock.Send(FSocket, FOutBuffer[1], Length(FOutBuffer), 0);
  796.         if (Remain = SOCKET_ERROR) and (WinSock.WSAGetLastError <>
  797.           WSAEINPROGRESS) then
  798.         begin
  799.           DoInfo(SiError, 'Socket Error On Send');
  800.           raise ESockException.Create('Send - Socket Error');
  801.         end
  802.         else
  803.         begin
  804.           if Remain > 0 then
  805.             Delete(FOutBuffer, 1, Remain);
  806.           Remain := Length(FOutBuffer);
  807.           DoInfo(SiSend, 'Blocking Outgoing Data');
  808.         end;
  809.       end;
  810.       FOutBuffer := '';
  811.     end
  812.     else
  813.     begin
  814.       // Do Not Loop For A Non-Blocking Socket
  815.       DoInfo(SiSend, 'Non-Blocking Outgoing Data');
  816.       Remain := WinSock.Send(FSocket, FOutBuffer[1], Length(FOutBuffer), 0);
  817.       if Remain > 0 then
  818.         Delete(FOutBuffer, 1, Remain);
  819.     end;
  820.   end
  821.   else
  822.     SendDatagram(Value, FHostName);
  823. end;
  824. function TSock.SendLine(Value: string): Boolean;
  825. var
  826.   Break: string;
  827. begin
  828.   case FLineBreak of
  829.     lbCR: Break := #13;
  830.     lbLF: Break := #10;
  831.   else
  832.     Break := #13#10;
  833.   end;
  834.   Result := Send(Value + Break);
  835. end;
  836. function TSock.Receive: string;
  837. begin
  838.   Result := ReceiveCount(-1);
  839. end;
  840. function TSock.ReceiveCount(Count: Integer): string;
  841. var
  842.   Res: Integer;
  843.   FDSet: PFDSet;
  844.   TV: PTimeVal;
  845.   Err: Integer;
  846.   HostN: string;
  847.   Cnt: Integer;
  848. begin
  849.   if (FSocket = INVALID_SOCKET) and (FInBuffer = '') then
  850.     raise ESockException.Create('Receive - Socket Not Connected');
  851.   if FListen then
  852.     raise
  853.       ESockException.Create('Receive - Cannot Receive On A Listener Socket');
  854.   Cnt := Count;
  855.   if (Cnt = -1) or (Cnt > SizeOf(FCharBuf)) then
  856.     Cnt := SizeOf(FCharBuf);
  857.   if FSocketType = stStream then
  858.   begin
  859.     if FBlocking then
  860.     begin
  861.       FDSet := New(PFDSet);
  862.       FDSet^.FD_Count := 1;
  863.       FDSet^.FD_Array[0] := FSocket;
  864.       if FBlockTime >= 0 then
  865.       begin
  866.         TV := New(PTimeVal);
  867.         TV^.tv_sec := FBlockTime;
  868.       end
  869.       else
  870.         TV := nil;
  871.       // Used To Loop While We're Connected And Anything Is In The Input Queue
  872.       if FConnected and (WinSock.Select(FSocket, FDSet, nil, nil, TV) > 0) then
  873.       begin
  874.         DoInfo(SiReceive, 'Blocking Incoming Data');
  875.         Res := WinSock.Recv(FSocket, FCharBuf, Cnt, 0);
  876.         if (Res = SOCKET_ERROR) then
  877.         begin
  878.           Err := WSAGetLastError;
  879.           Result := '';
  880.           FInBuffer := '';
  881.           Dispose(FDSet);
  882.           Dispose(TV);
  883.           DoInfo(SiError, 'Socket Error On Receive');
  884.           if (not (Err - WSABASEERR in [WSAEINTR - WSABASEERR, WSAEINPROGRESS -
  885.             WSABASEERR, WSAEOPNOTSUPP - WSABASEERR, WSAEWOULDBLOCK - WSABASEERR,
  886.             WSAEMSGSIZE - WSABASEERR])) then
  887.           begin
  888.             DoInfo(siClose, 'Socket Disconnected On Error On Receive');
  889.             Close;
  890.             if Assigned(FOnDisconnect) then
  891.               FOnDisconnect(Self);
  892.           end;
  893.           raise ESockException.Create('Receive - Socket Error ' +
  894.             ErrToStr(Err));
  895.         end
  896.         else
  897.         begin
  898.           if Res > 0 then
  899.             FInBuffer := FInBuffer + Copy(FCharBuf, 1, Res)
  900.           else if Res = 0 then
  901.           begin
  902.             DoInfo(siClose, 'Socket Disconnected On Receive');
  903.             Close;
  904.             if Assigned(FOnDisconnect) then
  905.               FOnDisconnect(Self);
  906.           end;
  907.         end;
  908.       end;
  909.       Result := FInBuffer;
  910.       FInBuffer := '';
  911.       Dispose(FDSet);
  912.       Dispose(TV);
  913.     end
  914.     else
  915.     begin
  916.       if ((Count <> -1) and (Length(FInBuffer) > Count)) then
  917.       begin
  918.         Result := Copy(FInBuffer, 1, Count);
  919.         Delete(FInBuffer, 1, Count);
  920.       end
  921.       else
  922.       begin
  923.         Result := FInBuffer;
  924.         FInBuffer := '';
  925.       end;
  926.     end;
  927.   end
  928.   else
  929.     Result := ReceiveDatagram(HostN);
  930. end;
  931. function TSock.ReceiveLine: string;
  932. var
  933.   CPos, CLen: LongInt;
  934.   Temp: string;
  935. begin
  936.   CPos := 0;
  937.   Result := '';
  938.   if FSocketType = stStream then
  939.   begin
  940.     if (FBlocking and FConnected) then
  941.     begin
  942.       Temp := FInBuffer;
  943.       FInBuffer := '';
  944.       Temp := Temp + Receive;
  945.       FInBuffer := Temp;
  946.     end;
  947.     if (FLastChar = #13) and (FLineBreak = lbSmart) and (FInBuffer[1] = #10)
  948.       then
  949.     begin
  950.       Delete(FInBuffer, 1, 1);
  951.       FLastChar := #0;
  952.     end;
  953.     case FLineBreak of
  954.       lbCR: CPos := Pos(#13, FInBuffer);
  955.       lbLF: CPos := Pos(#10, FInBuffer);
  956.       lbCRLF: CPos := Pos(#13#10, FInBuffer);
  957.       lbSmart:
  958.         begin
  959.           CPos := Pos(#13, FInBuffer);
  960.           if (CPos = 0) or (Pos(#10, FInBuffer) < CPos) then
  961.             CPos := Pos(#10, FInBuffer);
  962.           if CPos > 0 then
  963.             FLastChar := FInBuffer[CPos]
  964.           else
  965.             FLastChar := #0;
  966.         end;
  967.     end;
  968.     if FLineBreak = lbCRLF then
  969.       CLen := 2
  970.     else
  971.       CLen := 1;
  972.     if (CPos > 0) or (not FConnected) then
  973.     begin
  974.       if CPos > 0 then
  975.       begin
  976.         Result := Copy(FInBuffer, 1, CPos - 1);
  977.         Delete(FInBuffer, 1, CPos + (CLen - 1));
  978.       end
  979.       else
  980.       begin
  981.         Result := FInBuffer;
  982.         FInBuffer := '';
  983.       end;
  984.     end;
  985.   end
  986.   else
  987.     Result := Receive;
  988. end;
  989. function TSock.SendDatagram(Value, HostName: string): Boolean;
  990. begin
  991.   if FSocket = INVALID_SOCKET then
  992.     raise ESockException.Create('SendDatagram - Socket Not Connected');
  993.   if FSocketType = stStream then
  994.     raise
  995.       ESockException.Create('SendDatagram - Datagram Send Not Supported On Stream Sockets');
  996.   Result := True;
  997.   SetHostName(HostName);
  998.   if Value = '' then
  999.     Exit;
  1000.   WinSock.SendTo(FSocket, Value[1], Length(Value), 0, FSockAddrIn,
  1001.     SizeOf(TSockAddrIn));
  1002. end;
  1003. function TSock.ReceiveDatagram(var HostName: string): string;
  1004. var
  1005.   Res: Integer;
  1006.   FDSet: PFDSet;
  1007.   TV: PTimeVal;
  1008.   FLen: Integer;
  1009. begin
  1010.   if FSocket = INVALID_SOCKET then
  1011.     raise ESockException.Create('ReceiveDatagram - Socket Not Connected');
  1012.   if FSocketType = stStream then
  1013.     raise
  1014.       ESockException.Create('ReceiveDatagram - Datagram Receive Not Supported On Stream Sockets');
  1015.   FDSet := New(PFDSet);
  1016.   FDSet^.FD_Count := 1;
  1017.   FDSet^.FD_Array[0] := FSocket;
  1018.   Result := '';
  1019.   HostName := '';
  1020.   if FBlockTime >= 0 then
  1021.   begin
  1022.     TV := New(PTimeVal);
  1023.     TV^.tv_sec := FBlockTime;
  1024.   end
  1025.   else
  1026.     TV := nil;
  1027.   if WinSock.Select(FSocket, FDSet, nil, nil, TV) > 0 then
  1028.   begin
  1029.     FLen := Sizeof(FRecvAddrIn);
  1030.     Res := WinSock.RecvFrom(FSocket, FCharBuf, SizeOf(FCharBuf), 0, FRecvAddrIn,
  1031.       FLen);
  1032.     if Res > 0 then
  1033.     begin
  1034.       Result := Copy(FCharBuf, 1, Res);
  1035.       HostName := GetRemoteHost;
  1036.     end
  1037.     else
  1038.       raise ESockException.Create('Socket Error while Receiving Datagram:' +
  1039.         IntToStr(WSAGetLastError));
  1040.   end;
  1041.   Dispose(FDSet);
  1042.   Dispose(TV);
  1043. end;
  1044. function TSock.Accept(var NewSock: TSock): Boolean;
  1045. var
  1046.   AcSck: TSocket;
  1047.   AddrL: Integer;
  1048.   Addr: TSockAddrIn;
  1049. begin
  1050.   // Accept Creates A New Instance Of A TSock Component And Returns It To The
  1051.   // User Application.  The User Is Responsible For Freeing The Component.
  1052.   if not FListen then
  1053.     raise ESockException.Create('Accept - Socket Not In Listening Mode');
  1054.   if FBlocking then
  1055.     DoInfo(SiAccept, 'Blocking Accept');
  1056.   AddrL := SizeOf(Addr);
  1057. {$IFDEF VER93}
  1058.   AcSck := WinSock.Accept(FSocket, Addr, AddrL);
  1059. {$ELSE}
  1060. {$IFDEF WIN32}
  1061.   AcSck := WinSock.Accept(FSocket, @Addr, @AddrL);
  1062. {$ELSE}
  1063.   AcSck := WinSock.Accept(FSocket, Addr, AddrL);
  1064. {$ENDIF}
  1065. {$ENDIF}
  1066.   FRecvAddrIn := Addr;
  1067.   if AcSck <> INVALID_SOCKET then
  1068.   begin
  1069.     NewSock := TSock.CreateWithSocket(Self, AcSck);
  1070.     NewSock.PortName := FPortName;
  1071.     NewSock.LocalPortName := FLocalPortName;
  1072.     NewSock.HostName := INet_NToA(Addr.SIn_Addr);
  1073.     Result := True;
  1074.     DoInfo(SiAccept, 'Created New TSock Structure');
  1075.   end
  1076.   else
  1077.   begin
  1078.     Result := False;
  1079.     DoInfo(SiAccept, 'Could Not Accept Connection');
  1080.   end;
  1081. end;
  1082. function TSock.HostLookup(Value: string): TInAddr;
  1083. type
  1084.   PLongInt = ^LongInt;
  1085. var
  1086.   PHost: PHostEnt;
  1087.   Res, I: Integer;
  1088.   AllNumeric: Boolean;
  1089. begin
  1090.   if Value = '' then
  1091.     Exit;
  1092.   DoInfo(SiLookUp, 'Lookup Of Host ' + Value);
  1093.   FillChar(Result, SizeOf(TInAddr), #0);
  1094.   AllNumeric := True;
  1095.   for I := 1 to Length(Value) do
  1096.     if not (Value[I] in ['0'..'9', '.']) then
  1097.     begin
  1098.       AllNumeric := False;
  1099.       Break;
  1100.     end;
  1101.   if AllNumeric then
  1102.     Result := TInAddr(WinSock.Inet_Addr(PChar(Value)))
  1103.       // If It's Dot-Notation, Just Convert It From An IP Address
  1104.   else
  1105.   begin
  1106.     Res := IPCache.IndexOf(Value);
  1107.     if Res >= 0 then
  1108.       // It's Cached... Don't Bother Doing A Lookup
  1109.       Result.S_Addr := U_Long(IPCache.Objects[Res])
  1110.     else
  1111.     begin
  1112.       // Isn't Cached, Have To Do A GetHostByName
  1113.       if Value <> '' then
  1114.       begin
  1115.         PHost := WinSock.GetHostByName(PChar(Value));
  1116.         if PHost <> nil then
  1117.         begin
  1118.           Result.S_Addr := LongInt(PLongInt(PHost^.H_Addr_List^)^);
  1119.           IPCache.AddObject(Value, Pointer(Result.S_Addr));
  1120.         end
  1121.         else
  1122.         begin
  1123.           // If Assigned(FOnInfo) then   // added by coder@dsplayer.de
  1124.             //       FOnInfo(self,siError,'Host Lookup - Could Not Find Host Entry');
  1125.            //Raise ESockException.Create('Host Lookup - Could Not Find Host Entry');
  1126.         end;
  1127.       end
  1128.       else
  1129.         Result.S_Addr := HToNL(INADDR_ANY);
  1130.     end;
  1131.   end;
  1132. end;
  1133. function TSock.PortLookup(Value: string): U_Short;
  1134. var
  1135.   PEnt: PServEnt;
  1136.   Prot: string;
  1137. begin
  1138.   DoInfo(SiLookUp, 'Lookup Of Port ' + Value);
  1139.   if Pos(Value[1], '0123456789') > 0 then
  1140.     // It's Numeric, Just Convert It To A Network Byte Order Integer
  1141.     Result := HToNS(StrToInt(Value))
  1142.   else
  1143.   begin
  1144.     // Otherwise, Perform A GetServByName Based On The Protocol
  1145.     if FSocketType = stStream then
  1146.       Prot := 'tcp'
  1147.     else
  1148.       Prot := 'udp';
  1149.     PEnt := WinSock.GetServByName(PChar(Value), PChar(Prot));
  1150.     if PEnt <> nil then
  1151.       Result := PEnt^.S_Port
  1152.     else
  1153.       raise ESockException.Create('Port Lookup - Could Not Find Service Entry');
  1154.   end;
  1155. end;
  1156. function TSock.StartListen: Boolean;
  1157. begin
  1158.   SetListen(True);
  1159.   Result := FListen;
  1160. end;
  1161. function TSock.StopListen: Boolean;
  1162. begin
  1163.   Result := True;
  1164.   SetListen(False);
  1165. end;
  1166. //*** Additional General-Purpose Support Functions *****************************
  1167. function WSDescription: string;
  1168. begin
  1169.   Result := StrPas(WSAData.szDescription);
  1170. end;
  1171. function WSSystemStatus: string;
  1172. begin
  1173.   Result := StrPas(WSAData.szSystemStatus);
  1174. end;
  1175. function GetLocalHostname: string;
  1176. var
  1177.   CharHostname: array[0..255] of Char;
  1178. begin
  1179.   Result := 'localhost';
  1180.   if WinSock.GetHostname(CharHostname, SizeOf(CharHostname)) = 0 then
  1181.     Result := CharHostname
  1182.   else
  1183.     raise
  1184.       ESockException.Create('GetLocalHostname - Could Not Retrieve Hostname');
  1185. end;
  1186. function SocketInfoText(Value: TSocketInfo): string;
  1187. begin
  1188.   Result := SocketInfoMsg[Value];
  1189. end;
  1190. function ErrToStr(Value: Integer): string;
  1191. begin
  1192.   Result := 'UNKNOWN ERROR';
  1193.   case Value of
  1194.     WSABASEERR + 4: Result := 'WSAEINTR';
  1195.     WSABASEERR + 9: Result := 'WSAEBADF';
  1196.     WSABASEERR + 13: Result := 'WSAEACCES';
  1197.     WSABASEERR + 14: Result := 'WSAEFAULT';
  1198.     WSABASEERR + 22: Result := 'WSAEINVAL';
  1199.     WSABASEERR + 24: Result := 'WSAEMFILE';
  1200.     WSABASEERR + 35: Result := 'WSAEWOULDBLOCK';
  1201.     WSABASEERR + 36: Result := 'WSAEINPROGRESS';
  1202.     WSABASEERR + 37: Result := 'WSAEALREADY';
  1203.     WSABASEERR + 38: Result := 'WSAENOTSOCK';
  1204.     WSABASEERR + 39: Result := 'WSAEDESTADDRREQ';
  1205.     WSABASEERR + 40: Result := 'WSAEMSGSIZE';
  1206.     WSABASEERR + 41: Result := 'WSAEPROTOTYPE';
  1207.     WSABASEERR + 42: Result := 'WSAENOPROTOOPT';
  1208.     WSABASEERR + 43: Result := 'WSAEPROTONOSUPPORT';
  1209.     WSABASEERR + 44: Result := 'WSAESOCKTNOSUPPORT';
  1210.     WSABASEERR + 45: Result := 'WSAEOPNOTSUPP';
  1211.     WSABASEERR + 46: Result := 'WSAEPFNOSUPPORT';
  1212.     WSABASEERR + 47: Result := 'WSAEAFNOSUPPORT';
  1213.     WSABASEERR + 48: Result := 'WSAEADDRINUSE';
  1214.     WSABASEERR + 49: Result := 'WSAEADDRNOTAVAIL';
  1215.     WSABASEERR + 50: Result := 'WSAENETDOWN';
  1216.     WSABASEERR + 51: Result := 'WSAENETUNREACH';
  1217.     WSABASEERR + 52: Result := 'WSAENETRESET';
  1218.     WSABASEERR + 53: Result := 'WSAECONNABORTED';
  1219.     WSABASEERR + 54: Result := 'WSAECONNRESET';
  1220.     WSABASEERR + 55: Result := 'WSAENOBUFS';
  1221.     WSABASEERR + 56: Result := 'WSAEISCONN';
  1222.     WSABASEERR + 57: Result := 'WSAENOTCONN';
  1223.     WSABASEERR + 58: Result := 'WSAESHUTDOWN';
  1224.     WSABASEERR + 59: Result := 'WSAETOOMANYREFS';
  1225.     WSABASEERR + 60: Result := 'WSAETIMEDOUT';
  1226.     WSABASEERR + 61: Result := 'WSAECONNREFUSED';
  1227.     WSABASEERR + 62: Result := 'WSAELOOP';
  1228.     WSABASEERR + 63: Result := 'WSAENAMETOOLONG';
  1229.     WSABASEERR + 64: Result := 'WSAEHOSTDOWN';
  1230.     WSABASEERR + 65: Result := 'WSAEHOSTUNREACH';
  1231.     WSABASEERR + 66: Result := 'WSAENOTEMPTY';
  1232.     WSABASEERR + 67: Result := 'WSAEPROCLIM';
  1233.     WSABASEERR + 68: Result := 'WSAEUSERS';
  1234.     WSABASEERR + 69: Result := 'WSAEDQUOT';
  1235.     WSABASEERR + 70: Result := 'WSAESTALE';
  1236.     WSABASEERR + 71: Result := 'WSAEREMOTE';
  1237.     WSABASEERR + 91: Result := 'WSASYSNOTREADY';
  1238.     WSABASEERR + 92: Result := 'WSAVERNOTSUPPORTED';
  1239.     WSABASEERR + 93: Result := 'WSANOTINITIALISED';
  1240.     WSABASEERR + 101: Result := 'WSAEDISCON';
  1241.     WSABASEERR + 1001: Result := 'WSAHOST_NOT_FOUND';
  1242.     WSABASEERR + 1002: Result := 'WSATRY_AGAIN';
  1243.     WSABASEERR + 1003: Result := 'WSANO_RECOVERY';
  1244.     WSABASEERR + 1004: Result := 'WSANO_DATA';
  1245.   end;
  1246. end;
  1247. // Base-64 Encoding Is The Process Of Taking An Input Stream And Converting
  1248. // Every 3 Bytes Into 4 Bytes, Each Of Which Whose ASCII Value Fits Within
  1249. // A 64-Bit Range.  Base-64 Is Often Used For Encoding Binary Streams For
  1250. // Attaching To Email, But Is Perfect For Converting Binary To A Character
  1251. // Set That Can Be Used For URL-Encoding.  The Base-64 Character Set Does Not
  1252. // Include Characters That URLs Use For Delimiting Such As '=', '&', Carriage
  1253. // Returns, Etc...
  1254. function Base64Encode(Value: string): string;
  1255. var
  1256.   AIn: array[1..3] of Byte;
  1257.   AOut: array[1..4] of Byte;
  1258.   AWork: array[1..3] of Byte;
  1259.   I: Integer;
  1260.   O: LongInt;
  1261. begin
  1262.   Result := '';
  1263.   I := 1;
  1264.   O := Length(Value);
  1265.   case Length(Value) mod 3 of
  1266.     1: Value := Value + #0 + #0;
  1267.     2: Value := Value + #0;
  1268.   end;
  1269.   while I < Length(Value) do
  1270.   begin
  1271.     AIn[1] := Byte(Value[I]);
  1272.     AIn[2] := Byte(Value[I + 1]);
  1273.     AIn[3] := Byte(Value[I + 2]);
  1274.     AOut[1] := Byte(AIn[1] shr 2);
  1275.     AWork[1] := Byte(AIn[1] shl 4);
  1276.     AWork[2] := Byte(AWork[1] and $30);
  1277.     AWork[3] := Byte(AIn[2] shr 4);
  1278.     AOut[2] := Byte(AWork[2] or AWork[3]);
  1279.     AWork[1] := Byte(AIn[2] shl 2);
  1280.     AWork[2] := Byte(AWork[1] and $3C);
  1281.     AWork[3] := Byte(AIn[3] shr 6);
  1282.     AOut[3] := Byte(AWork[2] or AWork[3]);
  1283.     AOut[4] := Byte(AIn[3] and $3F);
  1284.     Inc(I, 3);
  1285.     Result := Result + Base64Table[AOut[1] + 1] + Base64Table[AOut[2] + 1] +
  1286.       Base64Table[AOut[3] + 1] + Base64Table[AOut[4] + 1];
  1287.   end;
  1288.   if O mod 3 > 0 then
  1289.     Result[Length(Result)] := '=';
  1290.   if O mod 3 = 1 then
  1291.     Result[Length(Result) - 1] := '=';
  1292. end;
  1293. function Base64Decode(Value: string): string;
  1294. var
  1295.   AIn: array[1..4] of Byte;
  1296.   AOut: array[1..3] of Byte;
  1297.   AWork: array[1..3] of Byte;
  1298.   I: Integer;
  1299.   C: Integer;
  1300. begin
  1301.   Result := '';
  1302.   I := 1;
  1303.   while I < Length(Value) do
  1304.   begin
  1305.     C := 3;
  1306.     FillChar(AWork, SizeOf(AWork), #0);
  1307.     FillChar(AOut, SizeOf(AWork), #0);
  1308.     AIn[1] := Byte(Pos(Value[I], Base64Table) - 1);
  1309.     AIn[2] := Byte(Pos(Value[I + 1], Base64Table) - 1);
  1310.     AIn[3] := Byte(Pos(Value[I + 2], Base64Table) - 1);
  1311.     AIn[4] := Byte(Pos(Value[I + 3], Base64Table) - 1);
  1312.     if Value[I + 3] = '=' then
  1313.     begin
  1314.       C := 2;
  1315.       AIn[4] := 0;
  1316.       if Value[I + 2] = '=' then
  1317.       begin
  1318.         C := 1;
  1319.         AIn[3] := 0;
  1320.       end;
  1321.     end;
  1322.     AWork[2] := Byte(AIn[1] shl 2);
  1323.     AWork[3] := Byte(AIn[2] shr 4);
  1324.     AOut[1] := Byte(AWork[2] or AWork[3]);
  1325.     AWork[2] := Byte(AIn[2] shl 4);
  1326.     AWork[3] := Byte(AIn[3] shr 2);
  1327.     AOut[2] := Byte(AWork[2] or AWork[3]);
  1328.     AWork[2] := Byte(AIn[3] shl 6);
  1329.     AOut[3] := Byte(AWork[2] or AIn[4]);
  1330.     Result := Result + Char(AOut[1]);
  1331.     if C > 1 then
  1332.       Result := Result + Char(AOut[2]);
  1333.     if C > 2 then
  1334.       Result := Result + Char(AOut[3]);
  1335.     Inc(I, 4);
  1336.   end;
  1337. end;
  1338. // This function converts a string into a RFC 1630 compliant URL,
  1339. // provided that the string does not contain illegal characters at illegal
  1340. // places, for example this URL is invalid because of the ! sign in the password:
  1341. // ftp://ward:pass!word@ftp.ward.nu/my_documents/ward@mymail?
  1342. function URLEncode(Value: string): string;
  1343. var
  1344.   I: Integer;
  1345. begin
  1346.   Result := '';
  1347.   for I := 1 to Length(Value) do
  1348.   begin
  1349.     if Pos(UpperCase(Value[I]), ValidURLChars) > 0 then
  1350.       Result := Result + Value[I]
  1351.     else
  1352.     begin
  1353.       if Value[I] = ' ' then
  1354.         Result := Result + '+'
  1355.       else
  1356.       begin
  1357.         Result := Result + '%';
  1358.         Result := Result + IntToHex(Byte(Value[I]), 2);
  1359.       end;
  1360.     end;
  1361.   end;
  1362. end;
  1363. function URLDecode(Value: string): string;
  1364. const
  1365.   HexChars = '0123456789ABCDEF';
  1366. var
  1367.   I: Integer;
  1368.   Ch, H1, H2: Char;
  1369. begin
  1370.   Result := '';
  1371.   I := 1;
  1372.   while I <= Length(Value) do
  1373.   begin
  1374.     Ch := Value[I];
  1375.     case Ch of
  1376.       '%':
  1377.         begin
  1378.           H1 := Value[I + 1];
  1379.           H2 := Value[I + 2];
  1380.           Inc(I, 2);
  1381.           Result := Result + Chr(((Pos(H1, HexChars) - 1) * 16) + (Pos(H2,
  1382.             HexChars) - 1));
  1383.         end;
  1384.       '+': Result := Result + ' ';
  1385.       '&': Result := Result + #13 + #10;
  1386.     else
  1387.       Result := Result + Ch;
  1388.     end;
  1389.     Inc(I);
  1390.   end;
  1391. end;
  1392. //*** Registration And Initialization ******************************************
  1393. procedure Register;
  1394. begin
  1395.   RegisterComponents('Ward', [TSock]);
  1396. end;
  1397. initialization // (moved to create)
  1398.   // We're Looking To Use Version 1.1 Of WinSock Here
  1399. {  If WinSock.WSAStartup($0101, WSAData) <> 0 Then
  1400.      Raise ESockException.Create('WSAStartup - Could Not Initialize WinSock');
  1401.   IPCache := TStringList.Create;
  1402.   IPCache.Clear; }
  1403. finalization // moved to destroy
  1404.   { IPCache.Free;
  1405.    WinSock.WSACleanup;  }
  1406. end.