(* History++ plugin for Miranda IM: the free IM client for Microsoft* Windows* Copyright (C) 2006-2009 theMIROn, 2003-2006 Art Fedorov. History+ parts (C) 2001 Christian Kastner This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *) unit PassForm; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, Menus, ExtCtrls, StdCtrls, m_api; type TfmPass = class(TForm) Image1: TImage; rbProtAll: TRadioButton; rbProtSel: TRadioButton; lvCList: TListView; bnPass: TButton; laPassState: TLabel; Bevel1: TBevel; bnCancel: TButton; bnOK: TButton; PopupMenu1: TPopupMenu; Refresh1: TMenuItem; Label1: TLabel; procedure bnCancelClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure rbProtSelClick(Sender: TObject); procedure bnPassClick(Sender: TObject); procedure bnOKClick(Sender: TObject); procedure Refresh1Click(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure FormDestroy(Sender: TObject); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); private PassMode: Byte; Password: AnsiString; FLastContact: THandle; procedure FillList; procedure UpdatePassword; procedure SetlastContact(const Value: THandle); procedure TranslateForm; public property LastContact: THandle read FLastContact write SetLastContact; { Public declarations } end; var fmPass: TfmPass; const PASSMODE_PROTNONE = 0; // no protection, not used PASSMODE_PROTALL = 1; // protect all contacts PASSMODE_PROTSEL = 2; // protect ONLY selected contacts PASSMODE_PROTNOTSEL = 3; // protect ALL, except selected contacts (not used) function ReadPassModeFromDB: Byte; function GetPassMode: Byte; function GetPassword: AnsiString; function IsPasswordBlank(const Password: AnsiString): Boolean; function IsUserProtected(hContact: THandle): Boolean; function CheckPassword(const Pass: AnsiString): Boolean; procedure RunPassForm; implementation uses PassNewForm, hpp_options, hpp_services, PassCheckForm, Checksum, hpp_global, hpp_contacts, hpp_database, hpp_forms; {$R *.DFM} procedure RunPassForm; begin if Assigned(PassFm) then begin PassFm.Show; exit; end; if Assigned(PassCheckFm) then begin PassCheckFm.Show; exit; end; if IsPasswordBlank(GetPassword) then begin if not Assigned(PassFm) then begin PassFm := TfmPass.Create(nil); end; PassFm.Show; end else begin PassCheckFm := TfmPassCheck.Create(nil); PassCheckFm.Show; end; end; function CheckPassword(const Pass: AnsiString): Boolean; begin Result := (DigToBase(HashString(Pass)) = GetPassword); end; function IsUserProtected(hContact: THandle): Boolean; begin Result := False; case GetPassMode of PASSMODE_PROTNONE: Result := False; PASSMODE_PROTALL: Result := True; PASSMODE_PROTSEL: Result := (DBGetContactSettingByte(hContact, hppDBName, 'PasswordProtect', 0) = 1); PASSMODE_PROTNOTSEL: Result := (DBGetContactSettingByte(hContact, hppDBName, 'PasswordProtect', 1) = 1); end; if IsPasswordBlank(GetPassword) then; end; function IsPasswordBlank(const Password: AnsiString): Boolean; begin Result := (Password = DigToBase(HashString(''))); end; function GetPassword: AnsiString; begin Result := GetDBStr(hppDBName,'Password',DigToBase(HashString(''))); end; function ReadPassModeFromDB: Byte; begin Result := GetDBByte(hppDBName,'PasswordMode',PASSMODE_PROTALL); end; function GetPassMode: Byte; begin Result := ReadPassModeFromDB; if IsPasswordBlank(GetPassword) then Result := PASSMODE_PROTNONE; end; procedure TfmPass.bnCancelClick(Sender: TObject); begin close; end; procedure AddContact(var lvCList:TListView; Contact: THandle); var li: TListItem; Capt: String; begin li := lvCList.Items.Add; if Contact = 0 then begin Capt := TranslateW('System History') + ' (' + GetContactDisplayName(Contact, 'ICQ') + ')'; end else Capt := GetContactDisplayName(Contact); li.Caption := Capt; li.Data := Pointer(Contact); li.Checked := DBGetContactSettingByte(Contact, hppDBName, 'PasswordProtect', 0) = 1; end; procedure TfmPass.FillList; var hCont: THandle; begin lvCList.Items.BeginUpdate; try lvCList.Items.Clear; hCont := CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); while hCont <> 0 do begin AddContact(lvCList,hCont); hCont := CallService(MS_DB_CONTACT_FINDNEXT, hCont, 0); end; AddContact(lvCList,0); lvCList.SortType := stNone; lvCList.SortType := stText; finally lvCList.Items.EndUpdate; end; end; procedure TfmPass.FormCreate(Sender: TObject); begin DesktopFont := True; MakeFontsParent(Self); TranslateForm; FillList; PassMode := ReadPassModeFromDB; if not(PassMode in [PASSMODE_PROTALL, PASSMODE_PROTSEL]) then PassMode := PASSMODE_PROTALL; Password := GetPassword; if PassMode = PASSMODE_PROTSEL then rbProtSel.Checked := True else rbProtAll.Checked := True; rbProtSelClick(Self); UpdatePassword; Image1.Picture.Icon.Handle := CopyIcon(hppIntIcons[0].Handle); end; procedure TfmPass.rbProtSelClick(Sender: TObject); begin if rbProtSel.Checked then PassMode := PASSMODE_PROTSEL else if rbProtAll.Checked then PassMode := PASSMODE_PROTALL; if rbProtSel.Checked then begin lvCList.Enabled := True; lvCList.Color := clWindow; end else begin lvCList.Enabled := False; lvCList.Color := clInactiveBorder; end; end; procedure TfmPass.bnPassClick(Sender: TObject); begin with TfmPassNew.Create(Self) do begin if ShowModal = mrOK then begin Password := DigToBase(HashString(AnsiString(edPass.Text))); UpdatePassword; end; Free; end; end; procedure TfmPass.UpdatePassword; begin if Password = DigToBase(HashString('')) then begin // password not set laPassState.Font.Style := laPassState.Font.Style + [fsBold]; laPassState.Caption := TranslateW('Password not set'); end else begin // password set laPassState.ParentFont := True; laPassState.Caption := TranslateW('Password set'); end; end; procedure TfmPass.bnOKClick(Sender: TObject); var i: Integer; li: TListItem; begin WriteDBByte(hppDBName,'PasswordMode',PassMode); WriteDBStr(hppDBName, 'Password', Password); if PassMode = PASSMODE_PROTSEL then begin for i := 0 to lvCList.Items.Count - 1 do begin li := lvCList.Items[i]; if li.Checked then DBWriteContactSettingByte(THANDLE(li.Data), hppDBName, 'PasswordProtect', 1) else DBDeleteContactSetting(THANDLE(li.Data), hppDBName, 'PasswordProtect'); end; end; close; end; procedure TfmPass.SetlastContact(const Value: THandle); begin FLastContact := Value; end; procedure TfmPass.Refresh1Click(Sender: TObject); begin FillList; end; procedure TfmPass.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; end; procedure TfmPass.FormDestroy(Sender: TObject); begin try PassFm := nil; except end; end; procedure TfmPass.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); var Mask: Integer; begin with Sender as TWinControl do begin if Perform(CM_CHILDKEY, Key, LPARAM(Sender)) <> 0 then Exit; Mask := 0; case Key of VK_TAB: Mask := DLGC_WANTTAB; VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN: // added to change radio buttons from keyboard // however, we have to disable it when lvCList is focused if not lvCList.Focused then Mask := DLGC_WANTARROWS; VK_RETURN, VK_EXECUTE, VK_ESCAPE, VK_CANCEL: Mask := DLGC_WANTALLKEYS; end; if (Mask <> 0) and (Perform(CM_WANTSPECIALKEY, Key, 0) = 0) and (Perform(WM_GETDLGCODE, 0, 0) and Mask = 0) and (Perform(CM_DIALOGKEY, Key, 0) <> 0) then exit; end; end; procedure TfmPass.TranslateForm; begin Caption := TranslateUnicodeString(Caption); Label1.Caption := TranslateUnicodeString(Label1.Caption); rbProtAll.Caption := TranslateUnicodeString(rbProtAll.Caption); rbProtSel.Caption := TranslateUnicodeString(rbProtSel.Caption); bnPass.Caption := TranslateUnicodeString(bnPass.Caption); bnOK.Caption := TranslateUnicodeString(bnOK.Caption); bnCancel.Caption := TranslateUnicodeString(bnCancel.Caption); Refresh1.Caption := TranslateUnicodeString(Refresh1.Caption); end; end.