unit Form_LoginDialog;

{$I _crw_sysdef}

{$IFDEF FPC}{$mode Delphi}{$ENDIF}{$H+}

interface

uses
 _crw_sharemem, // NB: THIS UNIT MUST BE FIRST !!!
 {$IFDEF UNIX} cthreads, dl, {$ENDIF}
 {$IFDEF WINDOWS} windows, {$ENDIF}
 sysutils, classes, graphics, controls, forms, dialogs, stdctrls, buttons,
 extctrls, comctrls, math, lcltype, lclproc, lclintf,
 Form_ListBoxSelection,
 _crw_alloc, _crw_str, _crw_ef, _crw_fio, _crw_plut, _crw_eldraw,
 _crw_appforms, _crw_apptools, _crw_lm;

type
  TFormLoginDialog = class(TMasterForm)
    PanelControls: TPanel;
    LabelUser: TLabel;
    EditUser: TEdit;
    LabelDomain: TLabel;
    EditDomain: TEdit;
    LabelPassword1: TLabel;
    EditPassword1: TEdit;
    LabelPassword2: TLabel;
    EditPassword2: TEdit;
    PanelButtons: TPanel;
    BitBtnOk: TBitBtn;
    BitBtnCancel: TBitBtn;
    StatusBar: TStatusBar;
    TimerSecurity: TTimer;
    ButtonDomain: TButton;
    CheckBoxDomainDetail: TCheckBox;
    ButtonUser: TButton;
    CheckBoxUserDetail: TCheckBox;
    procedure FormCreate(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure FormHide(Sender: TObject);
    procedure TimerSecurityTimer(Sender: TObject);
    procedure ButtonDomainClick(Sender: TObject);
    procedure ButtonUserClick(Sender: TObject);
  private
    { Private declarations }
    procedure ShowWaiting(aShow:Boolean);
  public
    { Public declarations }
  end;

const
 ld_ShowUser           = $0001;
 ld_EnableUser         = $0002;
 ld_ShowDomain         = $0004;
 ld_EnableDomain       = $0008;
 ld_RetypePassword     = $0010;
 ld_EnableUserMenu     = $0020;
 ld_EnableDomainMenu   = $0040;
 ld_EnableUserDetail   = $0080;
 ld_EnableDomainDetail = $0100;

function FormLoginDialogExecute(const aCaption:LongString;
                                var aUser, aDomain, aPassword:LongString;
                                Flags:Integer):Integer;

implementation

{$R *.lfm}

function FormLoginDialogExecute(const aCaption:LongString;
                                var aUser, aDomain, aPassword:LongString;
                                Flags:Integer):Integer;
const
 TheForm : TFormLoginDialog = nil;
begin
 Result:=mrCancel;
 aPassword:='';
 if CanShowModal(TheForm) then
 try
  if not TheForm.Ok then begin
   Application.CreateForm(TFormLoginDialog, TheForm);
   TheForm.Master:=@TheForm;
  end;
  if TheForm.Ok then begin
   TheForm.Caption:=aCaption;
   TheForm.EditUser.Text:=aUser;
   TheForm.EditDomain.Text:=aDomain;
   TheForm.StatusBar.SimpleText:='';
   TheForm.EditPassword1.Text:='';
   TheForm.EditPassword2.Text:='';
   TheForm.EditPassword1.PasswordChar:=ThePasswordChar;
   TheForm.EditPassword2.PasswordChar:=ThePasswordChar;
   TheForm.EditUser.Visible:=(Flags and ld_ShowUser <> 0);
   TheForm.LabelUser.Visible:=TheForm.EditUser.Visible;
   if TheForm.EditUser.Visible
   then TheForm.EditUser.Enabled:=(Flags and ld_EnableUser <> 0);
   TheForm.ButtonUser.Visible:=TheForm.EditUser.Visible and TheForm.EditUser.Enabled and (Flags and ld_EnableUserMenu<>0);
   TheForm.CheckBoxUserDetail.Visible:=TheForm.ButtonUser.Visible and (Flags and ld_EnableUserDetail<>0);
   TheForm.EditDomain.Visible:=(Flags and ld_ShowDomain <> 0);
   TheForm.LabelDomain.Visible:=TheForm.EditDomain.Visible;
   if TheForm.EditDomain.Visible
   then TheForm.EditDomain.Enabled:=(Flags and ld_EnableDomain <> 0);
   TheForm.ButtonDomain.Visible:=TheForm.EditDomain.Visible and TheForm.EditDomain.Enabled and (Flags and ld_EnableDomainMenu<>0);
   TheForm.CheckBoxDomainDetail.Visible:=TheForm.ButtonDomain.Visible  and (Flags and ld_EnableDomainDetail<>0);
   TheForm.EditPassword2.Visible:=(Flags and ld_RetypePassword <> 0);
   TheForm.LabelPassword2.Visible:=TheForm.EditPassword2.Visible;
   if mrVoice(TheForm.ShowModal)=mrOk then begin
    aUser:=TheForm.EditUser.Text;
    aDomain:=TheForm.EditDomain.Text;
    aPassword:=TheForm.EditPassword1.Text;
    Result:=mrOk;
    if TheForm.EditPassword2.Visible then 
    if TheForm.EditPassword2.Text<>TheForm.EditPassword1.Text then begin
     Warning(RusEng('Пароль введен некорректно!','Incorrect password input!'));
     Result:=mrCancel;
     aPassword:='';
    end;
   end;
   TheForm.EditUser.Text:='';
   TheForm.EditDomain.Text:='';
   TheForm.EditPassword1.Text:='';
   TheForm.EditPassword2.Text:='';
  end;
 except
  on E:Exception do BugReport(E);
 end;
end;

procedure TFormLoginDialog.FormCreate(Sender: TObject);
begin
 SetStandardFont(Self);
 SetAllButtonsCursor(Self,crHandPoint);
 SmartUpdate(BitBtnOk,mrCaption(mrOk));
 SmartUpdate(BitBtnCancel,mrCaption(mrCancel));
 LabelUser.Caption:=RusEng('Имя пользователя','User Name');
 LabelDomain.Caption:=RusEng('Имя домена','Domain Name');
 LabelPassword1.Caption:=RusEng('Введите пароль','Type password');
 LabelPassword2.Caption:=RusEng('Повторите пароль','Retype password');
 EditPassword1.PasswordChar:=ThePasswordChar;
 EditPassword2.PasswordChar:=ThePasswordChar;
 TimerSecurity.Enabled:=False;
 ShowWaiting(False);
end;

procedure TFormLoginDialog.FormActivate(Sender: TObject);
begin
 try
  if EditUser.Visible      and EditUser.Enabled      then ActiveControl:=EditUser   else
  if EditDomain.Visible    and EditDomain.Enabled    then ActiveControl:=EditDomain else
  if EditPassword1.Visible and EditPassword1.Enabled then ActiveControl:=EditPassword1;
 except
  on E:Exception do BugReport(E,Self);
 end;
end;

procedure TFormLoginDialog.FormShow(Sender: TObject);
begin
 ShowWaiting(False);
 TimerSecurity.Enabled:=True;
end;

procedure TFormLoginDialog.FormHide(Sender: TObject);
begin
 TimerSecurity.Enabled:=False;
 ShowWaiting(False);
end;

procedure TFormLoginDialog.ShowWaiting(aShow:Boolean);
begin
 if aShow then begin
  StatusBar.SimpleText:=RusEng('Подождите, идет поиск...','Searching, please wait...');
  Application.ProcessMessages;
 end else begin
  StatusBar.SimpleText:='';
  Application.ProcessMessages;
 end;
end;

{$IFDEF SKIP_DRAFT}
// TODO
{$ELSE}
function GetDomainList(s:LongString; i:Integer; b:Boolean):LongString;
begin
 Result:=HostName;
end;
function NetEnumTimeoutId:LongString;
begin
 Result:='';
end;
function GetHostList(a,b:LongString; c,d:Integer):LongString;
begin
 Result:=HostName;
end;
{$ENDIF ~SKIP_DRAFT}

function ListBoxParams(Anchor:TControl):LongString;
var p:TPoint;
begin
 Result:='';
 Result:=Result+'@set Panel.Font   Name:PT_Mono\Size:12\Color:Blue\Style:[Regular]'+EOL;
 Result:=Result+'@set ListBox.Font Name:PT_Mono\Size:12\Color:Black\Style:[Bold]'+EOL;
 if not Assigned(Anchor) then Exit;
 with Anchor do p:=ClientToScreen(Point(0,Height));
 Result:=Result+'@set Form.Left '+IntToStr(p.x)+' relative Screen'+EOL;
 Result:=Result+'@set Form.Top  '+IntToStr(p.y)+' relative Screen'+EOL;
end;

procedure TFormLoginDialog.ButtonDomainClick(Sender: TObject);
var t:TText; i,k:Integer; Patt,Domain:LongString;
begin
 try
  Domain:='';
  t:=NewText;
  try
   k:=0;
   ShowWaiting(True);
   if CheckBoxDomainDetail.Checked then begin
    t.Text:=GetDomainList('.',1,True);
   end else begin
    t.Text:=GetDomainList('.',0,False);
    i:=Max(t.MaxLength,Max(Length(ComputerName),Length('localhost')));
    t.InsLn(0,Format('%-*s localhost',[i,'.']));
    t.InsLn(1,Format('%-*s this_host',[i,'localhost']));
    t.InsLn(2,Format('%-*s localhost',[i,ComputerName]));
   end;
   Patt:=Trim(EditDomain.Text);
   if IsEmptyStr(Patt) then Patt:=ComputerName;
   for i:=0 to t.Count-1 do
   if IsSameText(ExtractWord(1,t[i],ScanSpaces),Patt) then begin
    k:=i;
    Break;
   end;
   ShowWaiting(False);
   if ListBoxSelection(RusEng('Выбор домена','Domain selection'),
                       RusEng('Выбрать домен','Select domain'),
                       t.Text,k,ListBoxParams(ButtonDomain))=mrOk
   then Domain:=ExtractWord(1,t[k],ScanSpaces);
   if IsSameText(Domain,NetEnumTimeoutId) then Domain:='';
  finally
   Kill(t);
   ShowWaiting(False);
  end;
  if Length(Domain)>0 then begin
   EditDomain.Text:=Domain;
   ActiveControl:=EditDomain;
  end;
 except
  on E:Exception do StatusBar.SimpleText:=E.Message;
 end;
end;

procedure TFormLoginDialog.ButtonUserClick(Sender: TObject);
var t:TText; i,k:Integer; Host,Patt,User:LongString;
begin
 try
  User:='';
  t:=NewText;
  try
   k:=0;
   ShowWaiting(True);
   Host:=Trim(EditDomain.Text);
   if IsEmptyStr(Host) then Host:='.' else
   if IsSameText(Host,'localhost') then Host:='.' else
   if IsSameText(Host,ComputerName) then Host:=ComputerName else begin
    Host:=ExtractWord(1,GetHostList('',Host,0,SV_TYPE_DOMAIN_CTRL),ScanSpaces);
   end;
   t.Text:=GetUserList(Host,Ord(CheckBoxUserDetail.Checked));
   if t.Count=0 then t.Text:=UserName;
   Patt:=Trim(EditUser.Text);
   if IsEmptyStr(Patt) then Patt:=UserName;
   for i:=0 to t.Count-1 do
   if IsSameText(ExtractWord(1,t[i],ScanSpaces),Patt) then begin
    k:=i;
    Break;
   end;
   ShowWaiting(False);
   Host:=Trim(EditDomain.Text);
   if IsEmptyStr(Host) or IsSameText(Host,'.') then Host:='localhost';
   if ListBoxSelection(RusEng('Выбор пользователя','User selection'),
                       RusEng('Выбрать пользователя на ','Select user on ')+Host,
                       t.Text,k,ListBoxParams(ButtonUser))=mrOk
   then User:=ExtractWord(1,t[k],ScanSpaces);
   if IsSameText(User,NetEnumTimeoutId) then User:='';
  finally
   Kill(t);
   ShowWaiting(False);
  end;
  if Length(User)>0 then begin
   EditUser.Text:=User;
   ActiveControl:=EditUser;
  end;
 except
  on E:Exception do StatusBar.SimpleText:=E.Message;
 end;
end;

procedure TFormLoginDialog.TimerSecurityTimer(Sender: TObject);
begin
 try
  if (CheckEditPasswordChar(EditPassword1,ThePasswordChar)<>ThePasswordChar)
  or (CheckEditPasswordChar(EditPassword2,ThePasswordChar)<>ThePasswordChar) then begin
   StatusBar.SimpleText:=RusEng('Программа атакована! Кто-то хочет украсть пароль...',
                                'Program attacked! Someone want to steal password...');
  end;
 except
  on E:Exception do BugReport(E,Self,'TimerSecurityTimer');
 end;
end;

end.
