UtilU1.pas
上传用户:dh8233980
上传日期:2014-10-16
资源大小:1015k
文件大小:21k
源码类别:

Email服务器

开发平台:

Delphi

  1. unit UtilU1;
  2. (******************************************************************************)
  3. (*                                                                            *)
  4. (* SMTP General Application Utilities                                         *)
  5. (* Part of Hermes SMTP/POP3 Server.                                           *)
  6. (* Copyright(C) 2000 by Alexander J. Fanti, All Rights Reserver Worldwide.    *)
  7. (*                                                                            *)
  8. (* Contains: Route Parsing Utilities, File and Shell Operations, File Name    *)
  9. (*           and Size tools, TimeZone utilities, etc.                         *)
  10. (*                                                                            *)
  11. (* Created January 10, 2000 by Alexander J. Fanti.  See License.txt           *)
  12. (*                                                                            *)
  13. (* Used by: most everything                                                   *)
  14. (*                                                                            *)
  15. (* Description: This little utility library contains all the miscelanious     *)
  16. (*              utilities that don't belong anywhere else.                    *)
  17. (*                                                                            *)
  18. (* Revisions: 1/25/2000  AJF  Commented                                       *)
  19. (*            1/28/2000  AJF  Added StringToInteger                           *)
  20. (*                                                                            *)
  21. (******************************************************************************)
  22. interface
  23. uses
  24.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  25.   FileCtrl, ShellAPI, Registry;
  26.   function FileOperation(FromFile, ToFile : String; Operation : String):Boolean;
  27.   function LaunchShellApp(CMDLine : String) : Boolean;
  28.   function GetFileSize(Filename : String) : Longint;
  29.   function GetUniqueFilename(Path : String) : String;
  30.   function GetFileCountInDirectory(Path : String) : Longint;
  31.   function GetFileSizeInDirectory(Path : String) : Longint;
  32.   function IsDomainNumber(Domain : String) : Boolean;
  33.   function IsDomainDottedIP(Domain : String) : Boolean;
  34.   function IsDomainValid(Domain : String) : Boolean;
  35.   function FormatedDomain(Domain : String) : String;
  36.   function FormatedAtDomain(Domain : String) : String;
  37.   function IsMailboxValid(Mailbox : String) : Boolean;
  38.   function FormattedMailbox(Mailbox : String) : String;
  39.   function FormatedAddress(Mailbox, Domain : String) : String;
  40.   function IsAddressValid(EMailAddress : String) : Boolean;
  41.   procedure FetchDNSList(DNSList : TStringList);
  42. //  function AddTextToFile(FQFilename : String; Data : TStringList) : Boolean;
  43. //  function AddTextToFile(FQFilename : String; Data : TStringList;
  44. //                         MaxLines : Longint) : Boolean;
  45.   function GetTimeZoneString : String;
  46.   function StringToInteger(AString : String; DefaultInteger : Integer) :Integer;
  47. implementation
  48. function FileOperation(FromFile, ToFile : String; Operation : String) : Boolean;
  49. var
  50.   pFrom, pTo : PChar;
  51.   FileOpStr : TSHFileOpStruct;
  52. begin
  53.   // Perform a Shell Operation (specifically, Copy, Move, Rename or Delete a
  54.   // file or folder...
  55.   FileOperation := False;
  56.   pFrom := StrAlloc(Length(FromFile) +2);
  57.   pTo   := StrAlloc(Length(ToFile) +2);
  58.   StrPCopy(pFrom, FromFile);
  59.   pFrom[Length(FromFile) +1] := #0;
  60.   StrPCopy(pTo, ToFile);
  61.   pTo[Length(ToFile) +1] := #0;
  62.   FileOpStr.Wnd:= Application.Handle;
  63.   if UpperCase(Operation) = 'COPY' then FileOpStr.wFunc:= FO_COPY;
  64.   if UpperCase(Operation) = 'DELETE' then FileOpStr.wFunc:= FO_DELETE;
  65.   if UpperCase(Operation) = 'MOVE' then FileOpStr.wFunc:= FO_MOVE;
  66.   if UpperCase(Operation) = 'RENAME' then FileOpStr.wFunc:= FO_RENAME;
  67.   FileOpStr.pFrom:= pFrom;
  68.   FileOpStr.pTo:= pTo;
  69.   FileOpStr.fFlags:= FOF_NOCONFIRMATION + FOF_SILENT + FOF_FILESONLY;
  70.   FileOpStr.fAnyOperationsAborted:= False;
  71.   FileOpStr.hNameMappings:= nil;
  72.   FileOpStr.lpszProgressTitle:= nil;
  73.   try
  74.     if SHFileOperation(FileOpStr) = 0 then FileOperation := True;
  75.   except
  76.     on E: Exception do FileOperation := False;
  77.   end;
  78.   StrDispose(pFrom);
  79.   StrDispose(pTo);
  80. end;
  81. (*
  82. function StripFileExtension(FQFilename : String) : String;
  83. var
  84.   x : longint;
  85. begin
  86.   // Remove a file extension from
  87.   StripFileExtension := FQFilename;
  88.   x := Length(FQFilename);
  89.   while (x > 0) and (Copy(FQFilename, x, 1) <> '.') do Dec(x);
  90.   if Copy(FQFilename, x, 1) = '.' then
  91.     StripFileExtension := Copy(FQFilename, 1, x -1);
  92. end;
  93. function WinExecAndWait32(FileName : String; Visibility : integer) : Boolean;
  94. var
  95.   zAppName : Array[0..512] of char;
  96.   zCurDir : Array[0..255] of char;
  97.   WorkDir : String;
  98.   StartupInfo : TStartupInfo;
  99.   ProcessInfo : TProcessInformation;
  100. begin
  101.   StrPCopy(zAppName, FileName) ;
  102.   GetDir(0, WorkDir) ;
  103.   StrPCopy(zCurDir,WorkDir) ;
  104.   FillChar(StartupInfo, Sizeof(StartupInfo),#0) ;
  105.   StartupInfo.cb := Sizeof(StartupInfo) ;
  106.   StartupInfo.dwFlags := STARTF_USESHOWWINDOW ;
  107.   StartupInfo.wShowWindow := Visibility ;
  108.   if CreateProcess(nil,
  109.       zAppName,                      { pointer to command line string }
  110.       nil,                           { pointer to process security attributes}
  111.       nil,                           { pointer to thread security attributes }
  112.       False,                         { handle inheritance flag }
  113.       CREATE_NEW_CONSOLE or          { creation flags }
  114.       NORMAL_PRIORITY_CLASS,
  115.       nil,                           { pointer to new environment block }
  116.       nil,                           { pointer to current directory name }
  117.       StartupInfo,                   { pointer to STARTUPINFO }
  118.       ProcessInfo) then begin
  119.     CloseHandle(ProcessInfo.hThread);
  120.     WaitforSingleObject(ProcessInfo.hProcess, INFINITE);
  121.     // this should hang the app till the other closes...!
  122. //    GetExitCodeProcess(ProcessInfo.hProcess, @tempInt);
  123.     CloseHandle(ProcessInfo.hProcess);
  124.     Result := True;
  125.   end else begin
  126.     // failed
  127.     Result := False;
  128.   end;
  129. end;
  130. *)
  131. function LaunchShellApp(CMDLine : String) : Boolean;
  132. var
  133.   Info : TShellExecuteInfo;
  134.   ErrorDescription : String;
  135.   zCMDLine : Array[0..512] of char;
  136.   zEXEName : Array[0..512] of char;
  137.   zEXEPath : Array[0..512] of char;
  138. begin
  139.   StrPCopy(zCMDLine, CMDLine);
  140.   StrPCopy(zEXEName, ExtractFilename(CMDLine));
  141.   StrPCopy(zEXEPath, ExtractFilePath(CMDLine));
  142.   Info.cbSize    := SizeOf(Info);
  143.   Info.fMask     := SEE_MASK_FLAG_DDEWAIT +
  144.                     SEE_MASK_NOCLOSEPROCESS +
  145.                     SEE_MASK_FLAG_NO_UI;
  146.   Info.Wnd       := Application.Handle;
  147.   Info.lpVerb    := 'open';
  148.   Info.lpFile    := zCMDLine;
  149.   Info.lpParameters := '';
  150.   Info.lpDirectory := '';
  151.   Info.nShow     := SW_SHOWNORMAL;
  152.   Info.hInstApp  := 0;
  153.   Info.lpIDList  := nil;
  154.   Info.lpClass   := nil;
  155.   Info.hkeyClass := 0;
  156.   Info.dwHotKey  := 0;
  157.   Info.hIcon     := 0;
  158.   Info.hProcess  := 0;
  159.   Result := ShellExecuteEX(@Info);
  160.   case Info.hInstApp of
  161.     SE_ERR_FNF : ErrorDescription := 'File not found';
  162.     SE_ERR_PNF : ErrorDescription := 'Path not found';
  163.     SE_ERR_ACCESSDENIED : ErrorDescription := 'Access denied';
  164.     SE_ERR_OOM : ErrorDescription := 'Out of memory';
  165.     SE_ERR_DLLNOTFOUND : ErrorDescription := 'Dynamic-link library not found';
  166.     SE_ERR_SHARE : ErrorDescription := 'Cannot share open file';
  167.     SE_ERR_ASSOCINCOMPLETE : ErrorDescription := 'File association ' +
  168.                                                  'information not complete';
  169.     SE_ERR_DDETIMEOUT : ErrorDescription := 'DDE operation timed out';
  170.     SE_ERR_DDEFAIL : ErrorDescription := 'DDE operation failed';
  171.     SE_ERR_DDEBUSY : ErrorDescription := 'DDE operation busy';
  172.     SE_ERR_NOASSOC : ErrorDescription := 'File association not available';
  173.   end;
  174. end;
  175. (*
  176. function LaunchShellAppwP(CMDLine, Parameters : String) : Boolean;
  177. var
  178.   Info : TShellExecuteInfo;
  179.   ErrorDescription : String;
  180.   zCMDLine : Array[0..512] of char;
  181.   zEXEName : Array[0..512] of char;
  182.   zEXEPath : Array[0..512] of char;
  183.   zParameters : Array[0..512] of char;
  184. begin
  185.   StrPCopy(zCMDLine, CMDLine);
  186.   StrPCopy(zEXEName, ExtractFilename(CMDLine));
  187.   StrPCopy(zEXEPath, ExtractFilePath(CMDLine));
  188.   StrPCopy(zParameters, Trim(Parameters));
  189.   Info.cbSize    := SizeOf(Info);
  190.   Info.fMask     := SEE_MASK_FLAG_DDEWAIT +
  191.                     SEE_MASK_NOCLOSEPROCESS +
  192.                     SEE_MASK_FLAG_NO_UI;
  193.   Info.Wnd       := Application.Handle;
  194.   Info.lpVerb    := 'open';
  195.   Info.lpFile    := zEXEName;
  196.   Info.lpParameters := zParameters;
  197.   Info.lpDirectory := zEXEPath;
  198.   Info.nShow     := SW_SHOWNORMAL;
  199.   Info.hInstApp  := 0;
  200.   Info.lpIDList  := nil;
  201.   Info.lpClass   := nil;
  202.   Info.hkeyClass := 0;
  203.   Info.dwHotKey  := 0;
  204.   Info.hIcon     := 0;
  205.   Info.hProcess  := 0;
  206.   Result := ShellExecuteEX(@Info);
  207.   case Info.hInstApp of
  208.     SE_ERR_FNF : ErrorDescription := 'File not found';
  209.     SE_ERR_PNF : ErrorDescription := 'Path not found';
  210.     SE_ERR_ACCESSDENIED : ErrorDescription := 'Access denied';
  211.     SE_ERR_OOM : ErrorDescription := 'Out of memory';
  212.     SE_ERR_DLLNOTFOUND : ErrorDescription := 'Dynamic-link library not found';
  213.     SE_ERR_SHARE : ErrorDescription := 'Cannot share open file';
  214.     SE_ERR_ASSOCINCOMPLETE : ErrorDescription := 'File association ' +
  215.                                                  'information not complete';
  216.     SE_ERR_DDETIMEOUT : ErrorDescription := 'DDE operation timed out';
  217.     SE_ERR_DDEFAIL : ErrorDescription := 'DDE operation failed';
  218.     SE_ERR_DDEBUSY : ErrorDescription := 'DDE operation busy';
  219.     SE_ERR_NOASSOC : ErrorDescription := 'File association not available';
  220.   end;
  221. end;
  222. *)
  223. function GetFileSize(Filename : String) : Longint;
  224. // Return the file size in bytes.
  225. // Return -1 if file does not exist...
  226. var
  227.   F : File of Byte;
  228. begin
  229.   // Return size of a file in bytes
  230.   Result := -1;
  231.   if FileExists(Filename) then begin
  232.     AssignFile(F, Filename);
  233.     try
  234.       Reset(F);
  235.       Result := FileSize(F);
  236.     except
  237.       on E: Exception do Result := -1;
  238.     end;
  239.     CloseFile(F);
  240.   end;
  241. end;
  242. function GetUniqueFilename(Path : String) : String;
  243. // returns just a file name that's unique in the given path
  244. // Regardless of extension
  245. var
  246.   SearchRec : TSearchRec;
  247.   SearchResult : longint;
  248.   Filename : String;
  249. begin
  250.   if Copy(Path, Length(Path), 1) <> '' then Path := Path + '';
  251.   ForceDirectories(Path);
  252.   SearchResult := 0;
  253.   while SearchResult = 0 do begin
  254.     // generate filename...
  255.     Filename := IntToStr(Random(99999));
  256.     // see if it exists?
  257.     SearchResult := FindFirst(Path + Filename + '.*', faAnyFile, SearchRec);
  258.     FindClose(SearchRec);
  259.   end;
  260.   Result := Filename;
  261. end;
  262. function GetFileCountInDirectory(Path : String) : Longint;
  263. var
  264.   SearchRec : TSearchRec;
  265.   SearchResult : longint;
  266.   Count : Longint;
  267. begin
  268.   Count := 0;
  269.   if Copy(Path, Length(Path), 1) <> '' then Path := Path + '';
  270.   if DirectoryExists(Path) then begin
  271.     SearchResult := FindFirst(Path + '*.*', 0, SearchRec);
  272.     while SearchResult = 0 do begin
  273.       Inc(Count);
  274.       SearchResult := FindNext(SearchRec);
  275.     end;
  276.     FindClose(SearchRec);
  277.   end;
  278.   Result := Count;
  279. end;
  280. function GetFileSizeInDirectory(Path : String) : Longint;
  281. var
  282.   SearchRec : TSearchRec;
  283.   SearchResult : longint;
  284.   Size, OneSize : Longint;
  285. begin
  286.   Size := 0;
  287.   if Copy(Path, Length(Path), 1) <> '' then Path := Path + '';
  288.   if DirectoryExists(Path) then begin
  289.     SearchResult := FindFirst(Path + '*.*', 0, SearchRec);
  290.     while SearchResult = 0 do begin
  291.       OneSize := GetFileSize(Path + SearchRec.Name);
  292.       if OneSize > 0 then Inc(Size, OneSize);
  293.       SearchResult := FindNext(SearchRec);
  294.     end;
  295.     FindClose(SearchRec);
  296.   end;
  297.   Result := Size;
  298. end;
  299. (*********************)
  300. (* Address Utilities *)
  301. (*********************)
  302. function IsDomainNumber(Domain : String) : Boolean;
  303. var
  304.   x : Longint;
  305. begin
  306.   Result := True;
  307.   for x := 1 to Length(Domain) do
  308.     if not ((Copy(Domain, x, 1) >= '0') and (Copy(Domain, x, 1) <= '9')) then
  309.       Result := False;
  310. end;
  311. function IsDomainDottedIP(Domain : String) : Boolean;
  312. var
  313.   x : Longint;
  314.   DotCount : Byte;
  315.   T, A, B, C, D : String;
  316.   An, Bn, Cn, Dn : Integer;
  317. begin
  318.   DotCount := 0;   // Check three dots
  319.   for x := 1 to Length(Domain) do
  320.     if Copy(Domain, x, 1) = '.' then Inc(DotCount);
  321.   if DotCount = 3 then begin
  322.     // verify each dot seperates a byte value
  323.     T := Domain;
  324.     A := Copy(T, 1, Pos('.', T) -1);
  325.     T := Copy(T, Pos('.', T) +1, Length(T));
  326.     B := Copy(T, 1, Pos('.', T) -1);
  327.     T := Copy(T, Pos('.', T) +1, Length(T));
  328.     C := Copy(T, 1, Pos('.', T) -1);
  329.     D := Copy(T, Pos('.', T) +1, Length(T));
  330.     try
  331.       An := StrToInt(A);
  332.       Bn := StrToInt(B);
  333.       Cn := StrToInt(C);
  334.       Dn := StrToInt(D);
  335.       Result := True;
  336.       if not ((An >= 0) and (An <= 255)) then Result := False;
  337.       if not ((Bn >= 0) and (Bn <= 255)) then Result := False;
  338.       if not ((Cn >= 0) and (Cn <= 255)) then Result := False;
  339.       if not ((Dn >= 0) and (Dn <= 255)) then Result := False;
  340.     except
  341.       on E: Exception do Result := False;
  342.     end;
  343.   end else Result := False;  // wrong number of .
  344. end;
  345. function IsDomainValid(Domain : String) : Boolean;
  346. // Check for invalid characters.  valid chars are 0..9, a..z, A..Z and .
  347. var
  348.   x : Longint;
  349. begin
  350.   Result := True;
  351.   for x := 1 to Length(Domain) do
  352.     if (not ((Copy(Domain, x, 1) >= '0') and (Copy(Domain, x, 1) <= '9'))) and
  353.        (not ((Copy(Domain, x, 1) >= 'a') and (Copy(Domain, x, 1) <= 'z'))) and
  354.        (not ((Copy(Domain, x, 1) >= 'A') and (Copy(Domain, x, 1) <= 'Z'))) and
  355.        (not (Copy(Domain, x, 1) = '-')) and
  356.        (not (Copy(Domain, x, 1) = '.')) then Result := False;
  357. end;
  358. function FormatedDomain(Domain : String) : String;
  359. begin
  360.   Result := '';
  361.   if IsDomainValid(Domain) then
  362.     if IsDomainNumber(Domain) then Result := '#' + Domain else
  363.       if IsDomainDottedIP(Domain) then Result := '[' + Domain + ']'
  364.         else Result := Domain;
  365. end;
  366. function FormatedAtDomain(Domain : String) : String;
  367. begin
  368.   Result := '';
  369.   if IsDomainValid(Domain) then
  370.     if IsDomainNumber(Domain) then Result := '@#' + Domain
  371.       else if IsDomainDottedIP(Domain) then Result := '@[' + Domain + ']'
  372.         else Result := '@' + Domain;
  373. end;
  374. // What are valid mailbox characters?
  375. // DEBUG
  376. function IsMailboxValid(Mailbox : String) : Boolean;
  377. // Check for invalid characters.  valid chars are 0..9, a..z, A..Z and .
  378. //var
  379. //  x : Longint;
  380. begin
  381.   Result := True;
  382. //for x := 1 to Length(Mailbox) do
  383. //  if (not ((Copy(Mailbox, x, 1) >= '0') and (Copy(Mailbox, x, 1) <= '9'))) and
  384. //     (not ((Copy(Mailbox, x, 1) >= 'a') and (Copy(Mailbox, x, 1) <= 'z'))) and
  385. //     (not ((Copy(Mailbox, x, 1) >= 'A') and (Copy(Mailbox, x, 1) <= 'Z'))) and
  386. //     (not (Copy(Mailbox, x, 1) = '.')) then Result := False;
  387. end;
  388. function FormattedMailbox(Mailbox : String) : String;
  389. var
  390.   x : Longint;
  391.   Quoted : Boolean;
  392. begin
  393.   if IsMailboxValid(Mailbox) then begin
  394.     Quoted := False;
  395.     for x := 1 to Length(Mailbox) do
  396.       if Copy(Mailbox, x, 1) = ' ' then Quoted := True;
  397.     if Quoted then Result := '"' + Mailbox + '"'
  398.       else Result := Mailbox;
  399.   end else Result := '';
  400. end;
  401. function FormatedAddress(Mailbox, Domain : String) : String;
  402. begin
  403.   Result := FormattedMailbox(Mailbox) + FormatedAtDomain(Domain);
  404. end;
  405. function IsAddressValid(EMailAddress : String) : Boolean;
  406. var
  407.   Mailbox, Domain : String;
  408. begin
  409.   Result := False;
  410.   if Pos('@', EMailAddress) > 0 then begin
  411.     // parse to mailbox and domain...
  412.     Mailbox := Copy(EMailAddress, 1, Pos('@', EMailAddress) -1);
  413.     Domain  := Copy(EMailAddress, Pos('@', EMailAddress) +1,
  414.                     Length(EMailAddress));
  415.     Result := IsMailBoxValid(Mailbox) and IsDomainValid(Domain);
  416.   end;
  417. end;
  418. procedure FetchDNSList(DNSList : TStringList);
  419. var
  420.   Reg : TRegistry;
  421.   tempStr : String;
  422. begin
  423.   if Assigned(DNSList) then begin
  424.     DNSList.Clear;
  425.     Reg := TRegistry.Create;
  426.     Reg.RootKey := HKEY_LOCAL_MACHINE;
  427.     if Reg.OpenKey('SystemCurrentControlSetServicesTcpipParameters', False) then begin
  428.       // Read Static Name Servers...
  429.       tempStr := Reg.ReadString('NameServer');
  430.       if tempStr <> '' then begin
  431.         while (Pos(',', tempStr) <> 0) or (Pos(' ', tempStr) <> 0) do begin
  432.           DNSList.Add(Trim( Copy(tempStr, 1, Pos(',', tempStr)-1) ));
  433.           tempStr := Copy(tempStr, Pos(',', tempStr)+1, Length(tempStr) );
  434.         end;
  435.         DNSList.Add( tempStr );
  436.       end;
  437.       // Read DHCP Name Servers...
  438.       tempStr := Reg.ReadString('DHCPNameServer');
  439.       if tempStr <> '' then begin
  440.         while Pos(' ', tempStr) <> 0 do begin
  441.           DNSList.Add(Trim( Copy(tempStr, 1, Pos(' ', tempStr)-1) ));
  442.           tempStr := Copy(tempStr, Pos(' ', tempStr)+1, Length(tempStr) );
  443.         end;
  444.         DNSList.Add( tempStr );
  445.       end;
  446.     end;
  447.     Reg.Free;
  448.   end;
  449. end;
  450. (*
  451. function AddTextToFile(FQFilename : String; Data : TStringList) : Boolean;
  452. var
  453.   F : TextFile;
  454.   x : Longint;
  455. begin
  456.   if Assigned(Data) then begin
  457.     AssignFile(F, FQFilename);
  458.     try
  459.       Append(F);
  460.       for x := 0 to Data.Count -1 do Writeln(F, Data[x]);
  461.     except
  462.       on E: Exception do try
  463.         ReWrite(F);
  464.         for x := 0 to Data.Count -1 do Writeln(F, Data[x]);
  465.       except
  466.         on E: Exception do begin end;
  467.       end;
  468.     end;
  469.     CloseFile(F);
  470.   end;
  471. end;
  472. *)
  473. (*
  474. function AddTextToFile(FQFilename : String; Data : TStringList;
  475.                        MaxLines : Longint) : Boolean;
  476. // Open a text file... add lines to it... truncate if too long.
  477. // This is used by message archive... it's too slow for logging.
  478. var
  479.   x, Drop : Longint;
  480.   SL : TStringList;
  481. begin
  482.   Result := False;
  483.   if Assigned(Data) and (FQFilename <> '') then begin
  484.     SL := TStringList.Create;
  485.     try
  486.       SL.LoadFromFile(FQFilename)
  487.     except
  488.       on E: Exception do begin end;
  489.     end;
  490.     for x := 0 to Data.Count -1 do SL.Add(Data[x]);
  491.     if MaxLines > 0 then
  492.       if MaxLines < SL.Count then begin
  493.         Drop := SL.Count -(MaxLines +1);
  494.         while (Drop >= 0) and (SL.Count > 0) do begin
  495.           SL.Delete(0);
  496.           Dec(Drop);
  497.         end;
  498.       end;
  499.     try
  500.       SL.SaveToFile(FQFilename);
  501.       Result := True;
  502.     except
  503.       on E: Exception do begin end;
  504.     end;
  505.     SL.Free;
  506.   end;
  507. end;
  508. *)
  509. function GetTimeZoneString : String;
  510. // Make a string representing the user's time zone (GMT+5:00)
  511. var
  512.   x, TimeZone : Longint;
  513.   TimeZoneStr : String;
  514.   TZInfo : TTimeZoneInformation;
  515.   TZSignStr, TZHourStr, TZMinuteStr, TZZoneStr : String;
  516.   OrigTZHour, TZHour, TZMinute : Integer;
  517. begin
  518.   x := GetTimeZoneInformation(TZInfo);
  519.   TimeZone := TZInfo.Bias;
  520.   if x = TIME_ZONE_ID_STANDARD then
  521.     TimeZone := -(TZInfo.Bias + TZInfo.StandardBias);
  522.   if x = TIME_ZONE_ID_DAYLIGHT then
  523.     TimeZone := -(TZInfo.Bias + TZInfo.DaylightBias);
  524.   OrigTZHour := -(TZInfo.Bias div 60);
  525.   if TimeZone >= 0 then TimeZoneStr := '+';
  526.   TimeZoneStr := TimeZoneStr + IntToStr(TimeZone div 60) + ':' +
  527.     Copy('0' + IntToStr(TimeZone mod 60), 1, 2);
  528.   // Old Style
  529.   Result := 'GMT' + TimeZoneStr;
  530.   // New Style
  531.   if TimeZone >= 0 then TZSignStr := '+';
  532.   TZHour := TimeZone div 60;
  533.   TZHourStr := '0' + IntToStr(TZHour);
  534.   TZHourStr := Copy(TZHourStr, Length(TZHourStr) -1, 2);
  535.   TZMinute := TimeZone mod 60;
  536.   TZMinuteStr := '0' + IntToStr(TZMinute);
  537.   TZMinuteStr := Copy(TZMinuteStr, Length(TZMinuteStr) -1, 2);
  538.   case OrigTZHour of
  539.     -12 : TZZoneStr := '()';
  540.     -11 : TZZoneStr := '()';
  541.      -9 : TZZoneStr := '()';
  542.      -8 : TZZoneStr := '()';
  543.      -7 : TZZoneStr := '()';
  544.      -6 : TZZoneStr := '()';
  545.      -5 : TZZoneStr := '()'; // EST
  546.      -4 : TZZoneStr := '()';
  547.      -3 : TZZoneStr := '()';
  548.      -2 : TZZoneStr := '()';
  549.      -1 : TZZoneStr := '()';
  550.       0 : TZZoneStr := '';
  551.       1 : TZZoneStr := '()';
  552.       2 : TZZoneStr := '()';
  553.       3 : TZZoneStr := '()';
  554.       4 : TZZoneStr := '()';
  555.       5 : TZZoneStr := '()';
  556.       6 : TZZoneStr := '()';
  557.       7 : TZZoneStr := '()';
  558.       8 : TZZoneStr := '()';
  559.       9 : TZZoneStr := '()';
  560.      10 : TZZoneStr := '()';
  561.      11 : TZZoneStr := '()';
  562.      12 : TZZoneStr := '()';
  563.      else TZZoneStr := '';
  564.   end;
  565.   if Length(TZZoneStr) <= 2 then TZZoneStr := '';
  566.   Result := TZSignStr + TZHourStr + ':' + TZMinuteStr + ' ' + TZZoneStr;
  567. end;
  568. function StringToInteger(AString : String; DefaultInteger : Integer) : Integer;
  569. // Convert a string to an integer, but capture errors and replace with a default
  570. var
  571.   x : Integer;
  572. begin
  573.   try
  574.     x := StrToInt(AString);
  575.   except
  576.     on E: Exception do x := DefaultInteger;
  577.   end;
  578.   Result := x;
  579. end;
  580. end.