home *** CD-ROM | disk | FTP | other *** search
/ Delphi 2 - Developers' Solutions / Delphi 2 Developers' Solutions.iso / dds / chap11 / howto06 / delphi10 / cciccpop.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-06-12  |  107.2 KB  |  3,010 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, CCFTP;
  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.     TheEncodingHeader : TStringList;
  32.     TheBoundaryString : String;
  33.     TheInputFileName : String;
  34.     TheOutputFileName : String;
  35.     TheInputTextFile : TextFile;
  36.     TheOutputTextFile : TextFile;
  37.     TheInputBinaryFile : File of Byte;
  38.     TheOutputBinaryFile : File of Byte;
  39.     constructor Create( AOwner : TComponent ); override;
  40.     function IsBoundaryToken( TheLine : String ) : String;
  41.     function IsDecodeName( TheLine : String ) : String;
  42.     function IsBase64( TheLine : String ) : Boolean;
  43.     function IsBoundary( TheLine : String ) : Boolean;
  44.     function DecodeMIMEFile : Boolean;
  45.     function EncodeMIMEFile : Boolean;
  46.     function OpenDecodeInputFile : Boolean;
  47.     function OpenDecodeOutputFile : Boolean;
  48.     function CloseDecodeFiles : Boolean;
  49.     function OpenEncodeFiles : Boolean;
  50.     function CloseEncodeFiles : Boolean;
  51.     procedure MIMEError( ECode : Integer; EMsg : String );
  52.     procedure MIMEUpdate( BSF , BT : LongInt );
  53.     function GetQuotedString( TheInputString : String ) : String;
  54.     function ConvertBase64Character( Current_Character : Char ) : SmallInt;
  55.     procedure InitializeMIMEDecode;
  56.     procedure InitializeMIMEEncode;
  57.     function WriteMIMEHeader : Boolean;
  58.     function WriteFinalMIMEEncoding : Boolean;
  59.     function GetTextFileSize( TheName : String ) : Longint;
  60.     function MIMEDecode( TheString : String ) : Boolean;
  61.     procedure CreateDefaultHeader( var TheEncodingHeader : TStringList );
  62.     function AddBinaryValueToStream( BinaryValue : SmallInt ) : Boolean;
  63.     function EncodeMIMEOutputByte( TheInputByte : Byte;
  64.                                    LastChar     : Boolean  )  : Boolean;
  65.     property OnMIMEErrorOccurred : TMIMEErrorEvent read FOnMIMEErrorOccurred
  66.      write FOnMIMEErrorOccurred;
  67.     property OnMIMEUpdateOccurred : TMIMEUpdateEvent read FOnMIMEUpdateOccurred
  68.      write FOnMIMEUpdateOccurred;
  69.   end;
  70.   { Component To Hold POP3/SMTP handling capabilities }
  71.   TPOP3SMTPComponent = class( TWinControl )
  72.   public
  73.     POP3CommandInProgress ,
  74.     SMTPCommandInProgress ,
  75.     Connection_Established : Boolean;
  76.     Socket1 : TCCSocket;
  77.     constructor Create( AOwner : TComponent ); override;
  78.     destructor Destroy; override;
  79.     function EstablishPOP3Connection( PCRPointer : PConnectionsRecord ) : Boolean;
  80.     function EstablishSMTPConnection( PCRPointer : PConnectionsRecord ) : Boolean;
  81.     function POP3Disconnect : Boolean;
  82.     function SMTPDisconnect : Boolean;
  83.     function DoCStyleFormat(       TheText      : string;
  84.                              const TheArguments : array of const ) : String;
  85.     procedure UpdateGauge( BytesFinished , TotalToHandle : longint );
  86.     procedure AddProgressText( WhatText : String );
  87.     procedure ShowProgressText( WhatText : String );
  88.     procedure ShowProgressErrorText( WhatText : String );
  89.     function GetPOP3ServerResponse( var ResponseString : String ) : integer;
  90.     function GetSMTPServerResponse( var ResponseString : String ) : integer;
  91.     procedure SetRecipient( WhichMemo : TMemo; WhatName : String );
  92.     procedure SetCarbonCopy( WhichMemo : TMemo; WhatName : String );
  93.     procedure POP3SMTPSocketsErrorOccurred( Sender     : TObject;
  94.                                      ErrorCode  : Integer;
  95.                                      TheMessage : String   );
  96.     function PerformPOP3Command(
  97.                     TheCommand   : string;
  98.               const TheArguments : array of const ) : Integer;
  99.     function PerformSMTPCommand(
  100.                     TheCommand   : string;
  101.               const TheArguments : array of const ) : Integer;
  102.     function PerformPOP3ExtendedCommand(
  103.                     TheCommand   : string;
  104.               const TheArguments : array of const ) : Integer;
  105.     function PerformSMTPExtendedCommand(
  106.                     TheCommand   : string;
  107.               const TheArguments : array of const ) : Integer;
  108.     function GetPOP3ServerExtendedResponse( ResponseString : PChar ) : integer;
  109.     function GetSMTPServerExtendedResponse( ResponseString : PChar ) : integer;
  110.     function GetNextSDItem(     WorkingString : String;
  111.                             var TheIndex      : Integer ) : String;
  112.     procedure PurgeTrashedMessageListings( TheEMBRecord : PEMailMailBoxRecord );
  113.     procedure TrashMessage( TheEMMRecord : PEMailMessageRecord );
  114.     procedure TrashAllMarkedMessages( TheLB       : TListBox;
  115.                                       TheMBRecord : PEMailMailboxRecord );
  116.     procedure ParseMailListing(     TheListing : String;
  117.                                 var TotalMessages : Longint;
  118.                                 var MessageBytes : Longint);
  119.     function CheckAllNewMail( var TotalBytes : Longint ) : Integer;
  120.     procedure SetMailHeaders( TheMemo      : TMemo;
  121.                              TheEMCRecord : PConnectionsRecord );
  122.     procedure InsertMIMETextHeader( TheMemo : TMemo );
  123.     procedure AddMIMEAttachment( TheMemo      : TMemo; TheFileToAdd : String );
  124.     procedure NewMIMEMessage( TheMemo      : TMemo; TheNewFile : String;
  125.                                TheEMCRecord : PConnectionsRecord );
  126.     procedure SetReplyMailHeaders( TheMemo         : TMemo ;
  127.                                   TheEMCRecord    : PConnectionsRecord;
  128.                                   TheEMBRecord    : PEmailMailBoxRecord;
  129.                                   MessageNumber   : Integer );
  130.     function GetMessageHeader( TheReturnList : TStringList ) : Longint;
  131.     function DownloadMessageListing( TheNumber   : Integer;
  132.                                      TheFileName : String;
  133.                                      TheHeaderSL : TStringList ) : Longint;
  134.     function DownloadAllMessageListings( TheEMBRecord : PEMailMailBoxRecord ) : Boolean;
  135.     function UploadMessageListing( TheEMMRecord : PEmailMessageRecord ) : Boolean;
  136.     function UploadAllMessageListings( PCRPointer : PConnectionsRecord;
  137.                                        TheEMBRecord : PEMailMailBoxRecord ) : Boolean;
  138.     function GetHeaderSubject( HList : TStringList ) : String;
  139.     function GetHeaderSender( HList : TStringList ) : String;
  140.     function GetHeaderRecipient( HList : TStringList ) : String;
  141.     function GetHeaderCarbons( HList : TStringList ) : String;
  142.     function GetHeaderBlindCarbons( HList : TStringList ) : String;
  143.     function GetRCPTHeaderRecipient( HList : TStringList ) : String;
  144.     function GetRCPTHeaderCarbons( HList : TStringList ) : String;
  145.     function GetRCPTHeaderBlindCarbons( HList : TStringList ) : String;
  146.     function GetHeaderDateTime( HList : TStringList ) : String;
  147.     procedure TransferMessage( SourceEMBRecord , TargetEMBRecord : PEMailMailBoxRecord;
  148.                               MessageNumber : Integer );
  149.     procedure ExtractHeaderInfoFromMemo( TheMemo      : TMemo;
  150.                                          TheEMMRecord : PEMailMessageRecord );
  151.     function LoginUser( PCRPointer : PConnectionsRecord ) : Boolean;
  152.     function SendPassword( PCRPointer : PConnectionsRecord ) : Boolean;
  153.     function SendHelo( PCRPointer : PConnectionsRecord ) : Boolean;
  154.     function SendMail( PCRPointer : PConnectionsRecord ) : Boolean;
  155.     function DeleteMailItem( TheNumber : Longint ) : Boolean;
  156.   end;
  157.  
  158. var
  159.   ThePOP3SMTPComponent  : TPOP3SMTPComponent; { Gee, which one is this? :) }
  160.   TheMIMEObject : TMIMECodingObject;
  161.  
  162. implementation
  163.  
  164. { Create constructor; sets update and error methods }
  165. constructor TMIMECodingObject.Create( AOwner : TComponent );
  166. begin
  167.   { Call inherited }
  168.   Inherited Create( AOwner );
  169.   { Setup two methods; can be overridden }
  170.   OnMIMEErrorOccurred := MIMEError;
  171.   OnMIMEUpdateOccurred := MIMEUpdate;
  172. end;
  173.  
  174. { This procedure resets the two decoding variables }
  175. procedure TMIMECodingObject.InitializeMIMEDecode;
  176. begin
  177.   The_Accumulator := 0;
  178.   Total_Bits_Shifted := 0;
  179.   BytesDone := 0;
  180. end;
  181.  
  182. { This procedure resets the two decoding variables }
  183. procedure TMIMECodingObject.InitializeMIMEEncode;
  184. begin
  185.   The_Accumulator := 0;
  186.   Total_Bits_Shifted := 0;
  187.   OutputString := '';
  188.   BytesDone := 0;
  189. end;
  190.  
  191. { This is the generic error handler }
  192. procedure TMIMECodingObject.MIMEError( ECode : Integer; EMsg : String );
  193. begin
  194.   { Do generic MessageBox }
  195.   MessageDlg( 'A MIME error code ' + IntToStr( ECode ) +
  196.    ' has happend with Message ' + EMsg , mtError , [mbOK] , 0 );
  197. end;
  198.  
  199. { This is the generic update procedure }
  200. procedure TMIMECodingObject.MIMEUpdate( BSF , BT : LongInt );
  201. begin
  202.   CCInetCCForm.UpdateMIMEGauge( BSF , BT );
  203. end;
  204.  
  205. { This function takes an input string and returns any "" delimited text in it }
  206. function TMIMECodingObject.GetQuotedString( TheInputString : String ) : String;
  207. var HoldingString : String;  { Interim results holder }
  208.     PositionIndex : Integer; { " position holder      }
  209. begin
  210.   { Look for initial positon of double quote }
  211.   PositionIndex := Pos( '"' , TheInputString );
  212.   { If not found, then no quoted text; return empty string }
  213.   if PositionIndex = 0 then
  214.   begin
  215.     Result := '';
  216.     exit;
  217.   end;
  218.   { Otherwise get from just beyond " to end of string, allowing for unlimited }
  219.   { string sizes now in Delphi 2.0                                            }
  220.   HoldingString := Copy( TheInputString , PositionIndex + 1 ,
  221.    ( Length( TheInputString ) - PositionIndex ));
  222.   { Find ending " if any }
  223.   PositionIndex := Pos( '"' , HoldingString );
  224.   { If no ending " then assume all from first quote is result }
  225.   if PositionIndex = 0 then
  226.   begin
  227.     Result := HoldingString;
  228.     exit;
  229.   end;
  230.   { Otherwise get down to 1 before closing " }
  231.   HoldingString := Copy( HoldingString , 1 , PositionIndex - 1 );
  232.   { and return the ""-stripped string as desired }
  233.   Result := HoldingString;
  234. end;
  235.  
  236. { This function scans a line of text for the keyword 'boundary=' }
  237. function TMIMECodingObject.IsBoundaryToken( TheLine : String ) : String;
  238. begin
  239.   { Find out if it's a boundary token symbol }
  240.   if Pos( 'boundary=' , lowercase( TheLine )) <> 0 then
  241.   begin
  242.     { And grab the value }
  243.     Result := GetQuotedString( TheLine );
  244.   end
  245.   else
  246.   begin
  247.     { Else return empty string }
  248.     Result := '';
  249.   end;
  250. end;
  251.  
  252. { This function determines if the "name=" token is on a line and if so }
  253. { Returns the quoted file name as its result; otherwise it returns ''  }
  254. function TMIMECodingObject.IsDecodeName( TheLine : String ) : String;
  255. var PositionIndex : Integer; { Holds possible position of name= token }
  256.     HoldingString : String;  { Holds working string once token found  }
  257.     ResultString  : String;  { Holds name once stripped out of ""     }
  258. begin
  259.   { Find out if name= token in line }
  260.   PositionIndex := Pos( 'name=' , lowercase( TheLine ));
  261.   { If not reutrn the empty string }
  262.   if PositionIndex = 0 then
  263.   begin
  264.     Result := '';
  265.   end
  266.   else
  267.   begin
  268.     { Otherwise strip out stuff before token }
  269.     HoldingString := Copy( TheLine , PositionIndex + 1 ,
  270.      ( Length( TheLine ) - PositionIndex ));
  271.     { And send rest through stripquotes to get filename }
  272.     ResultString := GetQuotedString( HoldingString );
  273.     { Send it back; if malformed will be '' }
  274.     Result := ResultString;
  275.   end;
  276. end;
  277.  
  278. { This function returns true if the Base64 token is found, otherwise false }
  279. function TMIMECodingObject.IsBase64( TheLine : String ) : Boolean;
  280. begin
  281.   { if substring found assume valid token and return true else return false }
  282.   if Pos( 'base64' , lowercase( TheLine )) > 0 then Result := true
  283.    else Result := false;
  284. end;
  285.  
  286. { This funcion assumes the boundary string has been found; once it's known }
  287. { this function tells whether a line contains it.                          }
  288. function TMIMECodingObject.IsBoundary( TheLine : String ) : Boolean;
  289. begin
  290.   { A valid substring hit means true otherwise false }
  291.   if Pos( TheBoundaryString , TheLine ) <> 0 then Result := true else
  292.    Result := false;
  293. end;
  294.  
  295. { This is a clever function to get the total bytes of a text file }
  296. function TMIMECodingObject.GetTextFileSize( TheName : String ) : Longint;
  297. var TheSR : TSearchRec; { Used for trick }
  298. begin
  299.   { This allows getting the data }
  300.   FindFirst( TheName , faAnyFile , TheSR );
  301.   { And this is the info }
  302.   Result := TheSR.Size;
  303.   { Needed for win32 }
  304.   {FindClose( TheSR )};
  305. end;
  306.  
  307. { This function uses Try..Except loops to check for valid file openings }
  308. function TMIMECodingObject.OpenDecodeInputFile : Boolean;
  309. begin
  310.   { Use a try..except loop to catch IOErrors }
  311.   try
  312.     { assign the text input file to the input filename }
  313.     AssignFile( TheInputTextFile , TheInputFileName );
  314.     { do a reset }
  315.     Reset( TheInputTextFile );
  316.     { Get total bytes of a text file! }
  317.     BytesToGet := GetTextFileSize( TheInputFileName );
  318.   except
  319.     { Set error information on an input/output failure }
  320.     On E:EInOutError do
  321.     begin
  322.       { Get error message from exception object }
  323.       ErrorResult := -E.ErrorCode;
  324.       { Get filename and error message from exception object }
  325.       ErrorMessage := 'Unable to open Input File ' + TheInputFileName +
  326.        ' Due to ' + E.Message;
  327.       { if assigned error event then call it with info }
  328.       if Assigned( FOnMIMEErrorOccurred ) then
  329.        OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  330.       { return false on an error }
  331.       Result := false;
  332.       exit;
  333.     end;
  334.   end;
  335.   { Return true on no error }
  336.   Result := true;
  337. end;
  338.  
  339. { This function uses Try..Except loops to check for valid file openings }
  340. function TMIMECodingObject.OpenDecodeOutputFile : Boolean;
  341. begin
  342.   { Use a try..except loop to catch IOErrors }
  343.   try
  344.     { assign the binary output file to the parsed output filename }
  345.     AssignFile( TheOutputBinaryFile , TheOutputFileName );
  346.     { do a rewrite }
  347.     ReWrite( TheOutputBinaryFile );
  348.   except
  349.     { Set error information on an input/output failure }
  350.     On E:EInOutError do
  351.     begin
  352.       { Get error message from exception object }
  353.       ErrorResult := -E.ErrorCode;
  354.       { Get filename and error message from exception object }
  355.       ErrorMessage := 'Unable to open Output File ' + TheOutputFileName +
  356.        ' Due to ' + E.Message;
  357.       { if assigned error event then call it with info }
  358.       if Assigned( FOnMIMEErrorOccurred ) then
  359.        OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  360.       { return false on an error }
  361.       Result := false;
  362.       exit;
  363.     end;
  364.   end;
  365.   { Return true on no error }
  366.   Result := true;
  367. end;
  368.  
  369. { This closes both files and signals any error }
  370. function TMIMECodingObject.CloseDecodeFiles : Boolean;
  371. begin
  372.   { Use try..except to catch errors }
  373.   try
  374.     { Do both closefiles }
  375.     CloseFile( TheInputTextFile );
  376.     CloseFile( TheOutputBinaryFile );
  377.   except
  378.     { Set error information on an input/output failure }
  379.     On E:EInOutError do
  380.     begin
  381.       { Get error message from exception object }
  382.       ErrorResult := -E.ErrorCode;
  383.       { Get filename and error message from exception object }
  384.       ErrorMessage := 'Unable to close file(s) ' + ' Due to ' + E.Message;
  385.       { if assigned error event then call it with info }
  386.       if Assigned( FOnMIMEErrorOccurred ) then
  387.        OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  388.       { return false on an error }
  389.       Result := false;
  390.       exit;
  391.     end;
  392.   end;
  393.   { No error sends true }
  394.   Result := true;
  395. end;
  396.  
  397. { This function opens all the encoding files at once and sends false if errors }
  398. function TMIMECodingObject.OpenEncodeFiles : Boolean;
  399. begin
  400.   { Use try..except to catch any IO Errors }
  401.   try
  402.     { For Encoding, can assume prior knowledge of both the input and output }
  403.     { file names; can do both at once.                                      }
  404.     AssignFile( TheInputBinaryFile , TheInputFileName );
  405.     Reset( TheInputBinaryFile );
  406.     { Get update information }
  407.     BytesToGet := FileSize( TheInputBinaryFile );
  408.   except
  409.     { Set error information on an input/output failure }
  410.     On E:EInOutError do
  411.     begin
  412.       { Get error message from exception object }
  413.       ErrorResult := -E.ErrorCode;
  414.       { Get filename and error message from exception object }
  415.       ErrorMessage := 'Unable to open Input File ' + TheInputFileName +
  416.        ' Due to ' + E.Message;
  417.       { if assigned error event then call it with info }
  418.       if Assigned( FOnMIMEErrorOccurred ) then
  419.        OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  420.       { return false on an error }
  421.       Result := false;
  422.       exit;
  423.     end;
  424.   end;
  425.   { Do the output file }
  426.   try
  427.     AssignFile( TheOutputTextFile , TheOutputFileName );
  428.     ReWrite( TheOutputTextFile );
  429.   except
  430.     { Set error information on an input/output failure }
  431.     On E:EInOutError do
  432.     begin
  433.       { Get error message from exception object }
  434.       ErrorResult := -E.ErrorCode;
  435.       { Get filename and error message from exception object }
  436.       ErrorMessage := 'Unable to open Output File ' + TheOutputFileName +
  437.        ' Due to ' + E.Message;
  438.       { if assigned error event then call it with info }
  439.       if Assigned( FOnMIMEErrorOccurred ) then
  440.        OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  441.       { return false on an error }
  442.       Result := false;
  443.       exit;
  444.     end;
  445.   end;
  446.   { Signal true if no errors }
  447.   Result := true;
  448. end;
  449.  
  450. { This function returns true if no errors closing encode files or false if not }
  451. function TMIMECodingObject.CloseEncodeFiles : Boolean;
  452. begin
  453.   { Use a try..except to catch errors }
  454.   try
  455.     { do both closefiles }
  456.     CloseFile( TheInputBinaryFile );
  457.     CloseFile( TheOutputTextFile );
  458.   except
  459.     { Set error information on an input/output failure }
  460.     On E:EInOutError do
  461.     begin
  462.       { Get error message from exception object }
  463.       ErrorResult := -E.ErrorCode;
  464.       { Get filename and error message from exception object }
  465.       ErrorMessage := 'Unable to close file(s) ' + ' Due to ' + E.Message;
  466.       { if assigned error event then call it with info }
  467.       if Assigned( FOnMIMEErrorOccurred ) then
  468.        OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  469.       { return false on an error }
  470.       Result := false;
  471.       exit;
  472.     end;
  473.   end;
  474.   { Return true if no errors }
  475.   Result := true;
  476. end;
  477.  
  478. { This function assumes the input filename is set but it does the rest }
  479. function TMIMECodingObject.DecodeMIMEFile : Boolean;
  480. var Finished      : Boolean; { Loop control variable }
  481.     Completed     : Boolean; { Loop control variable }
  482.     WorkingString : String;  { Input holder          }
  483. begin
  484.   { clear boundary marker }
  485.   TheBoundaryString := '';
  486.   { Set failure default return value; specific error handling }
  487.   { will be done be individual functions via ErrorResult and  }
  488.   { HandleMIMEError.                                          }
  489.   Result := false;
  490.   { Try to open the input text file }
  491.   if not OpenDecodeInputFile then exit;
  492.   { Clear loop variable }
  493.   Finished := false;
  494.   { Run till either end of file or signal done }
  495.   while (( not Finished ) and ( not EOF( TheInputTextFile ))) do
  496.   begin
  497.     { Get a line }
  498.     Readln( TheInputTextFile , WorkingString );
  499.     { Do the process count }
  500.     BytesDone := BytesDone + Length( WorkingString );
  501.     { Find out if the boundary token }
  502.     TheBoundaryString := IsBoundaryToken( WorkingString );
  503.     { If found then set exit variable }
  504.     if TheBoundaryString <> '' then Finished := true;
  505.   end;
  506.   { if no boundary marker found then go bye bye }
  507.   if TheBoundaryString = '' then
  508.   begin
  509.     { Set error message }
  510.     ErrorResult := -101;
  511.     { Get filename and error message from exception object }
  512.     ErrorMessage := 'No Boundary Token Found!';
  513.     { if assigned error event then call it with info }
  514.     if Assigned( FOnMIMEErrorOccurred ) then
  515.      OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  516.     exit;
  517.   end;
  518.   { Clear control variables }
  519.   Finished := false;
  520.   Base64Found := false;
  521.   TheOutputFileName := '';
  522.   { run loop to get name and confirm base64 encoding }
  523.   while (( not Finished ) and ( not EOF( TheInputTextFile ))) do
  524.   begin
  525.     { This outer loop grabs lines of text; does multiple boundaries }
  526.     Readln( TheInputTextFile , WorkingString );
  527.     { Do the process count }
  528.     BytesDone := BytesDone + Length( WorkingString );
  529.     { if hit a boundary then look for the base64 stuff }
  530.     if IsBoundary( WorkingString ) then
  531.     begin
  532.       { Set loop control }
  533.       Completed := false;
  534.       { run until run out of file or hit blank line }
  535.       while (( not Completed ) and ( not EOF( TheInputTextfile ))) do
  536.       begin
  537.         { Get line }
  538.         Readln( TheInputTextFile , WorkingString );
  539.         { Do the process count }
  540.         BytesDone := BytesDone + Length( WorkingString );
  541.         { if a blank then go bye bye }
  542.         if WorkingString = '' then
  543.         begin
  544.           Completed := true;
  545.         end
  546.         else
  547.         begin
  548.           { Get both possible output name and base64 OK }
  549.           if TheOutputFileName = '' then
  550.            TheOutputFileName := IsDecodeName( WorkingString );
  551.           if not Base64Found then
  552.            Base64Found := IsBase64( WorkingString );
  553.         end;
  554.       end;
  555.       { if found a blank line then check for valid base64 file }
  556.       if Completed then
  557.       begin
  558.         { If got an output filename and found b64 then set finished }
  559.         if (( TheOutputFileName <> '' ) and Base64Found ) then
  560.          Finished := true;
  561.       end;
  562.     end;
  563.   end;
  564.   { If never completed or output data not found then exit }
  565.   if not Finished then
  566.   begin
  567.     if TheOutputFileName = '' then
  568.     begin
  569.       { Set error message }
  570.       ErrorResult := -102;
  571.       { Get filename and error message from exception object }
  572.       ErrorMessage := 'No output filename found!';
  573.       { if assigned error event then call it with info }
  574.       if Assigned( FOnMIMEErrorOccurred ) then
  575.        OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  576.     end
  577.     else
  578.     begin
  579.       { Set error message }
  580.       ErrorResult := -103;
  581.       { Get filename and error message from exception object }
  582.       ErrorMessage := 'Not Base64 encoding!';
  583.       { if assigned error event then call it with info }
  584.       if Assigned( FOnMIMEErrorOccurred ) then
  585.        OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  586.     end;
  587.     exit;
  588.   end;
  589.   { Try to open the decode output file }
  590.   if not OpenDecodeOutputFile then exit;
  591.   { Set loop control variable }
  592.   Finished := false;
  593.   { Set up the decode variables }
  594.   InitializeMIMEDecode;
  595.   { run loop to get binary data }
  596.   while (( not Finished ) and ( not EOF( TheInputTextFile ))) do
  597.   begin
  598.     { Get an input line }
  599.     Readln( TheInputTextFile , WorkingString );
  600.     { Do the process count }
  601.     BytesDone := BytesDone + Length( WorkingString );
  602.     { If it's a boundary then don't process it otherwise do decode }
  603.     if not IsBoundary( WorkingString ) then
  604.     begin
  605.       { If decodes ok keep going else abort }
  606.       if not MIMEDecode( WorkingString ) then exit;
  607.       { Update status indicator }
  608.       if Assigned( FOnMIMEUpdateOccurred ) then
  609.        OnMIMEUpdateOccurred( BytesDone , BytesToGet );
  610.     end
  611.     { End processing if a boundary found }
  612.     else Finished := true;
  613.   end;
  614.   { Clear status indicator }
  615.   if Assigned( FOnMIMEUpdateOccurred ) then
  616.    OnMIMEUpdateOccurred( BytesToGet , BytesToGet );
  617.   { Close the files }
  618.   if not CloseDecodeFiles then exit;
  619.   { Return success }
  620.   Result := true;
  621. end;
  622.  
  623. { This function returns a binary number based on the ascii of the input char }
  624. function TMIMECodingObject.ConvertBase64Character( Current_Character : Char ) :
  625.  SmallInt;
  626. begin
  627.    { Decode ordinals of uppercase characters 0 - 25 }
  628.    if (( Current_Character >= 'A' ) and
  629.        ( Current_Character <= 'Z' )) then
  630.    begin
  631.      result :=
  632.       SmallInt( Ord( Current_Character ) - Ord( 'A' ));
  633.      exit;
  634.    end;
  635.    { Decode ordinals of lowercase characters 26 - 51 }
  636.    if (( Current_Character >= 'a') and
  637.        ( Current_Character <= 'z')) then
  638.    begin
  639.      result := 26 +
  640.        SmallInt( Ord( Current_Character ) - Ord( 'a' ));
  641.      exit;
  642.    end;
  643.    { Decode ordinals of numbers 52 - 61 }
  644.    if (( Current_Character >= '0') and
  645.        ( Current_Character <= '9' )) then
  646.    begin
  647.      result := 52 +
  648.        SmallInt( Ord( Current_Character ) - Ord( '0' ));
  649.      exit;
  650.    end;
  651.    { Decode + as 62 }
  652.    if ( Current_Character = '+' ) then
  653.    begin
  654.      result := 62;
  655.      exit;
  656.    end;
  657.    { Decode / as 63 }
  658.    if ( Current_Character = '/' ) then
  659.    begin
  660.      result := 63;
  661.      exit;
  662.    end;
  663.    { Signal padding character = by -2 }
  664.    if ( Current_Character = '=' ) then
  665.    begin
  666.      result := -2;
  667.      exit;
  668.    end;
  669.    { Signal invalid character by -1 }
  670.    result := -1;
  671. end;
  672.  
  673. { This function does bit magic on the current data state and when appropriate }
  674. { writes a byte to the output file.                                           }
  675. function TMIMECodingObject.AddBinaryValueToStream( BinaryValue : SmallInt ) :
  676.  Boolean;
  677. var WorkingValue : SmallInt; { Used to store bit conversion }
  678.     OutputValue  : Byte;     { Used to store output byte    }
  679. begin
  680.   { Assume success; only error will be file write failure }
  681.   Result := true;
  682.   { Shift over six bits of the accumulator }
  683.   The_Accumulator := The_Accumulator SHL 6;
  684.   { Add the shift to the counter }
  685.   Total_Bits_Shifted := Total_Bits_Shifted + 6;
  686.   { OR in the acquired bits }
  687.   { first char =  6 bits }
  688.   { 2nd   char = 12 bits; moved back to 4 }
  689.   { 3rd   char = 10 bits; moved back to 2 }
  690.   { 4th   char =  8 bits; moved back to 0 }
  691.   The_Accumulator := ( The_Accumulator or BinaryValue );
  692.   { If have at least one valid output byte }
  693.   if  Total_Bits_Shifted >= 8 then
  694.   begin
  695.     { Reduce remaining bits by 8 }
  696.     Total_Bits_Shifted := Total_Bits_Shifted - 8;
  697.     { Grab last full 8 bits in the accumulator }
  698.     { note that continual shifting clears it   }
  699.     WorkingValue := The_Accumulator SHR Total_Bits_Shifted;
  700.     { Mask off the high byte of the smallint }
  701.     OutputValue := byte( WorkingValue and $00FF );
  702.     { Use try..except to write out the byte }
  703.     try
  704.       { Do a seek for safety }
  705.       Seek( TheOutputBinaryFile , FileSize( TheOutputBinaryFile ));
  706.       { write the data byte }
  707.       Write( TheOutputBinaryFile , OutputValue );
  708.     except
  709.       { Set error information on an input/output failure }
  710.       On E:EInOutError do
  711.       begin
  712.         { Get error message from exception object }
  713.         ErrorResult := -E.ErrorCode;
  714.         { Get filename and error message from exception object }
  715.         ErrorMessage := 'Unable to Write output byte Due to ' + E.Message;
  716.         { if assigned error event then call it with info }
  717.         if Assigned( FOnMIMEErrorOccurred ) then
  718.          OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  719.         { return false on an error }
  720.         Result := false;
  721.         exit;
  722.       end;
  723.     end;
  724.   end;
  725. end;
  726.  
  727. { This function does the dirty work of doing the MIME decoding }
  728. function TMIMECodingObject.MIMEDecode( TheString : String ) : Boolean;
  729. var Counter_1         : Integer;   { Loop counter }
  730.     Current_Character : Char;      { Decode char  }
  731.     Binary_Value      : SmallInt;  { Output value }
  732. begin
  733.   { Assume success }
  734.   Result := true;
  735.   { Ignore blank lines }
  736.   if TheString = '' then exit;
  737.   { Run along string }
  738.   for Counter_1 := 1 to Length( TheString ) do
  739.   begin
  740.     { get char to decode }
  741.     Current_Character := TheString[ Counter_1 ];
  742.     { convert char to binary via lookup function }
  743.     Binary_Value := ConvertBase64Character( Current_Character );
  744.     { if -2 hit = padding char; abort }
  745.     if Binary_Value = -2 then exit;
  746.     { if invalid char signal error }
  747.     if Binary_Value = -1 then
  748.     begin
  749.       { Set error message }
  750.       ErrorResult := -104;
  751.       { Get filename and error message from exception object }
  752.       ErrorMessage := 'Invalid Input Character!';
  753.       { if assigned error event then call it with info }
  754.       if Assigned( FOnMIMEErrorOccurred ) then
  755.        OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  756.       { signal error and exit }
  757.       Result := false;
  758.       exit;
  759.     end;
  760.     { try to send the binary value through the byte cruncher }
  761.     if not AddBinaryValueToStream( Binary_Value ) then
  762.     begin
  763.       { If failed return error since had disk write error }
  764.       Result := false;
  765.       exit;
  766.     end;
  767.   end;
  768. end;
  769.  
  770. { This method will attempt to create the default stringlist of a MIME header }
  771. { It will include the file name without path.                                }
  772. procedure TMIMECodingObject.CreateDefaultHeader( var TheEncodingHeader : TStringList );
  773. begin
  774.   { Put in a lot of weird text }
  775.   TheBoundaryString := '=====================_CIUPKC158==_';
  776.   TheEncodingHeader := TStringList.Create;
  777.   with TheEncodingHeader do
  778.   begin
  779.     Add( 'Content-Type: multipart/mixed; boundary="' + TheBoundaryString + '"' );
  780.     Add( 'X-Attachments: ' + TheInputFileName );
  781.     Add( '--' + TheBoundaryString );
  782.     Add( 'Content-Type: octet-stream; name="' +
  783.      ExtractFileName( TheInputFileName ) + '"' );
  784.     Add( 'Content-Transfer-Encoding: base64' );
  785.     Add( 'Content-Disposition: attachment; filename="' +
  786.      ExtractFileName( TheInputFilename ) + '"' );
  787.     Add( '' );
  788.   end;
  789. end;
  790.  
  791. { This function does the actual encoding of an output byte into the four byte }
  792. { character quads and sends the characters out as needed.                     }
  793. function TMIMECodingObject.EncodeMIMEOutputByte( TheInputByte : Byte;
  794.           LastChar : Boolean ) : Boolean;
  795. var WorkingValue  : Cardinal; { This is 16 bits in win16 and 32 bits in win95 }
  796.     WorkingCharacter : Char;  { Holds output char value                       }
  797.     WorkingString : String;   { Holder for single-character addition string   }
  798. begin
  799.   { Default is good processing }
  800.   Result := true;
  801.   { Set up workingString for one character }
  802.   WorkingString := ' ';
  803.   { Promote the input byte }
  804.   WorkingValue := Cardinal( TheInputByte );
  805.   { Scoot current bit list oer 8 }
  806.   The_Accumulator := The_Accumulator SHL 8;
  807.   { Increment bitshift count }
  808.   Total_Bits_Shifted := Total_Bits_Shifted + 8;
  809.   { OR in the new bits }
  810.   The_Accumulator := ( The_Accumulator or WorkingValue );
  811.   { Except on last output, run chars into string until below 6 bits }
  812.   while ( Total_Bits_Shifted >= 6 ) do
  813.   begin
  814.     { Reduce total bitshift }
  815.     Total_Bits_Shifted := Total_Bits_Shifted - 6;
  816.     { Do bit magic on accumulator to get char value  masked to 1 byte}
  817.     WorkingValue := (( The_Accumulator SHR Total_Bits_Shifted ) and  $0000003F );
  818.     { get array index character from preset constant }
  819.     WorkingCharacter := The_Alphabet[ Byte( WorkingValue ) ];
  820.     { shove it into the working string }
  821.     WorkingString[ 1 ] := WorkingCharacter;
  822.     { And add it to the output string }
  823.     OutputString := OutputString + WorkingString;
  824.     { If hit 80 chars do output to file }
  825.     if ( Length( OutputString ) = 80 ) then
  826.     begin
  827.       { Usual try..except block }
  828.       try
  829.         Writeln( TheOutputTextFile , OutputString );
  830.         { Update status indicator }
  831.         if Assigned( FOnMIMEUpdateOccurred ) then
  832.          OnMIMEUpdateOccurred( BytesDone , BytesToGet );
  833.       except
  834.         { Set error information on an input/output failure }
  835.         On E:EInOutError do
  836.         begin
  837.           { Get error message from exception object }
  838.           ErrorResult := -E.ErrorCode;
  839.           { Get filename and error message from exception object }
  840.           ErrorMessage := 'Unable to Write output line Due to ' + E.Message;
  841.           { if assigned error event then call it with info }
  842.           if Assigned( FOnMIMEErrorOccurred ) then
  843.            OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  844.           { return false on an error }
  845.           Result := false;
  846.           exit;
  847.         end;
  848.       end;
  849.       { Reset the output string }
  850.       OutputString := '';
  851.     end;
  852.     { Don't loop on last dummy character to flush bit buffer }
  853.     if LastChar then exit;
  854.   end;
  855. end;
  856.  
  857. { This function writes out the preloaded stringlist with what }
  858. { is assumed to be a valid MIME header.                       }
  859. { If one is not found the default header is written.          }
  860. function TMIMECodingObject.WriteMIMEHeader : Boolean;
  861. var Counter_1 : Integer; { Loop counter }
  862. begin
  863.   { if the encoding header is not assigned then create a default }
  864.   if not Assigned( TheEncodingHeader ) then
  865.     CreateDefaultHeader( TheEncodingHeader );
  866.   { run along the string list and write its contents out to the file }
  867.   for Counter_1 := 0 to TheEncodingHeader.Count - 1 do
  868.   begin
  869.     { do try..except to catch errors }
  870.     try
  871.       Writeln( TheOutputTextFile , TheEncodingHeader.Strings[ Counter_1 ] );
  872.     except
  873.       { Set error information on an input/output failure }
  874.       On E:EInOutError do
  875.       begin
  876.         { Get error message from exception object }
  877.         ErrorResult := -E.ErrorCode;
  878.         { Get filename and error message from exception object }
  879.         ErrorMessage := 'Unable to Write output line Due to ' + E.Message;
  880.         { if assigned error event then call it with info }
  881.         if Assigned( FOnMIMEErrorOccurred ) then
  882.          OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  883.         { return false on an error }
  884.         Result := false;
  885.         exit;
  886.       end;
  887.     end;
  888.   end;
  889.   { Signal success }
  890.   Result := true;
  891. end;
  892.  
  893. { This function writes out any last bytes to the encoded file and flushes the }
  894. { output string if needed.                                                    }
  895. function TMIMECodingObject.WriteFinalMIMEEncoding : Boolean;
  896. begin
  897.   if Total_Bits_Shifted = 0 then
  898.   begin
  899.     if OutputString = '' then
  900.     begin
  901.       { Usual try..except block }
  902.       try
  903.         Writeln( TheOutputTextFile , '--' + TheBoundaryString );
  904.       except
  905.         { Set error information on an input/output failure }
  906.         On E:EInOutError do
  907.         begin
  908.           { Get error message from exception object }
  909.           ErrorResult := -E.ErrorCode;
  910.           { Get filename and error message from exception object }
  911.           ErrorMessage := 'Unable to Write output line Due to ' + E.Message;
  912.           { if assigned error event then call it with info }
  913.           if Assigned( FOnMIMEErrorOccurred ) then
  914.            OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  915.           { return false on an error }
  916.           Result := false;
  917.           exit;
  918.         end;
  919.       end;
  920.       Result := true;
  921.       exit;
  922.     end;
  923.     { Usual try..except block }
  924.     try
  925.       Writeln( TheOutputTextFile , OutputString );
  926.       Writeln( TheOutputTextFile , '--' + TheBoundaryString );
  927.     except
  928.       { Set error information on an input/output failure }
  929.       On E:EInOutError do
  930.       begin
  931.         { Get error message from exception object }
  932.         ErrorResult := -E.ErrorCode;
  933.         { Get filename and error message from exception object }
  934.         ErrorMessage := 'Unable to Write output line Due to ' + E.Message;
  935.         { if assigned error event then call it with info }
  936.         if Assigned( FOnMIMEErrorOccurred ) then
  937.          OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  938.         { return false on an error }
  939.         Result := false;
  940.         exit;
  941.       end;
  942.     end;
  943.     Result := true;
  944.   end
  945.   else
  946.   begin
  947.     if Total_Bits_Shifted = 4 then OutputString := OutputString + '=' else
  948.      OutputString := OutputString + '==';
  949.     { Usual try..except block }
  950.     try
  951.       Writeln( TheOutputTextFile , OutputString );
  952.       Writeln( TheOutputTextFile , '--' + TheBoundaryString );
  953.     except
  954.       { Set error information on an input/output failure }
  955.       On E:EInOutError do
  956.       begin
  957.         { Get error message from exception object }
  958.         ErrorResult := -E.ErrorCode;
  959.         { Get filename and error message from exception object }
  960.         ErrorMessage := 'Unable to Write output line Due to ' + E.Message;
  961.         { if assigned error event then call it with info }
  962.         if Assigned( FOnMIMEErrorOccurred ) then
  963.          OnMIMEErrorOccurred( ErrorResult , ErrorMessage );
  964.         { return false on an error }
  965.         Result := false;
  966.         exit;
  967.       end;
  968.     end;
  969.     Result := true;
  970.   end;
  971. end;
  972.  
  973. { This function does a MIME encode; reading in a binary file     }
  974. { and outputting MIME characters to a text file; it assumes      }
  975. { valid filenames and a valid MIME Header/boundary are in place. }
  976. function TMIMECodingObject.EncodeMIMEFile : Boolean;
  977. var InputCounter : Integer; { Counter for file seeking  }
  978.     Finished     : Boolean; { Loop controller           }
  979.     TheInputByte : Byte;    { Byte to hold read in data }
  980. begin
  981.   { Assume failure }
  982.   Result := false;
  983.   BytesDone := 1;
  984.   { Try to open the encode files and exit if fail }
  985.   if not OpenEncodeFiles then exit;
  986.   { Try to write the MIME header and exit if fail }
  987.   if not WriteMIMEHeader then exit;
  988.   { Clear loop variables }
  989.   InputCounter := 0;
  990.   Finished := false;
  991.   { Set up baseline for encoding }
  992.   InitializeMIMEEncode;
  993.   { Loop till abort or run out of input file }
  994.   while not Finished do
  995.   begin
  996.     { Seek along the binary input file }
  997.     Seek( TheInputBinaryFile , InputCounter );
  998.     { Get a byte of input data }
  999.     Read( TheInputBinaryFile , TheInputByte );
  1000.     { Update progress counter }
  1001.     Inc( BytesDone );
  1002.     { Move up the counter }
  1003.     Inc( InputCounter );
  1004.     { If greater than or equal to size of file then done }
  1005.     if InputCounter >= FileSize( TheInputBinaryFile ) then Finished := true;
  1006.     { Try to encode and write data and abort if fail }
  1007.     if not EncodeMIMEOutputByte( TheInputByte , false ) then exit;
  1008.   end;
  1009.   { Clear status indicator }
  1010.   if Assigned( FOnMIMEUpdateOccurred ) then
  1011.    OnMIMEUpdateOccurred( BytesToGet , BytesToGet );
  1012.   { Handle leftovers }  
  1013.   if Total_Bits_Shifted > 0 then EncodeMIMEOutputByte( 0  , true );
  1014.   { Write out left over ='s and final section boundary }
  1015.   if not WriteFinalMIMEEncoding then exit;
  1016.   { Try and close the files }
  1017.   if not CloseEncodeFiles then exit;
  1018.   { Only return true if everything went right }
  1019.   Result := true;
  1020. end;
  1021.  
  1022. procedure TPOP3SMTPComponent.TrashMessage( TheEMMRecord : PEMailMessageRecord );
  1023. begin
  1024.   TheEMMRecord^.MRMessageSender := 'DELETE ME';
  1025. end;
  1026.  
  1027. procedure TPOP3SMTPComponent.TrashAllMarkedMessages( TheLB       : TListBox;
  1028.                                                      TheMBRecord : PEMailMailboxRecord );
  1029. var Counter_1 : Integer;
  1030.     WorkingList : TList;
  1031. begin
  1032.   WorkingList := TList( TheMBRecord^.MBLTag );
  1033.   for Counter_1 := 0 to TheLB.Items.Count - 1 do
  1034.   begin
  1035.     if TheLB.Selected[ Counter_1 ] then
  1036.     begin
  1037.       TrashMessage( PEMailMessageRecord( WorkingList.Items[ Counter_1 ] ));
  1038.     end;
  1039.   end;
  1040. end;
  1041.  
  1042. procedure TPOP3SMTPComponent.SetRecipient( WhichMemo : TMemo; WhatName : String );
  1043. var Finished : Boolean;
  1044.     Counter_1 ,
  1045.     FoundLine   : Integer;
  1046. begin
  1047.   Finished := false;
  1048.   Counter_1 := 0;
  1049.   FoundLine := -1;
  1050.   while not Finished do
  1051.   begin
  1052.     if Pos( 'TO:' , Uppercase( WhichMemo.Lines[ Counter_1 ] )) <> 0 then
  1053.     begin
  1054.       FoundLine := Counter_1;
  1055.       Finished := true;
  1056.     end
  1057.     else Inc( Counter_1 );
  1058.     if Counter_1 > WhichMemo.Lines.Count then Finished := true;
  1059.   end;
  1060.   if FoundLine = -1 then exit;
  1061.   WhichMemo.Lines[ FoundLine ] := 'TO: ' + WhatName;
  1062. end;
  1063.  
  1064. procedure TPOP3SMTPComponent.SetCarbonCopy( WhichMemo : TMemo; WhatName : String );
  1065. var Finished : Boolean;
  1066.     Counter_1 ,
  1067.     FoundLine   : Integer;
  1068. begin
  1069.   Finished := false;
  1070.   Counter_1 := 0;
  1071.   FoundLine := -1;
  1072.   while not Finished do
  1073.   begin
  1074.     if Pos( 'CC:' , Uppercase( WhichMemo.Lines[ Counter_1 ] )) <> 0 then
  1075.     begin
  1076.       FoundLine := Counter_1;
  1077.       Finished := true;
  1078.     end
  1079.     else Inc( Counter_1 );
  1080.     if Counter_1 > WhichMemo.Lines.Count then Finished := true;
  1081.   end;
  1082.   if FoundLine = -1 then exit;
  1083.   WhichMemo.Lines[ FoundLine ] := 'CC: ' + WhatName;
  1084. end;
  1085.  
  1086. { This function calls an extended response POP3SMTP command routine }
  1087. function TPOP3SMTPComponent.PerformPOP3ExtendedCommand(
  1088.                TheCommand   : string;
  1089.          const TheArguments : array of const ) : Integer;
  1090. var TheBuffer : string; { Text buffer }
  1091. begin
  1092.   { If command in progress send back -1 error }
  1093.   if POP3CommandInProgress then
  1094.   begin
  1095.     Result := -1;
  1096.     exit;
  1097.   end;
  1098.   { Set status variable }
  1099.   POP3CommandInProgress := True;
  1100.   { Set global error code }
  1101.   GlobalErrorCode := 0;
  1102.   { Format output string }
  1103.   TheBuffer := Format( TheCommand , TheArguments );
  1104.   { Preset failure code }
  1105.   Result := TCPIP_STATUS_FATAL_ERROR;
  1106.   { If invalid socket or no connection abort }
  1107.   if ( Socket1.TheSocket = INVALID_SOCKET ) or not Connection_Established then
  1108.    exit;
  1109.   { Send the buffer plus EOL chars }
  1110.   Socket1.StringData := TheBuffer + #13#10;
  1111.   { if abort due to timeout or other error exit }
  1112.   if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  1113.   { Otherwise return preliminary code }
  1114.   Result := TCPIP_STATUS_PRELIMINARY;
  1115. end;
  1116.  
  1117. { This function calls an extended response POP3SMTP command routine }
  1118. function TPOP3SMTPComponent.PerformSMTPExtendedCommand(
  1119.                TheCommand   : string;
  1120.          const TheArguments : array of const ) : Integer;
  1121. var TheBuffer : string; { Text buffer }
  1122. begin
  1123.   { If command in progress send back -1 error }
  1124.   if SMTPCommandInProgress then
  1125.   begin
  1126.     Result := -1;
  1127.     exit;
  1128.   end;
  1129.   { Set status variable }
  1130.   SMTPCommandInProgress := True;
  1131.   { Set global error code }
  1132.   GlobalErrorCode := 0;
  1133.   { Format output string }
  1134.   TheBuffer := Format( TheCommand , TheArguments );
  1135.   { Preset failure code }
  1136.   Result := TCPIP_STATUS_FATAL_ERROR;
  1137.   { If invalid socket or no connection abort }
  1138.   if ( Socket1.TheSocket = INVALID_SOCKET ) or not Connection_Established then
  1139.    exit;
  1140.   { Send the buffer plus EOL chars }
  1141.   Socket1.StringData := TheBuffer + #13#10;
  1142.   { if abort due to timeout or other error exit }
  1143.   if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  1144.   { Otherwise return preliminary code }
  1145.   Result := TCPIP_STATUS_PRELIMINARY;
  1146. end;
  1147.  
  1148. { This function gets an extended period-ended multiline response from the server }
  1149. function TPOP3SMTPComponent.GetPOP3ServerExtendedResponse( ResponseString : PChar ) : integer;
  1150. var
  1151.   { Assume ResponseString already allocated as 0..513 }
  1152.   { Pointer to the response string }
  1153.   TheBuffer ,
  1154.   BufferPointer : array[0..255] of char;
  1155.   HolderBuffer : array[0..513] of char;
  1156.   { Character to check for response code }
  1157.   ResponseChar   : char;
  1158.   { Pointers into returned string }
  1159.   TheIndex ,
  1160.   TheLength     : integer;
  1161.   { Control variable }
  1162.   LeftoversInPan ,
  1163.   Finished      : Boolean;
  1164.   BufferString : String;
  1165. begin
  1166.   { Preset fatal error }
  1167.   Result := TCPIP_STATUS_FATAL_ERROR;
  1168.   { Start loop control }
  1169.   LeftoversInPan := false;
  1170.   Finished := false;
  1171.   StrCopy( HolderBuffer , '' );
  1172.   repeat
  1173.     { Do a peek }
  1174.     BufferString := Socket1.PeekData;
  1175.     { If timeout or other error exit }
  1176.     if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  1177.     { Find end of line character }
  1178.     TheIndex := Pos( #10 , BufferString );
  1179.     if TheIndex = 0 then
  1180.     begin
  1181.       TheIndex := Pos( #13 , BufferString );
  1182.       if TheIndex = 0 then
  1183.       begin
  1184.         TheIndex := Pos( #0 , BufferString );
  1185.         if TheIndex = 0 then
  1186.         begin
  1187.           TheIndex := Length( BufferString );
  1188.           LeftoversInPan := True;
  1189.           StrPCopy( TheBuffer , BufferString );
  1190.           StrCat( HolderBuffer , TheBuffer );
  1191.           LeftoversOnTable := false;
  1192.         end;
  1193.       end;
  1194.     end;
  1195.     { If an end of line then process the line }
  1196.     if TheIndex > 0 then
  1197.     begin
  1198.       { Get length of string }
  1199.       TheLength := TheIndex;
  1200.       { Receive actual data }
  1201.       Socket1.CCSockReceive( Socket1.TheSocket   ,
  1202.                              @BufferPointer[ 0 ] ,
  1203.                              TheLength              );
  1204.       { Abort if timeout or error }
  1205.       if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  1206.       { Put in the length byte }
  1207.       BufferPointer[ TheLength ] := Chr( 0 );
  1208.       if LeftOversOnTable then
  1209.       begin
  1210.         LeftOversOnTable := false;
  1211.         StrCopy( ResponseString , HolderBuffer );
  1212.         StrCat( ResponseString , BufferPointer );
  1213.       end
  1214.       else
  1215.       begin
  1216.         if not LeftoversInPan then StrCopy( ResponseString , BufferPointer );
  1217.       end;
  1218.       if LeftoversInPan then
  1219.       begin
  1220.         LeftoversInPan := false;
  1221.         LeftoversOnTable := true;
  1222.       end
  1223.       else
  1224.       begin
  1225.         ResponseChar := ResponseString[ 0 ];
  1226.         if (( ResponseChar = '.' ) and ( StrLen( ResponseString ) <= 3 )) then
  1227.         begin
  1228.           ResponseString[ 0 ] := ' ';
  1229.           Finished := true;
  1230.           Result := TCPIP_STATUS_COMPLETED;
  1231.         end
  1232.         else
  1233.         begin
  1234.           if ResponseChar = '.' then ResponseString[ 0 ] := ' ';
  1235.           Finished := true;
  1236.           Result := TCPIP_STATUS_PRELIMINARY;
  1237.         end;
  1238.       end;
  1239.     end;
  1240.   until ( Finished and ( not LeftoversOnTable ));
  1241.   StrLCopy( ResponseString , ResponseString , StrLen( ResponseString ) - 2 );
  1242. end;
  1243.  
  1244. { This function gets an extended period-ended multiline response from the server }
  1245. function TPOP3SMTPComponent.GetSMTPServerExtendedResponse( ResponseString : PChar ) : integer;
  1246. var
  1247.   { Assume ResponseString already allocated as 0..513 }
  1248.   { Pointer to the response string }
  1249.   TheBuffer ,
  1250.   BufferPointer : array[0..255] of char;
  1251.   HolderBuffer : array[0..513] of char;
  1252.   { Character to check for response code }
  1253.   ResponseChar   : char;
  1254.   { Pointers into returned string }
  1255.   TheIndex ,
  1256.   TheLength     : integer;
  1257.   { Control variable }
  1258.   LeftoversInPan ,
  1259.   Finished      : Boolean;
  1260.   BufferString : String;
  1261. begin
  1262.   { Preset fatal error }
  1263.   Result := TCPIP_STATUS_FATAL_ERROR;
  1264.   { Start loop control }
  1265.   LeftoversInPan := false;
  1266.   Finished := false;
  1267.   StrCopy( HolderBuffer , '' );
  1268.   repeat
  1269.     { Do a peek }
  1270.     BufferString := Socket1.PeekData;
  1271.     { If timeout or other error exit }
  1272.     if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  1273.     { Find end of line character }
  1274.     TheIndex := Pos( #10 , BufferString );
  1275.     if TheIndex = 0 then
  1276.     begin
  1277.       TheIndex := Pos( #13 , BufferString );
  1278.       if TheIndex = 0 then
  1279.       begin
  1280.         TheIndex := Pos( #0 , BufferString );
  1281.         if TheIndex = 0 then
  1282.         begin
  1283.           TheIndex := Length( BufferString );
  1284.           LeftoversInPan := True;
  1285.           StrPCopy( TheBuffer , BufferString );
  1286.           StrCat( HolderBuffer , TheBuffer );
  1287.           LeftoversOnTable := false;
  1288.         end;
  1289.       end;
  1290.     end;
  1291.     { If an end of line then process the line }
  1292.     if TheIndex > 0 then
  1293.     begin
  1294.       { Get length of string }
  1295.       TheLength := TheIndex;
  1296.       { Receive actual data }
  1297.       Socket1.CCSockReceive( Socket1.TheSocket   ,
  1298.                              @BufferPointer[ 0 ] ,
  1299.                              TheLength              );
  1300.       { Abort if timeout or error }
  1301.       if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  1302.       { Put in the length byte }
  1303.       BufferPointer[ TheLength ] := Chr( 0 );
  1304.       if LeftOversOnTable then
  1305.       begin
  1306.         LeftOversOnTable := false;
  1307.         StrCopy( ResponseString , HolderBuffer );
  1308.         StrCat( ResponseString , BufferPointer );
  1309.       end
  1310.       else
  1311.       begin
  1312.         if not LeftoversInPan then StrCopy( ResponseString , BufferPointer );
  1313.       end;
  1314.       if LeftoversInPan then
  1315.       begin
  1316.         LeftoversInPan := false;
  1317.         LeftoversOnTable := true;
  1318.       end
  1319.       else
  1320.       begin
  1321.         ResponseChar := ResponseString[ 0 ];
  1322.         if (( ResponseChar = '.' ) and ( StrLen( ResponseString ) <= 3 )) then
  1323.         begin
  1324.           ResponseString [ 0 ] := ' ';
  1325.           Finished := true;
  1326.           Result := TCPIP_STATUS_COMPLETED;
  1327.         end
  1328.         else
  1329.         begin
  1330.           if ResponseChar = '.' then ResponseString[ 0 ] := ' ';
  1331.           Finished := true;
  1332.           Result := TCPIP_STATUS_PRELIMINARY;
  1333.         end;
  1334.       end;
  1335.     end;
  1336.   until ( Finished and ( not LeftoversOnTable ));
  1337.   StrLCopy( ResponseString , ResponseString , StrLen( ResponseString ) - 2 );
  1338. end;
  1339.  
  1340. { This function moves along a string from an index, getting the next }
  1341. { string delimited item or last one on string.                       }
  1342. function TPOP3SMTPComponent.GetNextSDItem(     WorkingString : String;
  1343.                                        var TheIndex      : Integer ) : String;
  1344. var HoldingString : String;
  1345. begin
  1346.   HoldingString := Copy( WorkingString , TheIndex + 1 , 255 );
  1347.   TheIndex := Pos( ' ' , HoldingString );
  1348.   if TheIndex = 0 then
  1349.   begin
  1350.     Result := HoldingString;
  1351.   end
  1352.   else
  1353.   begin
  1354.     HoldingString := Copy( HoldingString , 1 , TheIndex - 1 );
  1355.     Result := HoldingString;
  1356.   end;
  1357. end;
  1358.  
  1359. { This function Inserts a MIME header into a memo for EMail usage }
  1360. procedure TPOP3SMTPComponent.InsertMIMETextHeader( TheMemo : TMemo );
  1361. var Counter_1 : Integer;
  1362.     Finished  : Boolean;
  1363. begin
  1364.   Counter_1 := 0;
  1365.   Finished := false;
  1366.   while not Finished do
  1367.   begin
  1368.     if TheMemo.Lines[ Counter_1 ] = '' then
  1369.     begin
  1370.       Finished := true;
  1371.     end
  1372.     else
  1373.     begin
  1374.       Inc( Counter_1 );
  1375.       if Counter_1 = TheMemo.Lines.Count then exit;
  1376.     end;
  1377.   end;
  1378.   TheMemo.Lines.Insert( Counter_1 - 1 , 'Mime-Version: 1.0' );
  1379.   TheMemo.Lines.Insert( Counter_1 , 'Content-Type: multipart/mixed; boundary="' +
  1380.    TheMIMEObject.TheBoundaryString + '"' );
  1381.   TheMemo.Lines.Insert( Counter_1 + 1 , '' );
  1382.   TheMemo.Lines.Insert( Counter_1 + 2 , '--' + TheMIMEObject.TheBoundaryString );
  1383.   TheMemo.Lines.Insert( Counter_1 + 3 , 'Content-Type: text/plain; charset="us-ascii"' );
  1384. end;
  1385.  
  1386. { this method adds a MIME file as an attachment to a message }
  1387. procedure TPOP3SMTPComponent.AddMIMEAttachment( TheMemo : TMemo;
  1388.  TheFileToAdd : String );
  1389. var TempMemo  : TMemo;
  1390.     Counter_1 : Integer;
  1391. begin
  1392.   InsertMIMETextHeader( TheMemo );
  1393.   TempMemo := TMemo.Create( self );
  1394.   TempMemo.parent := self;
  1395.   Tempmemo.Visible := false;
  1396.   TempMemo.Width := TheMemo.Width;
  1397.   TempMemo.Height := TheMemo.Height;
  1398.   TempMemo.Lines.LoadFromFile( TheFileToAdd );
  1399.   TheMemo.Lines.Add( '' );
  1400.   for Counter_1 := 0 to TempMemo.Lines.Count - 1 do
  1401.    TheMemo.Lines.Add( TempMemo.Lines[ Counter_1 ] );
  1402.   TempMemo.Free;
  1403.   TheMemo.Lines.Add( '--' + TheMIMEObject.TheBoundarystring );
  1404. end;
  1405.  
  1406. { This method creates a new message with a MIME attachment  }
  1407. procedure TPOP3SMTPComponent.NewMIMEMessage( TheMemo : TMemo;
  1408.  TheNewFile : String; TheEMCRecord : PConnectionsRecord  );
  1409. begin
  1410.   SetMailHeaders( TheMemo , TheEMCRecord );
  1411.   AddMimeAttachment( TheMemo , TheNewFile );
  1412. end;
  1413.  
  1414. { This method puts all the headers into the memo, getting the group name from gn }
  1415. procedure TPOP3SMTPComponent.SetMailHeaders( TheMemo      : TMemo;
  1416.                                             TheEMCRecord : PConnectionsRecord );
  1417. var DateString , TimeString : String;
  1418.     DateData , TimeData : Word;
  1419.     D1,D2,D3,D4 : Word;
  1420. begin
  1421.   DecodeTime( Time , D1 , D2 , D3 , D4 );
  1422.   TimeData := D1 + D2 + D3 + D4;
  1423.   DecodeDate( Date , D1 , D2 , D3 );
  1424.   DateData := D1 + D2 + D3;
  1425.   with TheEMCRecord^ do
  1426.   begin
  1427.     TheMemo.Clear;
  1428.     TheMemo.Lines.Add( 'To:');
  1429.     TheMemo.Lines.Add( 'From: ' + CStartDir );
  1430.     TheMemo.Lines.Add( 'CC:' );
  1431.     TheMemo.Lines.Add( 'BCC:' );
  1432.     TheMemo.Lines.Add( 'Subject:');
  1433.     TheMemo.Lines.Add( 'Message-ID: <' + IntToStr( DateData ) + IntToStr( TimeData ) +
  1434.      '@' + CIPAddress + '>' );
  1435.     TheMemo.Lines.Add( 'X-Mailer: CC Internet Command Center' );
  1436.     DateString := FormatDateTime( '"Date: "  ddd ' + '" " dd mmm yy', Date );
  1437.     TimeString := FormatDateTime( '" " hh:nn:ss' ,Time );
  1438.     TheMemo.Lines.Add( DateString  + TimeString + ' MDT' );
  1439.     TheMemo.Lines.Add( '' );
  1440.   end;
  1441. end;
  1442.  
  1443. { This function adds the text of an article to the current memo with > }
  1444. procedure TPOP3SMTPComponent.SetReplyMailHeaders(
  1445.           TheMemo         : TMemo ;
  1446.           TheEMCRecord    : PConnectionsRecord;
  1447.           TheEMBRecord    : PEmailMailBoxRecord;
  1448.           MessageNumber   : Integer );
  1449. var WorkingList     : TList;
  1450.     TheEMMRecord    : PEmailMessageRecord;
  1451.     Counter_1       : Integer;
  1452.     WorkingFileName : String;
  1453.     DateString ,
  1454.     TimeString      : String;
  1455.     DateData , TimeData : Word;
  1456.     D1,D2,D3,D4 : Word;
  1457. begin
  1458.   DecodeTime( Time , D1 , D2 , D3 , D4 );
  1459.   TimeData := D1 + D2 + D3 + D4;
  1460.   DecodeDate( Date , D1 , D2 , D3 );
  1461.   DateData := D1 + D2 + D3;
  1462.   WorkingList := TList( TheEMBRecord^.MBLTag );
  1463.   TheEMMRecord := PEmailMessageRecord( WorkingList.Items[ MessageNumber ] );
  1464.   WorkingFileName := TheEMMRecord^.MRFileName;
  1465.   WorkingFileName := MailPath + '\' + WorkingFileName;
  1466.   try
  1467.     TheMemo.Lines.LoadFromFile( WorkingFileName );
  1468.   except
  1469.     MessageDlg('Message File Too Big for Memo!',mtError,[mbOK],0);
  1470.   end;
  1471.   for Counter_1 := 0 to TheMemo.Lines.Count - 1 do
  1472.    TheMemo.Lines[ Counter_1 ] := '>' + TheMemo.Lines[ Counter_1 ];
  1473.   TheMemo.Lines.Insert( 0 , 'To:' + TheEMMRecord^.MRMessageSender );
  1474.   TheMemo.Lines.Insert( 1 , 'From:' + TheEMCRecord^.CStartDir );
  1475.   TheMemo.Lines.Insert( 2 , 'CC:' );
  1476.   TheMemo.Lines.Insert( 3 , 'BCC:' );
  1477.   TheMemo.Lines.Insert( 4 , 'Subject: Re: ' + TheEMMRecord^.MRMessageSubject );
  1478.   TheMemo.Lines.Insert( 5 , 'Message-ID: <' + IntToStr( DateData ) + IntToStr( TimeData ) +
  1479.    '@' + TheEMCRecord^.CIPAddress + '>' );
  1480.   TheMemo.Lines.Insert( 6 , 'X-Mailer: CC Internet Command Center' );
  1481.   DateString := FormatDateTime( '"Date: " ddd ' + '" "  dd mmm yy ', Date );
  1482.   TimeString := FormatDateTime( '" " hh:nn:ss' ,Time );
  1483.   TheMemo.Lines.Insert( 7 , DateString  + TimeString + ' MDT' );
  1484.   TheMemo.Lines.Insert( 8 , '' );
  1485. end;
  1486.  
  1487. { This method assumes logged into server; gets data via STAT command }
  1488. { returns total bytes in var'd param and total messages as result    }
  1489. function TPOP3SMTPComponent.CheckAllNewMail( var TotalBytes : Longint ) : Integer;
  1490. var TheReturnString : String;  { Internal string holder }
  1491.     TheResult       : Integer; { Internal int holder    }
  1492.     TheLResult      : Longint;
  1493. begin
  1494.   TheReturnString :=
  1495.    DoCStyleFormat( 'STAT' , [ nil ] );
  1496.   { Put result in progress and status line }
  1497.   AddProgressText( TheReturnString );
  1498.   ShowProgressText( TheReturnString );
  1499.   { Begin login sequence with user name }
  1500.   TheResult := PerformPOP3Command( 'STAT', [ nil ] );
  1501.   if TheResult <> TCPIP_STATUS_PRELIMINARY then
  1502.   begin
  1503.     POP3CommandInProgress := false;
  1504.     Result := -1;
  1505.     exit;
  1506.   end;
  1507.   repeat
  1508.     TheResult := GetPOP3ServerResponse( TheReturnString );
  1509.     { Put result in progress and status line }
  1510.     AddProgressText( TheReturnString );
  1511.     ShowProgressText( TheReturnString + #13#10 );
  1512.   until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  1513.   POP3CommandInProgress := false;
  1514.   if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  1515.   begin
  1516.     { Do clever C formatting trick }
  1517.     TheReturnString :=
  1518.      DoCStyleFormat( 'Mail Not Available!' , [ nil ] );
  1519.     { Put result in progress and status line }
  1520.     AddProgressText( TheReturnString );
  1521.     ShowProgressErrorText( TheReturnString );
  1522.     { Signal error }
  1523.     Result := -1;
  1524.     { leave }
  1525.     exit;
  1526.   end;
  1527.   ParseMailListing( TheReturnString , TheLResult , TotalBytes );
  1528.   Result := TheLResult;
  1529. end;
  1530.  
  1531. function TPOP3SMTPComponent.DeleteMailItem( TheNumber : Longint ) : Boolean;
  1532. var TheReturnString : String;  { Internal string holder }
  1533.     TheResult       : Integer; { Internal int holder    }
  1534. begin
  1535.   TheReturnString :=
  1536.    DoCStyleFormat( 'DELE %d' , [ TheNumber ] );
  1537.   { Put result in progress and status line }
  1538.   AddProgressText( TheReturnString );
  1539.   ShowProgressText( TheReturnString );
  1540.   { Begin login sequence with user name }
  1541.   TheResult := PerformPOP3Command( 'DELE %d', [ TheNumber ] );
  1542.   if TheResult <> TCPIP_STATUS_PRELIMINARY then
  1543.   begin
  1544.     POP3CommandInProgress := false;
  1545.     Result := false;
  1546.     exit;
  1547.   end;
  1548.   repeat
  1549.     TheResult := GetPOP3ServerResponse( TheReturnString );
  1550.     { Put result in progress and status line }
  1551.     AddProgressText( TheReturnString );
  1552.     ShowProgressText( TheReturnString + #13#10 );
  1553.   until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  1554.   POP3CommandInProgress := false;
  1555.   if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  1556.   begin
  1557.     { Do clever C formatting trick }
  1558.     TheReturnString :=
  1559.      DoCStyleFormat( 'Mail Not Available!' , [ nil ] );
  1560.     { Put result in progress and status line }
  1561.     AddProgressText( TheReturnString );
  1562.     ShowProgressErrorText( TheReturnString );
  1563.     { Signal error }
  1564.     Result := false;
  1565.     { leave }
  1566.     exit;
  1567.   end;
  1568.   Result := True;
  1569. end;
  1570.  
  1571. { This method splits up a listing and pulls out its component data }
  1572. procedure TPOP3SMTPComponent.ParseMailListing(     TheListing : String;
  1573.                                                var TotalMessages : Longint;
  1574.                                                var MessageBytes : Longint);
  1575. var HoldingString ,
  1576.     HoldingString2 : String;
  1577.     WorkingIndex  : Integer;
  1578. begin
  1579.   WorkingIndex := Pos( ' ' , TheListing );
  1580.   HoldingString := Copy( TheListing , WorkingIndex + 1 , 255 );
  1581.   WorkingIndex := Pos(  ' ' , HoldingString );
  1582.   HoldingString2 := Copy( HoldingString , 1 , WorkingIndex - 1 );
  1583.   TotalMessages := StrToInt( HoldingString2 );
  1584.   HoldingString := Copy( HoldingString , WorkingIndex + 1 , 255 );
  1585.   WorkingIndex := Pos(  ' ' , HoldingString );
  1586.   if WorkingIndex = 0 then WorkingIndex := 256;
  1587.   HoldingString2 := Copy( HoldingString , 1 , WorkingIndex - 1 );
  1588.   MessageBytes := StrToInt( HoldingString2 );
  1589. end;
  1590.  
  1591. { This method accumulates all the strings until '' as a messge header }
  1592. function TPOP3SMTPComponent.GetMessageHeader( TheReturnList : TStringList ) : Longint;
  1593. var TheReturnString : String;  { Internal string holder }
  1594.     TheResult       : Integer; { Internal int holder    }
  1595.     TheReturnPChar ,
  1596.     TheHoldingPChar : PChar;
  1597.     TotalGotten : Longint;
  1598. begin
  1599.   GetMem( TheReturnPChar , 514 );
  1600.   TheReturnList.Clear;
  1601.   TotalGotten := 0;
  1602.   repeat
  1603.     TheResult := GetPOP3ServerExtendedResponse( TheReturnPChar );
  1604.     if StrLen( TheReturnPChar ) < 3 then
  1605.     begin
  1606.      TheResult := TCPIP_STATUS_COMPLETED;
  1607.     end;
  1608.     TotalGotten := TotalGotten + StrLen( TheReturnPChar ) + 2;
  1609.     if StrLen( TheReturnPChar ) > 255 then
  1610.     begin
  1611.       Getmem( TheHoldingPChar , 255 );
  1612.       while StrLen( TheReturnPChar ) > 255 do
  1613.       begin
  1614.         StrCopy( TheHoldingPChar , '' );
  1615.         StrMove( TheHoldingPChar , TheReturnPChar , 255 );
  1616.         TheReturnPChar := TheReturnPChar + 256;
  1617.         TheReturnString := StrPas( TheHoldingPChar );
  1618.         TheReturnList.Add( TheReturnString );
  1619.       end;
  1620.       StrCopy( TheHoldingPChar , '' );
  1621.       StrMove( TheHoldingPChar , TheReturnPChar , StrLen( TheReturnPChar ));
  1622.       TheReturnString := StrPas( TheHoldingPChar );
  1623.       TheReturnString := '\' + TheReturnString;
  1624.       TheReturnList.Add( TheReturnString );
  1625.       FreeMem( TheHoldingPChar , 255 );
  1626.     end
  1627.     else
  1628.     begin
  1629.       TheReturnString := StrPas( TheReturnPChar );
  1630.       TheReturnList.Add( TheReturnString );
  1631.     end;
  1632.   until (( GlobalAbortedFlag ) or ( TheResult = TCPIP_STATUS_COMPLETED ));
  1633.   FreeMem( TheReturnPChar , 514 );
  1634.   Result := TotalGotten;
  1635. end;
  1636.  
  1637. { This method parses a header stringlist and obtains the subject line }
  1638. function TPOP3SMTPComponent.GetHeaderSubject( HList : TStringList ) : String;
  1639. var Counter_1     : Integer;
  1640.     Finished      : Boolean;
  1641.     WorkingIndex  : Integer;
  1642.     WorkingString : String;
  1643. begin
  1644.   Counter_1 := 0;
  1645.   Finished := false;
  1646.   WorkingString := '[No Subject]';
  1647.   while (( not Finished ) and ( Counter_1 <= HList.Count - 1 )) do
  1648.   begin
  1649.     WorkingIndex := Pos( 'SUBJECT:' , Uppercase( HList.Strings[ Counter_1 ] ));
  1650.     if WorkingIndex > 0 then
  1651.     begin
  1652.       WorkingString := Copy( HList.Strings[ Counter_1 ] , 9 , 255 );
  1653.       Finished := true;
  1654.     end
  1655.     else Inc( Counter_1 );
  1656.   end;
  1657.   Result := WorkingString;
  1658. end;
  1659.  
  1660. { This method parses a header stringlist and obtains the sender's ID }
  1661. function TPOP3SMTPComponent.GetHeaderSender( HList : TStringList ) : String;
  1662. var Counter_1     : Integer;
  1663.     Finished      : Boolean;
  1664.     WorkingIndex  : Integer;
  1665.     WorkingString : String;
  1666. begin
  1667.   Counter_1 := 0;
  1668.   Finished := false;
  1669.   WorkingString := '';
  1670.   while (( not Finished ) and ( Counter_1 <= HList.Count - 1 )) do
  1671.   begin
  1672.     WorkingIndex := Pos( 'FROM:' , Uppercase( HList.Strings[ Counter_1 ] ));
  1673.     if WorkingIndex > 0 then
  1674.     begin
  1675.       WorkingString := Copy( HList.Strings[ Counter_1 ] , 7 , 255 );
  1676.       Finished := true;
  1677.     end
  1678.     else Inc( Counter_1 );
  1679.   end;
  1680.   Result := WorkingString;
  1681. end;
  1682.  
  1683. { This method strips out the TO: field of a mail message header }
  1684. function TPOP3SMTPComponent.GetHeaderRecipient( HList : TStringList ) : String;
  1685. var Counter_1     : Integer;
  1686.     Finished      : Boolean;
  1687.     WorkingIndex  : Integer;
  1688.     WorkingString : String;
  1689. begin
  1690.   Counter_1 := 0;
  1691.   Finished := false;
  1692.   WorkingString := '';
  1693.   while (( not Finished ) and ( Counter_1 <= HList.Count - 1 )) do
  1694.   begin
  1695.     WorkingIndex := Pos( 'TO:' , Uppercase( HList.Strings[ Counter_1 ] ));
  1696.     if WorkingIndex > 0 then
  1697.     begin
  1698.       WorkingString := Copy( HList.Strings[ Counter_1 ] , 5 , 255 );
  1699.       Finished := true;
  1700.     end
  1701.     else Inc( Counter_1 );
  1702.   end;
  1703.   Result := WorkingString;
  1704. end;
  1705.  
  1706. { This method strips out the TO: field of a mail message header }
  1707. function TPOP3SMTPComponent.GetRCPTHeaderRecipient( HList : TStringList ) : String;
  1708. var Counter_1     : Integer;
  1709.     Finished      : Boolean;
  1710.     WorkingIndex  : Integer;
  1711.     WorkingString : String;
  1712. begin
  1713.   Counter_1 := 0;
  1714.   Finished := false;
  1715.   WorkingString := '';
  1716.   while (( not Finished ) and ( Counter_1 <= HList.Count - 1 )) do
  1717.   begin
  1718.     WorkingIndex := Pos( 'TO:' , Uppercase( HList.Strings[ Counter_1 ] ));
  1719.     if WorkingIndex > 0 then
  1720.     begin
  1721.       WorkingString := 'TO:<' + Copy( HList.Strings[ Counter_1 ] , 5 , 255 ) + '>';
  1722.       Finished := true;
  1723.     end
  1724.     else Inc( Counter_1 );
  1725.   end;
  1726.   Result := WorkingString;
  1727. end;
  1728.  
  1729. { This method strips out the CC: field of a mail message header }
  1730. function TPOP3SMTPComponent.GetHeaderCarbons( HList : TStringList ) : String;
  1731. var Counter_1     : Integer;
  1732.     Finished      : Boolean;
  1733.     WorkingIndex  : Integer;
  1734.     WorkingString : String;
  1735. begin
  1736.   Counter_1 := 0;
  1737.   Finished := false;
  1738.   WorkingString := '';
  1739.   while (( not Finished ) and ( Counter_1 <= HList.Count - 1 )) do
  1740.   begin
  1741.     WorkingIndex := Pos( 'CC:' , Uppercase( HList.Strings[ Counter_1 ] ));
  1742.     if WorkingIndex > 0 then
  1743.     begin
  1744.       WorkingString := Copy( HList.Strings[ Counter_1 ] , 5 , 255 );
  1745.       Finished := true;
  1746.     end
  1747.     else Inc( Counter_1 );
  1748.   end;
  1749.   Result := WorkingString;
  1750. end;
  1751.  
  1752. { This method strips out the CC: field of a mail message header }
  1753. function TPOP3SMTPComponent.GetRCPTHeaderCarbons( HList : TStringList ) : String;
  1754. var Counter_1     : Integer;
  1755.     Finished      : Boolean;
  1756.     WorkingIndex  : Integer;
  1757.     WorkingString : String;
  1758. begin
  1759.   Counter_1 := 0;
  1760.   Finished := false;
  1761.   WorkingString := '';
  1762.   while (( not Finished ) and ( Counter_1 <= HList.Count - 1 )) do
  1763.   begin
  1764.     WorkingIndex := Pos( 'CC:' , Uppercase( HList.Strings[ Counter_1 ] ));
  1765.     if WorkingIndex > 0 then
  1766.     begin
  1767.       WorkingString := 'CC:<' + Copy( HList.Strings[ Counter_1 ] , 5 , 255 ) + '>';
  1768.       Finished := true;
  1769.     end
  1770.     else Inc( Counter_1 );
  1771.   end;
  1772.   Result := WorkingString;
  1773. end;
  1774.  
  1775. { This method strips out the BCC: field of a mail message header }
  1776. function TPOP3SMTPComponent.GetHeaderBlindCarbons( HList : TStringList ) : String;
  1777. var Counter_1     : Integer;
  1778.     Finished      : Boolean;
  1779.     WorkingIndex  : Integer;
  1780.     WorkingString : String;
  1781. begin
  1782.   Counter_1 := 0;
  1783.   Finished := false;
  1784.   WorkingString := '';
  1785.   while (( not Finished ) and ( Counter_1 <= HList.Count - 1 )) do
  1786.   begin
  1787.     WorkingIndex := Pos( 'BCC:' , Uppercase( HList.Strings[ Counter_1 ] ));
  1788.     if WorkingIndex > 0 then
  1789.     begin
  1790.       WorkingString := Copy( HList.Strings[ Counter_1 ] , 6 , 255 );
  1791.       Finished := true;
  1792.     end
  1793.     else Inc( Counter_1 );
  1794.   end;
  1795.   Result := WorkingString;
  1796. end;
  1797.  
  1798. { This method strips out the BCC: field of a mail message header }
  1799. function TPOP3SMTPComponent.GetRCPTHeaderBlindCarbons( HList : TStringList ) : String;
  1800. var Counter_1     : Integer;
  1801.     Finished      : Boolean;
  1802.     WorkingIndex  : Integer;
  1803.     WorkingString : String;
  1804. begin
  1805.   Counter_1 := 0;
  1806.   Finished := false;
  1807.   WorkingString := '';
  1808.   while (( not Finished ) and ( Counter_1 <= HList.Count - 1 )) do
  1809.   begin
  1810.     WorkingIndex := Pos( 'BCC:' , Uppercase( HList.Strings[ Counter_1 ] ));
  1811.     if WorkingIndex > 0 then
  1812.     begin
  1813.       WorkingString := 'BCC:<' + Copy( HList.Strings[ Counter_1 ] , 6 , 255 ) + '>';
  1814.       Finished := true;
  1815.     end
  1816.     else Inc( Counter_1 );
  1817.   end;
  1818.   Result := WorkingString;
  1819. end;
  1820.  
  1821. { This method strips out the DATE: field of a mail message header }
  1822. function TPOP3SMTPComponent.GetHeaderDateTime( HList : TStringList ) : String;
  1823. var Counter_1     : Integer;
  1824.     Finished      : Boolean;
  1825.     WorkingIndex  : Integer;
  1826.     WorkingString : String;
  1827. begin
  1828.   Counter_1 := 0;
  1829.   Finished := false;
  1830.   WorkingString := '';
  1831.   while (( not Finished ) and ( Counter_1 <= HList.Count - 1 )) do
  1832.   begin
  1833.     WorkingIndex := Pos( 'DATE:' , Uppercase( HList.Strings[ Counter_1 ] ));
  1834.     if WorkingIndex > 0 then
  1835.     begin
  1836.       WorkingString := Copy( HList.Strings[ Counter_1 ] , 7 , 255 );
  1837.       Finished := true;
  1838.     end
  1839.     else Inc( Counter_1 );
  1840.   end;
  1841.   Result := WorkingString;
  1842. end;
  1843.  
  1844. { This method transfers a message from one mailbox to another }
  1845. procedure TPOP3SMTPComponent.TransferMessage( SourceEMBRecord ,
  1846.                                               TargetEMBRecord : PEMailMailBoxRecord;
  1847.                                               MessageNumber : Integer );
  1848. var  WorkingList1 , WorkingList2 : TList;
  1849.      TheEMMRecord : PEMailMessageRecord;
  1850. begin
  1851.   WorkingList1 := TList( SourceEMBRecord^.MBLTag );
  1852.   WorkingList2 := TList( TargetEMBRecord^.MBLTag );
  1853.   TheEMMRecord := PEMailMessageRecord( WorkingList1.Items[ MessageNumber ] );
  1854.   WorkingList2.Add( TheEMMRecord );
  1855.   SourceEMBRecord^.MBLTag := Longint( WorkingList1 );
  1856.   TargetEMBRecord^.MBLTag := Longint( WorkingList2 );
  1857. end;
  1858.  
  1859. { This function deletes all read/sent articles and associated files }
  1860. procedure TPOP3SMTPComponent.PurgeTrashedMessageListings( TheEMBRecord : PEMailMailBoxRecord );
  1861. var TheEMMRecord   : PEMailMessageRecord;
  1862.     Counter_1      : Integer;
  1863.     WorkingList    : TList;
  1864.     Finished       : Boolean;
  1865. begin
  1866.   { Do this for ease of coding }
  1867.   with TheEMBRecord^ do
  1868.   begin
  1869.     { Get the current TList of article headers }
  1870.     WorkingList := TList( MBLTag );
  1871.     { Run up to total new articles }
  1872.     for Counter_1 := 0 to WorkingList.Count - 1 do
  1873.     begin
  1874.       TheEMMRecord := PEMailMessageRecord( WorkingList.Items[ Counter_1 ] );
  1875.       if ( TheEMMRecord^.MRMessageSender = 'DELETE ME' ) then
  1876.       begin
  1877.         Dec( MBTotal );
  1878.         if not TheEMMRecord^.MRRead then if MBUnReadTotal > 0 then Dec( MBUnReadTotal );
  1879.         if not TheEMMRecord^.MRSent then if MBUnSentTotal > 0 then Dec( MBUnSentTotal );
  1880.         if FileExists( MailPath + '\' + TheEMMRecord^.MRFilename ) then
  1881.          {DeleteFile( MailPath + '\' + TheEMMRecord^.MRFileName )};
  1882.       end;
  1883.     end;
  1884.     Counter_1 := 0;
  1885.     Finished := False;
  1886.     if WorkingList.Count = 0 then Finished := true;
  1887.     while Not Finished do
  1888.     begin
  1889.       TheEMMRecord := PEMailMessageRecord( WorkingList.Items[ Counter_1 ] );
  1890.       if ( TheEMMRecord^.MRMessageSender = 'DELETE ME' ) then
  1891.       begin
  1892.         WorkingList.Delete( Counter_1 );
  1893.       end
  1894.       else Counter_1 := Counter_1 + 1;
  1895.       if Counter_1 > WorkingList.Count - 1 then Finished := true;
  1896.     end;
  1897.   end;
  1898. end;
  1899.  
  1900. { This method uses the ARTICLE command to obtain an article and put it in a  }
  1901. { preset/supplied file. It is designed to work by itself or inside DAALs     }
  1902. function TPOP3SMTPComponent.DownloadMessageListing( TheNumber   : Integer;
  1903.                                                     TheFileName : String;
  1904.                                                     TheHeaderSL : TStringList   ) : Longint;
  1905. var TheReturnString : String;  { Internal string holder }
  1906.     TheResult       : Integer; { Internal int holder    }
  1907.     TheReturnPChar ,
  1908.     TheHoldingPChar : PChar;
  1909.     TheMessageFile       : TextFile;
  1910.     Counter_1   : Integer;
  1911.     TotalGotten : Longint;
  1912. begin
  1913.   TheReturnString :=
  1914.    DoCStyleFormat( 'RETR %d' ,
  1915.     [ TheNumber ] );
  1916.   { Put result in progress and status line }
  1917.   AddProgressText( TheReturnString );
  1918.   ShowProgressText( TheReturnString );
  1919.   { Begin login sequence with user name }
  1920.   TheResult := PerformPOP3Command( 'RETR %d', [ TheNumber ] );
  1921.   if TheResult <> TCPIP_STATUS_PRELIMINARY then
  1922.   begin
  1923.     POP3CommandInProgress := false;
  1924.     Result := 0;
  1925.     exit;
  1926.   end;
  1927.   repeat
  1928.     TheResult := GetPOP3ServerResponse( TheReturnString );
  1929.     { Put result in progress and status line }
  1930.     AddProgressText( TheReturnString );
  1931.     ShowProgressText( TheReturnString + #13#10 );
  1932.   until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  1933.   POP3CommandInProgress := false;
  1934.   if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  1935.   begin
  1936.     { Do clever C formatting trick }
  1937.     TheReturnString :=
  1938.      DoCStyleFormat( 'Retrieve Message %d Failed!' ,
  1939.       [ TheNumber ] );
  1940.     { Put result in progress and status line }
  1941.     AddProgressText( TheReturnString );
  1942.     ShowProgressErrorText( TheReturnString );
  1943.     { Signal error }
  1944.     Result := 0;
  1945.     { leave }
  1946.     exit;
  1947.   end;
  1948.   GetMem( TheReturnPChar , 514 );
  1949.   try
  1950.     AssignFile( TheMessageFile , TheFileName );
  1951.     Rewrite( TheMessageFile );
  1952.   except
  1953.     MessageDlg( 'Unable to open Mail Message file ' + TheFileName + '!' ,
  1954.      mtError , [mbok],0 );
  1955.     Socket1.OutOfBand := 'ABOR'+#13#10;
  1956.     repeat
  1957.       TheResult := GetPOP3ServerResponse( TheReturnString );
  1958.       { Put result in progress and status line }
  1959.       AddProgressText( TheReturnString );
  1960.       ShowProgressText( TheReturnString  + #13#10 );
  1961.     until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  1962.     result := 0;
  1963.     exit;
  1964.   end;
  1965.   TotalGotten := GetMessageHeader( TheHeaderSL );
  1966.   for Counter_1 := 0 to TheHeaderSL.Count - 1 do
  1967.    Writeln( TheMessageFile , TheHeaderSL.Strings[ Counter_1 ] );
  1968.   repeat
  1969.     TheResult := GetPOP3ServerExtendedResponse( TheReturnPChar );
  1970.     TotalGotten := TotalGotten + StrLen( TheReturnPChar ) + 2;
  1971.     if StrLen( TheReturnPChar ) > 255 then
  1972.     begin
  1973.       Getmem( TheHoldingPChar , 255 );
  1974.       while StrLen( TheReturnPChar ) > 255 do
  1975.       begin
  1976.         StrCopy( TheHoldingPChar , '' );
  1977.         StrMove( TheHoldingPChar , TheReturnPChar , 255 );
  1978.         TheReturnPChar := TheReturnPChar + 256;
  1979.         TheReturnString := StrPas( TheHoldingPChar );
  1980.         Writeln( TheMessageFile , TheReturnString );
  1981.       end;
  1982.       StrCopy( TheHoldingPChar , '' );
  1983.       StrMove( TheHoldingPChar , TheReturnPChar , StrLen( TheReturnPChar ));
  1984.       TheReturnString := StrPas( TheHoldingPChar );
  1985.       TheReturnString := '\' + TheReturnString;
  1986.       Writeln( TheMessageFile , TheReturnString );
  1987.       FreeMem( TheHoldingPChar , 255 );
  1988.     end
  1989.     else
  1990.     begin
  1991.       TheReturnString := StrPas( TheReturnPChar );
  1992.       Writeln( TheMessageFile , TheReturnString );
  1993.     end;
  1994.   until (( GlobalAbortedFlag ) or ( TheResult = TCPIP_STATUS_COMPLETED ));
  1995.   FreeMem( TheReturnPChar , 514 );
  1996.   CloseFile( TheMessageFile );
  1997.   Result := TotalGotten;
  1998. end;
  1999.  
  2000. { This method Gets all the Article Listings for a newsgroup which have not been  }
  2001. { Downloaded and gets them into text files. It displays Article count, # & bytes }
  2002. { in the status line during the process.                                         }
  2003. function TPOP3SMTPComponent.DownloadAllMessageListings(
  2004.   TheEMBRecord : PEMailMailBoxRecord ) : Boolean;
  2005. var WorkingList   : TList;
  2006.     TheEMMRecord  : PEMailMessageRecord;
  2007.     Counter_1 : Integer;
  2008.     WorkingID ,
  2009.     WorkingNumber : Integer;
  2010.     WorkingFileName : String;
  2011.     BytesToGet : Longint;
  2012.     TotalMessages : Integer;
  2013.     WorkingSL : TStringList;
  2014.     BytesGotten : Longint;
  2015. begin
  2016.   Result := true;
  2017.   TotalMessages := CheckAllNewMail( BytesToGet );
  2018.   if TotalMessages < 0 then exit;
  2019.   if TotalMessages = 0 then
  2020.   begin
  2021.     MessageDlg( 'No New Mail!' , mtInformation, [mbOK],0);
  2022.     exit;
  2023.   end;
  2024.   with TheEMBRecord^ do
  2025.   begin
  2026.     WorkingID := MBIDNumber;
  2027.     WorkingNumber := MBMaxMsgNumber;
  2028.     WorkingList := TList( MBLTag );
  2029.     WorkingSL := TStringList.Create;
  2030.     for Counter_1 := 1 to TotalMessages do
  2031.     begin
  2032.       New( TheEMMRecord );
  2033.       WorkingNumber := WorkingNumber + 1;
  2034.       with TheEMMRecord^ do
  2035.       begin
  2036.         WorkingFileName := 'EM' + IntToStr( WorkingNumber );
  2037.         if Length( WorkingFileName ) > 8 then WorkingFileName :=
  2038.          Copy( WorkingFileName , 1 , 8 );
  2039.         WorkingFileName := WorkingFileName + '.' +
  2040.          IntToStr( WorkingID );
  2041.         MRFileName := WorkingFileName;
  2042.         WorkingFileName := MailPath + '\' + WorkingFileName;
  2043.         BytesGotten := DownloadMessageListing( Counter_1 , WorkingFileName , WorkingSL );
  2044.         if EMRemoteDeletionVector = 2 then DeleteMailItem( Counter_1 );
  2045.         UpdateGauge( BytesGotten , BytesToGet );
  2046.         MRMailBoxName      := MBName;
  2047.         MRMessageSubject   := GetHeaderSubject( WorkingSL );
  2048.         MRMessageRecipient := GetHeaderRecipient( WorkingSL );
  2049.         MRMessageSender    := GetHeaderSender( WorkingSL );
  2050.         MRCarbonCopy       := GetHeaderCarbons( WorkingSL );
  2051.         MRBlindCarbonCopy  := GetHeaderBlindCarbons( WorkingSL );
  2052.         MRDateTime         := GetHeaderDateTime( WorkingSL );
  2053.         MRRead             := false;
  2054.         MRSent             := false;
  2055.         MRFileName         := ExtractFileName( WorkingFileName );
  2056.         WorkingList.Add( TheEMMRecord );
  2057.       end;
  2058.     end;
  2059.     UpdateGauge( BytesToGet , BytesToGet );
  2060.     MBLTag := Longint( WorkingList );
  2061.     MBMaxMsgNumber := WorkingNumber;
  2062.     MBTotal       := MBTotal + TotalMessages;
  2063.     MBUnReadTotal := MBUnReadTotal + TotalMessages;
  2064.     Result := true;
  2065.   end;
  2066. end;
  2067.  
  2068. { This method sends a message via RCPT and DATA commands (assumes HELO and }
  2069. { and MAIL already sent via EstablishSMTPConnection.)                      }
  2070. function TPOP3SMTPComponent.UploadMessageListing(
  2071.           TheEMMRecord : PEmailMessageRecord ): Boolean;
  2072. var WorkingString   : String;
  2073.     WorkingFile     : TextFile;
  2074.     TheReturnString : String;  { Internal string holder }
  2075.     TheResult       : Integer; { Internal int holder    }
  2076. begin
  2077.   with TheEMMRecord^ do
  2078.   begin
  2079.     MRSent := true;
  2080.     MRRead := true;
  2081.     WorkingString := MailPath + '\' + MRFileName;
  2082.     try
  2083.       AssignFile( WorkingFile , WorkingString );
  2084.       Reset( WorkingFile );
  2085.     except
  2086.       MessageDlg( 'Unable to Send due to open error on '
  2087.        + Workingstring + '!' , mtError , [mbok],0 );
  2088.       Result := false;
  2089.       exit;
  2090.     end;
  2091.     if MRMessageRecipient <> '' then
  2092.     begin
  2093.       TheReturnString :=
  2094.        DoCStyleFormat( 'RCPT %s' ,
  2095.         [ MRMessageRecipient ] );
  2096.       { Put result in progress and status line }
  2097.       AddProgressText( TheReturnString );
  2098.       ShowProgressText( TheReturnString );
  2099.       SMTPCommandInProgress := false;
  2100.       { Begin login sequence with user name }
  2101.       TheResult := PerformSMTPCommand( 'RCPT %s', [ MRMessageRecipient ] );
  2102.       if TheResult <> TCPIP_STATUS_PRELIMINARY then
  2103.       begin
  2104.         SMTPCommandInProgress := false;
  2105.         Result := false;
  2106.         exit;
  2107.       end;
  2108.       repeat
  2109.         TheResult := GetSMTPServerResponse( TheReturnString );
  2110.         { Put result in progress and status line }
  2111.         AddProgressText( TheReturnString );
  2112.         ShowProgressText( TheReturnString + #13#10 );
  2113.       until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  2114.     end;
  2115.     if MRCarbonCopy <> 'CC:<>' then
  2116.     begin
  2117.       TheReturnString :=
  2118.        DoCStyleFormat( 'RCPT %s' ,
  2119.         [ MRCarbonCopy ] );
  2120.       { Put result in progress and status line }
  2121.       AddProgressText( TheReturnString );
  2122.       ShowProgressText( TheReturnString );
  2123.       { Begin login sequence with user name }
  2124.       SMTPCommandInProgress := false;
  2125.       TheResult := PerformSMTPCommand( 'RCPT %s', [ MRCarbonCopy ] );
  2126.       if TheResult <> TCPIP_STATUS_PRELIMINARY then
  2127.       begin
  2128.         SMTPCommandInProgress := false;
  2129.         Result := false;
  2130.         exit;
  2131.       end;
  2132.       repeat
  2133.         TheResult := GetSMTPServerResponse( TheReturnString );
  2134.         { Put result in progress and status line }
  2135.         AddProgressText( TheReturnString );
  2136.         ShowProgressText( TheReturnString + #13#10 );
  2137.       until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  2138.     end;
  2139.     if MRBlindCarbonCopy <> 'BCC:<>' then
  2140.     begin
  2141.       TheReturnString :=
  2142.        DoCStyleFormat( 'RCPT %s' ,
  2143.         [ MRBlindCarbonCopy ] );
  2144.       { Put result in progress and status line }
  2145.       AddProgressText( TheReturnString );
  2146.       ShowProgressText( TheReturnString );
  2147.       { Begin login sequence with user name }
  2148.       SMTPCommandInProgress := false;
  2149.       TheResult := PerformSMTPCommand( 'RCPT %s' , [ MRBlindCarbonCopy ] );
  2150.       if TheResult <> TCPIP_STATUS_PRELIMINARY then
  2151.       begin
  2152.         SMTPCommandInProgress := false;
  2153.         Result := false;
  2154.         exit;
  2155.       end;
  2156.       repeat
  2157.         TheResult := GetSMTPServerResponse( TheReturnString );
  2158.         { Put result in progress and status line }
  2159.         AddProgressText( TheReturnString );
  2160.         ShowProgressText( TheReturnString + #13#10 );
  2161.       until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  2162.     end;
  2163.     TheReturnString :=
  2164.      DoCStyleFormat( 'DATA' ,
  2165.       [ nil ] );
  2166.     { Put result in progress and status line }
  2167.     AddProgressText( TheReturnString );
  2168.     ShowProgressText( TheReturnString );
  2169.     { Begin login sequence with user name }
  2170.     SMTPCommandInProgress := false;
  2171.     TheResult := PerformSMTPCommand( 'DATA' , [ nil ] );
  2172.     if TheResult <> TCPIP_STATUS_PRELIMINARY then
  2173.     begin
  2174.       SMTPCommandInProgress := false;
  2175.       Result := false;
  2176.       exit;
  2177.     end;
  2178.     repeat
  2179.       TheResult := GetSMTPServerResponse( TheReturnString );
  2180.       { Put result in progress and status line }
  2181.       AddProgressText( TheReturnString );
  2182.       ShowProgressText( TheReturnString + #13#10 );
  2183.     until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  2184.     repeat
  2185.       SMTPCommandInProgress := false;
  2186.       ReadLn( WorkingFile , WorkingString );
  2187.       if WorkingString[ 1 ] = '.' then WorkingString := '.' + WorkingString;
  2188.       TheResult := PerformSMTPCommand( WorkingString , [ nil ] );
  2189.       if TheResult <> TCPIP_STATUS_PRELIMINARY then
  2190.       begin
  2191.         SMTPCommandInProgress := false;
  2192.         Result := false;
  2193.         exit;
  2194.       end;
  2195.     until EOF( WorkingFile );
  2196.     CloseFile( WorkingFile );
  2197.     SMTPCommandInProgress := false;
  2198.     TheResult := PerformSMTPCommand( '.' , [ nil ] );
  2199.     if TheResult <> TCPIP_STATUS_PRELIMINARY then
  2200.     begin
  2201.       SMTPCommandInProgress := false;
  2202.       Result := false;
  2203.       exit;
  2204.     end;
  2205.     repeat
  2206.       TheResult := GetSMTPServerResponse( TheReturnString );
  2207.       { Put result in progress and status line }
  2208.       AddProgressText( TheReturnString );
  2209.       ShowProgressText( TheReturnString  + #13#10 );
  2210.     until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  2211.     Result := true;
  2212.   end;
  2213. end;
  2214.  
  2215. procedure TPOP3SMTPComponent.ExtractHeaderInfoFromMemo(
  2216.            TheMemo : TMemo; TheEMMRecord : PEMailMessageRecord );
  2217. var Counter_1    : Integer;
  2218.     Finished     : Boolean;
  2219.     TheWorkingSL : TStringList;
  2220. begin
  2221.   Counter_1 := 0;
  2222.   Finished := false;
  2223.   TheWorkingSL := TStringList.Create;
  2224.   while not Finished do
  2225.   begin
  2226.     if TheMemo.Lines[ Counter_1 ] = '' then
  2227.     begin
  2228.       Finished := true;
  2229.     end
  2230.     else
  2231.     begin
  2232.       TheWorkingSL.Add( TheMemo.Lines[ Counter_1 ] );
  2233.       Inc( Counter_1 );
  2234.     end;
  2235.   end;
  2236.   with TheEMMRecord^ do
  2237.   begin
  2238.     MRMessageSubject   := GetHeaderSubject( TheWorkingSL );
  2239.     MRMessageRecipient := GetRCPTHeaderRecipient( TheWorkingSL );
  2240.     MRMessageSender    := 'CIUPKC158';
  2241.     MRCarbonCopy       := GetRCPTHeaderCarbons( TheWorkingSL );
  2242.     MRBlindCarbonCopy  := GetRCPTHeaderBlindCarbons( TheWorkingSL );
  2243.     MRDateTime         := GetHeaderDateTime( TheWorkingSL );
  2244.   end;
  2245.   TheWorkingSL.Free;
  2246. end;
  2247.  
  2248. { This method takes an entire Newsgroup and scans for SENDER = CIUPKC158 and }
  2249. { if that article has not been posted posts it. (Used by queue system.)      }
  2250. function TPOP3SMTPComponent.UploadAllMessageListings( PCRPointer : PConnectionsRecord;
  2251.           TheEMBRecord : PEMailMailBoxRecord ) : Boolean;
  2252. var WorkingList : TList;
  2253.     Counter_1   : Integer;
  2254.     WorkingEMMRecord : PEMailMessageRecord;
  2255.     TheReturnString  : String;
  2256. begin
  2257.   Result := true;
  2258.   with TheEMBRecord^ do
  2259.   begin
  2260.     WorkingList := TList( MBLTag );
  2261.     for Counter_1 := 0 to WorkingList.Count - 1 do
  2262.     begin
  2263.       WorkingEMMRecord :=
  2264.        PEMailMessageRecord( WorkingList.Items[ Counter_1 ] );
  2265.       with WorkingEMMRecord^ do
  2266.       begin
  2267.         if MRMessageSender = 'CIUPKC158' then
  2268.         begin
  2269.           if not MRSent then
  2270.           begin
  2271.             SMTPCommandInProgress := false;
  2272.             SendMail( PCRPointer );
  2273.             UploadMessageListing( WorkingEMMRecord );
  2274.             Dec( MBUnSentTotal );
  2275.           end;
  2276.         end;
  2277.       end;
  2278.     end;
  2279.     MBLTag := Longint( WorkingList );
  2280.   end;
  2281.   TheReturnString := 'Message(s) Uploaded!';
  2282.   AddProgressText( TheReturnString );
  2283.   ShowProgressText( TheReturnString + #13#10 );
  2284. end;
  2285.  
  2286. { This sends FTP progress text to the Inet form }
  2287. procedure TPOP3SMTPComponent.ShowProgressErrorText( WhatText : String );
  2288. begin
  2289.  CCInetCCForm.ShowProgressErrorText( WhatText );
  2290. end;
  2291.  
  2292. { This is a core function! It performs an FTP command and if no timeout }
  2293. { return a preliminary ok.                                              }
  2294. function TPOP3SMTPComponent.PerformPOP3Command(
  2295.                  TheCommand        : string;
  2296.            const TheArguments      : array of const ) : Integer;
  2297. var TheBuffer : string; { Text buffer }
  2298. begin
  2299.   { If command in progress send back -1 error }
  2300.   if POP3CommandInProgress then
  2301.   begin
  2302.     Result := -1;
  2303.     exit;
  2304.   end;
  2305.   { Set status variable }
  2306.   POP3CommandInProgress := True;
  2307.   { Set global error code }
  2308.   GlobalErrorCode := 0;
  2309.   { Format output string }
  2310.   TheBuffer := Format( TheCommand , TheArguments );
  2311.   { Preset failure code }
  2312.   Result := TCPIP_STATUS_FATAL_ERROR;
  2313.   { If invalid socket or no connection abort }
  2314.   if ( Socket1.TheSocket = INVALID_SOCKET ) or not Connection_Established then
  2315.    exit;
  2316.   { Send the buffer plus EOL chars }
  2317.   Socket1.StringData := TheBuffer + #13#10;
  2318.   { if abort due to timeout or other error exit }
  2319.   if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  2320.   { Otherwise return preliminary code }
  2321.   Result := TCPIP_STATUS_PRELIMINARY;
  2322. end;
  2323.  
  2324. { This is a core function! It performs an FTP command and if no timeout }
  2325. { return a preliminary ok.                                              }
  2326. function TPOP3SMTPComponent.PerformSMTPCommand(
  2327.                  TheCommand        : string;
  2328.            const TheArguments      : array of const ) : Integer;
  2329. var TheBuffer : string; { Text buffer }
  2330. begin
  2331.   { If command in progress send back -1 error }
  2332.   if SMTPCommandInProgress then
  2333.   begin
  2334.     Result := -1;
  2335.     exit;
  2336.   end;
  2337.   { Set status variable }
  2338.   SMTPCommandInProgress := True;
  2339.   { Set global error code }
  2340.   GlobalErrorCode := 0;
  2341.   { Format output string }
  2342.   TheBuffer := Format( TheCommand , TheArguments );
  2343.   { Preset failure code }
  2344.   Result := TCPIP_STATUS_FATAL_ERROR;
  2345.   { If invalid socket or no connection abort }
  2346.   if ( Socket1.TheSocket = INVALID_SOCKET ) or not Connection_Established then
  2347.    exit;
  2348.   { Send the buffer plus EOL chars }
  2349.   Socket1.StringData := TheBuffer + #13#10;
  2350.   { if abort due to timeout or other error exit }
  2351.   if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  2352.   { Otherwise return preliminary code }
  2353.   Result := TCPIP_STATUS_PRELIMINARY;
  2354. end;
  2355.  
  2356. { This function gets up to 255 chars of data plus a return code from FTP serv }
  2357. function TPOP3SMTPComponent.GetPOP3ServerResponse(
  2358.           var ResponseString : String ) : integer;
  2359. var
  2360.   { Buffer string for response line }
  2361.   TheBuffer     : string;
  2362.   { Pointer to the response string }
  2363.   BufferPointer : array[0..255] of char absolute TheBuffer;
  2364.   { Character to check for response code }
  2365.   ResponseChar   : char;
  2366.   { Pointers into returned string }
  2367.   TheIndex ,
  2368.   TheLength     : integer;
  2369.   { Control variable }
  2370.   LeftoversInPan ,
  2371.   Finished      : Boolean;
  2372. begin
  2373.   { Preset fatal error }
  2374.   Result := TCPIP_STATUS_FATAL_ERROR;
  2375.   { Start loop control }
  2376.   LeftoversInPan := false;
  2377.   Finished := false;
  2378.   repeat
  2379.     { Do a peek }
  2380.     TheBuffer := Socket1.PeekData;
  2381.     { If timeout or other error exit }
  2382.     if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  2383.     { Find end of line character }
  2384.     TheIndex := Pos( #10 , TheBuffer );
  2385.     if TheIndex = 0 then
  2386.     begin
  2387.       TheIndex := Pos( #13 , TheBuffer );
  2388.       if TheIndex = 0 then
  2389.       begin
  2390.         TheIndex := Pos( #0 , TheBuffer );
  2391.         if TheIndex = 0 then
  2392.         begin
  2393.           TheIndex := Length( TheBuffer );
  2394.           LeftoversInPan := True;
  2395.           LeftoverText := LeftoverText + TheBuffer;
  2396.           LeftoversOnTable := false;
  2397.         end;
  2398.       end;
  2399.     end;
  2400.     { If an end of line then process the line }
  2401.     if TheIndex > 0 then
  2402.     begin
  2403.       { Get length of string }
  2404.       TheLength := TheIndex;
  2405.       { Receive actual data }
  2406.       Socket1.CCSockReceive( Socket1.TheSocket   ,
  2407.                              @BufferPointer[ 1 ] ,
  2408.                              TheLength              );
  2409.       { Abort if timeout or error }
  2410.       if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  2411.       { Put in the length byte }
  2412.       BufferPointer[ 0 ] := Chr( TheLength );
  2413.       if LeftOversOnTable then
  2414.       begin
  2415.         LeftOversOnTable := false;
  2416.         ResponseString := LeftoverText + TheBuffer;
  2417.         TheBuffer := ResponseString;
  2418.         LeftoverText := '';
  2419.       end;
  2420.       if LeftoversInPan then
  2421.       begin
  2422.         LeftoversInPan := false;
  2423.         LeftoversOnTable := true;
  2424.       end;
  2425.       { Get first number character }
  2426.       ResponseChar := TheBuffer[ 1 ];
  2427.       { Get the value of the number from 1 to 5 }
  2428.       if (( ResponseChar = '+' ) or ( ResponseChar = '-' )) then
  2429.       begin
  2430.         Finished := true;
  2431.         if ResponseChar = '+' then Result := TCPIP_STATUS_COMPLETED
  2432.          else Result := TCPIP_STATUS_FATAL_ERROR;
  2433.       end;
  2434.     end
  2435.     else
  2436.     begin
  2437.     end;
  2438.   until ( Finished and ( not LeftoversOnTable ));
  2439.   { Return buffer as response string }
  2440.   ResponseString := TheBuffer;
  2441.   ResponseString := Copy( ResponseString , 1, Length( ResponseString ) - 2 );
  2442. end;
  2443.  
  2444. { This function gets up to 255 chars of data plus a return code from FTP serv }
  2445. function TPOP3SMTPComponent.GetSMTPServerResponse(
  2446.           var ResponseString : String ) : integer;
  2447. var
  2448.   { Buffer string for response line }
  2449.   TheBuffer     : string;
  2450.   { Pointer to the response string }
  2451.   BufferPointer : array[0..255] of char absolute TheBuffer;
  2452.   { Character to check for response code }
  2453.   ResponseChar   : char;
  2454.   { Pointers into returned string }
  2455.   TheIndex ,
  2456.   TheLength     : integer;
  2457.   { Control variable }
  2458.   LeftoversInPan ,
  2459.   Finished      : Boolean;
  2460. begin
  2461.   { Preset fatal error }
  2462.   Result := TCPIP_STATUS_FATAL_ERROR;
  2463.   { Start loop control }
  2464.   LeftoversInPan := false;
  2465.   Finished := false;
  2466.   repeat
  2467.     { Do a peek }
  2468.     TheBuffer := Socket1.PeekData;
  2469.     { If timeout or other error exit }
  2470.     if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  2471.     { Find end of line character }
  2472.     TheIndex := Pos( #10 , TheBuffer );
  2473.     if TheIndex = 0 then
  2474.     begin
  2475.       TheIndex := Pos( #13 , TheBuffer );
  2476.       if TheIndex = 0 then
  2477.       begin
  2478.         TheIndex := Pos( #0 , TheBuffer );
  2479.         if TheIndex = 0 then
  2480.         begin
  2481.           TheIndex := Length( TheBuffer );
  2482.           LeftoversInPan := True;
  2483.           LeftoverText := LeftoverText + TheBuffer;
  2484.           LeftoversOnTable := false;
  2485.         end;
  2486.       end;
  2487.     end;
  2488.     { If an end of line then process the line }
  2489.     if TheIndex > 0 then
  2490.     begin
  2491.       { Get length of string }
  2492.       TheLength := TheIndex;
  2493.       { Receive actual data }
  2494.       Socket1.CCSockReceive( Socket1.TheSocket   ,
  2495.                              @BufferPointer[ 1 ] ,
  2496.                              TheLength              );
  2497.       { Abort if timeout or error }
  2498.       if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 )) then exit;
  2499.       { Put in the length byte }
  2500.       BufferPointer[ 0 ] := Chr( TheLength );
  2501.       if LeftOversOnTable then
  2502.       begin
  2503.         LeftOversOnTable := false;
  2504.         ResponseString := LeftoverText + TheBuffer;
  2505.         TheBuffer := ResponseString;
  2506.         LeftoverText := '';
  2507.       end;
  2508.       if LeftoversInPan then
  2509.       begin
  2510.         LeftoversInPan := false;
  2511.         LeftoversOnTable := true;
  2512.       end;
  2513.       { Get first number character }
  2514.       ResponseChar := TheBuffer[ 1 ];
  2515.       { Get the value of the number from 1 to 5 }
  2516.       if (( ResponseChar >= '1' ) and ( ResponseChar <= '5' )) then
  2517.       begin
  2518.         if TheBuffer[ 4 ] = '-' then
  2519.         begin
  2520.           Finished := true;
  2521.           Result := TCPIP_STATUS_PRELIMINARY;
  2522.         end
  2523.         else
  2524.         begin
  2525.           Finished := true;
  2526.           Result := Ord( ResponseChar ) - 48;
  2527.         end;
  2528.       end;
  2529.     end
  2530.     else
  2531.     begin
  2532.     end;
  2533.   until ( Finished and ( not LeftoversOnTable ));
  2534.   { Return buffer as response string }
  2535.   ResponseString := TheBuffer;
  2536.   ResponseString := Copy( ResponseString , 1, Length( ResponseString ) - 2 );
  2537. end;
  2538.  
  2539.  
  2540. { Boilerplate error routine }
  2541. procedure TPOP3SMTPComponent.POP3SMTPSocketsErrorOccurred( Sender     : TObject;
  2542.                                                  ErrorCode  : Integer;
  2543.                                                  TheMessage : String   );
  2544. begin
  2545.   CCInetCCForm.SocketsErrorOccurred( Sender,ErrorCode,TheMessage );
  2546. end;
  2547.  
  2548. { This is the POP3SMTP components POP3 initial connection routine }
  2549. function TPOP3SMTPComponent.EstablishPOP3Connection(
  2550.           PCRPointer : PConnectionsRecord ) : Boolean;
  2551. var TheReturnString : String;  { Internal string holder }
  2552.     TheResult       : Integer; { Internal int holder    }
  2553. begin
  2554.   { Set default FTP Port value }
  2555.   Socket1.PortName := '110';
  2556.   { Get the ip address from the record }
  2557.   Socket1.IPAddressName := PCRPointer^.CIPAddress;
  2558.   { Set blocking mode }
  2559.   Socket1.AsynchMode := False;
  2560.   { Clear condition variables }
  2561.   GlobalErrorCode := 0;
  2562.   GlobalAbortedFlag := false;
  2563.   { Actually attempt to connect }
  2564.   Socket1.CCSockConnect;
  2565.   { Check if connected }
  2566.   if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 ) or
  2567.       ( Socket1.TheSocket = INVALID_SOCKET )) then
  2568.   begin { Didn't connect; signal error and abort }
  2569.     { Do clever C formatting trick }
  2570.     TheReturnString :=
  2571.      DoCStyleFormat( 'POP3 Host %s Connection Failed!' ,
  2572.       [ PCRPointer^.CIPAddress ] );
  2573.     { Put result in progress and status line }
  2574.     AddProgressText( TheReturnString );
  2575.     ShowProgressErrorText( TheReturnString );
  2576.     { Signal error }
  2577.     Result := False;
  2578.     { leave }
  2579.     exit;
  2580.   end
  2581.   else
  2582.   begin
  2583.     Connection_Established := true;
  2584.     { Signal successful connection }
  2585.     TheReturnString := DoCStyleFormat(
  2586.       'Connected on Local port: %s with IP: %s',
  2587.       [ Socket1.GetSocketPort( Socket1.TheSocket ),
  2588.         Socket1.GetSocketIPAddress( Socket1.TheSocket )]);
  2589.     { Put result in progress and status line }
  2590.     CCINetCCForm.AddProgressText( TheReturnString );
  2591.     CCINetCCForm.ShowProgressText( TheReturnString );
  2592.     TheReturnString := DoCStyleFormat(
  2593.      'Connected to Remote port: %s with IP: %s',
  2594.       [ Socket1.GetSocketPeerPort( Socket1.TheSocket ),
  2595.         Socket1.GetSocketPeerIPAddress( Socket1.TheSocket )]);
  2596.     { Put result in progress and status line }
  2597.     CCINetCCForm.AddProgressText( TheReturnString );
  2598.     CCINetCCForm.ShowProgressText( TheReturnString );
  2599.     TheReturnString := DoCStyleFormat( 'Successfully connected to %s',
  2600.      [ Socket1.IPAddressName ]);
  2601.     { Put result in progress and status line }
  2602.     CCINetCCForm.AddProgressText( TheReturnString );
  2603.     CCINetCCForm.ShowProgressText( TheReturnString );
  2604.     repeat
  2605.       TheResult := GetPOP3ServerResponse( TheReturnString );
  2606.       { Put result in progress and status line }
  2607.       AddProgressText( TheReturnString );
  2608.       ShowProgressText( TheReturnString );
  2609.     until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  2610.     if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  2611.     begin
  2612.       { Do clever C formatting trick }
  2613.       TheReturnString :=
  2614.        DoCStyleFormat( 'POP3 Host %s Connection Failed!' ,
  2615.         [ PCRPointer^.CIPAddress ] );
  2616.       { Put result in progress and status line }
  2617.       AddProgressText( TheReturnString );
  2618.       ShowProgressErrorText( TheReturnString );
  2619.       { Signal error }
  2620.       Result := False;
  2621.       { leave }
  2622.       exit;
  2623.     end
  2624.     else Result := true; { Signal no problem }
  2625.   end;
  2626. end;
  2627.  
  2628. { This is the POP3SMTP components SMTP initial connection routine }
  2629. function TPOP3SMTPComponent.EstablishSMTPConnection(
  2630.           PCRPointer : PConnectionsRecord ) : Boolean;
  2631. var TheReturnString : String;  { Internal string holder }
  2632.     TheResult       : Integer; { Internal int holder    }
  2633. begin
  2634.   { Set default FTP Port value }
  2635.   Socket1.PortName := '25';
  2636.   { Get the ip address from the record }
  2637.   Socket1.IPAddressName := PCRPointer^.CIPAddress;
  2638.   { Set blocking mode }
  2639.   Socket1.AsynchMode := False;
  2640.   { Clear condition variables }
  2641.   GlobalErrorCode := 0;
  2642.   GlobalAbortedFlag := false;
  2643.   { Actually attempt to connect }
  2644.   Socket1.CCSockConnect;
  2645.   { Check if connected }
  2646.   if (( GlobalAbortedFlag ) or ( GlobalErrorCode <> 0 ) or
  2647.       ( Socket1.TheSocket = INVALID_SOCKET )) then
  2648.   begin { Didn't connect; signal error and abort }
  2649.     { Do clever C formatting trick }
  2650.     TheReturnString :=
  2651.      DoCStyleFormat( 'SMTP Host %s Connection Failed!' ,
  2652.       [ PCRPointer^.CIPAddress ] );
  2653.     { Put result in progress and status line }
  2654.     AddProgressText( TheReturnString );
  2655.     ShowProgressErrorText( TheReturnString );
  2656.     { Signal error }
  2657.     Result := False;
  2658.     { leave }
  2659.     exit;
  2660.   end
  2661.   else
  2662.   begin
  2663.     Connection_Established := true;
  2664.     { Signal successful connection }
  2665.     TheReturnString := DoCStyleFormat(
  2666.       'Connected on Local port: %s with IP: %s',
  2667.       [ Socket1.GetSocketPort( Socket1.TheSocket ),
  2668.         Socket1.GetSocketIPAddress( Socket1.TheSocket )]);
  2669.     { Put result in progress and status line }
  2670.     CCINetCCForm.AddProgressText( TheReturnString );
  2671.     CCINetCCForm.ShowProgressText( TheReturnString );
  2672.     TheReturnString := DoCStyleFormat(
  2673.      'Connected to Remote port: %s with IP: %s',
  2674.       [ Socket1.GetSocketPeerPort( Socket1.TheSocket ),
  2675.         Socket1.GetSocketPeerIPAddress( Socket1.TheSocket )]);
  2676.     { Put result in progress and status line }
  2677.     CCINetCCForm.AddProgressText( TheReturnString );
  2678.     CCINetCCForm.ShowProgressText( TheReturnString );
  2679.     TheReturnString := DoCStyleFormat( 'Successfully connected to %s',
  2680.      [ Socket1.IPAddressName ]);
  2681.     { Put result in progress and status line }
  2682.     CCINetCCForm.AddProgressText( TheReturnString );
  2683.     CCINetCCForm.ShowProgressText( TheReturnString );
  2684.     repeat
  2685.       TheResult := GetSMTPServerResponse( TheReturnString );
  2686.       { Put result in progress and status line }
  2687.       AddProgressText( TheReturnString );
  2688.       ShowProgressText( TheReturnString + #13#10 );
  2689.     until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  2690.     if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  2691.     begin
  2692.       { Do clever C formatting trick }
  2693.       TheReturnString :=
  2694.        DoCStyleFormat( 'SMTP Host %s Connection Failed!' ,
  2695.         [ PCRPointer^.CIPAddress ] );
  2696.       { Put result in progress and status line }
  2697.       AddProgressText( TheReturnString );
  2698.       ShowProgressErrorText( TheReturnString );
  2699.       { Signal error }
  2700.       Result := False;
  2701.       { leave }
  2702.       exit;
  2703.     end
  2704.     else Result := true; { Signal no problem }
  2705.   end;
  2706. end;
  2707.  
  2708. { This sends FTP progress text to the Inet form }
  2709. procedure TPOP3SMTPComponent.AddProgressText( WhatText : String );
  2710. begin
  2711.   CCInetCCForm.AddProgressText( WhatText );
  2712. end;
  2713.  
  2714. { This sends FTP progress text to the Inet form }
  2715. procedure TPOP3SMTPComponent.ShowProgressText( WhatText : String );
  2716. begin
  2717.   CCInetCCForm.ShowProgressText( WhatText );
  2718. end;
  2719.  
  2720. { This is a clever c-style formatting trick }
  2721. function TPOP3SMTPComponent.DoCStyleFormat(
  2722.                 TheText      : string;
  2723.           const TheArguments : array of const ) : String;
  2724. begin
  2725.   Result := Format( TheText , TheArguments ) + #13#10;
  2726. end;
  2727.  
  2728. { This is the FTP components USER login routine }
  2729. function TPOP3SMTPComponent.LoginUser(
  2730.           PCRPointer : PConnectionsRecord ) : Boolean;
  2731. var TheReturnString : String;  { Internal string holder }
  2732.     TheResult       : Integer; { Internal int holder    }
  2733. begin
  2734.   TheReturnString :=
  2735.    DoCStyleFormat( 'USER %s' ,
  2736.     [ PCRPointer^.CUserName ] );
  2737.   { Put result in progress and status line }
  2738.   AddProgressText( TheReturnString );
  2739.   ShowProgressText( TheReturnString );
  2740.   { Begin login sequence with user name }
  2741.   TheResult := PerformPOP3Command( 'USER %s',
  2742.                                   [ PCRPointer^.CUserName ] );
  2743.   if TheResult <> TCPIP_STATUS_PRELIMINARY then
  2744.   begin
  2745.     POP3CommandInProgress := false;
  2746.     Result := false;
  2747.     exit;
  2748.   end;
  2749.   repeat
  2750.     TheResult := GetPOP3ServerResponse( TheReturnString );
  2751.     { Put result in progress and status line }
  2752.     AddProgressText( TheReturnString );
  2753.     ShowProgressText( TheReturnString + #13#10 );
  2754.   until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  2755.   POP3CommandInProgress := false;
  2756.   if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  2757.   begin
  2758.     { Do clever C formatting trick }
  2759.     TheReturnString :=
  2760.      DoCStyleFormat( 'POP3 Host %s Login Failed!' ,
  2761.       [ PCRPointer^.CIPAddress ] );
  2762.     { Put result in progress and status line }
  2763.     AddProgressText( TheReturnString );
  2764.     ShowProgressErrorText( TheReturnString );
  2765.     { Signal error }
  2766.     Result := False;
  2767.     { leave }
  2768.     exit;
  2769.   end
  2770.   else Result := true; { Signal no problem }
  2771. end;
  2772.  
  2773. { This is the FTP components USER login routine }
  2774. function TPOP3SMTPComponent.SendHelo(
  2775.           PCRPointer : PConnectionsRecord ) : Boolean;
  2776. var TheReturnString : String;  { Internal string holder }
  2777.     TheResult       : Integer; { Internal int holder    }
  2778. begin
  2779.   TheReturnString :=
  2780.    DoCStyleFormat( 'HELO %s' ,
  2781.     [ Socket1.GetSocketIPAddress( Socket1.TheSocket ) ] );
  2782.   { Put result in progress and status line }
  2783.   AddProgressText( TheReturnString );
  2784.   ShowProgressText( TheReturnString );
  2785.   { Begin login sequence with user name }
  2786.   TheResult := PerformSMTPCommand( 'HELO %s',
  2787.                 [ Socket1.GetSocketIPAddress( Socket1.TheSocket ) ] );
  2788.   if TheResult <> TCPIP_STATUS_PRELIMINARY then
  2789.   begin
  2790.     POP3CommandInProgress := false;
  2791.     Result := false;
  2792.     exit;
  2793.   end;
  2794.   repeat
  2795.     TheResult := GetSMTPServerResponse( TheReturnString );
  2796.     { Put result in progress and status line }
  2797.     AddProgressText( TheReturnString );
  2798.     ShowProgressText( TheReturnString + #13#10 );
  2799.   until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  2800.   SMTPCommandInProgress := false;
  2801.   if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  2802.   begin
  2803.     { Do clever C formatting trick }
  2804.     TheReturnString :=
  2805.      DoCStyleFormat( 'SMTP Host %s Login Failed!' ,
  2806.       [ PCRPointer^.CIPAddress ] );
  2807.     { Put result in progress and status line }
  2808.     AddProgressText( TheReturnString );
  2809.     ShowProgressErrorText( TheReturnString );
  2810.     { Signal error }
  2811.     Result := False;
  2812.     { leave }
  2813.     exit;
  2814.   end
  2815.   else Result := true; { Signal no problem }
  2816. end;
  2817.  
  2818. { This is the FTP components USER login routine }
  2819. function TPOP3SMTPComponent.SendMail(
  2820.           PCRPointer : PConnectionsRecord ) : Boolean;
  2821. var TheReturnString : String;  { Internal string holder }
  2822.     TheResult       : Integer; { Internal int holder    }
  2823. begin
  2824.   TheReturnString :=
  2825.    DoCStyleFormat( 'MAIL FROM:<%s>' ,
  2826.     [ PCRPointer^.CStartDir ] );
  2827.   { Put result in progress and status line }
  2828.   AddProgressText( TheReturnString );
  2829.   ShowProgressText( TheReturnString );
  2830.   { Begin login sequence with user name }
  2831.   TheResult := PerformSMTPCommand( 'MAIL FROM:<%s>',
  2832.                                   [ PCRPointer^.CStartDir ] );
  2833.   if TheResult <> TCPIP_STATUS_PRELIMINARY then
  2834.   begin
  2835.     SMTPCommandInProgress := false;
  2836.     Result := false;
  2837.     exit;
  2838.   end;
  2839.   repeat
  2840.     TheResult := GetSMTPServerResponse( TheReturnString );
  2841.     { Put result in progress and status line }
  2842.     AddProgressText( TheReturnString );
  2843.     ShowProgressText( TheReturnString + #13#10 );
  2844.   until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  2845.   SMTPCommandInProgress := false;
  2846.   if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  2847.   begin
  2848.     { Do clever C formatting trick }
  2849.     TheReturnString :=
  2850.      DoCStyleFormat( 'SMTP Host %s Login Failed!' ,
  2851.       [ PCRPointer^.CIPAddress ] );
  2852.     { Put result in progress and status line }
  2853.     AddProgressText( TheReturnString );
  2854.     ShowProgressErrorText( TheReturnString );
  2855.     { Signal error }
  2856.     Result := False;
  2857.     { leave }
  2858.     exit;
  2859.   end
  2860.   else Result := true; { Signal no problem }
  2861. end;
  2862.  
  2863. { This is the FTP components PASSWORD routine }
  2864. function TPOP3SMTPComponent.SendPassword(
  2865.           PCRPointer : PConnectionsRecord ) : Boolean;
  2866. var TheReturnString : String;  { Internal string holder }
  2867.     TheResult       : Integer; { Internal int holder    }
  2868. begin
  2869.   TheReturnString := 'PASS XXXXXX' + #13#10;
  2870.   { Put result in progress and status line }
  2871.   AddProgressText( TheReturnString );
  2872.   ShowProgressText( TheReturnString );
  2873.   { Send Password sequence }
  2874.   TheResult := PerformPOP3Command( 'PASS %s',
  2875.                                   [ PCRPointer^.CPassword ] );
  2876.   if TheResult <> TCPIP_STATUS_PRELIMINARY then
  2877.   begin
  2878.     Result := false;
  2879.     POP3CommandInProgress := false;
  2880.     exit;
  2881.   end;
  2882.   repeat
  2883.     TheResult := GetPOP3ServerResponse( TheReturnString );
  2884.     { Put result in progress and status line }
  2885.     AddProgressText( TheReturnString );
  2886.     ShowProgressText( TheReturnString + #13#10 );
  2887.   until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  2888.   POP3CommandInProgress := false;
  2889.   if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  2890.   begin
  2891.     { Do clever C formatting trick }
  2892.     TheReturnString :=
  2893.      DoCStyleFormat( 'POP3 Host %s Login Failed!' ,
  2894.       [ PCRPointer^.CIPAddress ] );
  2895.     { Put result in progress and status line }
  2896.     AddProgressText( TheReturnString );
  2897.     ShowProgressErrorText( TheReturnString );
  2898.     { Signal error }
  2899.     Result := False;
  2900.     { leave }
  2901.     exit;
  2902.   end
  2903.   else Result := true; { Signal no problem }
  2904. end;
  2905.  
  2906. { This is the FTP component constructor; it creates 2 sockets }
  2907. constructor TPOP3SMTPComponent.Create( AOwner : TComponent );
  2908. begin
  2909.   { do inherited create }
  2910.   inherited Create( AOwner );
  2911.   { Create sockets, put in their parents, and error procs }
  2912.   Socket1 := TCCSocket.Create( Self );
  2913.   Socket1.Parent := Self;
  2914.   Socket1.OnErrorOccurred := POP3SMTPSocketsErrorOccurred;
  2915.   { Set up booleans }
  2916.   Connection_Established := false;
  2917.   POP3CommandInProgress := false;
  2918.   SMTPCommandInProgress := false;
  2919. end;
  2920.  
  2921. { This is the FTP component destructor; it frees 2 sockets }
  2922. destructor TPOP3SMTPComponent.Destroy;
  2923. begin
  2924.   { Free the sockets }
  2925.   Socket1.Free;
  2926.   { and call inherited }
  2927.   inherited Destroy;
  2928. end;
  2929.  
  2930. { This is the POP3 components QUIT routine }
  2931. function TPOP3SMTPComponent.POP3Disconnect : Boolean;
  2932. var TheReturnString : String;  { Internal string holder }
  2933.     TheResult       : Integer; { Internal int holder    }
  2934. begin
  2935.   TheReturnString :=
  2936.    DoCStyleFormat( 'QUIT' ,
  2937.     [ nil ] );
  2938.   { Put result in progress and status line }
  2939.   AddProgressText( TheReturnString );
  2940.   ShowProgressText( TheReturnString );
  2941.   { Begin login sequence with user name }
  2942.   PerformPOP3Command( 'QUIT', [ nil ] );
  2943.   repeat
  2944.     TheResult := GetPOP3ServerResponse( TheReturnString );
  2945.     { Put result in progress and status line }
  2946.     AddProgressText( TheReturnString );
  2947.     ShowProgressText( TheReturnString + #13#10 );
  2948.   until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  2949.   POP3CommandInProgress := false;
  2950.   if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  2951.   begin
  2952.     { Do clever C formatting trick }
  2953.     TheReturnString :=
  2954.      DoCStyleFormat( 'EMail Host Connection Failed!' ,
  2955.       [ nil ] );
  2956.     { Put result in progress and status line }
  2957.     AddProgressText( TheReturnString );
  2958.     ShowProgressErrorText( TheReturnString );
  2959.     { Signal error }
  2960.     Result := False;
  2961.     { leave }
  2962.     exit;
  2963.   end
  2964.   else Result := true; { Signal no problem }
  2965. end;
  2966.  
  2967. { This is the POP3 components QUIT routine }
  2968. function TPOP3SMTPComponent.SMTPDisconnect : Boolean;
  2969. var TheReturnString : String;  { Internal string holder }
  2970.     TheResult       : Integer; { Internal int holder    }
  2971. begin
  2972.   TheReturnString :=
  2973.    DoCStyleFormat( 'QUIT' ,
  2974.     [ nil ] );
  2975.   { Put result in progress and status line }
  2976.   AddProgressText( TheReturnString );
  2977.   ShowProgressText( TheReturnString );
  2978.   { Begin login sequence with user name }
  2979.   PerformSMTPCommand( 'QUIT', [ nil ] );
  2980.   repeat
  2981.     TheResult := GetSMTPServerResponse( TheReturnString );
  2982.     { Put result in progress and status line }
  2983.     AddProgressText( TheReturnString );
  2984.     ShowProgressText( TheReturnString + #13#10 );
  2985.   until (( GlobalAbortedFlag ) or ( TheResult <> TCPIP_STATUS_PRELIMINARY ));
  2986.   SMTPCommandInProgress := false;
  2987.   if ( GlobalAbortedFlag or ( TheResult <> TCPIP_STATUS_COMPLETED )) then
  2988.   begin
  2989.     { Do clever C formatting trick }
  2990.     TheReturnString :=
  2991.      DoCStyleFormat( 'EMail Host Connection Failed!' ,
  2992.       [ nil ] );
  2993.     { Put result in progress and status line }
  2994.     AddProgressText( TheReturnString );
  2995.     ShowProgressErrorText( TheReturnString );
  2996.     { Signal error }
  2997.     Result := False;
  2998.     { leave }
  2999.     exit;
  3000.   end
  3001.   else Result := true; { Signal no problem }
  3002. end;
  3003.  
  3004. procedure TPOP3SMTPComponent.UpdateGauge( BytesFinished , TotalToHandle : longint );
  3005. begin
  3006.   CCInetCCForm.UpdateMailGauge( BytesFinished , TotalToHandle );
  3007. end;
  3008.  
  3009. end.
  3010.