unit Mod_Trillian;

interface

uses
  Windows, Mod_Common, Mod_Miranda, Classes, SysUtils, xBase;

type
  TModuleTrillian = class(TModule)
  private
    procedure FreeIMList;
    function DecryptPass(const Password: String): String;
  protected
    class function GetModuleName: String; override;
    class function GetModuleVersion: Integer; override;
    class function GetModuleID: Integer; override;
    function GetIsEmpty: Boolean; override;
  public
    IMList: TList;

    procedure Run; override;
    destructor Destroy; override;

    function GetAsText: String; override;
    procedure GetAsTree; override;

    procedure ExportModule(DBStream: TMemoryStream); override;
    procedure ImportModule(DBStream: TMemoryStream); override;        
  end;


implementation

const
  TYPE_TRILL_NAME	  = 0;
  TYPE_TRILL_PASS	  = 1;

{ TModuleTrillian }

destructor TModuleTrillian.Destroy;
begin
  FreeIMList;
  inherited;
end;

procedure TModuleTrillian.FreeIMList;
var
  i: Integer;
begin
  if IMList = nil then Exit;
  for i := 0 to IMList.Count-1 do begin
    PIMItem(IMList.Items[i]).UIN := '';
    PIMItem(IMList.Items[i]).Password := '';
    Dispose(IMList.Items[i]);
  end;
  IMList.Free;
end;

function TModuleTrillian.DecryptPass(const Password: String): String;
const
  TXorTable: array[0..15] of Byte = (
    $F3, $26, $81, $C4, $39, $86, $DB, $92,
    $71, $A3, $B9, $E6, $53, $7A, $95, $7C
  );
var
  i, j: Integer;
  S: String;
begin
  Result := '';
  if Length(Password) > 32 then Exit;
  j := 0;
  for i := 1 to Length(Password) do begin
    S := S + Password[i];
    if Length(S) = 2 then begin
      Result := Result + Chr(HexToInt(S) xor TXorTable[j]);
      Inc(j);
      S := '';
    end;
  end;
end;

procedure TModuleTrillian.Run;
var
  DataItem: TDataItem;
  P: PIMItem;
begin
  inherited;

  IMList := TList.Create;

  P := nil;
  while HasMoreData do begin
    DataItem := ReadData;
    case DataItem.cType of
      TYPE_TRILL_NAME: begin
        New(P); IMList.Add(P);
        P.UIN := DataItem.Data;
        if IsICQUIN(P.UIN) then
          P.IMType := IM_ICQ
        else
          P.IMType := IM_AIM;
      end;
      TYPE_TRILL_PASS: if P <> nil then
        P.Password := DecryptPass(DataItem.Data);
    else begin
        FError := ERR_UNK_ITEM;
        Exit;
      end;
    end;
  end;
end;

function TModuleTrillian.GetAsText: String;
var
  i: Integer;
begin
  Result := '';
  
  for i := 0 to IMList.Count-1 do begin
    Result := Result + 'UIN/SN: ' + PIMItem(IMList.Items[i]).UIN + #13#10;
    Result := Result + 'Password: ' + PIMItem(IMList.Items[i]).Password + #13#10;
    Result := Result + #13#10;
  end;
end;

class function TModuleTrillian.GetModuleName: String;
begin
  Result := 'Trillian';
end;

procedure TModuleTrillian.GetAsTree;
var
  i: Integer;
begin
  Append(ModuleName, 'Этот модуль содержит ICQ и AIM пароли Trillian''а', ICON_FOLDER);
  MoveIn;
  for i := 0 to IMList.Count-1 do
    Append(PIMItem(IMList.Items[i]).UIN, GenHTMLList(['UIN/SN: ' + PIMItem(IMList.Items[i]).UIN, 'Password: ' + PIMItem(IMList.Items[i]).Password + ' (hex: ' + PassToHex(PIMItem(IMList.Items[i]).Password) + ')']), ICON_TRILLIAN);
  MoveOut;
end;

class function TModuleTrillian.GetModuleID: Integer;
begin
  Result := MODULE_TRILLIAN;
end;

class function TModuleTrillian.GetModuleVersion: Integer;
begin
  Result := 0;
end;

function TModuleTrillian.GetIsEmpty: Boolean;
begin
  Result := IMList.Count = 0;
end;

procedure TModuleTrillian.ExportModule(DBStream: TMemoryStream);
var
  i: Integer;
begin
  inherited;

  ExportData([IMList.Count]);
  for i := 0 to IMList.Count-1 do
    with PIMItem(IMList.Items[i])^ do
      ExportData([UIN, Password, Ord(IMType)]);
end;

procedure TModuleTrillian.ImportModule(DBStream: TMemoryStream);
var
  i: Integer;
  P: PIMItem;
begin
  inherited;

  IMList := TList.Create;

  for i := 0 to ImportData-1 do begin
    New(P); IMList.Add(P);
    with P^ do begin
      UIN := ImportData;
      Password := ImportData;
      IMType := ImportData;
    end;
  end;
end;

end.
