home *** CD-ROM | disk | FTP | other *** search
/ Delphi 2 - Developers' Solutions / Delphi 2 Developers' Solutions.iso / dds / chap10 / howto01 / delphi10 / ccicnntp.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-06-12  |  11.6 KB  |  337 lines

  1. unit Ccicnntp;
  2.  
  3. interface
  4.  
  5. uses
  6.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  7.   Forms, Dialogs, ExtCtrls, StdCtrls, Buttons, Menus, FileCtrl, CCWSock, CCICCInf,
  8.   CCICCPrf, IniFiles, Gauges, CCiccfrm;
  9. type
  10.   { Component to hold NNTP handling capabilities }
  11.   TNNTPComponent = class( TWinControl )
  12.   public
  13.     NNTPCommandInProgress ,
  14.     Connection_Established : Boolean;
  15.     Socket1 : TCCSocket;
  16.     constructor Create( AOwner : TComponent ); override;
  17.     destructor Destroy; override;
  18.     function EstablishConnection( PCRPointer : PConnectionsRecord ) : Boolean;
  19.     function Disconnect : Boolean;
  20.     function DoCStyleFormat(       TheText      : string;
  21.                              const TheArguments : array of const ) : String;
  22.     procedure UpdateGauge( BytesFinished , TotalToHandle : longint );
  23.     procedure AddProgressText( WhatText : String );
  24.     procedure ShowProgressText( WhatText : String );
  25.     procedure ShowProgressErrorText( WhatText : String );
  26.     function GetNNTPServerResponse( var ResponseString : String ) : integer;
  27.     procedure NNTPSocketsErrorOccurred( Sender     : TObject;
  28.                                      ErrorCode  : Integer;
  29.                                      TheMessage : String   );
  30.     function PerformNNTPCommand(
  31.                     TheCommand   : string;
  32.               const TheArguments : array of const ) : Integer;
  33.   end;
  34.  
  35. implementation
  36.  
  37. { This is another "Network" command which sets the GROUP to the name of the }
  38. { This sends FTP progress text to the Inet form }
  39. procedure TNNTPComponent.ShowProgressErrorText( WhatText : String );
  40. begin
  41.   CCInetCCForm.ShowProgressErrorText( WhatText );
  42. end;
  43.  
  44. { This is a core function! It performs an FTP command and if no timeout }
  45. { return a preliminary ok.                                              }
  46. function TNNTPComponent.PerformNNTPCommand(
  47.                  TheCommand        : string;
  48.            const TheArguments      : array of const ) : Integer;
  49. var TheBuffer : string; { Text buffer }
  50. begin
  51.   { If command in progress send back -1 error }
  52.   if NNTPCommandInProgress then
  53.   begin
  54.     Result := -1;
  55.     exit;
  56.   end;
  57.   { Set status variable }
  58.   NNTPCommandInProgress := True;
  59.   { Set global error code }
  60.   GlobalErrorCode := 0;
  61.   { Format output string }
  62.   TheBuffer := Format( TheCommand , TheArguments );
  63.   { Preset failure code }
  64.   Result := TCPIP_STATUS_FATAL_ERROR;
  65.   { If invalid socket or no connection abort }
  66.   if ( Socket1.TheSocket = INVALID_SOCKET ) or not Connection_Established then
  67.    exit;
  68.   { Send the buffer plus EOL chars }
  69.   Socket1.StringData := TheBuffer + #13#10;
  70.   { if abort due to timeout or other error exit }
  71.   if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  72.   { Otherwise return preliminary code }
  73.   Result := TCPIP_STATUS_PRELIMINARY;
  74. end;
  75.  
  76. { This function gets up to 255 chars of data plus a return code from FTP serv }
  77. function TNNTPComponent.GetNNTPServerResponse(
  78.           var ResponseString : String ) : integer;
  79. var
  80.   { Buffer string for response line }
  81.   TheBuffer     : string;
  82.   { Pointer to the response string }
  83.   BufferPointer : array[0..255] of char absolute TheBuffer;
  84.   { Character to check for response code }
  85.   ResponseChar   : char;
  86.   { Pointers into returned string }
  87.   TheIndex ,
  88.   TheLength     : integer;
  89.   { Control variable }
  90.   LeftoversInPan ,
  91.   Finished      : Boolean;
  92. begin
  93.   { Preset fatal error }
  94.   Result := TCPIP_STATUS_FATAL_ERROR;
  95.   { Start loop control }
  96.   LeftoversInPan := false;
  97.   Finished := false;
  98.   repeat
  99.     { Do a peek }
  100.     TheBuffer := Socket1.PeekData;
  101.     { If timeout or other error exit }
  102.     if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  103.     { Find end of line character }
  104.     TheIndex := Pos( #10 , TheBuffer );
  105.     if TheIndex = 0 then
  106.     begin
  107.       TheIndex := Pos( #13 , TheBuffer );
  108.       if TheIndex = 0 then
  109.       begin
  110.         TheIndex := Pos( #0 , TheBuffer );
  111.         if TheIndex = 0 then
  112.         begin
  113.           TheIndex := Length( TheBuffer );
  114.           LeftoversInPan := True;
  115.           LeftoverText := LeftoverText + TheBuffer;
  116.           LeftoversOnTable := false;
  117.         end;
  118.       end;
  119.     end;
  120.     { If an end of line then process the line }
  121.     if TheIndex > 0 then
  122.     begin
  123.       { Get length of string }
  124.       TheLength := TheIndex;
  125.       { Receive actual data }
  126.       Socket1.CCSockReceive( Socket1.TheSocket   ,
  127.                              @BufferPointer[ 1 ] ,
  128.                              TheLength              );
  129.       { Abort if timeout or error }
  130.       if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  131.       { Put in the length byte }
  132.       BufferPointer[ 0 ] := Chr( TheLength );
  133.       if LeftOversOnTable then
  134.       begin
  135.         LeftOversOnTable := false;
  136.         ResponseString := LeftoverText + TheBuffer;
  137.         TheBuffer := ResponseString;
  138.         LeftoverText := '';
  139.       end;
  140.       if LeftoversInPan then
  141.       begin
  142.         LeftoversInPan := false;
  143.         LeftoversOnTable := true;
  144.       end;
  145.       { Get first number character }
  146.       ResponseChar := TheBuffer[ 1 ];
  147.       { Get the value of the number from 1 to 5 }
  148.       if (( ResponseChar >= '1' ) and ( ResponseChar <= '5' )) then
  149.       begin
  150.         Finished := true;
  151.         Result := Ord( ResponseChar ) - 48;
  152.       end;
  153.     end
  154.     else
  155.     begin
  156.     end;
  157.   until ( Finished and ( not LeftoversOnTable ));
  158.   { Return buffer as response string }
  159.   ResponseString := TheBuffer;
  160. end;
  161.  
  162. { Boilerplate error routine }
  163. procedure TNNTPComponent.NNTPSocketsErrorOccurred( Sender     : TObject;
  164.                                                  ErrorCode  : Integer;
  165.                                                  TheMessage : String   );
  166. begin
  167.   CCInetCCForm.SocketsErrorOccurred( Sender,ErrorCode,TheMessage );
  168. end;
  169.  
  170. { This is the FTP components initial connection routine }
  171. function TNNTPComponent.EstablishConnection(
  172.           PCRPointer : PConnectionsRecord ) : Boolean;
  173. var TheReturnString : String;  { Internal string holder }
  174.     TheResult       : Integer; { Internal int holder    }
  175. begin
  176.   { Set default FTP Port value }
  177.   Socket1.PortName := '119';
  178.   { Get the ip address from the record }
  179.   Socket1.IPAddressName := PCRPointer^.CIPAddress;
  180.   { Set blocking mode }
  181.   Socket1.AsynchMode := False;
  182.   { Clear condition variables }
  183.   GlobalErrorCode := 0;
  184.   GlobalAbortedFlag := false;
  185.   { Actually attempt to connect }
  186.   Socket1.CCSockConnect;
  187.   { Check if connected }
  188.   if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 ) or
  189.       ( Socket1.TheSocket = INVALID_SOCKET )) then
  190.   begin { Didn't connect; signal error and abort }
  191.     { Do clever C formatting trick }
  192.     TheReturnString :=
  193.      DoCStyleFormat( 'NNTP Host %s Connection Failed!' ,
  194.       [ PCRPointer^.CIPAddress ] );
  195.     { Put result in progress and status line }
  196.     AddProgressText( TheReturnString );
  197.     ShowProgressErrorText( TheReturnString );
  198.     { Signal error }
  199.     Result := False;
  200.     { leave }
  201.     exit;
  202.   end
  203.   else
  204.   begin
  205.     Connection_Established := true;
  206.     { Signal successful connection }
  207.     TheReturnString := DoCStyleFormat(
  208.       'Connected on Local port: %s with IP: %s',
  209.       [ Socket1.GetSocketPort( Socket1.TheSocket ),
  210.         Socket1.GetSocketIPAddress( Socket1.TheSocket )]);
  211.     { Put result in progress and status line }
  212.     CCINetCCForm.AddProgressText( TheReturnString );
  213.     CCINetCCForm.ShowProgressText( TheReturnString );
  214.     TheReturnString := DoCStyleFormat(
  215.      'Connected to Remote port: %s with IP: %s',
  216.       [ Socket1.GetSocketPeerPort( Socket1.TheSocket ),
  217.         Socket1.GetSocketPeerIPAddress( Socket1.TheSocket )]);
  218.     { Put result in progress and status line }
  219.     CCINetCCForm.AddProgressText( TheReturnString );
  220.     CCINetCCForm.ShowProgressText( TheReturnString );
  221.     TheReturnString := DoCStyleFormat( 'Successfully connected to %s',
  222.      [ Socket1.IPAddressName ]);
  223.     { Put result in progress and status line }
  224.     CCINetCCForm.AddProgressText( TheReturnString );
  225.     CCINetCCForm.ShowProgressText( TheReturnString );
  226.     repeat
  227.       TheResult := GetNNTPServerResponse( TheReturnString );
  228.       { Put result in progress and status line }
  229.       AddProgressText( TheReturnString );
  230.       ShowProgressText( TheReturnString );
  231.     until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  232.     if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  233.     begin
  234.       { Do clever C formatting trick }
  235.       TheReturnString :=
  236.        DoCStyleFormat( 'NNTP Host %s Connection Failed!' ,
  237.         [ PCRPointer^.CIPAddress ] );
  238.       { Put result in progress and status line }
  239.       AddProgressText( TheReturnString );
  240.       ShowProgressErrorText( TheReturnString );
  241.       { Signal error }
  242.       Result := False;
  243.       { leave }
  244.       exit;
  245.     end
  246.     else Result := true; { Signal no problem }
  247.   end;
  248. end;
  249.  
  250. { This is the FTP component constructor; it creates 2 sockets }
  251. constructor TNNTPComponent.Create( AOwner : TComponent );
  252. begin
  253.   { do inherited create }
  254.   inherited Create( AOwner );
  255.   { Create socket, put in their parent, and error procs }
  256.   Socket1 := TCCSocket.Create( Self );
  257.   Socket1.Parent := Self;
  258.   Socket1.OnErrorOccurred := NNTPSocketsErrorOccurred;
  259.   { Set up booleans }
  260.   Connection_Established := false;
  261.   NNTPCommandInProgress := false;
  262. end;
  263.  
  264. { This is the FTP component destructor; it frees 2 sockets }
  265. destructor TNNTPComponent.Destroy;
  266. begin
  267.   { Free the socket }
  268.   Socket1.Free;
  269.   { and call inherited }
  270.   inherited Destroy;
  271. end;
  272.  
  273. procedure TNNTPComponent.UpdateGauge( BytesFinished , TotalToHandle : longint );
  274. begin
  275.   CCInetCCForm.UpdateGauge( BytesFinished , TotalToHandle );
  276. end;
  277.  
  278. { This sends FTP progress text to the Inet form }
  279. procedure TNNTPComponent.AddProgressText( WhatText : String );
  280. begin
  281.   CCInetCCForm.AddProgressText( WhatText );
  282. end;
  283.  
  284. { This sends FTP progress text to the Inet form }
  285. procedure TNNTPComponent.ShowProgressText( WhatText : String );
  286. begin
  287.   CCInetCCForm.ShowProgressText( WhatText );
  288. end;
  289.  
  290. { This is the FTP components QUIT routine }
  291. function TNNTPComponent.Disconnect : Boolean;
  292. var TheReturnString : String;  { Internal string holder }
  293.     TheResult       : Integer; { Internal int holder    }
  294. begin
  295.   TheReturnString :=
  296.    DoCStyleFormat( 'QUIT' ,
  297.     [ nil ] );
  298.   { Put result in progress and status line }
  299.   AddProgressText( TheReturnString );
  300.   ShowProgressText( TheReturnString );
  301.   { Begin login sequence with user name }
  302.   PerformNNTPCommand( 'QUIT', [ nil ] );
  303.   repeat
  304.     TheResult := GetNNTPServerResponse( TheReturnString );
  305.     { Put result in progress and status line }
  306.     AddProgressText( TheReturnString );
  307.     ShowProgressText( TheReturnString );
  308.   until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  309.   NNTPCommandInProgress := false;
  310.   if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  311.   begin
  312.     { Do clever C formatting trick }
  313.     TheReturnString :=
  314.      DoCStyleFormat( 'NNTP Host Connection Failed!' ,
  315.       [ nil ] );
  316.     { Put result in progress and status line }
  317.     AddProgressText( TheReturnString );
  318.     ShowProgressErrorText( TheReturnString );
  319.     { Signal error }
  320.     Result := False;
  321.     { leave }
  322.     exit;
  323.   end
  324.   else Result := true; { Signal no problem }
  325. end;
  326.  
  327. { This is a clever c-style formatting trick }
  328. function TNNTPComponent.DoCStyleFormat(
  329.                 TheText      : string;
  330.           const TheArguments : array of const ) : String;
  331. begin
  332.   Result := Format( TheText , TheArguments ) + #13#10;
  333. end;
  334.  
  335.  
  336. end.
  337.