home *** CD-ROM | disk | FTP | other *** search
/ Delphi 2 - Developers' Solutions / Delphi 2 Developers' Solutions.iso / dds / chap11 / howto04 / delphi10 / cciccpop.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-06-12  |  60.4 KB  |  1,703 lines

  1. unit Cciccpop;
  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 , CCUUCode, CCiccfrm;
  9.  
  10. const
  11.     The_Alphabet : array[ 0 .. 63 ] of char  =
  12.      'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  13. type
  14.   TMIMEErrorEvent = procedure( ErrorCode : Integer; ErrorMessage : String )
  15.    of object;
  16.   TMIMEUpdateEvent = procedure( BytesCompleted , TotalBytes : LongInt )
  17.    of object;
  18.   TMIMECodingObject = class( TWinControl )
  19.   private
  20.     FOnMIMEErrorOccurred  : TMIMEErrorEvent;
  21.     FOnMIMEUpdateOccurred : TMIMEUpdateEvent;
  22.   public
  23.     OutputString       : String;
  24.     The_Accumulator    : LongInt;
  25.     Total_Bits_Shifted : SmallInt;
  26.     BytesDone ,
  27.     BytesToGet        : Longint;
  28.     ErrorResult       : Integer;
  29.     ErrorMessage      : String;
  30.     Base64Found       : Boolean;
  31.     TheBoundaryString : String;
  32.     TheInputFileName : String;
  33.     TheOutputFileName : String;
  34.     TheInputTextFile : TextFile;
  35.     TheOutputBinaryFile : File of Byte;
  36.     constructor Create( AOwner : TComponent ); override;
  37.     function IsBoundaryToken( TheLine : String ) : String;
  38.     function IsDecodeName( TheLine : String ) : String;
  39.     function IsBase64( TheLine : String ) : Boolean;
  40.     function IsBoundary( TheLine : String ) : Boolean;
  41.     function DecodeMIMEFile : Boolean;
  42.     function OpenDecodeInputFile : Boolean;
  43.     function OpenDecodeOutputFile : Boolean;
  44.     function CloseDecodeFiles : Boolean;
  45.     procedure MIMEError( ECode : Integer; EMsg : String );
  46.     procedure MIMEUpdate( BSF , BT : LongInt );
  47.     function GetQuotedString( TheInputString : String ) : String;
  48.     function ConvertBase64Character( Current_Character : Char ) : SmallInt;
  49.     procedure InitializeMIMEDecode;
  50.     function GetTextFileSize( TheName : String ) : Longint;
  51.     function MIMEDecode( TheString : String ) : Boolean;
  52.     function AddBinaryValueToStream( BinaryValue : SmallInt ) : Boolean;
  53.     property OnMIMEErrorOccurred : TMIMEErrorEvent read FOnMIMEErrorOccurred
  54.      write FOnMIMEErrorOccurred;
  55.     property OnMIMEUpdateOccurred : TMIMEUpdateEvent read FOnMIMEUpdateOccurred
  56.      write FOnMIMEUpdateOccurred;
  57.   end;
  58.   { Component To Hold POP3/SMTP handling capabilities }
  59.   TPOP3SMTPComponent = class( TWinControl )
  60.   public
  61.     POP3CommandInProgress ,
  62.     Connection_Established : Boolean;
  63.     Socket1 : TCCSocket;
  64.     constructor Create( AOwner : TComponent ); override;
  65.     destructor Destroy; override;
  66.     function EstablishPOP3Connection( PCRPointer : PConnectionsRecord ) : Boolean;
  67.     function POP3Disconnect : Boolean;
  68.     function DoCStyleFormat(       TheText      : string;
  69.                              const TheArguments : array of const ) : String;
  70.     procedure UpdateGauge( BytesFinished , TotalToHandle : longint );
  71.     procedure AddProgressText( WhatText : String );
  72.     procedure ShowProgressText( WhatText : String );
  73.     procedure ShowProgressErrorText( WhatText : String );
  74.     function GetPOP3ServerResponse( var ResponseString : String ) : integer;
  75.     procedure POP3SMTPSocketsErrorOccurred( Sender     : TObject;
  76.                                      ErrorCode  : Integer;
  77.                                      TheMessage : String   );
  78.     function PerformPOP3Command(
  79.                     TheCommand   : string;
  80.               const TheArguments : array of const ) : Integer;
  81.     function PerformPOP3ExtendedCommand(
  82.                     TheCommand   : string;
  83.               const TheArguments : array of const ) : Integer;
  84.     function GetPOP3ServerExtendedResponse( ResponseString : PChar ) : integer;
  85.     function GetNextSDItem(     WorkingString : String;
  86.                             var TheIndex      : Integer ) : String;
  87.     procedure PurgeTrashedMessageListings( TheEMBRecord : PEMailMailBoxRecord );
  88.     procedure TrashMessage( TheEMMRecord : PEMailMessageRecord );
  89.     procedure TrashAllMarkedMessages( TheLB       : TListBox;
  90.                                       TheMBRecord : PEMailMailboxRecord );
  91.     procedure ParseMailListing(     TheListing : String;
  92.                                 var TotalMessages : Longint;
  93.                                 var MessageBytes : Longint);
  94.     function CheckAllNewMail( var TotalBytes : Longint ) : Integer;
  95.     function GetMessageHeader( TheReturnList : TStringList ) : Longint;
  96.     function DownloadMessageListing( TheNumber   : Integer;
  97.                                      TheFileName : String;
  98.                                      TheHeaderSL : TStringList ) : Longint;
  99.     function DownloadAllMessageListings( TheEMBRecord : PEMailMailBoxRecord ) : Boolean;
  100.     function GetHeaderSubject( HList : TStringList ) : String;
  101.     function GetHeaderSender( HList : TStringList ) : String;
  102.     function GetHeaderRecipient( HList : TStringList ) : String;
  103.     function GetHeaderCarbons( HList : TStringList ) : String;
  104.     function GetHeaderBlindCarbons( HList : TStringList ) : String;
  105.     function GetHeaderDateTime( HList : TStringList ) : String;
  106.     procedure TransferMessage( SourceEMBRecord , TargetEMBRecord : PEMailMailBoxRecord;
  107.                               MessageNumber : Integer );
  108.     function LoginUser( PCRPointer : PConnectionsRecord ) : Boolean;
  109.     function SendPassword( PCRPointer : PConnectionsRecord ) : Boolean;
  110.     function DeleteMailItem( TheNumber : Longint ) : Boolean;
  111.   end;
  112.  
  113. var
  114.   ThePOP3SMTPComponent  : TPOP3SMTPComponent; { Gee, which one is this? :) }
  115.   TheMIMEObject : TMIMECodingObject;
  116.  
  117. implementation
  118.  
  119. { Create constructor; sets update and error methods }
  120. constructor TMIMECodingObject.Create( AOwner : TComponent );
  121. begin
  122.   { Call inherited }
  123.   Inherited Create( AOwner );
  124.   { Setup two methods; can be overridden }
  125.   OnMIMEErrorOccurred := MIMEError;
  126.   OnMIMEUpdateOccurred := MIMEUpdate;
  127. end;
  128.  
  129. { This procedure resets the two decoding variables }
  130. procedure TMIMECodingObject.InitializeMIMEDecode;
  131. begin
  132.   The_Accumulator := 0;
  133.   Total_Bits_Shifted := 0;
  134.   BytesDone := 0;
  135. end;
  136.  
  137. { This is the generic error handler }
  138. procedure TMIMECodingObject.MIMEError( ECode : Integer; EMsg : String );
  139. begin
  140.   { Do generic MessageBox }
  141.   MessageDlg( 'A MIME error code ' + IntToStr( ECode ) +
  142.    ' has happend with Message ' + EMsg , mtError , [mbOK] , 0 );
  143. end;
  144.  
  145. { This is the generic update procedure }
  146. procedure TMIMECodingObject.MIMEUpdate( BSF , BT : LongInt );
  147. begin
  148.   CCInetCCForm.UpdateMIMEGauge( BSF , BT );
  149. end;
  150.  
  151. { This function takes an input string and returns any "" delimited text in it }
  152. function TMIMECodingObject.GetQuotedString( TheInputString : String ) : String;
  153. var HoldingString : String;  { Interim results holder }
  154.     PositionIndex : Integer; { " position holder      }
  155. begin
  156.   { Look for initial positon of double quote }
  157.   PositionIndex := Pos( '"' , TheInputString );
  158.   { If not found, then no quoted text; return empty string }
  159.   if PositionIndex = 0 then
  160.   begin
  161.     Result := '';
  162.     exit;
  163.   end;
  164.   { Otherwise get from just beyond " to end of string, allowing for unlimited }
  165.   { string sizes now in Delphi 2.0                                            }
  166.   HoldingString := Copy( TheInputString , PositionIndex + 1 ,
  167.    ( Length( TheInputString ) - PositionIndex ));
  168.   { Find ending " if any }
  169.   PositionIndex := Pos( '"' , HoldingString );
  170.   { If no ending " then assume all from first quote is result }
  171.   if PositionIndex = 0 then
  172.   begin
  173.     Result := HoldingString;
  174.     exit;
  175.   end;
  176.   { Otherwise get down to 1 before closing " }
  177.   HoldingString := Copy( HoldingString , 1 , PositionIndex - 1 );
  178.   { and return the ""-stripped string as desired }
  179.   Result := HoldingString;
  180. end;
  181.  
  182. { This function scans a line of text for the keyword 'boundary=' }
  183. function TMIMECodingObject.IsBoundaryToken( TheLine : String ) : String;
  184. begin
  185.   { Find out if it's a boundary token symbol }
  186.   if Pos( 'boundary=' , lowercase( TheLine )) <> 0 then
  187.   begin
  188.     { And grab the value }
  189.     Result := GetQuotedString( TheLine );
  190.   end
  191.   else
  192.   begin
  193.     { Else return empty string }
  194.     Result := '';
  195.   end;
  196. end;
  197.  
  198. { This function determines if the "name=" token is on a line and if so }
  199. { Returns the quoted file name as its result; otherwise it returns ''  }
  200. function TMIMECodingObject.IsDecodeName( TheLine : String ) : String;
  201. var PositionIndex : Integer; { Holds possible position of name= token }
  202.     HoldingString : String;  { Holds working string once token found  }
  203.     ResultString  : String;  { Holds name once stripped out of ""     }
  204. begin
  205.   { Find out if name= token in line }
  206.   PositionIndex := Pos( 'name=' , lowercase( TheLine ));
  207.   { If not reutrn the empty string }
  208.   if PositionIndex = 0 then
  209.   begin
  210.     Result := '';
  211.   end
  212.   else
  213.   begin
  214.     { Otherwise strip out stuff before token }
  215.     HoldingString := Copy( TheLine , PositionIndex + 1 ,
  216.      ( Length( TheLine ) - PositionIndex ));
  217.     { And send rest through stripquotes to get filename }
  218.     ResultString := GetQuotedString( HoldingString );
  219.     { Send it back; if malformed will be '' }
  220.     Result := ResultString;
  221.   end;
  222. end;
  223.  
  224. { This function returns true if the Base64 token is found, otherwise false }
  225. function TMIMECodingObject.IsBase64( TheLine : String ) : Boolean;
  226. begin
  227.   { if substring found assume valid token and return true else return false }
  228.   if Pos( 'base64' , lowercase( TheLine )) > 0 then Result := true
  229.    else Result := false;
  230. end;
  231.  
  232. { This funcion assumes the boundary string has been found; once it's known }
  233. { this function tells whether a line contains it.                          }
  234. function TMIMECodingObject.IsBoundary( TheLine : String ) : Boolean;
  235. begin
  236.   { A valid substring hit means true otherwise false }
  237.   if Pos( TheBoundaryString , TheLine ) <> 0 then Result := true else
  238.    Result := false;
  239. end;
  240.  
  241. { This is a clever function to get the total bytes of a text file }
  242. function TMIMECodingObject.GetTextFileSize( TheName : String ) : Longint;
  243. var TheSR : TSearchRec; { Used for trick }
  244. begin
  245.   { This allows getting the data }
  246.   FindFirst( TheName , faAnyFile , TheSR );
  247.   { And this is the info }
  248.   Result := TheSR.Size;
  249.   { Needed for win32 }
  250.   {FindClose( TheSR )};
  251. end;
  252.  
  253. { This function uses Try..Except loops to check for valid file openings }
  254. function TMIMECodingObject.OpenDecodeInputFile : Boolean;
  255. begin
  256.   { Use a try..except loop to catch IOErrors }
  257.   try
  258.     { assign the text input file to the input filename }
  259.     AssignFile( TheInputTextFile , TheInputFileName );
  260.     { do a reset }
  261.     Reset( TheInputTextFile );
  262.     { Get total bytes of a text file! }
  263.     BytesToGet := GetTextFileSize( TheInputFileName );
  264.   except
  265.     { Set error information on an input/output failure }
  266.     On E:EInOutError do
  267.     begin
  268.       { Get error message from exception object }
  269.       ErrorResult := -E.ErrorCode;
  270.       { Get filename and error message from exception object }
  271.       ErrorMessage := 'Unable to open Input File ' + TheInputFileName +
  272.        ' Due to ' + E.Message;
  273.       { if assigned error event then call it with info }
  274.       if Assigned( FOnMIMEErrorOccurred ) then
  275.        OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  276.       { return false on an error }
  277.       Result := false;
  278.       exit;
  279.     end;
  280.   end;
  281.   { Return true on no error }
  282.   Result := true;
  283. end;
  284.  
  285. { This function uses Try..Except loops to check for valid file openings }
  286. function TMIMECodingObject.OpenDecodeOutputFile : Boolean;
  287. begin
  288.   { Use a try..except loop to catch IOErrors }
  289.   try
  290.     { assign the binary output file to the parsed output filename }
  291.     AssignFile( TheOutputBinaryFile , TheOutputFileName );
  292.     { do a rewrite }
  293.     ReWrite( TheOutputBinaryFile );
  294.   except
  295.     { Set error information on an input/output failure }
  296.     On E:EInOutError do
  297.     begin
  298.       { Get error message from exception object }
  299.       ErrorResult := -E.ErrorCode;
  300.       { Get filename and error message from exception object }
  301.       ErrorMessage := 'Unable to open Output File ' + TheOutputFileName +
  302.        ' Due to ' + E.Message;
  303.       { if assigned error event then call it with info }
  304.       if Assigned( FOnMIMEErrorOccurred ) then
  305.        OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  306.       { return false on an error }
  307.       Result := false;
  308.       exit;
  309.     end;
  310.   end;
  311.   { Return true on no error }
  312.   Result := true;
  313. end;
  314.  
  315. { This closes both files and signals any error }
  316. function TMIMECodingObject.CloseDecodeFiles : Boolean;
  317. begin
  318.   { Use try..except to catch errors }
  319.   try
  320.     { Do both closefiles }
  321.     CloseFile( TheInputTextFile );
  322.     CloseFile( TheOutputBinaryFile );
  323.   except
  324.     { Set error information on an input/output failure }
  325.     On E:EInOutError do
  326.     begin
  327.       { Get error message from exception object }
  328.       ErrorResult := -E.ErrorCode;
  329.       { Get filename and error message from exception object }
  330.       ErrorMessage := 'Unable to close file(s) ' + ' Due to ' + E.Message;
  331.       { if assigned error event then call it with info }
  332.       if Assigned( FOnMIMEErrorOccurred ) then
  333.        OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  334.       { return false on an error }
  335.       Result := false;
  336.       exit;
  337.     end;
  338.   end;
  339.   { No error sends true }
  340.   Result := true;
  341. end;
  342.  
  343. { This function assumes the input filename is set but it does the rest }
  344. function TMIMECodingObject.DecodeMIMEFile : Boolean;
  345. var Finished      : Boolean; { Loop control variable }
  346.     Completed     : Boolean; { Loop control variable }
  347.     WorkingString : String;  { Input holder          }
  348. begin
  349.   { clear boundary marker }
  350.   TheBoundaryString := '';
  351.   { Set failure default return value; specific error handling }
  352.   { will be done be individual functions via ErrorResult and  }
  353.   { HandleMIMEError.                                          }
  354.   Result := false;
  355.   { Try to open the input text file }
  356.   if not OpenDecodeInputFile then exit;
  357.   { Clear loop variable }
  358.   Finished := false;
  359.   { Run till either end of file or signal done }
  360.   while (( not Finished ) and ( not EOF( TheInputTextFile ))) do
  361.   begin
  362.     { Get a line }
  363.     Readln( TheInputTextFile , WorkingString );
  364.     { Do the process count }
  365.     BytesDone := BytesDone + Length( WorkingString );
  366.     { Find out if the boundary token }
  367.     TheBoundaryString := IsBoundaryToken( WorkingString );
  368.     { If found then set exit variable }
  369.     if TheBoundaryString <> '' then Finished := true;
  370.   end;
  371.   { if no boundary marker found then go bye bye }
  372.   if TheBoundaryString = '' then
  373.   begin
  374.     { Set error message }
  375.     ErrorResult := -101;
  376.     { Get filename and error message from exception object }
  377.     ErrorMessage := 'No Boundary Token Found!';
  378.     { if assigned error event then call it with info }
  379.     if Assigned( FOnMIMEErrorOccurred ) then
  380.      OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  381.     exit;
  382.   end;
  383.   { Clear control variables }
  384.   Finished := false;
  385.   Base64Found := false;
  386.   TheOutputFileName := '';
  387.   { run loop to get name and confirm base64 encoding }
  388.   while (( not Finished ) and ( not EOF( TheInputTextFile ))) do
  389.   begin
  390.     { This outer loop grabs lines of text; does multiple boundaries }
  391.     Readln( TheInputTextFile , WorkingString );
  392.     { Do the process count }
  393.     BytesDone := BytesDone + Length( WorkingString );
  394.     { if hit a boundary then look for the base64 stuff }
  395.     if IsBoundary( WorkingString ) then
  396.     begin
  397.       { Set loop control }
  398.       Completed := false;
  399.       { run until run out of file or hit blank line }
  400.       while (( not Completed ) and ( not EOF( TheInputTextfile ))) do
  401.       begin
  402.         { Get line }
  403.         Readln( TheInputTextFile , WorkingString );
  404.         { Do the process count }
  405.         BytesDone := BytesDone + Length( WorkingString );
  406.         { if a blank then go bye bye }
  407.         if WorkingString = '' then
  408.         begin
  409.           Completed := true;
  410.         end
  411.         else
  412.         begin
  413.           { Get both possible output name and base64 OK }
  414.           if TheOutputFileName = '' then
  415.            TheOutputFileName := IsDecodeName( WorkingString );
  416.           if not Base64Found then
  417.            Base64Found := IsBase64( WorkingString );
  418.         end;
  419.       end;
  420.       { if found a blank line then check for valid base64 file }
  421.       if Completed then
  422.       begin
  423.         { If got an output filename and found b64 then set finished }
  424.         if (( TheOutputFileName <> '' ) and Base64Found ) then
  425.          Finished := true;
  426.       end;
  427.     end;
  428.   end;
  429.   { If never completed or output data not found then exit }
  430.   if not Finished then
  431.   begin
  432.     if TheOutputFileName = '' then
  433.     begin
  434.       { Set error message }
  435.       ErrorResult := -102;
  436.       { Get filename and error message from exception object }
  437.       ErrorMessage := 'No output filename found!';
  438.       { if assigned error event then call it with info }
  439.       if Assigned( FOnMIMEErrorOccurred ) then
  440.        OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  441.     end
  442.     else
  443.     begin
  444.       { Set error message }
  445.       ErrorResult := -103;
  446.       { Get filename and error message from exception object }
  447.       ErrorMessage := 'Not Base64 encoding!';
  448.       { if assigned error event then call it with info }
  449.       if Assigned( FOnMIMEErrorOccurred ) then
  450.        OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  451.     end;
  452.     exit;
  453.   end;
  454.   { Try to open the decode output file }
  455.   if not OpenDecodeOutputFile then exit;
  456.   { Set loop control variable }
  457.   Finished := false;
  458.   { Set up the decode variables }
  459.   InitializeMIMEDecode;
  460.   { run loop to get binary data }
  461.   while (( not Finished ) and ( not EOF( TheInputTextFile ))) do
  462.   begin
  463.     { Get an input line }
  464.     Readln( TheInputTextFile , WorkingString );
  465.     { Do the process count }
  466.     BytesDone := BytesDone + Length( WorkingString );
  467.     { If it's a boundary then don't process it otherwise do decode }
  468.     if not IsBoundary( WorkingString ) then
  469.     begin
  470.       { If decodes ok keep going else abort }
  471.       if not MIMEDecode( WorkingString ) then exit;
  472.       { Update status indicator }
  473.       if Assigned( FOnMIMEUpdateOccurred ) then
  474.        OnMIMEUpdateOccurred( BytesDone , BytesToGet );
  475.     end
  476.     { End processing if a boundary found }
  477.     else Finished := true;
  478.   end;
  479.   { Clear status indicator }
  480.   if Assigned( FOnMIMEUpdateOccurred ) then
  481.    OnMIMEUpdateOccurred( BytesToGet , BytesToGet );
  482.   { Close the files }
  483.   if not CloseDecodeFiles then exit;
  484.   { Return success }
  485.   Result := true;
  486. end;
  487.  
  488. { This function returns a binary number based on the ascii of the input char }
  489. function TMIMECodingObject.ConvertBase64Character( Current_Character : Char ) :
  490.  SmallInt;
  491. begin
  492.    { Decode ordinals of uppercase characters 0 - 25 }
  493.    if (( Current_Character >= 'A' ) and
  494.        ( Current_Character <= 'Z' )) then
  495.    begin
  496.      result :=
  497.       SmallInt( Ord( Current_Character ) - Ord( 'A' ));
  498.      exit;
  499.    end;
  500.    { Decode ordinals of lowercase characters 26 - 51 }
  501.    if (( Current_Character >= 'a') and
  502.        ( Current_Character <= 'z')) then
  503.    begin
  504.      result := 26 +
  505.        SmallInt( Ord( Current_Character ) - Ord( 'a' ));
  506.      exit;
  507.    end;
  508.    { Decode ordinals of numbers 52 - 61 }
  509.    if (( Current_Character >= '0') and
  510.        ( Current_Character <= '9' )) then
  511.    begin
  512.      result := 52 +
  513.        SmallInt( Ord( Current_Character ) - Ord( '0' ));
  514.      exit;
  515.    end;
  516.    { Decode + as 62 }
  517.    if ( Current_Character = '+' ) then
  518.    begin
  519.      result := 62;
  520.      exit;
  521.    end;
  522.    { Decode / as 63 }
  523.    if ( Current_Character = '/' ) then
  524.    begin
  525.      result := 63;
  526.      exit;
  527.    end;
  528.    { Signal padding character = by -2 }
  529.    if ( Current_Character = '=' ) then
  530.    begin
  531.      result := -2;
  532.      exit;
  533.    end;
  534.    { Signal invalid character by -1 }
  535.    result := -1;
  536. end;
  537.  
  538. { This function does bit magic on the current data state and when appropriate }
  539. { writes a byte to the output file.                                           }
  540. function TMIMECodingObject.AddBinaryValueToStream( BinaryValue : SmallInt ) :
  541.  Boolean;
  542. var WorkingValue : SmallInt; { Used to store bit conversion }
  543.     OutputValue  : Byte;     { Used to store output byte    }
  544. begin
  545.   { Assume success; only error will be file write failure }
  546.   Result := true;
  547.   { Shift over six bits of the accumulator }
  548.   The_Accumulator := The_Accumulator SHL 6;
  549.   { Add the shift to the counter }
  550.   Total_Bits_Shifted := Total_Bits_Shifted + 6;
  551.   { OR in the acquired bits }
  552.   { first char =  6 bits }
  553.   { 2nd   char = 12 bits; moved back to 4 }
  554.   { 3rd   char = 10 bits; moved back to 2 }
  555.   { 4th   char =  8 bits; moved back to 0 }
  556.   The_Accumulator := ( The_Accumulator or BinaryValue );
  557.   { If have at least one valid output byte }
  558.   if  Total_Bits_Shifted >= 8 then
  559.   begin
  560.     { Reduce remaining bits by 8 }
  561.     Total_Bits_Shifted := Total_Bits_Shifted - 8;
  562.     { Grab last full 8 bits in the accumulator }
  563.     { note that continual shifting clears it   }
  564.     WorkingValue := The_Accumulator SHR Total_Bits_Shifted;
  565.     { Mask off the high byte of the smallint }
  566.     OutputValue := byte( WorkingValue and $00FF );
  567.     { Use try..except to write out the byte }
  568.     try
  569.       { Do a seek for safety }
  570.       Seek( TheOutputBinaryFile , FileSize( TheOutputBinaryFile ));
  571.       { write the data byte }
  572.       Write( TheOutputBinaryFile , OutputValue );
  573.     except
  574.       { Set error information on an input/output failure }
  575.       On E:EInOutError do
  576.       begin
  577.         { Get error message from exception object }
  578.         ErrorResult := -E.ErrorCode;
  579.         { Get filename and error message from exception object }
  580.         ErrorMessage := 'Unable to Write output byte Due to ' + E.Message;
  581.         { if assigned error event then call it with info }
  582.         if Assigned( FOnMIMEErrorOccurred ) then
  583.          OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  584.         { return false on an error }
  585.         Result := false;
  586.         exit;
  587.       end;
  588.     end;
  589.   end;
  590. end;
  591.  
  592. { This function does the dirty work of doing the MIME decoding }
  593. function TMIMECodingObject.MIMEDecode( TheString : String ) : Boolean;
  594. var Counter_1         : Integer;   { Loop counter }
  595.     Current_Character : Char;      { Decode char  }
  596.     Binary_Value      : SmallInt;  { Output value }
  597. begin
  598.   { Assume success }
  599.   Result := true;
  600.   { Ignore blank lines }
  601.   if TheString = '' then exit;
  602.   { Run along string }
  603.   for Counter_1 := 1 to Length( TheString ) do
  604.   begin
  605.     { get char to decode }
  606.     Current_Character := TheString[ Counter_1 ];
  607.     { convert char to binary via lookup function }
  608.     Binary_Value := ConvertBase64Character( Current_Character );
  609.     { if -2 hit = padding char; abort }
  610.     if Binary_Value = -2 then exit;
  611.     { if invalid char signal error }
  612.     if Binary_Value = -1 then
  613.     begin
  614.       { Set error message }
  615.       ErrorResult := -104;
  616.       { Get filename and error message from exception object }
  617.       ErrorMessage := 'Invalid Input Character!';
  618.       { if assigned error event then call it with info }
  619.       if Assigned( FOnMIMEErrorOccurred ) then
  620.        OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  621.       { signal error and exit }
  622.       Result := false;
  623.       exit;
  624.     end;
  625.     { try to send the binary value through the byte cruncher }
  626.     if not AddBinaryValueToStream( Binary_Value ) then
  627.     begin
  628.       { If failed return error since had disk write error }
  629.       Result := false;
  630.       exit;
  631.     end;
  632.   end;
  633. end;
  634.  
  635. procedure TPOP3SMTPComponent.TrashMessage( TheEMMRecord : PEMailMessageRecord );
  636. begin
  637.   TheEMMRecord^.MRMessageSender := 'DELETE ME';
  638. end;
  639.  
  640. procedure TPOP3SMTPComponent.TrashAllMarkedMessages( TheLB       : TListBox;
  641.                                                      TheMBRecord : PEMailMailboxRecord );
  642. var Counter_1 : Integer;
  643.     WorkingList : TList;
  644. begin
  645.   WorkingList := TList( TheMBRecord^.MBLTag );
  646.   for Counter_1 := 0 to TheLB.Items.Count - 1 do
  647.   begin
  648.     if TheLB.Selected[ Counter_1 ] then
  649.     begin
  650.       TrashMessage( PEMailMessageRecord( WorkingList.Items[ Counter_1 ] ));
  651.     end;
  652.   end;
  653. end;
  654.  
  655. { This function calls an extended response POP3SMTP command routine }
  656. function TPOP3SMTPComponent.PerformPOP3ExtendedCommand(
  657.                TheCommand   : string;
  658.          const TheArguments : array of const ) : Integer;
  659. var TheBuffer : string; { Text buffer }
  660. begin
  661.   { If command in progress send back -1 error }
  662.   if POP3CommandInProgress then
  663.   begin
  664.     Result := -1;
  665.     exit;
  666.   end;
  667.   { Set status variable }
  668.   POP3CommandInProgress := True;
  669.   { Set global error code }
  670.   GlobalErrorCode := 0;
  671.   { Format output string }
  672.   TheBuffer := Format( TheCommand , TheArguments );
  673.   { Preset failure code }
  674.   Result := TCPIP_STATUS_FATAL_ERROR;
  675.   { If invalid socket or no connection abort }
  676.   if ( Socket1.TheSocket = INVALID_SOCKET ) or not Connection_Established then
  677.    exit;
  678.   { Send the buffer plus EOL chars }
  679.   Socket1.StringData := TheBuffer + #13#10;
  680.   { if abort due to timeout or other error exit }
  681.   if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  682.   { Otherwise return preliminary code }
  683.   Result := TCPIP_STATUS_PRELIMINARY;
  684. end;
  685.  
  686. { This function gets an extended period-ended multiline response from the server }
  687. function TPOP3SMTPComponent.GetPOP3ServerExtendedResponse( ResponseString : PChar ) : integer;
  688. var
  689.   { Assume ResponseString already allocated as 0..513 }
  690.   { Pointer to the response string }
  691.   TheBuffer ,
  692.   BufferPointer : array[0..255] of char;
  693.   HolderBuffer : array[0..513] of char;
  694.   { Character to check for response code }
  695.   ResponseChar   : char;
  696.   { Pointers into returned string }
  697.   TheIndex ,
  698.   TheLength     : integer;
  699.   { Control variable }
  700.   LeftoversInPan ,
  701.   Finished      : Boolean;
  702.   BufferString : String;
  703. begin
  704.   { Preset fatal error }
  705.   Result := TCPIP_STATUS_FATAL_ERROR;
  706.   { Start loop control }
  707.   LeftoversInPan := false;
  708.   Finished := false;
  709.   StrCopy( HolderBuffer , '' );
  710.   repeat
  711.     { Do a peek }
  712.     BufferString := Socket1.PeekData;
  713.     { If timeout or other error exit }
  714.     if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  715.     { Find end of line character }
  716.     TheIndex := Pos( #10 , BufferString );
  717.     if TheIndex = 0 then
  718.     begin
  719.       TheIndex := Pos( #13 , BufferString );
  720.       if TheIndex = 0 then
  721.       begin
  722.         TheIndex := Pos( #0 , BufferString );
  723.         if TheIndex = 0 then
  724.         begin
  725.           TheIndex := Length( BufferString );
  726.           LeftoversInPan := True;
  727.           StrPCopy( TheBuffer , BufferString );
  728.           StrCat( HolderBuffer , TheBuffer );
  729.           LeftoversOnTable := false;
  730.         end;
  731.       end;
  732.     end;
  733.     { If an end of line then process the line }
  734.     if TheIndex > 0 then
  735.     begin
  736.       { Get length of string }
  737.       TheLength := TheIndex;
  738.       { Receive actual data }
  739.       Socket1.CCSockReceive( Socket1.TheSocket   ,
  740.                              @BufferPointer[ 0 ] ,
  741.                              TheLength              );
  742.       { Abort if timeout or error }
  743.       if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  744.       { Put in the length byte }
  745.       BufferPointer[ TheLength ] := Chr( 0 );
  746.       if LeftOversOnTable then
  747.       begin
  748.         LeftOversOnTable := false;
  749.         StrCopy( ResponseString , HolderBuffer );
  750.         StrCat( ResponseString , BufferPointer );
  751.       end
  752.       else
  753.       begin
  754.         if not LeftoversInPan then StrCopy( ResponseString , BufferPointer );
  755.       end;
  756.       if LeftoversInPan then
  757.       begin
  758.         LeftoversInPan := false;
  759.         LeftoversOnTable := true;
  760.       end
  761.       else
  762.       begin
  763.         ResponseChar := ResponseString[ 0 ];
  764.         if (( ResponseChar = '.' ) and ( StrLen( ResponseString ) <= 3 )) then
  765.         begin
  766.           ResponseString[ 0 ] := ' ';
  767.           Finished := true;
  768.           Result := TCPIP_STATUS_COMPLETED;
  769.         end
  770.         else
  771.         begin
  772.           if ResponseChar = '.' then ResponseString[ 0 ] := ' ';
  773.           Finished := true;
  774.           Result := TCPIP_STATUS_PRELIMINARY;
  775.         end;
  776.       end;
  777.     end;
  778.   until ( Finished and ( not LeftoversOnTable ));
  779.   StrLCopy( ResponseString , ResponseString , StrLen( ResponseString ) - 2 );
  780. end;
  781.  
  782.  
  783. { This function moves along a string from an index, getting the next }
  784. { string delimited item or last one on string.                       }
  785. function TPOP3SMTPComponent.GetNextSDItem(     WorkingString : String;
  786.                                        var TheIndex      : Integer ) : String;
  787. var HoldingString : String;
  788. begin
  789.   HoldingString := Copy( WorkingString , TheIndex + 1 , 255 );
  790.   TheIndex := Pos( ' ' , HoldingString );
  791.   if TheIndex = 0 then
  792.   begin
  793.     Result := HoldingString;
  794.   end
  795.   else
  796.   begin
  797.     HoldingString := Copy( HoldingString , 1 , TheIndex - 1 );
  798.     Result := HoldingString;
  799.   end;
  800. end;
  801.  
  802. { This method assumes logged into server; gets data via STAT command }
  803. { returns total bytes in var'd param and total messages as result    }
  804. function TPOP3SMTPComponent.CheckAllNewMail( var TotalBytes : Longint ) : Integer;
  805. var TheReturnString : String;  { Internal string holder }
  806.     TheResult       : Integer; { Internal int holder    }
  807.     TheLResult      : Longint;
  808. begin
  809.   TheReturnString :=
  810.    DoCStyleFormat( 'STAT' , [ nil ] );
  811.   { Put result in progress and status line }
  812.   AddProgressText( TheReturnString );
  813.   ShowProgressText( TheReturnString );
  814.   { Begin login sequence with user name }
  815.   TheResult := PerformPOP3Command( 'STAT', [ nil ] );
  816.   if TheResult <> TCPIP_STATUS_PRELIMINARY then
  817.   begin
  818.     POP3CommandInProgress := false;
  819.     Result := -1;
  820.     exit;
  821.   end;
  822.   repeat
  823.     TheResult := GetPOP3ServerResponse( TheReturnString );
  824.     { Put result in progress and status line }
  825.     AddProgressText( TheReturnString );
  826.     ShowProgressText( TheReturnString + #13#10 );
  827.   until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  828.   POP3CommandInProgress := false;
  829.   if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  830.   begin
  831.     { Do clever C formatting trick }
  832.     TheReturnString :=
  833.      DoCStyleFormat( 'Mail Not Available!' , [ nil ] );
  834.     { Put result in progress and status line }
  835.     AddProgressText( TheReturnString );
  836.     ShowProgressErrorText( TheReturnString );
  837.     { Signal error }
  838.     Result := -1;
  839.     { leave }
  840.     exit;
  841.   end;
  842.   ParseMailListing( TheReturnString , TheLResult , TotalBytes );
  843.   Result := TheLResult;
  844. end;
  845.  
  846. function TPOP3SMTPComponent.DeleteMailItem( TheNumber : Longint ) : Boolean;
  847. var TheReturnString : String;  { Internal string holder }
  848.     TheResult       : Integer; { Internal int holder    }
  849. begin
  850.   TheReturnString :=
  851.    DoCStyleFormat( 'DELE %d' , [ TheNumber ] );
  852.   { Put result in progress and status line }
  853.   AddProgressText( TheReturnString );
  854.   ShowProgressText( TheReturnString );
  855.   { Begin login sequence with user name }
  856.   TheResult := PerformPOP3Command( 'DELE %d', [ TheNumber ] );
  857.   if TheResult <> TCPIP_STATUS_PRELIMINARY then
  858.   begin
  859.     POP3CommandInProgress := false;
  860.     Result := false;
  861.     exit;
  862.   end;
  863.   repeat
  864.     TheResult := GetPOP3ServerResponse( TheReturnString );
  865.     { Put result in progress and status line }
  866.     AddProgressText( TheReturnString );
  867.     ShowProgressText( TheReturnString + #13#10 );
  868.   until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  869.   POP3CommandInProgress := false;
  870.   if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  871.   begin
  872.     { Do clever C formatting trick }
  873.     TheReturnString :=
  874.      DoCStyleFormat( 'Mail Not Available!' , [ nil ] );
  875.     { Put result in progress and status line }
  876.     AddProgressText( TheReturnString );
  877.     ShowProgressErrorText( TheReturnString );
  878.     { Signal error }
  879.     Result := false;
  880.     { leave }
  881.     exit;
  882.   end;
  883.   Result := True;
  884. end;
  885.  
  886. { This method splits up a listing and pulls out its component data }
  887. procedure TPOP3SMTPComponent.ParseMailListing(     TheListing : String;
  888.                                                var TotalMessages : Longint;
  889.                                                var MessageBytes : Longint);
  890. var HoldingString ,
  891.     HoldingString2 : String;
  892.     WorkingIndex  : Integer;
  893. begin
  894.   WorkingIndex := Pos( ' ' , TheListing );
  895.   HoldingString := Copy( TheListing , WorkingIndex + 1 , 255 );
  896.   WorkingIndex := Pos(  ' ' , HoldingString );
  897.   HoldingString2 := Copy( HoldingString , 1 , WorkingIndex - 1 );
  898.   TotalMessages := StrToInt( HoldingString2 );
  899.   HoldingString := Copy( HoldingString , WorkingIndex + 1 , 255 );
  900.   WorkingIndex := Pos(  ' ' , HoldingString );
  901.   if WorkingIndex = 0 then WorkingIndex := 256;
  902.   HoldingString2 := Copy( HoldingString , 1 , WorkingIndex - 1 );
  903.   MessageBytes := StrToInt( HoldingString2 );
  904. end;
  905.  
  906. { This method accumulates all the strings until '' as a messge header }
  907. function TPOP3SMTPComponent.GetMessageHeader( TheReturnList : TStringList ) : Longint;
  908. var TheReturnString : String;  { Internal string holder }
  909.     TheResult       : Integer; { Internal int holder    }
  910.     TheReturnPChar ,
  911.     TheHoldingPChar : PChar;
  912.     TotalGotten : Longint;
  913. begin
  914.   GetMem( TheReturnPChar , 514 );
  915.   TheReturnList.Clear;
  916.   TotalGotten := 0;
  917.   repeat
  918.     TheResult := GetPOP3ServerExtendedResponse( TheReturnPChar );
  919.     if StrLen( TheReturnPChar ) < 3 then
  920.     begin
  921.      TheResult := TCPIP_STATUS_COMPLETED;
  922.     end;
  923.     TotalGotten := TotalGotten + StrLen( TheReturnPChar ) + 2;
  924.     if StrLen( TheReturnPChar ) > 255 then
  925.     begin
  926.       Getmem( TheHoldingPChar , 255 );
  927.       while StrLen( TheReturnPChar ) > 255 do
  928.       begin
  929.         StrCopy( TheHoldingPChar , '' );
  930.         StrMove( TheHoldingPChar , TheReturnPChar , 255 );
  931.         TheReturnPChar := TheReturnPChar + 256;
  932.         TheReturnString := StrPas( TheHoldingPChar );
  933.         TheReturnList.Add( TheReturnString );
  934.       end;
  935.       StrCopy( TheHoldingPChar , '' );
  936.       StrMove( TheHoldingPChar , TheReturnPChar , StrLen( TheReturnPChar ));
  937.       TheReturnString := StrPas( TheHoldingPChar );
  938.       TheReturnString := '\' + TheReturnString;
  939.       TheReturnList.Add( TheReturnString );
  940.       FreeMem( TheHoldingPChar , 255 );
  941.     end
  942.     else
  943.     begin
  944.       TheReturnString := StrPas( TheReturnPChar );
  945.       TheReturnList.Add( TheReturnString );
  946.     end;
  947.   until (( GlobalAbortedFlag ) or ( TheResult = TCPIP_STATUS_COMPLETED ));
  948.   FreeMem( TheReturnPChar , 514 );
  949.   Result := TotalGotten;
  950. end;
  951.  
  952. { This method parses a header stringlist and obtains the subject line }
  953. function TPOP3SMTPComponent.GetHeaderSubject( HList : TStringList ) : String;
  954. var Counter_1     : Integer;
  955.     Finished      : Boolean;
  956.     WorkingIndex  : Integer;
  957.     WorkingString : String;
  958. begin
  959.   Counter_1 := 0;
  960.   Finished := false;
  961.   WorkingString := '[No Subject]';
  962.   while (( not Finished ) and ( Counter_1 <= HList.Count - 1 )) do
  963.   begin
  964.     WorkingIndex := Pos( 'SUBJECT:' , Uppercase( HList.Strings[ Counter_1 ] ));
  965.     if WorkingIndex > 0 then
  966.     begin
  967.       WorkingString := Copy( HList.Strings[ Counter_1 ] , 9 , 255 );
  968.       Finished := true;
  969.     end
  970.     else Inc( Counter_1 );
  971.   end;
  972.   Result := WorkingString;
  973. end;
  974.  
  975. { This method parses a header stringlist and obtains the sender's ID }
  976. function TPOP3SMTPComponent.GetHeaderSender( HList : TStringList ) : String;
  977. var Counter_1     : Integer;
  978.     Finished      : Boolean;
  979.     WorkingIndex  : Integer;
  980.     WorkingString : String;
  981. begin
  982.   Counter_1 := 0;
  983.   Finished := false;
  984.   WorkingString := '';
  985.   while (( not Finished ) and ( Counter_1 <= HList.Count - 1 )) do
  986.   begin
  987.     WorkingIndex := Pos( 'FROM:' , Uppercase( HList.Strings[ Counter_1 ] ));
  988.     if WorkingIndex > 0 then
  989.     begin
  990.       WorkingString := Copy( HList.Strings[ Counter_1 ] , 7 , 255 );
  991.       Finished := true;
  992.     end
  993.     else Inc( Counter_1 );
  994.   end;
  995.   Result := WorkingString;
  996. end;
  997.  
  998. { This method strips out the TO: field of a mail message header }
  999. function TPOP3SMTPComponent.GetHeaderRecipient( HList : TStringList ) : String;
  1000. var Counter_1     : Integer;
  1001.     Finished      : Boolean;
  1002.     WorkingIndex  : Integer;
  1003.     WorkingString : String;
  1004. begin
  1005.   Counter_1 := 0;
  1006.   Finished := false;
  1007.   WorkingString := '';
  1008.   while (( not Finished ) and ( Counter_1 <= HList.Count - 1 )) do
  1009.   begin
  1010.     WorkingIndex := Pos( 'TO:' , Uppercase( HList.Strings[ Counter_1 ] ));
  1011.     if WorkingIndex > 0 then
  1012.     begin
  1013.       WorkingString := Copy( HList.Strings[ Counter_1 ] , 5 , 255 );
  1014.       Finished := true;
  1015.     end
  1016.     else Inc( Counter_1 );
  1017.   end;
  1018.   Result := WorkingString;
  1019. end;
  1020.  
  1021. { This method strips out the CC: field of a mail message header }
  1022. function TPOP3SMTPComponent.GetHeaderCarbons( HList : TStringList ) : String;
  1023. var Counter_1     : Integer;
  1024.     Finished      : Boolean;
  1025.     WorkingIndex  : Integer;
  1026.     WorkingString : String;
  1027. begin
  1028.   Counter_1 := 0;
  1029.   Finished := false;
  1030.   WorkingString := '';
  1031.   while (( not Finished ) and ( Counter_1 <= HList.Count - 1 )) do
  1032.   begin
  1033.     WorkingIndex := Pos( 'CC:' , Uppercase( HList.Strings[ Counter_1 ] ));
  1034.     if WorkingIndex > 0 then
  1035.     begin
  1036.       WorkingString := Copy( HList.Strings[ Counter_1 ] , 5 , 255 );
  1037.       Finished := true;
  1038.     end
  1039.     else Inc( Counter_1 );
  1040.   end;
  1041.   Result := WorkingString;
  1042. end;
  1043.  
  1044. { This method strips out the BCC: field of a mail message header }
  1045. function TPOP3SMTPComponent.GetHeaderBlindCarbons( HList : TStringList ) : String;
  1046. var Counter_1     : Integer;
  1047.     Finished      : Boolean;
  1048.     WorkingIndex  : Integer;
  1049.     WorkingString : String;
  1050. begin
  1051.   Counter_1 := 0;
  1052.   Finished := false;
  1053.   WorkingString := '';
  1054.   while (( not Finished ) and ( Counter_1 <= HList.Count - 1 )) do
  1055.   begin
  1056.     WorkingIndex := Pos( 'BCC:' , Uppercase( HList.Strings[ Counter_1 ] ));
  1057.     if WorkingIndex > 0 then
  1058.     begin
  1059.       WorkingString := Copy( HList.Strings[ Counter_1 ] , 6 , 255 );
  1060.       Finished := true;
  1061.     end
  1062.     else Inc( Counter_1 );
  1063.   end;
  1064.   Result := WorkingString;
  1065. end;
  1066.  
  1067. { This method strips out the DATE: field of a mail message header }
  1068. function TPOP3SMTPComponent.GetHeaderDateTime( HList : TStringList ) : String;
  1069. var Counter_1     : Integer;
  1070.     Finished      : Boolean;
  1071.     WorkingIndex  : Integer;
  1072.     WorkingString : String;
  1073. begin
  1074.   Counter_1 := 0;
  1075.   Finished := false;
  1076.   WorkingString := '';
  1077.   while (( not Finished ) and ( Counter_1 <= HList.Count - 1 )) do
  1078.   begin
  1079.     WorkingIndex := Pos( 'DATE:' , Uppercase( HList.Strings[ Counter_1 ] ));
  1080.     if WorkingIndex > 0 then
  1081.     begin
  1082.       WorkingString := Copy( HList.Strings[ Counter_1 ] , 7 , 255 );
  1083.       Finished := true;
  1084.     end
  1085.     else Inc( Counter_1 );
  1086.   end;
  1087.   Result := WorkingString;
  1088. end;
  1089.  
  1090. { This method transfers a message from one mailbox to another }
  1091. procedure TPOP3SMTPComponent.TransferMessage( SourceEMBRecord ,
  1092.                                               TargetEMBRecord : PEMailMailBoxRecord;
  1093.                                               MessageNumber : Integer );
  1094. var  WorkingList1 , WorkingList2 : TList;
  1095.      TheEMMRecord : PEMailMessageRecord;
  1096. begin
  1097.   WorkingList1 := TList( SourceEMBRecord^.MBLTag );
  1098.   WorkingList2 := TList( TargetEMBRecord^.MBLTag );
  1099.   TheEMMRecord := PEMailMessageRecord( WorkingList1.Items[ MessageNumber ] );
  1100.   WorkingList2.Add( TheEMMRecord );
  1101.   SourceEMBRecord^.MBLTag := Longint( WorkingList1 );
  1102.   TargetEMBRecord^.MBLTag := Longint( WorkingList2 );
  1103. end;
  1104.  
  1105. { This function deletes all read/sent articles and associated files }
  1106. procedure TPOP3SMTPComponent.PurgeTrashedMessageListings( TheEMBRecord : PEMailMailBoxRecord );
  1107. var TheEMMRecord   : PEMailMessageRecord;
  1108.     Counter_1      : Integer;
  1109.     WorkingList    : TList;
  1110.     Finished       : Boolean;
  1111. begin
  1112.   { Do this for ease of coding }
  1113.   with TheEMBRecord^ do
  1114.   begin
  1115.     { Get the current TList of article headers }
  1116.     WorkingList := TList( MBLTag );
  1117.     { Run up to total new articles }
  1118.     for Counter_1 := 0 to WorkingList.Count - 1 do
  1119.     begin
  1120.       TheEMMRecord := PEMailMessageRecord( WorkingList.Items[ Counter_1 ] );
  1121.       if ( TheEMMRecord^.MRMessageSender = 'DELETE ME' ) then
  1122.       begin
  1123.         Dec( MBTotal );
  1124.         if not TheEMMRecord^.MRRead then if MBUnReadTotal > 0 then Dec( MBUnReadTotal );
  1125.         if not TheEMMRecord^.MRSent then if MBUnSentTotal > 0 then Dec( MBUnSentTotal );
  1126.         if FileExists( MailPath + '\' + TheEMMRecord^.MRFilename ) then
  1127.          {DeleteFile( MailPath + '\' + TheEMMRecord^.MRFileName )};
  1128.       end;
  1129.     end;
  1130.     Counter_1 := 0;
  1131.     Finished := False;
  1132.     if WorkingList.Count = 0 then Finished := true;
  1133.     while Not Finished do
  1134.     begin
  1135.       TheEMMRecord := PEMailMessageRecord( WorkingList.Items[ Counter_1 ] );
  1136.       if ( TheEMMRecord^.MRMessageSender = 'DELETE ME' ) then
  1137.       begin
  1138.         WorkingList.Delete( Counter_1 );
  1139.       end
  1140.       else Counter_1 := Counter_1 + 1;
  1141.       if Counter_1 > WorkingList.Count - 1 then Finished := true;
  1142.     end;
  1143.   end;
  1144. end;
  1145.  
  1146. { This method uses the ARTICLE command to obtain an article and put it in a  }
  1147. { preset/supplied file. It is designed to work by itself or inside DAALs     }
  1148. function TPOP3SMTPComponent.DownloadMessageListing( TheNumber   : Integer;
  1149.                                                     TheFileName : String;
  1150.                                                     TheHeaderSL : TStringList   ) : Longint;
  1151. var TheReturnString : String;  { Internal string holder }
  1152.     TheResult       : Integer; { Internal int holder    }
  1153.     TheReturnPChar ,
  1154.     TheHoldingPChar : PChar;
  1155.     TheMessageFile       : TextFile;
  1156.     Counter_1   : Integer;
  1157.     TotalGotten : Longint;
  1158. begin
  1159.   TheReturnString :=
  1160.    DoCStyleFormat( 'RETR %d' ,
  1161.     [ TheNumber ] );
  1162.   { Put result in progress and status line }
  1163.   AddProgressText( TheReturnString );
  1164.   ShowProgressText( TheReturnString );
  1165.   { Begin login sequence with user name }
  1166.   TheResult := PerformPOP3Command( 'RETR %d', [ TheNumber ] );
  1167.   if TheResult <> TCPIP_STATUS_PRELIMINARY then
  1168.   begin
  1169.     POP3CommandInProgress := false;
  1170.     Result := 0;
  1171.     exit;
  1172.   end;
  1173.   repeat
  1174.     TheResult := GetPOP3ServerResponse( TheReturnString );
  1175.     { Put result in progress and status line }
  1176.     AddProgressText( TheReturnString );
  1177.     ShowProgressText( TheReturnString + #13#10 );
  1178.   until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  1179.   POP3CommandInProgress := false;
  1180.   if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  1181.   begin
  1182.     { Do clever C formatting trick }
  1183.     TheReturnString :=
  1184.      DoCStyleFormat( 'Retrieve Message %d Failed!' ,
  1185.       [ TheNumber ] );
  1186.     { Put result in progress and status line }
  1187.     AddProgressText( TheReturnString );
  1188.     ShowProgressErrorText( TheReturnString );
  1189.     { Signal error }
  1190.     Result := 0;
  1191.     { leave }
  1192.     exit;
  1193.   end;
  1194.   GetMem( TheReturnPChar , 514 );
  1195.   try
  1196.     AssignFile( TheMessageFile , TheFileName );
  1197.     Rewrite( TheMessageFile );
  1198.   except
  1199.     MessageDlg( 'Unable to open Mail Message file ' + TheFileName + '!' ,
  1200.      mtError , [mbok],0 );
  1201.     Socket1.OutOfBand := 'ABOR'+#13#10;
  1202.     repeat
  1203.       TheResult := GetPOP3ServerResponse( TheReturnString );
  1204.       { Put result in progress and status line }
  1205.       AddProgressText( TheReturnString );
  1206.       ShowProgressText( TheReturnString  + #13#10 );
  1207.     until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  1208.     result := 0;
  1209.     exit;
  1210.   end;
  1211.   TotalGotten := GetMessageHeader( TheHeaderSL );
  1212.   for Counter_1 := 0 to TheHeaderSL.Count - 1 do
  1213.    Writeln( TheMessageFile , TheHeaderSL.Strings[ Counter_1 ] );
  1214.   repeat
  1215.     TheResult := GetPOP3ServerExtendedResponse( TheReturnPChar );
  1216.     TotalGotten := TotalGotten + StrLen( TheReturnPChar ) + 2;
  1217.     if StrLen( TheReturnPChar ) > 255 then
  1218.     begin
  1219.       Getmem( TheHoldingPChar , 255 );
  1220.       while StrLen( TheReturnPChar ) > 255 do
  1221.       begin
  1222.         StrCopy( TheHoldingPChar , '' );
  1223.         StrMove( TheHoldingPChar , TheReturnPChar , 255 );
  1224.         TheReturnPChar := TheReturnPChar + 256;
  1225.         TheReturnString := StrPas( TheHoldingPChar );
  1226.         Writeln( TheMessageFile , TheReturnString );
  1227.       end;
  1228.       StrCopy( TheHoldingPChar , '' );
  1229.       StrMove( TheHoldingPChar , TheReturnPChar , StrLen( TheReturnPChar ));
  1230.       TheReturnString := StrPas( TheHoldingPChar );
  1231.       TheReturnString := '\' + TheReturnString;
  1232.       Writeln( TheMessageFile , TheReturnString );
  1233.       FreeMem( TheHoldingPChar , 255 );
  1234.     end
  1235.     else
  1236.     begin
  1237.       TheReturnString := StrPas( TheReturnPChar );
  1238.       Writeln( TheMessageFile , TheReturnString );
  1239.     end;
  1240.   until (( GlobalAbortedFlag ) or ( TheResult = TCPIP_STATUS_COMPLETED ));
  1241.   FreeMem( TheReturnPChar , 514 );
  1242.   CloseFile( TheMessageFile );
  1243.   Result := TotalGotten;
  1244. end;
  1245.  
  1246. { This method Gets all the Article Listings for a newsgroup which have not been  }
  1247. { Downloaded and gets them into text files. It displays Article count, # & bytes }
  1248. { in the status line during the process.                                         }
  1249. function TPOP3SMTPComponent.DownloadAllMessageListings(
  1250.   TheEMBRecord : PEMailMailBoxRecord ) : Boolean;
  1251. var WorkingList   : TList;
  1252.     TheEMMRecord  : PEMailMessageRecord;
  1253.     Counter_1 : Integer;
  1254.     WorkingID ,
  1255.     WorkingNumber : Integer;
  1256.     WorkingFileName : String;
  1257.     BytesToGet : Longint;
  1258.     TotalMessages : Integer;
  1259.     WorkingSL : TStringList;
  1260.     BytesGotten : Longint;
  1261. begin
  1262.   Result := true;
  1263.   TotalMessages := CheckAllNewMail( BytesToGet );
  1264.   if TotalMessages < 0 then exit;
  1265.   if TotalMessages = 0 then
  1266.   begin
  1267.     MessageDlg( 'No New Mail!' , mtInformation, [mbOK],0);
  1268.     exit;
  1269.   end;
  1270.   with TheEMBRecord^ do
  1271.   begin
  1272.     WorkingID := MBIDNumber;
  1273.     WorkingNumber := MBMaxMsgNumber;
  1274.     WorkingList := TList( MBLTag );
  1275.     WorkingSL := TStringList.Create;
  1276.     for Counter_1 := 1 to TotalMessages do
  1277.     begin
  1278.       New( TheEMMRecord );
  1279.       WorkingNumber := WorkingNumber + 1;
  1280.       with TheEMMRecord^ do
  1281.       begin
  1282.         WorkingFileName := 'EM' + IntToStr( WorkingNumber );
  1283.         if Length( WorkingFileName ) > 8 then WorkingFileName :=
  1284.          Copy( WorkingFileName , 1 , 8 );
  1285.         WorkingFileName := WorkingFileName + '.' +
  1286.          IntToStr( WorkingID );
  1287.         MRFileName := WorkingFileName;
  1288.         WorkingFileName := MailPath + '\' + WorkingFileName;
  1289.         BytesGotten := DownloadMessageListing( Counter_1 , WorkingFileName , WorkingSL );
  1290.         if EMRemoteDeletionVector = 2 then DeleteMailItem( Counter_1 );
  1291.         UpdateGauge( BytesGotten , BytesToGet );
  1292.         MRMailBoxName      := MBName;
  1293.         MRMessageSubject   := GetHeaderSubject( WorkingSL );
  1294.         MRMessageRecipient := GetHeaderRecipient( WorkingSL );
  1295.         MRMessageSender    := GetHeaderSender( WorkingSL );
  1296.         MRCarbonCopy       := GetHeaderCarbons( WorkingSL );
  1297.         MRBlindCarbonCopy  := GetHeaderBlindCarbons( WorkingSL );
  1298.         MRDateTime         := GetHeaderDateTime( WorkingSL );
  1299.         MRRead             := false;
  1300.         MRSent             := false;
  1301.         MRFileName         := ExtractFileName( WorkingFileName );
  1302.         WorkingList.Add( TheEMMRecord );
  1303.       end;
  1304.     end;
  1305.     UpdateGauge( BytesToGet , BytesToGet );
  1306.     MBLTag := Longint( WorkingList );
  1307.     MBMaxMsgNumber := WorkingNumber;
  1308.     MBTotal       := MBTotal + TotalMessages;
  1309.     MBUnReadTotal := MBUnReadTotal + TotalMessages;
  1310.     Result := true;
  1311.   end;
  1312. end;
  1313.  
  1314. { This sends FTP progress text to the Inet form }
  1315. procedure TPOP3SMTPComponent.ShowProgressErrorText( WhatText : String );
  1316. begin
  1317.  CCInetCCForm.ShowProgressErrorText( WhatText );
  1318. end;
  1319.  
  1320. { This is a core function! It performs an FTP command and if no timeout }
  1321. { return a preliminary ok.                                              }
  1322. function TPOP3SMTPComponent.PerformPOP3Command(
  1323.                  TheCommand        : string;
  1324.            const TheArguments      : array of const ) : Integer;
  1325. var TheBuffer : string; { Text buffer }
  1326. begin
  1327.   { If command in progress send back -1 error }
  1328.   if POP3CommandInProgress then
  1329.   begin
  1330.     Result := -1;
  1331.     exit;
  1332.   end;
  1333.   { Set status variable }
  1334.   POP3CommandInProgress := True;
  1335.   { Set global error code }
  1336.   GlobalErrorCode := 0;
  1337.   { Format output string }
  1338.   TheBuffer := Format( TheCommand , TheArguments );
  1339.   { Preset failure code }
  1340.   Result := TCPIP_STATUS_FATAL_ERROR;
  1341.   { If invalid socket or no connection abort }
  1342.   if ( Socket1.TheSocket = INVALID_SOCKET ) or not Connection_Established then
  1343.    exit;
  1344.   { Send the buffer plus EOL chars }
  1345.   Socket1.StringData := TheBuffer + #13#10;
  1346.   { if abort due to timeout or other error exit }
  1347.   if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  1348.   { Otherwise return preliminary code }
  1349.   Result := TCPIP_STATUS_PRELIMINARY;
  1350. end;
  1351.  
  1352. { This function gets up to 255 chars of data plus a return code from FTP serv }
  1353. function TPOP3SMTPComponent.GetPOP3ServerResponse(
  1354.           var ResponseString : String ) : integer;
  1355. var
  1356.   { Buffer string for response line }
  1357.   TheBuffer     : string;
  1358.   { Pointer to the response string }
  1359.   BufferPointer : array[0..255] of char absolute TheBuffer;
  1360.   { Character to check for response code }
  1361.   ResponseChar   : char;
  1362.   { Pointers into returned string }
  1363.   TheIndex ,
  1364.   TheLength     : integer;
  1365.   { Control variable }
  1366.   LeftoversInPan ,
  1367.   Finished      : Boolean;
  1368. begin
  1369.   { Preset fatal error }
  1370.   Result := TCPIP_STATUS_FATAL_ERROR;
  1371.   { Start loop control }
  1372.   LeftoversInPan := false;
  1373.   Finished := false;
  1374.   repeat
  1375.     { Do a peek }
  1376.     TheBuffer := Socket1.PeekData;
  1377.     { If timeout or other error exit }
  1378.     if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  1379.     { Find end of line character }
  1380.     TheIndex := Pos( #10 , TheBuffer );
  1381.     if TheIndex = 0 then
  1382.     begin
  1383.       TheIndex := Pos( #13 , TheBuffer );
  1384.       if TheIndex = 0 then
  1385.       begin
  1386.         TheIndex := Pos( #0 , TheBuffer );
  1387.         if TheIndex = 0 then
  1388.         begin
  1389.           TheIndex := Length( TheBuffer );
  1390.           LeftoversInPan := True;
  1391.           LeftoverText := LeftoverText + TheBuffer;
  1392.           LeftoversOnTable := false;
  1393.         end;
  1394.       end;
  1395.     end;
  1396.     { If an end of line then process the line }
  1397.     if TheIndex > 0 then
  1398.     begin
  1399.       { Get length of string }
  1400.       TheLength := TheIndex;
  1401.       { Receive actual data }
  1402.       Socket1.CCSockReceive( Socket1.TheSocket   ,
  1403.                              @BufferPointer[ 1 ] ,
  1404.                              TheLength              );
  1405.       { Abort if timeout or error }
  1406.       if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  1407.       { Put in the length byte }
  1408.       BufferPointer[ 0 ] := Chr( TheLength );
  1409.       if LeftOversOnTable then
  1410.       begin
  1411.         LeftOversOnTable := false;
  1412.         ResponseString := LeftoverText + TheBuffer;
  1413.         TheBuffer := ResponseString;
  1414.         LeftoverText := '';
  1415.       end;
  1416.       if LeftoversInPan then
  1417.       begin
  1418.         LeftoversInPan := false;
  1419.         LeftoversOnTable := true;
  1420.       end;
  1421.       { Get first number character }
  1422.       ResponseChar := TheBuffer[ 1 ];
  1423.       { Get the value of the number from 1 to 5 }
  1424.       if (( ResponseChar = '+' ) or ( ResponseChar = '-' )) then
  1425.       begin
  1426.         Finished := true;
  1427.         if ResponseChar = '+' then Result := TCPIP_STATUS_COMPLETED
  1428.          else Result := TCPIP_STATUS_FATAL_ERROR;
  1429.       end;
  1430.     end
  1431.     else
  1432.     begin
  1433.     end;
  1434.   until ( Finished and ( not LeftoversOnTable ));
  1435.   { Return buffer as response string }
  1436.   ResponseString := TheBuffer;
  1437.   ResponseString := Copy( ResponseString , 1, Length( ResponseString ) - 2 );
  1438. end;
  1439.  
  1440. { Boilerplate error routine }
  1441. procedure TPOP3SMTPComponent.POP3SMTPSocketsErrorOccurred( Sender     : TObject;
  1442.                                                  ErrorCode  : Integer;
  1443.                                                  TheMessage : String   );
  1444. begin
  1445.   CCInetCCForm.SocketsErrorOccurred( Sender,ErrorCode,TheMessage );
  1446. end;
  1447.  
  1448. { This is the POP3SMTP components POP3 initial connection routine }
  1449. function TPOP3SMTPComponent.EstablishPOP3Connection(
  1450.           PCRPointer : PConnectionsRecord ) : Boolean;
  1451. var TheReturnString : String;  { Internal string holder }
  1452.     TheResult       : Integer; { Internal int holder    }
  1453. begin
  1454.   { Set default FTP Port value }
  1455.   Socket1.PortName := '110';
  1456.   { Get the ip address from the record }
  1457.   Socket1.IPAddressName := PCRPointer^.CIPAddress;
  1458.   { Set blocking mode }
  1459.   Socket1.AsynchMode := False;
  1460.   { Clear condition variables }
  1461.   GlobalErrorCode := 0;
  1462.   GlobalAbortedFlag := false;
  1463.   { Actually attempt to connect }
  1464.   Socket1.CCSockConnect;
  1465.   { Check if connected }
  1466.   if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 ) or
  1467.       ( Socket1.TheSocket = INVALID_SOCKET )) then
  1468.   begin { Didn't connect; signal error and abort }
  1469.     { Do clever C formatting trick }
  1470.     TheReturnString :=
  1471.      DoCStyleFormat( 'POP3 Host %s Connection Failed!' ,
  1472.       [ PCRPointer^.CIPAddress ] );
  1473.     { Put result in progress and status line }
  1474.     AddProgressText( TheReturnString );
  1475.     ShowProgressErrorText( TheReturnString );
  1476.     { Signal error }
  1477.     Result := False;
  1478.     { leave }
  1479.     exit;
  1480.   end
  1481.   else
  1482.   begin
  1483.     Connection_Established := true;
  1484.     { Signal successful connection }
  1485.     TheReturnString := DoCStyleFormat(
  1486.       'Connected on Local port: %s with IP: %s',
  1487.       [ Socket1.GetSocketPort( Socket1.TheSocket ),
  1488.         Socket1.GetSocketIPAddress( Socket1.TheSocket )]);
  1489.     { Put result in progress and status line }
  1490.     CCINetCCForm.AddProgressText( TheReturnString );
  1491.     CCINetCCForm.ShowProgressText( TheReturnString );
  1492.     TheReturnString := DoCStyleFormat(
  1493.      'Connected to Remote port: %s with IP: %s',
  1494.       [ Socket1.GetSocketPeerPort( Socket1.TheSocket ),
  1495.         Socket1.GetSocketPeerIPAddress( Socket1.TheSocket )]);
  1496.     { Put result in progress and status line }
  1497.     CCINetCCForm.AddProgressText( TheReturnString );
  1498.     CCINetCCForm.ShowProgressText( TheReturnString );
  1499.     TheReturnString := DoCStyleFormat( 'Successfully connected to %s',
  1500.      [ Socket1.IPAddressName ]);
  1501.     { Put result in progress and status line }
  1502.     CCINetCCForm.AddProgressText( TheReturnString );
  1503.     CCINetCCForm.ShowProgressText( TheReturnString );
  1504.     repeat
  1505.       TheResult := GetPOP3ServerResponse( TheReturnString );
  1506.       { Put result in progress and status line }
  1507.       AddProgressText( TheReturnString );
  1508.       ShowProgressText( TheReturnString );
  1509.     until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  1510.     if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  1511.     begin
  1512.       { Do clever C formatting trick }
  1513.       TheReturnString :=
  1514.        DoCStyleFormat( 'POP3 Host %s Connection Failed!' ,
  1515.         [ PCRPointer^.CIPAddress ] );
  1516.       { Put result in progress and status line }
  1517.       AddProgressText( TheReturnString );
  1518.       ShowProgressErrorText( TheReturnString );
  1519.       { Signal error }
  1520.       Result := False;
  1521.       { leave }
  1522.       exit;
  1523.     end
  1524.     else Result := true; { Signal no problem }
  1525.   end;
  1526. end;
  1527.  
  1528. { This sends FTP progress text to the Inet form }
  1529. procedure TPOP3SMTPComponent.AddProgressText( WhatText : String );
  1530. begin
  1531.   CCInetCCForm.AddProgressText( WhatText );
  1532. end;
  1533.  
  1534. { This sends FTP progress text to the Inet form }
  1535. procedure TPOP3SMTPComponent.ShowProgressText( WhatText : String );
  1536. begin
  1537.   CCInetCCForm.ShowProgressText( WhatText );
  1538. end;
  1539.  
  1540. { This is a clever c-style formatting trick }
  1541. function TPOP3SMTPComponent.DoCStyleFormat(
  1542.                 TheText      : string;
  1543.           const TheArguments : array of const ) : String;
  1544. begin
  1545.   Result := Format( TheText , TheArguments ) + #13#10;
  1546. end;
  1547.  
  1548. { This is the FTP components USER login routine }
  1549. function TPOP3SMTPComponent.LoginUser(
  1550.           PCRPointer : PConnectionsRecord ) : Boolean;
  1551. var TheReturnString : String;  { Internal string holder }
  1552.     TheResult       : Integer; { Internal int holder    }
  1553. begin
  1554.   TheReturnString :=
  1555.    DoCStyleFormat( 'USER %s' ,
  1556.     [ PCRPointer^.CUserName ] );
  1557.   { Put result in progress and status line }
  1558.   AddProgressText( TheReturnString );
  1559.   ShowProgressText( TheReturnString );
  1560.   { Begin login sequence with user name }
  1561.   TheResult := PerformPOP3Command( 'USER %s',
  1562.                                   [ PCRPointer^.CUserName ] );
  1563.   if TheResult <> TCPIP_STATUS_PRELIMINARY then
  1564.   begin
  1565.     POP3CommandInProgress := false;
  1566.     Result := false;
  1567.     exit;
  1568.   end;
  1569.   repeat
  1570.     TheResult := GetPOP3ServerResponse( TheReturnString );
  1571.     { Put result in progress and status line }
  1572.     AddProgressText( TheReturnString );
  1573.     ShowProgressText( TheReturnString + #13#10 );
  1574.   until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  1575.   POP3CommandInProgress := false;
  1576.   if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  1577.   begin
  1578.     { Do clever C formatting trick }
  1579.     TheReturnString :=
  1580.      DoCStyleFormat( 'POP3 Host %s Login Failed!' ,
  1581.       [ PCRPointer^.CIPAddress ] );
  1582.     { Put result in progress and status line }
  1583.     AddProgressText( TheReturnString );
  1584.     ShowProgressErrorText( TheReturnString );
  1585.     { Signal error }
  1586.     Result := False;
  1587.     { leave }
  1588.     exit;
  1589.   end
  1590.   else Result := true; { Signal no problem }
  1591. end;
  1592.  
  1593. { This is the FTP components PASSWORD routine }
  1594. function TPOP3SMTPComponent.SendPassword(
  1595.           PCRPointer : PConnectionsRecord ) : Boolean;
  1596. var TheReturnString : String;  { Internal string holder }
  1597.     TheResult       : Integer; { Internal int holder    }
  1598. begin
  1599.   TheReturnString := 'PASS XXXXXX' + #13#10;
  1600.   { Put result in progress and status line }
  1601.   AddProgressText( TheReturnString );
  1602.   ShowProgressText( TheReturnString );
  1603.   { Send Password sequence }
  1604.   TheResult := PerformPOP3Command( 'PASS %s',
  1605.                                   [ PCRPointer^.CPassword ] );
  1606.   if TheResult <> TCPIP_STATUS_PRELIMINARY then
  1607.   begin
  1608.     Result := false;
  1609.     POP3CommandInProgress := false;
  1610.     exit;
  1611.   end;
  1612.   repeat
  1613.     TheResult := GetPOP3ServerResponse( TheReturnString );
  1614.     { Put result in progress and status line }
  1615.     AddProgressText( TheReturnString );
  1616.     ShowProgressText( TheReturnString + #13#10 );
  1617.   until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  1618.   POP3CommandInProgress := false;
  1619.   if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  1620.   begin
  1621.     { Do clever C formatting trick }
  1622.     TheReturnString :=
  1623.      DoCStyleFormat( 'POP3 Host %s Login Failed!' ,
  1624.       [ PCRPointer^.CIPAddress ] );
  1625.     { Put result in progress and status line }
  1626.     AddProgressText( TheReturnString );
  1627.     ShowProgressErrorText( TheReturnString );
  1628.     { Signal error }
  1629.     Result := False;
  1630.     { leave }
  1631.     exit;
  1632.   end
  1633.   else Result := true; { Signal no problem }
  1634. end;
  1635.  
  1636. { This is the FTP component constructor; it creates 2 sockets }
  1637. constructor TPOP3SMTPComponent.Create( AOwner : TComponent );
  1638. begin
  1639.   { do inherited create }
  1640.   inherited Create( AOwner );
  1641.   { Create sockets, put in their parents, and error procs }
  1642.   Socket1 := TCCSocket.Create( Self );
  1643.   Socket1.Parent := Self;
  1644.   Socket1.OnErrorOccurred := POP3SMTPSocketsErrorOccurred;
  1645.   { Set up booleans }
  1646.   Connection_Established := false;
  1647.   POP3CommandInProgress := false;
  1648. end;
  1649.  
  1650. { This is the FTP component destructor; it frees 2 sockets }
  1651. destructor TPOP3SMTPComponent.Destroy;
  1652. begin
  1653.   { Free the sockets }
  1654.   Socket1.Free;
  1655.   { and call inherited }
  1656.   inherited Destroy;
  1657. end;
  1658.  
  1659. { This is the POP3 components QUIT routine }
  1660. function TPOP3SMTPComponent.POP3Disconnect : Boolean;
  1661. var TheReturnString : String;  { Internal string holder }
  1662.     TheResult       : Integer; { Internal int holder    }
  1663. begin
  1664.   TheReturnString :=
  1665.    DoCStyleFormat( 'QUIT' ,
  1666.     [ nil ] );
  1667.   { Put result in progress and status line }
  1668.   AddProgressText( TheReturnString );
  1669.   ShowProgressText( TheReturnString );
  1670.   { Begin login sequence with user name }
  1671.   PerformPOP3Command( 'QUIT', [ nil ] );
  1672.   repeat
  1673.     TheResult := GetPOP3ServerResponse( TheReturnString );
  1674.     { Put result in progress and status line }
  1675.     AddProgressText( TheReturnString );
  1676.     ShowProgressText( TheReturnString + #13#10 );
  1677.   until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  1678.   POP3CommandInProgress := false;
  1679.   if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  1680.   begin
  1681.     { Do clever C formatting trick }
  1682.     TheReturnString :=
  1683.      DoCStyleFormat( 'EMail Host Connection Failed!' ,
  1684.       [ nil ] );
  1685.     { Put result in progress and status line }
  1686.     AddProgressText( TheReturnString );
  1687.     ShowProgressErrorText( TheReturnString );
  1688.     { Signal error }
  1689.     Result := False;
  1690.     { leave }
  1691.     exit;
  1692.   end
  1693.   else Result := true; { Signal no problem }
  1694. end;
  1695.  
  1696.  
  1697. procedure TPOP3SMTPComponent.UpdateGauge( BytesFinished , TotalToHandle : longint );
  1698. begin
  1699.   CCInetCCForm.UpdateMailGauge( BytesFinished , TotalToHandle );
  1700. end;
  1701.  
  1702. end.
  1703.