unit PXStuff;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ComCtrls, FileCtrl, Base64sup, Registry, ShellAPI, ActiveX, ShlObj,
  IniFiles, MMSystem, MailParser, Buttons, typInfo,
  Menus, ExtCtrls, StdCtrls,  ExtListView, PMLanguage;

type
  PAccountData = ^TAccountData;
  TAccountData = record
    Path, Name: string;
    FromMail, FromDesc, ReplyMail, ReplyDesc: string;
    POPServer, POPPort, POPUser, POPPass: string;
    SMTPServer, SMTPPort, KeepFilter, DeleteFilter: string;
    SMTPAuthenticate: boolean;
    SMTPUserName, SMTPPassword: string;
    Organization: string;
    DoSMTP, DoPOP, DoSMTPAfterPOP, StandardDownload, PromptPassword,
    ShowDownload : Byte; 
  end;
  PFolderData = ^TFolderData;
  TFolderData = record
    Path, Name: string;
    Filter: string;
    Outbox, Inbox, Drafts: Boolean;
  end;

  TIndexData= packed record
    Index:Int64;
    Delete:boolean;
    Read:boolean;
    Edit:boolean;
    Address:string[64];
    Subject:string[64];
    SDate:Tdatetime;
    STime:Tdatetime;
    Priority:string[6];
    Attach:integer;
    Position:Int64;
    Size:Int64;
  end;

resourcestring
  sMHHomepage = 'http://www.deemstone.com/';
  sVersion = 'beta'; //0.95
  sAppTitle = 'SMAIL';
  // Mail Header Options
  sDispositionNotification = 'Disposition-Notification-To';
  sReturnReceipt = 'Return-Receipt-To';
const
  //Version
  //  sInfoVersion = 'Version X-MMI "RoundAbout/RE"';
  // AH changed the slash into a hyphen.
  sInfoVersion = '1.0'; // DBR Do not change the last 2 IDs
  sXMailer = 'SMAIL ' + sInfoVersion;

  sZipOutFileName: string = ''; //ZipOut-Attachment-Filename
//  AttSection = 'www.rr4u.de'; //Section in WIN.INI for ZipOut-Attachment-File
  AttSection = 'hoogervorst.freehosting.net';
  Neuer_Kontakt: Boolean = false;
  FirstShow: Boolean = true;
  byGlobalSearchMode: Byte = 0;

  //TODO -oMjg:modify for html
  StandardMsgType: TMsgType = mtHtml;
  crHandCursor = 5;

  WM_TASKICON = WM_USER + 521;
  WM_PREVINSTRUN = WM_USER + 522;
  WM_GETFORMHANDLES = WM_USER + 523;
  WM_SPELLCHECKFINISHED = WM_USER + 524;

  { listview column info constants }
const
  ciSubject = 0;
  ciFrom = 1;
  ciTo = 2;
  ciDateTime = 3;
  ciSize = 4;
  ciLabel = 5;
  ciFileName = 6;

  { treenode stateindex constants }
const
  tnAccount = 1;
  tnFolder = 2;
  tnThrashBag = 3;
  tnAccounts = 4;
  tnRepository = 5;
  tnStationary = 6;
  tnStationaryFolder=7;


  { online session type }
type
  TOnlineTyp = Byte;
  TPXFolders = set of Byte;    
const
  otFetchMail = 1; // Fetch Mail from one Account
  otSendMail = 2; // Send Mails from one Account
  otGoOnline = 3; // Fetch / Send Mails from all Accounts
  otScheduled = 4;
  otFetchAll = 5; // Fetch Mails from all Accounts
  otSendAll = 6; // Send Mails from all Accounts
  otFetchSendOne = 7; // Fetch and send Mails from one Account //RR33
  otSendSelected = 8; //  Support for selective send.
  otSendReceipt =9;

  { download type }
type
  TDownloadType = Byte;

const
  dtDownloadAndDelete = 0;
  dtDeleteFromServer = 1;
  dtKeepOnServer = 2;
  dtDownloadWithoutDeleting = 3;

  { download protocol log type }
type
  TLogTyp = Byte;
  TFileSomething = procedure(dir : string; SearchRec : TSearchRec) of object;

const
  ltStatus = 1;
  ltSend = 2;
  ltReceive = 3;
  setSysFolders = [tnThrashBag, tnAccounts, tnRepository,  tnStationary];  // AH03
  setEditableFolders = [tnFolder, tnStationary];
  paMailEmptyEmail = 0;
  paMailCompleteEmail = 1;
  paMailAttachEmail = 2;

const
  CrLf = #13#10;

// AH03 Header macros
const
   iHmacros = 7;
   HMacros : array [0..iHmacros -1 ] of string = (
             ('%RECEIVER%'),
             ('%RECEIVERFULL%'),
             ('%SENDER%'),
             ('%SENDERNAME%'),
             ('%SENDERFULL%'),
             ('%ORGANIZATION%'),
             ('%SUBJECT%'));
var
////////////////////////////////////////////////////////
  AccountsNode, TrashNode, RepositoryNode, StationaryNode,
  ActiveAccount : TTreeNode;
  IndexFile,MailFile,TempMailFile: file of byte;
  sMailIndexFile,sMailFile:string;
  buf:PChar;
  IndexData:TIndexData;
  iPosition,iSize:integer;

  UseHtml:boolean=true;
  HaveAttach:Boolean=false;
  CurrentIndex:integer;
  FileMightBeInUse : boolean;
  bNewDoc:boolean=false;
  bEdit:boolean=true;
  sBackGround:AnsiString;
  bNewPic:boolean=false;
  sLinkMail:string='';
  sParamStr:string='';
  sAccountPath:string;
  FNode: TTreeNode;
  AddressInfo:TstringList;
///////////////////////////////////////////////////////
  CurrentEMail: TEMail;
  LangHolder : TLanguageHolder;

  DefaultLanguage: string;
  sTemporaryFolder: string;
  sTempMessageFile: olevariant;
  sAccountRootFolder: string;
  sSignatureFolder: string;
  sRepositoryFolder: string;
  sTrashFolder: string;

  sStationaryFolder : string; // AH03
  sToDoFolder : string;
  sTemplateFolder: string; //wipwap
  sTemplateFileName: string; //wipwap
  Dir:string;

  sSaveAsFolder: string;
  sProtocolFile: string;
  sAddressBookFolder: string;
  sTempNewMessageFile: string;
  sSettingsFile: string;
  sStandardAccountDataFile: string;
  sWriteNewMessage1, sWriteNewMessage2, sWriteNewMessage3: string;
  iParamCommand : integer;
  sWinTempFolder: string;
  sLabel1, sLabel2, sLabel3, sLabel4, sLabel5, sLabel6, sLabel7, sLabel8, sLabel9 : string;
  sVirusProg, sVirusParams, sMessageFile: string;
  bVirusMin, bVirusAutoScan: Boolean;
  bMakeProtocol, bShowTips, bAskToGoOffline: Boolean;
  bAskForDelFromServer, bFriendlyPrinter: Boolean;
  bGoOnlineAtStart, bStartAtWindowsStart, bEmptyTrashWhenExit,
    bEmptyRepositWhenExit, bClearSearchHisWhenExit: Boolean;
  // AHRK19 Removed bListMailsAtDownload...
  bScheduleC1, bScheduleC2, bScheduleC3, bScheduleC4, bScheduleC5,
    bCheckForStdEMail : Boolean;
  sScheduleS2, sScheduleS3: string;
  sTextViewer, sQuickViewer, sPicViewer: string;
  sLastAttSaveDir, sLastAttOpenDir: string;
  iActualTip, iMarkAsReadSec, iFontCharSet: Integer;
  iPanelsStyle : Integer;
  iLineBreakAt: integer;
  bHighlightQuoted: boolean;
  iSizeQuoted : integer;  // AH15 reintroduced...
  cColorQuoted, cBackColorQuoted: TColor;
  sQuoteStyles : string;
  sDUNConnection, sDUNUsername, sDUNPassword: string;
  bDUNAskForPassword, bDUNAutoQuit, bViewStatusAtEnd, bDUNNormalQuit: Boolean;
  iDUNAutoQuitTime, sScheduleS1: Integer;
  sSoundFile1, sSoundFile2, sSoundFile3: string;
  sAccountsCaption, sTrashBagCaption, sRepositoryCaption, sStationaryCaption : string;
  bShowCntInBrackets, bHideAnimations: Boolean;
  iAnimation : Integer; //AH15
  bIgnoreDipositRequest: boolean;
  bWarnBeforeDelToTrash, bWarnBeforeDelPermanent: boolean;
  bSelectFirstItem: boolean;
  bSelectLastItem: boolean;
  bAddToAddressBookWhenReply: boolean;
  iDoubleClickAction: integer;
  ColorScheme, LowColor, bDrawBK: Boolean;

  //============================================
  bNeedReceipt:boolean;
  bReceipt:integer;
  isReceipt:Boolean=false;

  //============================================


  iColorDepth: Integer;

  SaveMessage: Boolean;

  bStartMin: boolean; // -min Switch
  bFlatStyle: boolean;
  bUseDrafts: boolean; //Neue Mails im Entwürfe-Ordner speichern
  bUsePMBook: Boolean;
  bWarnOpen: Boolean; //Warnen vor .txt.vbs
  bShowDefaultAccount: Boolean;
  sDefaultAccount : string; // AH14...
  bAutoMarkReplied:Boolean; //RR26
  bUseColouredLabels: Boolean; //RR27a/AH04
  // AH16 Have to be here if all forms need to be
  // drawn with gradient.... Damn.
  actStartColor, actEndColor, actFontColor,
  inActStartColor, inActEndColor, inactFontColor,
  lblStartColor, lblEndColor, lblFontColor : TColor;
  bDitheredCaption : Boolean;
  bPlainColours : Boolean;
  // New introduced....
  iLVFontColour : TColor;
  iLVFontSize : integer;
  fsLVFontStyle : TFontStyles;
  sLVFontName : string;
  iLVBackGround : TColor;
  iLV2Icons : Integer;
  iAutoCompleteItems : Byte; // AHRK37
  iSubjectItems : Byte; //AHRK138
  iMessageItems : Byte; // AHRK139

const
  bSearchDate: Boolean = false;
  bSearchName: Boolean = false;
  MessageCount = 170; //RR27a/AH04

  //TODO -oMjg:All messages about translation
  Messages: array[0..MessageCount] of string = (
    'Account', //0
    'Garbage bin', //1
    'Repository',//2
    'New Account',//3
    'Outbox',//4
    'Inbox',//5
    'Draft',//6
    'New Folder',//7
    'Do you really want to remove the folder "%s"?',//8
    'Do you really want to remove the account "%s"?',//9
    'Unable to create folder, the folder "%s" already exists!',//10
    'To',//11
    'From',//12
    'The file "%s" already exists! Overwrite?',//13
    'Do you really want to remove the file "%s"',  //14AH02 Correction
    'RE:',//15
    'You wrote on %s:',//16
    'Hi %s on %s you wrote:',
    'No printer found!',//18
    'The Printer is busy. Please try again!',//19
    'Subject:',//20
    'From:',//21
    'To:',//22
    'Date:',//23
    'Page:',//24
    'End of message.',//25
    'Please, first create an account!',//26
    'Selected Account: %s',//27
    '%s of %s E-Mails unread',//28
    '%s Attachments',//29
    'Forwarded Message',//30
    'FWD:',
    'Redirected Message',
    'RED:',
    'Offline',
    'Connected to %s',//35
    'Online',
    'Please fill in your E-mail address.',
    '%s Addresses, %s selected',
    'You first have to make a new Addressbook.',
    'New Address',//40
    'Remove item "%s"?',
    'New Addressbook',
    'Title:',
    'The following characters are not allowed: \ / < > : ; , ? * " |  Please choose another name.',
    'Delete Addressbook "%s"?',//45
    'Are you sure you want to delete the addressbook "%s"?',
    'Rename Addressbook',
    'New signature',
    'Semicolon (;) is not allowed. Please choose other characters.',
    'The folder "%s" already exists. Please choose other name.',//50
    'Filters are only possible for Inboxes.',
    'To',
    'CC',
    'BCC',
    'Field',//55
    'Value',
    'You must fill in the receiver.',
    'There''s an error here.',
    '%s of %s E-Mails received.',
    'You haven''t received an e-mail yet.',//60
    '1 E-Mail sent.',
    '%s E-Mails sent.',
    'There are no e-mails to send.',
    'Starting Connection with %s...',
    'Sending account name and password...',//65
    'Receiving number of E-Mails...',
    'Fetching information about %s of %s E-Mails...',
    'Fetching %s of %s E-Mails...',
    'Deleting %s of %s E-Mails from Server...',
    'Closing Connection...',
    'Connecting...',
    'Sending information about E-Mails...',
    'Sending E-Mails...',
    'Waiting for confirmation...',
    'Search term "%s" not found.',//75
    'You need a monitor that supports over 256 colors. Continue?',
    'You can''t start SMAIL Mail from CDROM!',
    'The Address already exists in this Address book. Continue?',
    'No Automatic Connection',
    'Dial Up Adapter',//80
    'The Connection will be closed after %s minutes.',
    'Connection process aborted.',
    'Time Out!',
    '&Clear %s',
    'C&lear %s',//85
    'Lost connection with socket %s',
    'There was an error while connecting to %s.',
    '%s from %s',
    'Remove E-Mail "%s" from %s on the server?',
    'SMAIL is already sending or retrieving mails. Do you want to kill that process?',//90
    'Seperator',
    '>',
    'Receipt notification for "%s"',
    'This is a notification that the E-mail to %s from %s has been received',
    'This is a confirmation that the E-mail has been received %s.',//95
    '(No subject)',
    'Stationary',//97
    'Exported %s',	// 98
    'Edit Address',	// 99
    'MessageXX.txt',	// 100
    'Save address(es)',	// 101
    'Copy address(es) to: ',	// 102
    'Importing %s',	// 103
    'Please restart to load Addressbook',	// 104
    'Information',	// 105
    '&Cancel',	// 106
    '&Close',	// 107
    'Do you really want to clear the Favourites and the Autocomplete list?',	// 108
    'Confirm',	// 109
    'You can delete an address by pressing the CTRL button while holding the mousebutton.',	// 110
    '%s object(s)',	// 111
    'Subject',	// 112
    'Folder',	// 113
    'SMAIL is busy searching, please end the search action first!',	// 114
    'Searching...',	// 115
    'Search',	// 116
    'Copy e-mail to folder',	// 117
    'Move e-mail to folder',	// 118
    'Moving %s of %s',	// 119
    'Copying %s of %s',	// 120
    'Do you really want to remove these e-mails permanently?',	// 121
    'Deleting files',	// 122
    'Deleted: ',	// 123
    'Reply to %s, around %s:',	// 124
    '%d at %t O''Clock',	// 125
    'New Salutation',	// 126
    'Hello %f',	// 127
    'Do you want to use the example?',	// 128
    'Example',	// 129
    'You can only drag & drop one stationary!',	// 130
    'The sender requested a notification that you read this Mail.',	// 131
    'Send a Mail to the Sender?',	// 132
    'Don''t ask again.',	// 133
    'Do you really want to move these mails to the folder %s?',	// 134
    'The account %s has been set to default.',	// 135
    '%s E-Mails were imported to ',	// 136
    'Address',	// 137
    'Find Current date',	// 138
    'First Name Last Name <E-Mail>',	// 139
    'Addressbook',	// 140
    'Confirmation',	// 141
    'Date and time',	// 142
    'Label',	// 143
    'Size',	// 144
    '%s of %s E-Mails queued',	// 145 AH11
    'The file %s has two file extensions. Do you really want to execute the file??',
    'Receive e-mails for %s',	// 147 AH16
    'Send e-mails from %s',	// 148 AH16
    'Receive/Send e-mails from %s',	// 149 AH16
    'Details',	// 150
    'Category',
    'Description',
    'Priority',
    'Start date',
    'End date',	// 155
    'Finished',
    'Please enter the name of the new category',
    'Please enter the new name',
    'The following file(s) is/are in use: %s Please close those files first.',
    'Choose Program files',       // 160
    'Programs (*.exe, *.com)|*.exe;*.com|All Files (*.*)|*.*',
    'Choose sound files',
    'Sound files (*.wav)|*.wav|All files (*.*)|*.*',
    'Salutation-Manager',
    'Signature-Manager',	// 165
    'Salutation name',
    'Signature name',
    '168',
    '169',
    '170'	// 170
    ); // AH03 name for Stationary...


// general
function DoubleExtension(FileName: string): Boolean;
function KeyPressed(Key: Integer): Boolean;
function BolToStr(B: boolean): string;
function BrowseForFolder(Title: string; StartMenu: Boolean): string;
function FormatByteText(I: Integer): string;
function FileCopy(Progress: TProgressBar; SourceName, DestName: string): string;
procedure MoveTreeViewNode(const TreeView: TTreeView; Source, Target:
  TTreeNode);
function MakeValidDirName(Dir: string): string;
procedure CreateFolder(Dir: string);
procedure MoveFolder(OldDir, NewDir: string);
function GetParentFolder(Dir: string): string;
procedure DeleteFolder(Dir, TrashFileFolder: string);
function SetFileAttr(Filename: string; faReadOnly, faArchive, faHidden,
  faSystem: Boolean): Boolean;
function HexToInt(S: string): Integer;
function MHEncrypt(S: string): string;
function MHDecrypt(S: string): string;
function ClearFolder(S: string; var DoCheck : Boolean) : string;
function GetFileSize(Filename: string): Integer;
procedure PlaySound(Filename: string);
function GetMessageString(AIndex: integer): string;
procedure SetMessageString(AIndex: integer; AValue: string);
procedure SetMessageString4Q(AIndex: integer; AValue: string); //4Q=for quotes ;-)
function GetSystemDir: string;
function InStr(AStart: integer; AString, ASubString: string; ACompare: integer = 1): integer;
function GetAppPath: string;
function CompactPath(const APath: string; AWidth: integer; AHdc: HDC): string;
// more concrete
function CheckForPrevInstance: Boolean;
procedure ClearUpCheckForPrevInstance;
function CheckColorDepth: Boolean;
function CheckCDROMStart: Boolean;
procedure CheckForStandardEMailProgram;
procedure InitializePX;
procedure ClearUpPX;
function StyleToString( styles: TFontStyles ): string;
function StringToStyle( S: string ): TFontStyles;
//procedure SetPanels(astyles : integer);
function StringIndex(const SearchString: string; StrList: array of string): Integer; //AH03
function GetParsedTemplateString(sTemplateFileName, Rec, Subj: string): string; //wipwap
function GetFirstName(Rec: string): string;//wipwap
function GetLastName(Rec: string): string; //wipwap
function GetParsedString(Msg, Rec, Subj: string): string; //wipwap
function GetTreeByDirName(Node : TTreeNode;adir : string; ASet : TPXFolders) : TTreenode; // AH06
function IsTypeOfFolder(Node : TTreeNode; Aset : TPXFolders) : Boolean; //AH17
function WalkAccountChildren(AParent, StartNode : TTreeNode; FolderSet
  : TPXFolders) : TTreeNode; // AH16
function GetNodeDirName(AStartNode : TTreeNode)
  : string;
function GetSelectedAccountNode(Anode : TTreeNode) : TTreeNode;
procedure CreateGradientBitmap(StartPos: Integer; startcol,
    endcol : TColor; ACanvas:  TCanvas; ARect : TRect; border : integer = 0); //AH16
procedure DeleteItemListView(acolumn : integer; string1 : string); //AH17
procedure AddItemListView(afilename : string); // AHRK86
function FromOldAccountToNewAccount(FirstNode, SecondNode : TTreeNode)
   : boolean;
// AHRK26
procedure AddPop3Command(Anode : TTreeNode; var AstringList : TStringList);
procedure AddSMTPCommand(Anode : TTreeNode; var AstringList : TStringList;
  aMsgList : TStringList);
function GenerateName(prefix : string) : string;
// AHRK93--
function ShowProperties(hWndOwner: HWND; const afilename: string): Boolean;
function GetLongFilename( shortname: string ): string;
function PMRegistry : TLanguageHolder;
function GetFiles(directory, mask : string; attr : integer;
   af : TFileSomething; recursive : Boolean) : integer;
procedure AddItemToHistoryStrings(anitem : string; StL : TStrings; maxitems :
  integer; AddToTop : Boolean);
procedure SaveImageListToFile(afilename : string; anImageList : TImageList);

implementation

{$R PXStuff.res}

uses
  Main, FMStdMail, ParserSup;

var
  Mutex: THandle;
  TextFile: Text;
  MessageList: TStringList;



function DoubleExtension(FileName: string): Boolean;
var count, b: Byte;
  s: string;
begin
  s := ExtractFileName(FileName);
  count := 0;
  for b := 1 to length(s) do
  begin
    if s[b] = '.' then inc(count);
  end;
  Result := count > 1;
end;

function KeyPressed(Key: Integer): Boolean;
begin
  KeyPressed := (GetAsyncKeyState(Key) and $8000 <> 0);
end;


function GetFileSize(Filename: string): Integer;
var
  H: HFile;
begin
  Result := 0;
  try
    H := CreateFile(PChar(Filename), GENERIC_READ, 0, nil, OPEN_EXISTING,
      FILE_ATTRIBUTE_ARCHIVE, 0);
    if H <> 0 then begin
      Result := Windows.GetFileSize(H, nil);
      CloseHandle(H);
    end;
    if Result < 0 then
      Result := 0;
  except
  end;
end;

function BolToStr(B: boolean): string;
begin
  Result := IntToStr(Ord(B)); // AH16
end;

function FormatByteText(I: Integer): string;
var
  R: Real;
begin
  Result := 'n.a.';
  try
    R := I / 1024;
    if I = 0 then
      Result := '0 Byte'
    else if I < 1048576 then
      Result := FloatToStrF(R, ffNumber, 18, 1) + ' KB'
    else if I < 1073741824 then begin
      R := R / 1024;
      I := Round(R);
      if I < 10 then
        Result := FloatToStrF(R, ffNumber, 18, 1) + ' MB'
      else
        Result := IntToStr(I) + ' MB';
    end
    else begin
      I := Round(R / 1024 / 1024);
      Result := IntToStr(I) + ' GB';
    end;
    if (Result[Length(Result) - 3] = '0') and (Result[Length(Result) - 4] = ',')
    then
      Delete(Result, Length(Result) - 4, 2);
  except
  end;
end;

function BrowseForFolder(Title: string; StartMenu: Boolean): string;
var
  BrowseInfo: TBrowseInfo;
  pszName: array[0..MAX_PATH] of Char;
  IDL: PITEMIDLIST;
begin
  Result := '';
  try
    if SHGetSpecialFolderLocation(Application.Handle, CSIDL_PROGRAMS, IDL) <>
      NOERROR then
      IDL := nil;
    if not StartMenu then
      IDL := nil;
    with BrowseInfo do begin
      hwndOwner := Application.Handle;
      pidlRoot := IDL;
      pszDisplayName := @pszName;
      lpszTitle := PChar(Title);
      ulFlags := BIF_RETURNONLYFSDIRS;
      lpfn := nil;
    end;
    IDL := SHBrowseForFolder(BrowseInfo);
    if IDL <> nil then
      if SHGetPathFromIDList(IDL, @pszName) then
        Result := MakeValidDirName(pszName);
  except
  end;
end;

function FileCopy(Progress: TProgressBar; SourceName, DestName: string): string;
var
  S, D: file;
  Buffer: array[1..4096] of Byte;
  Counter: Integer;
  OrgFileMode: Byte;
  Attributes: Cardinal;
begin
  Result := '';
  Attributes := GetFileAttributes(PChar(SourceName));
  try
    OrgFileMode := FileMode;
    FileMode := 0;
    try
      AssignFile(S, SourceName);
      Reset(S, 1);
      AssignFile(D, DestName);
      Rewrite(D, 1);
      while not EoF(S) do begin
        BlockRead(S, Buffer, SizeOf(Buffer), Counter);
        BlockWrite(D, Buffer, Counter);
        if Assigned(Progress) then
          Progress.StepIt;
        Application.ProcessMessages;
      end;
    finally
      FileMode := OrgFileMode;
      try
        CloseFile(S);
        CloseFile(D);
      except
      end;
    end;
    SetFileAttributes(PChar(DestName), Attributes);
  except
    Result := 'An error occured while trying to copy ' + SourceName + ' to ' +
      DestName + '!';
  end;
end;

procedure MoveTreeViewNode(const TreeView: TTreeView; Source, Target:
  TTreeNode);
var
  Data: PFolderData;
  Node: TTreeNode;

  procedure CopySubNotes(Source, Target: TTreeNode);
  var
    I: Integer;
    Node: TTreeNode;
  begin
    for I := 0 to Source.Count - 1 do begin
      Node := TreeView.Items.AddChild(Target,
        GetPXTreeNodeName(Source.Item[I]));
      New(Data);
      Data^.Path := PFolderData(Target.Data)^.Path +
        GetPXTreeNodeName(Source.Item[I]) + '\';
      Data^.Name := PFolderData(Source.Item[I].Data)^.Name;
      Data^.Filter := PFolderData(Source.Item[I].Data)^.Filter;
      Data^.Inbox := PFolderData(Source.Item[I].Data)^.Inbox;
      Data^.Outbox := PFolderData(Source.Item[I].Data)^.Outbox;
      Data^.Drafts := PFolderData(Source.Item[I].Data)^.Drafts;
      Node.Data := Data;
      Node.ImageIndex := Source.Item[I].ImageIndex;
      Node.StateIndex := Source.Item[I].StateIndex;
      Node.SelectedIndex := Source.Item[I].SelectedIndex;
      if Source.Count > 0 then
        CopySubNotes(Source.Item[I], Node);
    end;
  end;

begin
  Node := TreeView.Items.AddChild(Target, GetPXTreeNodeName(Source));
  New(Data);
  Data^.Path := PFolderData(Source.Data)^.Path;
  Data^.Name := PFolderData(Source.Data)^.Name;
  Data^.Filter := PFolderData(Source.Data)^.Filter;
  Data^.Inbox := PFolderData(Source.Data)^.Inbox;
  Data^.Outbox := PFolderData(Source.Data)^.Outbox;
  Data^.Drafts := PFolderData(Source.Data)^.Drafts;
  Node.Data := Data;
  Node.ImageIndex := Source.ImageIndex;
  Node.StateIndex := Source.StateIndex;
  Node.SelectedIndex := Source.SelectedIndex;
  CopySubNotes(Source, Node);
  Source.Delete;
  Node.Expand(True);
  Node.Selected := True;
  TreeView.AlphaSort;
end;

function HexToInt(S: string): Integer;
var
  I, E, F, G: Integer;

  function DigitValue(C: Char): Integer;
  begin
    Result := 0;
    try
      case C of
        'A': Result := 10;
        'B': Result := 11;
        'C': Result := 12;
        'D': Result := 13;
        'E': Result := 14;
        'F': Result := 15;
      else
        Result := StrToIntDef(C, 0); //Ah17
      end;
    except
    end;
  end;

begin
  S := UpperCase(S);
  if S[1] = '$' then
    Delete(S, 1, 1);
  if S[2] = 'X' then
    Delete(S, 1, 2);
  E := -1;
  Result := 0;
  for I := Length(S) downto 1 do begin
    G := 1;
    for F := 0 to E do
      G := G * 16;
    Result := Result + (DigitValue(S[I]) * G);
    Inc(E);
  end;
end;

function MHEncrypt(S: string): string;
var
  I: Integer;
  T: string;
begin
  Result := '';
  if S = '' then
    Exit;
  T := IntToHex(Random(15) + 1, 1);
  T := T + IntToHex(Length(S), 2);
  for I := 1 to Length(S) do
    T := T + IntToHex(Ord(S[I]), 2);
  for I := 1 to Random(8) + 2 do
    T := T + IntToHex(Random(256), 2);
  T := T + IntToHex(Random(15) + 1, 1);
  S := '';
  for I := 1 to (Length(T) div 2) do
    S := S + Chr(HexToInt(T[I * 2 - 1] + T[I * 2]));
  S := Chr(Random(26) + 65) + StringToBase64(S);
  Result := '';
  for I := Length(S) downto 1 do
    Result := Result + S[I];
end;

function MHDecrypt(S: string): string;
var
  I, E: Integer;
  T: string;
begin
  Result := '';
  if S = '' then
    Exit;
  T := '';
  for I := Length(S) downto 1 do
    T := T + S[I];
  Delete(T, 1, 1);
  S := Base64ToString(T);
  T := '';
  for I := 1 to Length(S) do
    T := T + IntToHex(Ord(S[I]), 2);
  E := HexToInt(T[2] + T[3]);
  Delete(T, 1, 3);
  S := '';
  for I := 1 to E do
    S := S + Chr(HexToInt(T[I * 2 - 1] + T[I * 2]));
  Result := S;
end;

function MakeValidDirName(Dir: string): string;
begin
  if Dir[Length(Dir)] <> '\' then
    Dir := Dir + '\';
  Result := Dir;
end;

procedure CreateFolder(Dir: string);
begin
  ForceDirectories(Dir);
  if not DirectoryExists(Dir) then begin
    ShowMessage('Error creating folder ' + Dir);
    Halt;
  end;
end;

procedure MoveFolder(OldDir, NewDir: string);
begin
  if OldDir[Length(OldDir)] = '\' then
    Delete(OldDir, Length(OldDir), 1);
  if NewDir[Length(NewDir)] = '\' then
    Delete(NewDir, Length(NewDir), 1);
  RenameFile(OldDir, NewDir);
end;

function GetParentFolder(Dir: string): string;
var
  I: Integer;
begin
  if Dir[Length(Dir)] = '\' then
    Delete(Dir, Length(Dir), 1);
  I := Length(Dir);
  while Dir[I] <> '\' do
    Dec(I);
  Delete(Dir, I + 1, Length(Dir) - I);
  if Pos('\', Dir) = 0 then
    Dir := Dir + '\';
  Result := Dir;
end;

procedure DeleteFolder(Dir, TrashFileFolder: string);
var
  SL: TStringList;
  I: Integer;

  procedure DeleteAllFiles(Dir: string);
  var
    SearchRec: TSearchRec;
    Found: Integer;
  begin
    Found := FindFirst(Dir + '*.*', faAnyFile, SearchRec);
    while Found = 0 do begin
      SetFileAttr(Dir + SearchRec.Name, False, True, False, False);
      if TrashFileFolder <> '' then
        CopyFile(PChar(Dir + SearchRec.Name), PChar(TrashFileFolder +
          SearchRec.Name), False);
      DeleteFile(Dir + SearchRec.Name);
      Found := FindNext(SearchRec);
    end;
    FindClose(SearchRec);
  end;

  procedure RecurseDirs(Dir: string);
  var
    SearchRec: TSearchRec;
    Found: Integer;
  begin
    Found := FindFirst(Dir + '*.*', $37, SearchRec);
    while Found = 0 do begin
      if (SearchRec.Attr and $10 = $10) and (SearchRec.Name <> '.') and
        (SearchRec.Name <> '..') then begin
        SL.Add(Dir + SearchRec.Name + '\');
        DeleteAllFiles(Dir + SearchRec.Name + '\');
        RecurseDirs(Dir + SearchRec.Name + '\');
      end;
      Found := FindNext(SearchRec);
    end;
    FindClose(SearchRec);
  end;

begin
  SL := TStringList.Create;
  SL.Add(Dir);
  DeleteAllFiles(Dir);
  RecurseDirs(Dir);
  for I := SL.Count - 1 downto 0 do
    RemoveDir(SL.Strings[I]);
  SL.Free;
end;

function SetFileAttr(Filename: string; faReadOnly, faArchive, faHidden,
  faSystem: Boolean): Boolean;
var
  I: Integer;
begin
  I := 0;
  if faReadOnly then
    I := I or FILE_ATTRIBUTE_READONLY;
  if faArchive then
    I := I or FILE_ATTRIBUTE_ARCHIVE;
  if faHidden then
    I := I or FILE_ATTRIBUTE_HIDDEN;
  if faSystem then
    I := I or FILE_ATTRIBUTE_SYSTEM;
  Result := SetFileAttributes(PChar(Filename), I);
end;


function ClearFolder(S: string; var DoCheck : Boolean) : string;
var
  Found: Integer;
  SearchRec: TSearchRec;
  filestream : TFileStream;
begin
  result := '';
  // AHRJ extra condition (minus extra faDirectory).
  Found := FindFirst(S + '*.*', faAnyFile - faDirectory, SearchRec);
  while Found = 0 do
  begin
    if DoCheck then
    begin
      try
        filestream:= TFilestream.create(s + SearchRec.Name,
         fmOpenRead or fmShareExclusive);
        filestream.free;
        SetFileAttr(S + SearchRec.Name, False, True, False, False);
        DeleteFile(S + SearchRec.Name);
      except
        result := result + s + SearchRec.Name + #13#10;
      end;
    end
    else
    begin
      SetFileAttr(S + SearchRec.Name, False, True, False, False);
      DeleteFile(S + SearchRec.Name);
    end;
    Found := FindNext(SearchRec);
  end;
  DoCheck := (Result <> '');
  FindClose(SearchRec);
end;

procedure PlaySound(Filename: string);
begin
  if FileExists(Filename) then
    SndPlaySound(PChar(Filename), SND_ASYNC or SND_NODEFAULT);
end;


function CheckForPrevInstance: Boolean;
var
  S: string;
  H: HWnd;
  I : Integer;
  procedure WriteFile;
  begin
    try
      AssignFile(TextFile, sTempNewMessageFile);
      Rewrite(TextFile);
      WriteLn(TextFile, sWriteNewMessage1);
      WriteLn(TextFile, sWriteNewMessage2);
      WriteLn(TextFile, sWriteNewMessage3);
      CloseFile(TextFile);
    except
    end;
  end;
begin
  Result := False;
//  sTempNewMessageFile := GetAppPath + 'tmpmsgad.tmp';
  sTempNewMessageFile := GetAppPath + 'tmpmsgRR.tmp';
  sWriteNewMessage1 := '';
  sWriteNewMessage2 := '';
  sWriteNewMessage3 := '';
  // AHRK16 Param count > 0
  iParamCommand := paMailEmptyEMail;
  if ParamCount > 0 then
  begin
    if CompareText(ParamStr(1), '-newmail') = 0 then
    begin
      // AHRK13
      ParseMailto(ParamStr(2), sWriteNewMessage1, sWriteNewMessage2, sWriteNewMessage3);
      // Opera doesn't pass the subject in the Commandline ;-/
      if sWriteNewMessage1 = '' then
        iParamCommand := paMailEmptyEMail
      else
        iParamCommand := paMailCompleteEMail;
    end
    else
    begin
      // AHRK16
      for i := 1 to ParamCount do
      begin
        // Easy is as easy does.
        // RRRK100
        if FileExists(ExtractShortPathName(ParamStr(i))) then
          sWriteNewMessage1 := sWriteNewMessage1 + ExtractShortPathName(ParamStr(i))
            + ',';
      end;
      // AHRK16
      if Trim(sWriteNewMessage1) <> '' then
      begin
        Delete(sWriteNewMessage1, Length(sWriteNewMessage1), 1);
        iParamCommand := paMailAttachEmail;
      end;
    end;
  end;

  S := 'SMAIL Previous Instance';
  Mutex := CreateMutex(nil, True, PChar(S));
  if (Mutex <> 0) and (GetLastError = 0) then begin
    Result := True;
  end
  else
  begin
    H := FindWindow(nil, PChar(sAppTitle));
    if H <> 0 then
    begin
      // AH13 --- Normal processing, send message 0/1 depending on
      //          body text....
      case iParamCommand of
        paMailEmptyEmail : SendMessage(H, WM_PREVINSTRUN, iparamcommand, 0);
        paMailCompleteEmail :
        begin
          WriteFile;
          sWriteNewMessage1 := '';
          sWriteNewMessage2 := '';
          sWriteNewMessage3 := '';
          SendMessage(H, WM_PREVINSTRUN, iparamcommand, 0);
        end;
        paMailAttachEmail :
        begin
          WriteFile;
          SendMessage(H, WM_PREVINSTRUN, iparamcommand, 0);
        end;
      end;
      // AH13 Ends here...
    end;
  end;
end;


procedure ClearUpCheckForPrevInstance;
begin
  if Mutex <> 0 then
    CloseHandle(Mutex);
  Mutex := 0;
end;

function CheckColorDepth: Boolean;
var
  DC: HDC;
begin
  Result := True;
  DC := GetDC(GetDesktopWindow);
  iColorDepth := GetDeviceCaps(DC, BITSPIXEL) * GetDeviceCaps(DC, PLANES);
  if iColorDepth < 8 then
    LowColor := True
  else
    LowColor := False;
  if ColorToRGB(clBtnFace) = clSilver then
    ColorScheme := False
  else
    ColorScheme := True;
end;

procedure CheckForStandardEMailProgram;
const
  DummyArray: array[1..4] of Byte = (2, 0, 0, 0);
var
  NativeReg: TRegistry;
  S: string;
begin
  if bCheckForStdEMail = False then
    Exit;
  S := '"' + Application.ExeName + '" -newmail "%1"';
  NativeReg := TRegistry.Create;
  with NativeReg do begin
    RootKey := HKEY_CLASSES_ROOT;
    OpenKey('mailto\shell\open\command', True);
    if CompareText(ReadString(''), S) <> 0 then begin
      StdMailForm := TStdMailForm.Create(Application);
      if Assigned(LangHolder) then
      begin
        if LangHolder.Language <> '' then
            LangHolder.Translate([StdMailForm]);
      end;

      if StdMailForm.ShowModal = mrYes then begin
        WriteString('', S);
        CloseKey;
        OpenKey('mailto\DefaultIcon', True);
        WriteString('', '"' + Application.ExeName + '",0');
        CloseKey;
        RootKey := HKEY_LOCAL_MACHINE;
        OpenKey('SOFTWARE\Clients\Mail', True);
        WriteString('', 'SMAIL');
        CloseKey;
        OpenKey('SOFTWARE\Clients\Mail\SMAIL', True);
        WriteString('', 'SMAIL');
        CloseKey;
        OpenKey('SOFTWARE\Clients\Mail\SMAIL\Protocols\mailto', True);
        WriteString('', 'URL:MailTo Protocol');
        WriteBinaryData('Edit Flags', DummyArray, 4);
        WriteString('URL Protocol', '');
        CloseKey;
        OpenKey('SOFTWARE\Clients\Mail\SMAIL\Protocols\mailto\DefaultIcon', True);
        WriteString('', '"' + Application.ExeName + '",0');
        CloseKey;
        OpenKey('SOFTWARE\Clients\Mail\SMAIL\Protocols\mailto\shell\open\command', True);
        WriteString('', S);
        CloseKey;
        OpenKey('SOFTWARE\Clients\Mail\SMAIL\shell\open\command', True);
        WriteString('', '"' + Application.ExeName + '"');
      end;
      bCheckForStdEMail := not StdMailForm.CheckBox1.Checked;
      StdMailForm.Free;
    end;
    CloseKey;
    Free;
  end;
  Application.ProcessMessages;
end;

function CheckCDROMStart: Boolean;
begin
  Result := True;
  if GetDriveType(PChar(Application.ExeName[1] + ':\')) = DRIVE_CDROM then begin
    MessageDlg(GetMessageString(77), mtError, [mbOK], 0);
    Result := False;
  end;
end;

function GetSystemDir: string;
var
  A: array[0..MAX_PATH] of Char;
  l: integer;
begin
  l := GetSystemDirectory(A, MAX_PATH);
  Result := MakeValidDirName(Copy(string(A), 1, l));
end;

function GetAppPath: string;
begin
  Result := MakeValidDirName(ExtractFilePath(Application.ExeName));
end;


//
procedure InitializePX;
var
  S, M: string;
  NativeReg: TRegistry;
  IniFile: TIniFile;
  A: array[0..MAX_PATH] of Char;
  i: integer;
begin
  Application.Title := sAppTitle;
  Randomize;
  PrepareBase64Support;

  ////////////////////Create folders and  configration files////////////////////
  S := LowerCase(GetAppPath);
  sAccountRootFolder := S + 'Mail\';////
  CreateFolder(sAccountRootFolder);

  sTemplateFolder := S + 'Setting\'; //wipwap

  sTemporaryFolder := sTemplateFolder + 'Temp\';
  CreateFolder(sTemporaryFolder);
  sTempMessageFile := sTemporaryFolder + 'PMMsgRR.txt';

  CreateFolder(sTemplateFolder);
  sProtocolFile := sTemplateFolder+ 'ProtocolAH.txt';
  sSettingsFile := sTemplateFolder + 'SettingsAH.ini';
  sStandardAccountDataFile := sTemplateFolder + 'DefaultAH.ini';
  sMessageFile := sTemplateFolder+ 'MessagesAH.txt';


  sAddressBookFolder := sTemplateFolder + 'Address\';
  CreateFolder(sAddressBookFolder);
  sSignatureFolder := sTemplateFolder+ 'Signat\';
  CreateFolder(sSignatureFolder);
  sSaveAsFolder := sTemplateFolder+ 'Archive\';
  CreateFolder(sSaveAsFolder);


  ////////////////////Create folders and  configration files////////////////////
  MessageList := TStringList.Create;
  if FileExists(sMessageFile) then
  begin
    MessageList.LoadFromFile(sMessageFile);
    if MessageList.Count -1 <> MessageCount then
    begin
      I := 0;
      while FileExists(S + 'messages' + IntToStr(I) + '.bak') do
       Inc(I);
      M := 'The current messages file is not up-to-date.' + CRLf +
        'If you''re using a foreign version, please' + CRLF +
        'use the messages file included with the release.' + CRLF + CRLF +
        'SMAIL will now back-up the existing messages file to ' + crlf
        + ExtractFileName(S + 'messages' + IntToStr(I) + '.bak') + crlf +
        'and create a new messages file.';
      Application.MessageBox(PChar(M + ExtractFileName(s)),
        PChar('SMAIL'), MB_OK + MB_ICONINFORMATION);
      RenameFile(sMessageFile, S + 'messages' + IntToStr(I) + '.bak');
      MessageList.Clear;
      for i := 0 to MessageCount do
         MessageList.Add(Messages[i]);
    end;
  end
  else
    for i := 0 to MessageCount do
       MessageList.Add(Messages[i]);


  GetTempPath(MAX_PATH, A);
  sWinTempFolder := MakeValidDirName(A);
  // Registry


  IniFile := TIniFile.Create(sSettingsFile);
  with IniFile do begin
    bMakeProtocol := ReadBool('Settings', 'Protocol', True);
    bShowTips := ReadBool('Settings', 'ShowTipsOnStartUp', True);
    iActualTip := ReadInteger('Settings', 'ActualTip', 0);
    iFontCharSet := ReadInteger('Settings', 'FontCharSet', 0);
    bAskToGoOffline := ReadBool('Settings', 'AskToGoOffline', False);
    sVirusProg := ReadString('Settings', 'VirusScanner', '');
    sVirusParams := ReadString('Settings', 'ScannerParameter', '');
    bVirusMin := ReadBool('Settings', 'RunScannerMinimized', True);
    bVirusAutoScan := ReadBool('Settings', 'VirusAutoScan', True);
    sTextViewer := ReadString('Settings', 'TextViewer', 'notepad.exe');
    bNeedReceipt := ReadBool('Settings', 'NeedReceipt', false);
    bReceipt:= ReadInteger('Settings', 'Receipt', 0);


    // AHRK135 -- Don't do this anymore.... Bad. Bad. Bad!
    //  --> sQuickViewer := ReadString('Settings', 'QuickViewer', GetSystemDir +
    //  --> 'viewers\Quikview.exe');
    // Additionally, sQuickViewer is now closely associated with
    // 'iDoubleClickAction'!
    iDoubleClickAction := ReadInteger('Settings', 'DblClickAction', 1);
    sQuickViewer := ReadString('Settings', 'QuickViewer', '');
    // AHRK135 -- Make sure this thing exists!
    if sQuickViewer <> '' then
    begin
      if not FileExists(sQuickViewer) then
      begin
        sQuickViewer := '';
        iDoubleClickAction := iDoubleClickAction
          * Ord(not (iDoubleClickAction = 1));
      end;
    end;
    sPicViewer := ReadString('Settings', 'PicViewer', '');
    bAskForDelFromServer := ReadBool('Settings', 'AskForDelFromServer', False);
    bGoOnlineAtStart := ReadBool('Settings', 'GoOnlineAtStart', False);
    bEmptyTrashWhenExit := ReadBool('Settings', 'EmptyTrashWhenExit', False);
    bEmptyRepositWhenExit := ReadBool('Settings', 'EmptyRepositWhenExit',
      False);
    bClearSearchHisWhenExit := ReadBool('Settings', 'ClearSearchWhenExit',
      False);

    sLabel1 := ReadString('Settings', 'MLabel1', 'Label 1');
    sLabel2 := ReadString('Settings', 'MLabel2', 'Label 2');
    sLabel3 := ReadString('Settings', 'MLabel3', 'Label 3');
    sLabel4 := ReadString('Settings', 'MLabel4', 'Label 4');
    sLabel5 := ReadString('Settings', 'MLabel5', 'Label 5');
    sLabel6 := ReadString('Settings', 'MLabel6', 'Label 6');
    sLabel7 := ReadString('Settings', 'MLabel7', 'Label 7');
    sLabel8 := ReadString('Settings', 'MLabel8', '«');
    sLabel9 := ReadString('Settings', 'MLabel9', '»');

    bAutoMarkReplied := ReadBool('Settings', 'AutoMarkReplied', False);
    bUseColouredLabels := ReadBool('Settings', 'UseColouredLabels', True); //RR27a/AH04
    iPanelsStyle := ReadInteger('Settings', 'PanelsStyle', 0);

    iLineBreakAt := ReadInteger('Settings', 'LineBreakAt', 75);
    if iLineBreakAt < 40 then iLineBreakAt := 40;   //RR02B
    if iLineBreakAt >=255 then iLineBreakAt := 255; //RR02b


    iMarkAsReadSec := ReadInteger('Settings', 'MarkAsReadSec', 5);
    sLastAttSaveDir := ReadString('Settings', 'LastAttSaveDir', '');
    sLastAttOpenDir := ReadString('Settings', 'LastAttOpenDir', '');
    bFriendlyPrinter := ReadBool('Settings', 'FriendlyPrinter', True);
    // AHRK19
    // bListMailsAtDownload := ReadBool('Settings', 'ListMailsAtDownload', True);
    bCheckForStdEMail := ReadBool('Settings', 'CheckForStdEMail', True);
    bScheduleC1 := ReadBool('Settings', 'ScheduleC1', False);
    bScheduleC2 := ReadBool('Settings', 'ScheduleC2', False);
    bScheduleC3 := ReadBool('Settings', 'ScheduleC3', False);
    bScheduleC4 := ReadBool('Settings', 'ScheduleC4', False);
    bScheduleC5 := ReadBool('Settings', 'ScheduleC5', False);
    sScheduleS1 := ReadInteger('Settings', 'ScheduleS1', 60);
    sScheduleS2 := ReadString('Settings', 'ScheduleS2', '04:20');
    sScheduleS3 := ReadString('Settings', 'ScheduleS3', '22:20');
    bViewStatusAtEnd := ReadBool('Settings', 'ViewStatusAtEnd', True);
    bSelectFirstItem := ReadBool('Settings', 'SelectFirstItem', False);
    bSelectLastItem := ReadBool('Settings', 'SelectLastItem', False);
    bFlatStyle := ReadBool('Settings', 'FlatStyle', False);
    bUseDrafts := ReadBool('Settings', 'UseDrafts', False);
    bUsePMBook := ReadBool('Settings', 'UsePMBook', True);
    bWarnOpen := ReadBool('Settings', 'WarnOpen', True);
    bShowDefaultAccount := ReadBool('Settings', 'ShowDefaultAccount', False);
    sDefaultAccount :=  ReadString('Settings', 'DefaultAccount', ''); // AH14
    bShowCntInBrackets := ReadBool('Settings', 'ShowCountInBrackets', False);
    bAddToAddressBookWhenReply := ReadBool('Settings', 'AddToABWhenReply',
      true);
    bIgnoreDipositRequest := ReadBool('Settings', 'IgnoreDiposit', false);
    bWarnBeforeDelToTrash := ReadBool('Settings', 'WarnDelToTrash', true);
    bWarnBeforeDelPermanent := ReadBool('Settings', 'WarnDelPermanent', true);
    // AH16
    actStartColor := TColor(ReadInteger('Settings', 'ActStartColor', clBlack));
    actEndColor := TColor(ReadInteger('Settings', 'ActEndColor', clInfoBK));
    actFontColor := TColor(ReadInteger('Settings', 'ActFontColor', clWhite));
    inActStartColor := TColor(ReadInteger('Settings', 'inActStartColor',
      clBlack));
    inActEndColor := TColor(ReadInteger('Settings', 'inActEndColor',
      clInActivecaption));
    inactFontColor := TColor(ReadInteger('Settings', 'InActFontColor',
      clWhite));
    lblStartColor := TColor(ReadInteger('Settings', 'LabelStartColor', clBtnShadow));
    lblEndColor := TColor(ReadInteger('Settings', 'LabelEndColor', clInfoBk));
    lblFontColor := TColor(ReadInteger('Settings', 'LabelFontColor', clWhite));
    bPlainColours := ReadBool('Settings', 'PlainColours', False);
    bDitheredCaption := ReadBool('Settings', 'DitheredCaption', True);
    iAutoCompleteItems :=
      Byte(ReadInteger('Settings', 'AutoCompleteItems', 10));
    //AHRK138
    iSubjectItems := Byte(ReadInteger('Settings', 'SubjectHistoryItems', 10));
    // AHRK139    
    iMessageItems := Byte(ReadInteger('Settings', 'MessageHistoryItems', 10));

    iDUNAutoQuitTime := ReadInteger('DUN', 'AutoQuitTime', 15);
    bDUNAutoQuit := ReadBool('DUN', 'AutoQuit', False);
    sDUNConnection := ReadString('DUN', 'Connection', '');
    sDUNUsername := ReadString('DUN', 'Username', '');
    sDUNPassword := MHDecrypt(ReadString('DUN', 'Password', ''));
    bDUNAskForPassword := ReadBool('DUN', 'AskForPassword', False);
    bDUNNormalQuit := ReadBool('DUN', 'DUNNormalQuit', False);

    sSoundFile1 := ReadString('Sound', 'SoundFile1', S + 'newmail.wav');
    sSoundFile2 := ReadString('Sound', 'SoundFile2', S + 'error.wav');
    sSoundFile3 := ReadString('Sound', 'SoundFile3', S + 'status.wav');

    bHideAnimations := ReadBool('Style', 'HideAnimations', False);
    iAnimation := ReadInteger('Style', 'Animation', 0); // AH15
    bHighlightQuoted := ReadBool('Style', 'HighlightQuoted', False);
    iSizeQuoted := ReadInteger('Style', 'QuotedSize', 8);
    cColorQuoted := TColor(ReadInteger('Style', 'QuotedColor', clWindowText));
    cBackColorQuoted := TColor(ReadInteger('Style', 'QuotedColorBack', clInfoBk));
    sQuoteStyles := ReadString('Style', 'QuoteStyles', '[]');

    iLVFontColour := TColor(ReadInteger('ListView1', 'FontColor', clBlack));
    iLVFontSize := ReadInteger('ListView1', 'FontSize', 8);
    sLVFontName := ReadString('ListView1', 'FontName', 'MS Sans Serif');
    fsLVFontStyle := TFontStyles(Byte(ReadInteger('ListView1', 'FontStyle',
      Byte(0))));

    iLVBackGround := TColor(ReadInteger('ListView1', 'BackGround', clinfoBk));
    iLV2Icons := Cardinal(ReadInteger('ListView2', 'IconSize',
      SHGFI_LARGEICON));

    DefaultLanguage := ReadString('Settings','DefaultLanguage','');
    if DefaultLanguage <> '' then
    begin
      if FileExists(sTemplateFolder + DefaultLanguage + '.lng') then
        LangHolder.Language := DefaultLanguage
      else
        DefaultLanguage := ''; // Make sure it's empty here
    end;
    Free;
  end;
  //Stuff
  Screen.Cursors[crHandCursor] := LoadCursor(hInstance, 'PX400');
  NativeReg := TRegistry.Create;

  with NativeReg do begin
    RootKey := HKEY_LOCAL_MACHINE;
    OpenKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Run', True);
    bStartAtWindowsStart := ValueExists('SMAIL');
    CloseKey;
    Free;
  end;

  //TEMail
  CurrentEMail := TEMail.Create;
  SaveMessage := False;
end;

procedure ClearUpPX;
var
  NativeReg: TRegistry;
  IniFile: TIniFile;
  s : Boolean;
begin
  IniFile := TIniFile.Create(sSettingsFile);
  with IniFile do begin
    WriteBool('Settings', 'Protocol', bMakeProtocol);
    WriteBool('Settings', 'ShowTipsOnStartUp', bShowTips);
    WriteInteger('Settings', 'ActualTip', iActualTip);
    WriteBool('Settings', 'AskToGoOffline', bAskToGoOffline);
    WriteString('Settings', 'VirusScanner', sVirusProg);
    WriteString('Settings', 'ScannerParameter', sVirusParams);
    WriteBool('Settings', 'RunScannerMinimized', bVirusMin);
    WriteBool('Settings', 'VirusAutoScan', bVirusAutoScan);
    WriteString('Settings', 'TextViewer', sTextViewer);
    WriteString('Settings', 'QuickViewer', sQuickViewer);
    WriteString('Settings', 'PicViewer', sPicViewer);

    WriteInteger('Settings', 'Receipt', bReceipt);
    WriteBool('Settings', 'NeedReceipt', bNeedReceipt);


    WriteBool('Settings', 'AskForDelFromServer', bAskForDelFromServer);
    WriteBool('Settings', 'CheckForStdEMail', bCheckForStdEMail);
    // AHRK9
    // WriteBool('Settings', 'ListMailsAtDownload', bListMailsAtDownload);

    WriteString('Settings', 'MLabel1', sLabel1);
    WriteString('Settings', 'MLabel2', sLabel2);
    WriteString('Settings', 'MLabel3', sLabel3);
    WriteString('Settings', 'MLabel4', sLabel4);
    WriteString('Settings', 'MLabel5', sLabel5);
    WriteString('Settings', 'MLabel6', sLabel6);
    WriteString('Settings', 'MLabel7', sLabel7);
    WriteString('Settings', 'MLabel8', sLabel8);
    WriteString('Settings', 'MLabel9', sLabel9);

    WriteInteger('Settings', 'PanelsStyle', iPanelsStyle);
    if iLineBreakAt >= 255 then iLineBreakAt := 255; //RR02b
    WriteInteger('Settings', 'LineBreakAt', iLineBreakAt);
    WriteInteger('Settings', 'MarkAsReadSec', iMarkAsReadSec);
    WriteString('Settings', 'LastAttSaveDir', sLastAttSaveDir);
    WriteString('Settings', 'LastAttOpenDir', sLastAttOpenDir);


    WriteBool('Settings', 'FriendlyPrinter', bFriendlyPrinter);
    WriteBool('Settings', 'GoOnlineAtStart', bGoOnlineAtStart);
    WriteBool('Settings', 'EmptyTrashWhenExit', bEmptyTrashWhenExit);
    WriteBool('Settings', 'EmptyRepositWhenExit', bEmptyRepositWhenExit);
    WriteBool('Settings', 'ClearSearchWhenExit', bClearSearchHisWhenExit);
    WriteBool('Settings', 'ScheduleC1', bScheduleC1);
    WriteBool('Settings', 'ScheduleC2', bScheduleC2);
    WriteBool('Settings', 'ScheduleC3', bScheduleC3);
    WriteBool('Settings', 'ScheduleC4', bScheduleC4);
    WriteBool('Settings', 'ScheduleC5', bScheduleC5);
    WriteInteger('Settings', 'ScheduleS1', sScheduleS1);
    WriteString('Settings', 'ScheduleS2', sScheduleS2);
    WriteString('Settings', 'ScheduleS3', sScheduleS3);

    WriteInteger('DUN', 'AutoQuitTime', iDUNAutoQuitTime);
    WriteBool('DUN', 'AutoQuit', bDUNAutoQuit);
    WriteString('DUN', 'Connection', sDUNConnection);
    WriteString('DUN', 'Username', sDUNUsername);
    WriteString('DUN', 'Password', MHEncrypt(sDUNPassword));
    WriteBool('DUN', 'AskForPassword', bDUNAskForPassword);
    WriteBool('Settings', 'ViewStatusAtEnd', bViewStatusAtEnd);
    WriteString('Sound', 'SoundFile1', sSoundFile1);
    WriteString('Sound', 'SoundFile2', sSoundFile2);
    WriteString('Sound', 'SoundFile3', sSoundFile3);
    WriteBool('DUN', 'DUNNormalQuit', bDUNNormalQuit);
    WriteString('Captions', 'Accounts', sAccountsCaption);
    WriteString('Captions', 'TrashBag', sTrashBagCaption);
    WriteString('Captions', 'Repository', sRepositoryCaption);
    WriteBool('Settings', 'ShowCountInBrackets', bShowCntInBrackets);
    WriteBool('Settings', 'AddToABWhenReply', bAddToAddressBookWhenReply);
    WriteBool('Settings', 'IgnoreDiposit', bIgnoreDipositRequest);
    WriteBool('Settings', 'WarnDelToTrash', bWarnBeforeDelToTrash);
    WriteBool('Settings', 'WarnDelPermanent', bWarnBeforeDelPermanent);
    WriteInteger('Settings', 'DblClickAction', iDoubleClickAction);

    WriteBool('Style', 'HideAnimations', bHideAnimations);
    WriteInteger('Style', 'Animation', iAnimation); // AH15
    WriteBool('Style', 'HighlightQuoted', bHighlightQuoted);
    WriteInteger('Style', 'QuotedSize', iSizeQuoted);
    WriteInteger('Style', 'QuotedColor', Integer(cColorQuoted));
    WriteInteger('Style', 'QuotedColorBack', Integer(cBackColorQuoted));

    WriteString('Style', 'QuoteStyles', sQuoteStyles);

    WriteBool('Settings', 'SelectFirstItem', bSelectFirstItem);
    WriteBool('Settings', 'FlatStyle', bFlatStyle);
    WriteBool('Settings', 'UseDrafts', bUseDrafts);
    WriteBool('Settings', 'UsePMBook', bUsePMBook);
    WriteBool('Settings', 'WarnOpen', bWarnOpen);
    WriteBool('Settings', 'ShowDefaultAccount', bShowDefaultAccount);

    WriteString('Settings', 'DefaultAccount', sDefaultAccount); // AH14

    WriteBool('Settings', 'AutoMarkReplied', bAutoMarkReplied);
    WriteBool('Settings', 'SelectLastItem', bSelectLastItem);
    WriteBool('Settings', 'UseColouredLabels', bUseColouredLabels); //RR27a/AH04
    WriteInteger('Settings', 'AutoCompleteItems', iAutoCompleteItems); //AHRK37
    WriteInteger('Settings', 'SubjectHistoryItems', iSubjectItems); //AHRK138
    WriteInteger('Settings', 'MessageHistoryItems', iMessageItems); // AHRK139
    // AH16
    WriteInteger('Settings', 'ActStartColor', Integer(actStartColor));
    WriteInteger('Settings', 'ActEndColor',  Integer(actEndColor));
    WriteInteger('Settings', 'ActFontColor', Integer(actFontColor));
    WriteInteger('Settings', 'inActStartColor', Integer(inActStartColor));
    WriteInteger('Settings', 'inActEndColor', Integer(inActEndColor));
    WriteInteger('Settings', 'InActFontColor',Integer(inactFontColor));
    WriteInteger('Settings', 'LabelStartColor', Integer(lblStartColor));
    WriteInteger('Settings', 'LabelEndColor', Integer(lblEndColor));
    WriteInteger('Settings', 'LabelFontColor', Integer(lblFontColor));
    WriteBool('Settings', 'PlainColours', bPlainColours);
    WriteBool('Settings', 'DitheredCaption', bDitheredCaption);
    WriteInteger('ListView1', 'BackGround', iLVFontColour);
    WriteString('ListView1', 'FontName', sLVFontName);
    WriteInteger('ListView1', 'FontSize', iLVFontSize);
    WriteInteger('ListView1', 'FontColor', iLVFontColour);
    WriteInteger('ListView1', 'FontStyle', Byte(fsLVFontStyle));
    WriteInteger('ListView1', 'BackGround', iLVBackGround);
    WriteInteger('ListView2', 'IconSize', iLV2Icons);
    WriteString('Settings','DefaultLanguage', DefaultLanguage);
    Free;
  end;
  NativeReg := TRegistry.Create;
  with NativeReg do begin
    RootKey := HKEY_LOCAL_MACHINE;
    OpenKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Run', True);
    if bStartAtWindowsStart then begin
      WriteString('SMAIL', '"' + Application.ExeName + '" -min');
    end
    else begin
      DeleteValue('SMAIL');
    end;
    CloseKey;
    Free;
  end;

  MessageList.SaveToFile(sMessageFile);
  MessageList.Free;

  CurrentEMail.Free;
  // Seperate check here...
  s := True;
  ClearFolder(sTemporaryFolder, s);
  LangHolder.Free;
  ClearUpCheckForPrevInstance;
end;

function GetMessageString(AIndex: integer): string;
begin
  if (AIndex < 0) and (AIndex > MessageList.Count - 1) then begin
    Result := Format('Index out of bounds %d in "GetMessageString".' + CrLf +
      'You should delete the File "Messages.txt"', [AIndex]);
    Exit;
  end;
  if DefaultLanguage = '' then
    Result := MessageList.Strings[AIndex]
  else
    Result := LangHolder.MessagesStrings[Aindex];
end;

procedure SetMessageString(AIndex: integer; AValue: string);
begin
  if (AIndex < 0) and (AIndex > MessageList.Count - 1) then begin
    Application.MessageBox(PChar(Format('Index out of bounds %d.' + CrLf +
      'You should delete the File "Messages.txt" located in the Programfolder.', [AIndex])),
      'SetMessageString', MB_ICONSTOP + MB_OK);
    Exit;
  end;
  MessageList.Strings[AIndex] := AValue;
end;

// AH05 From Roland
procedure SetMessageString4Q(AIndex: integer; AValue: string); //4Q=for quotes ;-)
var
  AV, forbidden: string;
  i: Integer;
begin
  if (AIndex < 0) and (AIndex > MessageList.Count - 1) then begin
    Application.MessageBox(PChar(Format('Index out of bounds %d.' + CrLf +
      'You should delete the File "MessagesXX.txt" located in the Programfolder.', [AIndex])),
      'SetMessageString', MB_ICONSTOP + MB_OK);
    Exit;
  end;
  AV:=AValue;
  forbidden:=' .,:;"'; //chars not allowed for the new linebreaker, first is a blank
  for I:=1 to length(AV) do
      begin
      if pos(AV[i],forbidden)<>0 then AV[i]:=#160; //replace all forbidden with #160-blanks
      end;
  MessageList.Strings[AIndex] := AV;
end;
// AH05

function InStr(AStart: integer; AString, ASubString: string; ACompare: integer = 1): integer;
var
  tmpstr, tmpfstring: string;
begin
  Delete(AString, 1, AStart);
  if ACompare = 0 then begin // Binary Compare
    tmpstr := AString;
    tmpfstring := ASubString;
  end else begin // Text Comapare (ignore case)
    tmpfstring := LowerCase(ASubString);
    tmpstr := LowerCase(AString);
  end;
  Result := Pos(tmpfstring, tmpstr);
end;

function CompactPath(const APath: string; AWidth: integer; AHdc: HDC): string;
var
  rc: TRect;
  Buffer: PChar;
begin
  GetMem(Buffer, Length(APath) + 1);
  StrCopy(Buffer, PChar(APath));
  rc.Left := 0;
  rc.Right := AWidth;
  if DrawTextEx(AHdc, PChar(Buffer), Length(Buffer), rc, DT_PATH_ELLIPSIS
    or DT_MODIFYSTRING, nil) <> 0 then
    Result := Buffer
  else
    Result := 'Error while compacting Path';
  FreeMem(Buffer);
end;

function StyleToString( styles: TFontStyles ): string;
var
  style: TFontStyle;
begin
  Result := '[';
  for style := Low(style) to High(style) do
  begin
    if style in styles then
    begin
      if Length(result) > 1 Then
        result := result + ',';
      result := result + GetEnumname( typeInfo(TFontStyle), Ord(style));
    end;
  end;
  Result := Result + ']';
end;

function StringToStyle( S: string ): TFontStyles;
var
  sl   : TStringlist;
  style: TfontStyle;
  i    : Integer;
begin
  Result := [];
  if Length(S) < 2 then Exit;

  if S[1] = '[' then
    Delete(S, 1, 1);
  if S[Length(S)] = ']' then
    Delete(S, Length(S), 1);

  if Length(S) = 0 then Exit;

  sl := TStringlist.Create;
  try
    sl.commatext := S;
    for i := 0 to sl.Count-1 do begin
      try
        style := TFontStyle( GetEnumValue( Typeinfo(TFontStyle), sl[i] ));
        Include( Result, style );
      except
      end;
    end; { For }
  finally
    sl.free
  end;
end;



function StringIndex(const SearchString: string; StrList: array of string): Integer;
var
  I: Integer;
begin
  Result:= -1;
  for I:= 0 to High(StrList) do
    if CompareText(SearchString, StrList[I]) = 0 then
    begin
      Result:= I;
      Break;
    end;
end;

// wipwap
function GetFirstName(Rec: string): string;
var s: string;
  wo: byte;
begin
  result := '';
  wo := pos(#32, rec);
  if wo <> 0 then
  begin
    s := copy(rec, 1, wo - 1);
    result := s;
  end;
end;

function GetLastName(Rec: string): string;
var s: string;
  wo: byte;
begin
  result := rec;
  wo := pos('<', rec);
  if wo > 1 then
  begin
    s := copy(rec, 1, wo - 2);
    wo := pos(#32, s);
    if wo <> 0 then delete(s, 1, wo);
    result := s;
  end;
end;

function GetParsedString(Msg, Rec, Subj: string): string;
var fns, lns, ds, ts, ns, ss, s: string;
  wo: longInt;
begin
  s := Msg;
  wo := pos('%f', s); //replace firstnames
  while wo <> 0 do
  begin
    delete(s, wo, 2);
    fns := GetFirstName(Rec);
    insert(fns, s, wo);
    wo := pos('%f', s);
  end;
  wo := pos('%l', s); //replace lastnames
  while wo <> 0 do
  begin
    delete(s, wo, 2);
    lns := GetLastName(Rec);
    insert(lns, s, wo);
    wo := pos('%l', s);
  end;
  wo := pos('%d', s); //replace dates
  while wo <> 0 do
  begin
    delete(s, wo, 2);
    ds := FormatDateTime('ddddd', now);
    insert(ds, s, wo);
    wo := pos('%d', s);
  end;
  wo := pos('%t', s); //replace times
  while wo <> 0 do
  begin
    delete(s, wo, 2);
    ts := FormatDateTime('t', now);
    insert(ts, s, wo);
    wo := pos('%t', s);
  end;
  wo := pos('%n', s); //replace nows
  while wo <> 0 do
  begin
    delete(s, wo, 2);
    ns := FormatDateTime('ddddd, t', now);
    insert(ns, s, wo);
    wo := pos('%n', s);
  end;
  wo := pos('%s', s); //replace subjects
  while wo <> 0 do
  begin
    delete(s, wo, 2);
    ss := subj;
    insert(ss, s, wo);
    wo := pos('%s', s);
  end;

  Result := s;
end;

function GetParsedTemplateString(sTemplateFileName, Rec, Subj: string): string;
var fn, s: string;
  F: Text;
begin
  result := '';
  if sTemplateFileName = '' then exit;
  // AH04  fn := sTemplateFolder + sTemplateFileName + '.txt';
  if not FileExists(sTemplateFileName) then exit;
  AssignFile(F, sTemplateFilename);
  reset(F);
  fn := '';
  while not eof(F) do
  begin
    readln(F, s);
    fn := fn + #13#10 + s;
  end;
  CloseFile(F);
  result := GetParsedString(fn, Rec, Subj);
end;

function GetTreeByDirName(Node : TTreeNode;adir : string; ASet : TPXFolders) : TTreenode;
var s : string;
begin
  Result := Node;
  while Result <> nil do
  begin
    // CH03
    if Result.StateIndex in ASet then
    begin
      case Result.StateIndex of
        tnAccounts : s := sAccountRootFolder;
        tnAccount : s := MakeValidDirName(PAccountData(Result.Data)^.Path);
        tnFolder : s := MakeValidDirName(PFolderData(Result.Data)^.Path);
        tnRepository : s := sRepositoryFolder;
        tnThrashBag : s := sTrashFolder;
      end;
      // CH03
      if CompareText(s, adir) = 0 then
          exit;
    end;
    Result := result.GetNext;
  end;
end;

function IsTypeOfFolder(Node : TTreeNode; Aset : TPXFolders) : Boolean;
begin
  Result := False;
  if Assigned(Node) then
  begin
    if Node.StateIndex in Aset then
      Result := True;
  end;
end;


function WalkAccountChildren(AParent, StartNode : TTreeNode; FolderSet
  : TPXFolders) : TTreeNode;
var
  ANode : TTreeNode;
begin
  Result := nil;
  // You know why...
  if (Aparent = nil) or (StartNode = nil) then exit;

  if StartNode <> AParent then
  begin
    Anode := StartNode;
  end
  else
  begin
    Anode := Aparent.GetFirstChild;
    if Anode = nil then
    begin
      exit;
    end
  end;
  // I have a headache, so no recursion for me today Ma'am.
  while Anode.Level > AParent.Level do
  begin
    if Anode.StateIndex in FolderSet then
    begin
      // We found one, so let's hit that eject button and
      // bail out.
      Result := Anode;
      exit;
    end;
    Anode := Anode.GetNext;
  end;
end;

// Retrieve the Node's dir name by tnXXXXXX. Function added for cleanup
// reasons...
function GetNodeDirName(AStartNode : TTreeNode) : string;
begin
  Result := '';
  if AStartNode = nil then exit;
  case AStartNode.StateIndex of
    tnAccount: Result :=
                 MakeValidDirName(PAccountData(AStartNode.Data)^.Path);
    tnFolder: Result :=
                 MakeValidDirName(PFolderData(AStartNode.Data)^.Path);
    tnThrashBag: Result := sTrashFolder;
    tnAccounts: Result := sAccountRootFolder;
    tnRepository: Result := sRepositoryFolder;
    tnStationary: Result := sStationaryFolder;
  end;
end;

function GetSelectedAccountNode(Anode : TTreeNode) : TTreeNode;
var Node : TTreeNode;
begin
  Result := nil;
  if Assigned(Anode) then begin
    Node := Anode;
    if Node.Level < 1 then
      Exit;
    while Node.Level <> 1 do
      Node := Node.Parent;
    if Node.StateIndex = tnAccount then
      Result := Node;
  end;
end;


function FromOldAccountToNewAccount(FirstNode, SecondNode : TTreeNode)
   : boolean;
var acNode1, acNode2 : TTreeNode;
begin
  Result := False;
  acNode1 := GetSelectedAccountNode(FirstNode);
  if AcNode1 = nil then exit;
  acNode2 := GetSelectedAccountNode(SecondNode);
  if AcNode2 = nil then exit;

  if AcNode1 <> AcNode2 then
  begin
    // Do only for folders!
    if isTypeOfFolder(FirstNode, [tnFolder]) then
    begin
      if PFolderData(FirstNode.Data)^.Outbox or
        PFolderData(FirstNode.Data)^.Drafts
        then  Result := True
    end;

    if isTypeOfFolder(SecondNode, [tnFolder]) then
    begin
      if PFolderData(SecondNode.Data)^.Outbox or
        PFolderData(SecondNode.Data)^.Drafts then
      Result := Result and True;
    end;
  end;
end;

procedure CreateGradientBitmap(StartPos: Integer; startcol,
    endcol : TColor; ACanvas:  TCanvas; ARect : TRect; border : integer = 0);
var
  I, Steps : Integer;
  R, G, B, OldR, OldG, OldB: Real;
  StartC, EndC, OldC: TColor;
begin
  ACanvas.Pen.Color := startcol;
  ACanvas.Brush.COlor := startcol;
  ACanvas.FillRect(ARect);

  if iColorDepth > 8 then begin
    Steps := (ARect.Right  - ARect.Left) - StartPos;
    StartC := ColorToRGB(startcol);
    EndC := ColorToRGB(endcol);
    R := (GetRValue(EndC) - GetRValue(StartC)) / Steps;
    G := (GetGValue(EndC) - GetGValue(StartC)) / Steps;
    B := (GetBValue(EndC) - GetBValue(StartC)) / Steps;
    OldC := StartC;
    OldR := GetRValue(StartC);
    OldG := GetGValue(StartC);
    OldB := GetBValue(StartC);
    for I := 0 to Steps - 1 do
    begin
      ACanvas.Pen.Color := OldC;
      ACanvas.Rectangle(I + StartPos, border, I + StartPos + 1, Arect.bottom - border);
      OldR := OldR + R;
      OldG := OldG + G;
      OldB := OldB + B;
      if (OldR < 0) or (OldR > 255) then
        OldR := GetRValue(EndC);
      if (OldG < 0) or (OldG > 255) then
        OldG := GetGValue(EndC);
      if (OldB < 0) or (OldB > 255) then
        OldB := GetBValue(EndC);
      OldC := RGB(Round(OldR), Round(OldG), Round(OldB));
    end;
    // Draw last vertical line...
    ACanvas.Pen.Color := Startcol;
    ACanvas.Rectangle(ARect.right - border, border, Arect.Right, ARect.Bottom -
      border);

  end;
end;
// AH16---------------------------------------------------------------
// AH17---------------------------------------------------------------
procedure DeleteItemListView(acolumn : integer; string1 : string);
var i : integer;
begin
  // AHRK64--
  // This was initially a loop counting from 0 -> Items.Count. Which
  // is completely stupid if you do this in such a loop...
  with MainForm.ListView1 do
  begin
    i := 0;
    while i < Items.Count do
    begin
      if CompareText(Items[i].SubItems[acolumn], String1) = 0 then
      begin
        Items.BeginUpdate;
        Items[i].Delete;
        Items.EndUpdate;
        Invalidate;
        Application.ProcessMessages;
        Break;
      end;
      inc(i);
    end;
  end;
end;
// AH17

// AHRK85
procedure AddItemListView(afilename : string);
var Email : TEmail;
    Item : TListItem;
begin
  EMail := TEMail.Create;
  EMail.ParseMail(afilename, True);
  MainForm.ListView1.Items.BeginUpdate;
  Item := MainForm.ListView1.Items.Add;
  Application.ProcessMessages;
  Item.ImageIndex := -1;
  if FileGetAttr(afilename) and faArchive = 0 then begin
    if (CompareText(EMail.Priority, 'low') = 0) then
      Item.ImageIndex := 9
    else if (CompareText(EMail.Priority, 'normal') = 0) then
      Item.ImageIndex := 10
    else if (CompareText(EMail.Priority, 'high') = 0) then
      Item.ImageIndex := 11;
  end;
  with Item.SubItems do begin
    Add(EMail.Subject);
    Add(EMail.From);
    Add(StringListToCommataString(EMail.ToReceiver, false));
    Add(DateToStr(EMail.ADate) + ' ' + TimeToStr(EMail.ATime));
    Add(FormatByteText(GetFileSize(afilename)));
    Add('');
    Add(afilename);
  end;

  with MainForm.ListView1 do
  begin
    Resort; // AH? Is this necessary? I mean, it will be added anyways...
    Items.EndUpdate;
    Invalidate;
  end;
  EMail.Free;
end;
// AHRK85

// AHRK26
procedure AddPop3Command(Anode : TTreeNode; var AstringList : TStringList);
begin
  if (Assigned(AstringList)) and (Assigned(Anode)) then
  begin
    with AStringList do
    begin
      Add('POP3');
      Add(PAccountData(ANode.Data)^.Name);
      Add(PAccountData(ANode.Data)^.POPServer);
      Add(PAccountData(ANode.Data)^.POPPort);
      Add(PAccountData(ANode.Data)^.POPUser);
      if PAccountData(ANode.Data)^.PromptPassword = 1 then
        Add('')
      else
        Add(PAccountData(ANode.Data)^.POPPass);
      Add('');
      Add(IntToStr(PAccountData(ANode.Data)^.StandardDownload));
      Add(PAccountData(ANode.Data)^.DeleteFilter);
      Add(PAccountData(ANode.Data)^.KeepFilter);
      Add(PAccountData(ANode.Data)^.Path);
      Add(IntToStr(Integer(@ANode)));
      // AHRK19 --
      Add(IntToStr(PAccountData(ANode.Data)^.ShowDownload));
    end;
  end;
end;

procedure AddSMTPCommand(Anode : TTreeNode; var AstringList : TStringList;
  aMsgList : TStringList);
var I : integer;
begin
  if (Assigned(AstringList)) and (Assigned(Anode)) then
  begin
    with AStringList do
    begin
      Add('SMTP');
      Add(PAccountData(ANode.Data)^.Name);
      Add(PAccountData(ANode.Data)^.SMTPServer);
      Add(PAccountData(ANode.Data)^.SMTPPort);
      Add('');
      Add('');
      Add('<' + ExtractEMailAddress(PAccountData(ANode.Data)^.FromMail) + '>');
      Add('');
      Add('');
      Add('');
      Add(PAccountData(ANode.Data)^.Path);
      Add(IntToStr(Integer(ANode)));    // AH16
      Add(''); // AHRK19
      Add(BolToStr(PAccountData(ANode.Data)^.SMTPAuthenticate));
      Add(PAccountData(ANode.Data)^.SMTPUserName);
      Add(PAccountData(ANode.Data)^.SMTPPassword);
      Add(IntToStr(AmsgList.Count));
      for I := 0 to AMsgList.Count - 1 do
        Add(AmsgList.Strings[I]);
    end;
  end;
end;
// AHRK26
function GenerateName(prefix : string) : string;
var l : TTimeStamp;
begin
  l := DateTimeToTimeStamp(Now);
  result := prefix + IntToStr(l.Date) + IntToStr(l.Time);
end;

// AHRK93--
function ShowProperties(hWndOwner: HWND; const afilename: string): Boolean;
var Info: TShellExecuteInfo;
begin
  with Info do
  begin
    cbSize := SizeOf(Info);
    fMask := SEE_MASK_NOCLOSEPROCESS or
             SEE_MASK_INVOKEIDLIST or
             SEE_MASK_FLAG_NO_UI;
    wnd  := hWndOwner;
    lpVerb := 'properties';
    lpFile := pChar(afileName);
    lpParameters := nil;
    lpDirectory := nil;
    nShow := 0;
    hInstApp := 0;
    lpIDList := nil;
  end;
  Result := ShellExecuteEx(@Info);
end;

// Carefully borrowed from Peter Below.
function GetLongFilename( shortname: string ): string;
  function GetL( shortname: string ) : string;
  var
    srec: TSearchRec;
  begin
    Result := ExtractFileDir( shortname );
    if (Result <> shortname) then
    begin
      if FindFirst( shortname, faAnyfile, srec ) = 0 then
      try
        Result := GetL( Result )+'\'+srec.Name;
      finally
        FindClose( srec );
      end
      else
        raise Exception.CreateFmt('Path %s does not exist!', [shortname]);
    end
    else
      Delete(Result, length(result),1);
  end;
begin
  Result := GetL( ExpandFilename( shortname ));
end;

function PMRegistry : TLanguageHolder;
begin
  if not Assigned(LangHolder) then
  begin
    LangHolder := TLanguageHolder.Create;
  end;
  result := LangHolder;
end;

function GetFiles(directory, mask : string; attr : integer;
  af : TFileSomething; recursive : Boolean) : integer;
var
  SearchRec: TSearchRec;
  Found, i : Integer;
begin
  i := 0;
  Found := FindFirst(Directory + '\' + mask, faAnyFile, SearchRec);
  while Found = 0 do
  begin
    if SearchRec.Attr and attr <> 0 then
    begin
      af(Directory, SearchRec);
      inc(i);
    end;
    Found := FindNext(SearchRec);
  end;

  if recursive then
  begin
    found:= FindFirst(Directory + '\' + '*.*', faDirectory, SearchRec);
    while Found = 0 do
    begin
      if (SearchRec.Attr and faDirectory > 1) and (SearchRec.NAME <> '.')
       and (SearchRec.NAME <> '..') then
         i := i + GetFiles(directory + '\' + SearchRec.NAME + '\',
           mask, attr, af, Recursive);
      Found := FindNext(SearchRec);
    end;
  end;

  FindClose(SearchRec);

  result := i;
end;

//AHRK138
procedure AddItemToHistoryStrings(anitem : string; StL : TStrings; maxitems :
  integer; AddToTop : Boolean);
var i : integer;
begin
  // Heh: we just do it in one funny function.
  i := StL.IndexOf(AnItem);
  if i > - 1 then
  begin
    // For the people who don't believe in Boolean magic:
    // If AddToTop then move the current item to *0*,
    // Else move it to the last position!
    Stl.Move(i, Ord(not AddToTop) * (StL.Count -1));
  end
  else
  begin
    if AddToTop then
      StL.Insert(0, anitem)
    else
      StL.Add(anItem);


    while StL.Count > maxitems do
    begin
      // For the people who don't believe in Boolean magic:
      // If AddToTop then remove the *last* item else
      //   remove the *first* item.
      StL.Delete(Ord(AddToTop) * (Stl.Count -1));
    end;
  end;
end;

// For internal/future purposes
procedure SaveImageListToFile(afilename : string; anImageList : TImageList);
var bump : TBitmap;
    X : integer;
begin
  bump:= TBitmap.Create;
  try
    bump.width := anImageList.width * anImageList.count;
    bump.height:= anImageList.height;
    with bump.canvas do
    begin
      brush.color := clFuchsia;
      brush.style := bsSolid;
      fillrect(cliprect);
    end;
    for X := 0 to AnImageList.count-1 do
      Animagelist.draw(bump.canvas, X * AnImagelist.width, 0, X);
    bump.savetofile(afilename);
  finally
    bump.free
end;

end;

end.

