unit MailUnit;

interface

uses
  sysutils, forms, Unicode, Classes, IdPOP3;

type
  TMailAccountState = packed record
    AccountName: string;
    NewMail: Integer;
  end;

  TMailState = packed record
    AccountCount: Integer;
    States: array of TMailAccountState;
  end;

  TMailCheckThread = class(TThread)
  private
    Checker: TIdPOP3;
  protected
    procedure Execute; override;
  public
    constructor Create; overload;
    destructor Destroy; override;
  end;

function getNewMailCount: Integer;

var
  MailState: TMailState;

implementation

uses Jabber1, IdCoderMIME, IniFiles, RosterWindow;

function SlashSep(const Path, S: string): string;
begin
  if AnsiLastChar(Path)^ <> '\' then
    Result := Path + '\' + S
  else
    Result := Path + S;
end;

function ReadDirectoryNames(const ParentDirectory: string;
  DirectoryList: TStringList): Integer;
var
  Status: Integer;
  SearchRec: TSearchRec;
begin
  Result := 0;
  Status := FindFirst(SlashSep(ParentDirectory, '*.*'), faDirectory, SearchRec);
  try
    while Status = 0 do
    begin
      if (SearchRec.Attr and faDirectory = faDirectory) then
      begin
        if (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then
        begin
          DirectoryList.Add(SearchRec.Name);
          Inc(Result);
        end;
      end;
      Status := FindNext(SearchRec);
    end;
  finally
    FindClose(SearchRec);
  end;
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 MHDecrypt(S: string): string;
var
  I, E: Integer;
  T: string;
  Decoder: TIdDecoderMIME;
begin
  Result := '';
  if S = '' then
    Exit;
  T := '';
  for I := Length(S) downto 1 do
    T := T + S[I];
  Delete(T, 1, 1);
  Decoder := TIdDecoderMIME.Create(nil);
  S := Decoder.DecodeToString(T);
  Decoder.Free;
  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;

{ TMailCheckThread }

constructor TMailCheckThread.Create;
begin
  Checker := TIdPOP3.Create(nil);
  inherited Create(False);
  FreeOnTerminate := True;
end;

destructor TMailCheckThread.Destroy;
begin
  frmAnyQ.TimerMailcheck.Enabled := true;
  Checker.Free;
  inherited;
end;

procedure TMailCheckThread.Execute;
var
  i, j, Count, CountOld, CountNew: integer;
  DirList: TStringList;
  NewMailState: TmailState;
  inifn: string;
  ini: Tinifile;
  tmps: string;
begin
  DirList := TStringList.Create;
  ReadDirectoryNames(SlashSep(ExtractFilePath(Application.ExeName), 'SMAIL\Mail'), DirList);
  Count := 0;
  for i := 0 to DirList.count - 1 do
  begin
    inifn := SlashSep(ExtractFilePath(Application.ExeName),
      'SMAIL\Mail\' + DirList[i] + '\Account.ini');
    if not FileExists(inifn) then continue;
    ini := Tinifile.Create(inifn);
    inc(Count);
    NewMailState.AccountCount := Count;
    Setlength(NewMailState.States, Count);
    tmps := ini.ReadString('Account', 'Name', '');
    if tmps <> '' then
      NewMailState.States[Count - 1].AccountName := tmps
    else
      NewMailState.States[Count - 1].AccountName := DirList[i];
    NewMailState.States[Count - 1].NewMail := 0;

    if ini.ReadString('POP3', 'PromptPassword', '1') <> '0' then
      Continue;
    Checker.Host := ini.ReadString('POP3', 'Server', '');
    Checker.Port := ini.ReadInteger('POP3', 'Port', 110);
    Checker.Username := ini.ReadString('POP3', 'User', '');
    Checker.Password := MHDecrypt(ini.ReadString('POP3', 'Password', ''));
    try
      Checker.Connect(3000);
      if Checker.Connected then
        NewMailState.States[Count - 1].NewMail := Checker.CheckMessages;
      Checker.Disconnect;
    except
    end;
  end;
  DirList.Free;

  CountOld := 0;
  for i := 0 to MailState.AccountCount - 1 do
  begin
    CountOld := CountOld + MailState.states[i].NewMail;
  end;
  CountNew := 0;
  for i := 0 to NewMailState.AccountCount - 1 do
  begin
    CountNew := CountNew + NewMailState.states[i].NewMail;
  end;

  setlength(MailState.States, 0);
  MailState := NewMailState;

  if CountNew > CountOld then
  begin
    frmRosterWindow.UpdateMailGroup;
  //通知系统已收到新邮件
  end;
end;

function getNewMailCount: Integer;
var
  i: integer;
begin
  Result := 0;
  for i := 0 to MailState.AccountCount - 1 do
  begin
    Result := Result + MailState.states[i].NewMail;
  end;
end;

initialization
  MailState.AccountCount := 0;

end.
