Initial commit
[keepassx] / src / dialogs / PasswordDlg.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2008 by Tarek Saidi                                *
3  *   tarek.saidi@arcor.de                                                  *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; version 2 of the License.               *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18  ***************************************************************************/
19
20 #include <QTimer>
21 #include "dialogs/PasswordDlg.h"
22
23 PasswordDialog::PasswordDialog(QWidget* parent,DlgMode mode,DlgFlags flags,const QString& filename)
24 : QDialog(parent)
25 {
26         Q_UNUSED(flags);
27         setupUi(this);
28         Mode=mode;
29         Filename=filename;
30         QString BannerTitle;
31         if(Mode==Mode_Ask){
32                 BannerTitle=tr("Enter Master Key");
33         }
34         else if(Mode==Mode_Set){
35                 BannerTitle=tr("Set Master Key");
36         }
37         else if(Mode==Mode_Change){
38                 BannerTitle=tr("Change Master Key");
39         }
40         
41         if(filename==QString()){
42                 setWindowTitle(tr("Database Key"));
43         }
44         else {
45                 setWindowTitle(filename);
46         }
47         
48         // Add list of subdirs in the mounting dir to the combobox.
49         // For example making /media/cd1 and /media/myflashdrive to two entries cd1 and myflashdrive in the combobox
50         QDir mountDir(config->mountDir());
51         if(mountDir.exists()){
52                 QStringList Paths;
53                 Paths=mountDir.entryList(QStringList()<<"*",QDir::Dirs | QDir::NoDotAndDotDot);
54                 for(int i=0;i<Paths.count();i++)
55                         Combo_KeyFile->addItem(config->mountDir()+Paths[i]);
56         }
57         Combo_KeyFile->setEditText(QString());
58         
59         if(config->rememberLastKey() && Mode!=Mode_Change && Mode!=Mode_Set){
60                 switch(config->lastKeyType()){
61                 case PASSWORD:
62                         Check_Password->setChecked(true);
63                         Check_KeyFile->setChecked(false);
64                         Combo_KeyFile->setEditText("");
65                         Edit_Password->setFocus(Qt::OtherFocusReason);
66                         break;
67                         
68                 case KEYFILE:
69                         Check_Password->setChecked(false);
70                         Check_KeyFile->setChecked(true);
71                         Combo_KeyFile->setEditText(QDir::cleanPath(QDir::current().absoluteFilePath(config->lastKeyLocation())));
72                         Combo_KeyFile->setFocus(Qt::OtherFocusReason);
73                         break;
74
75                 case BOTH:
76                         Check_Password->setChecked(true);
77                         Check_KeyFile->setChecked(true);
78                         Combo_KeyFile->setEditText(QDir::cleanPath(QDir::current().absoluteFilePath(config->lastKeyLocation())));
79                         Edit_Password->setFocus(Qt::OtherFocusReason);
80                         break;
81                 }
82         }
83         else{
84                 Edit_Password->setFocus(Qt::OtherFocusReason);
85         }
86
87         if(Mode!=Mode_Set && Mode!=Mode_Change){
88                 Button_GenKeyFile->hide();
89         }
90         /*if(flags & Flag_Auto){
91                 / *
92                 QPushButton* Button_Quit = buttonBox->addButton(tr("Quit"),QDialogButtonBox::DestructiveRole);
93                 connect(Button_Quit,SIGNAL(clicked()),this,SLOT(OnButtonQuit()));
94                 * /
95                 if(config->rememberLastKey()){
96                         switch(config->lastKeyType()){
97                         case PASSWORD:
98                                 Check_Password->setChecked(true);
99                                 Check_KeyFile->setChecked(false);
100                                 break;
101                         case KEYFILE:
102                                 Check_Password->setChecked(false);
103                                 Check_KeyFile->setChecked(true);
104                                 Combo_KeyFile->setEditText(config->lastKeyLocation());
105                                 break;
106                         case BOTH:
107                                 Check_Password->setChecked(true);
108                                 Check_KeyFile->setChecked(true);
109                                 Combo_KeyFile->setEditText(config->lastKeyLocation());
110                                 break;
111                         }
112                 }
113         }*/
114         
115         // Setting up the bookmark button
116         if(Mode==Mode_Ask && config->featureBookmarks()){
117                 // Button Color
118                 QPalette palette=Button_Bookmarks->palette();
119                 palette.setColor(QPalette::Active,QPalette::Button,config->bannerColor1());
120                 palette.setColor(QPalette::Inactive,QPalette::Button,config->bannerColor1());
121                 palette.setColor(QPalette::Active,QPalette::Window,config->bannerColor2());
122                 palette.setColor(QPalette::Inactive,QPalette::Window,config->bannerColor2());
123                 Button_Bookmarks->setPalette(palette);
124                 palette=Label_Bookmark->palette();
125                 palette.setColor(QPalette::Active,QPalette::WindowText,config->bannerTextColor());
126                 palette.setColor(QPalette::Inactive,QPalette::WindowText,config->bannerTextColor());
127                 Label_Bookmark->setPalette(palette);            
128                 // Create menu and add "last file" menu entry
129                 QMenu* BookmarkMenu=new QMenu(this);
130                 QAction* action=new QAction(this);
131                 action->setData(QString());
132                 action->setText(tr("Last File"));
133                 action->setIcon(getIcon("document"));
134                 BookmarkMenu->addAction(action);
135                 BookmarkMenu->addSeparator();
136                 // Adding all existing bookmarks
137                 for(int i=0;i<KpxBookmarks::count();i++){
138                         QAction* action=new QAction(this);
139                         action->setData(KpxBookmarks::path(i));
140                         action->setText(KpxBookmarks::title(i));
141                         action->setIcon(getIcon("document"));
142                         BookmarkMenu->addAction(action);                
143                 }
144                 Button_Bookmarks->setMenu(BookmarkMenu);
145                 connect(BookmarkMenu,SIGNAL(triggered(QAction*)),this,SLOT(OnBookmarkTriggered(QAction*)));
146         }
147         else {
148                 Button_Bookmarks->hide();
149                 Label_Bookmark->hide();
150         }
151         
152         connect(buttonBox->button(QDialogButtonBox::Cancel), SIGNAL( clicked() ), this, SLOT( OnCancel() ) );
153         connect(ButtonChangeEchoMode, SIGNAL( clicked() ), this, SLOT( ChangeEchoModeDatabaseKey() ) );
154         connect(Edit_Password, SIGNAL( returnPressed() ), this, SLOT( OnOK() ) );
155         connect(Edit_PwRepeat, SIGNAL( returnPressed() ), this, SLOT( OnOK() ) );
156         connect(buttonBox->button(QDialogButtonBox::Ok), SIGNAL( clicked() ), this, SLOT( OnOK() ) );
157         connect(Button_Browse, SIGNAL( clicked() ), this, SLOT( OnButtonBrowse() ) );
158         connect(Button_GenKeyFile,SIGNAL(clicked()),this,SLOT(OnGenKeyFile()));
159         connect(Check_Password,SIGNAL(stateChanged(int)),this,SLOT(OnCheckBoxesChanged()));
160         connect(Check_KeyFile,SIGNAL(stateChanged(int)),this,SLOT(OnCheckBoxesChanged()));
161         connect(Button_Back,SIGNAL(clicked()),this,SLOT(OnButtonBack()));
162         if(!config->showPasswordsPasswordDlg())
163                 ChangeEchoModeDatabaseKey();
164         else
165                 ButtonChangeEchoMode->setIcon(getIcon("pwd_show"));
166         
167         adjustSize();
168         setMaximumSize(size());
169         setMinimumSize(size());
170         createBanner(&BannerPixmap,getPixmap("key"),BannerTitle,width());
171         Button_Bookmarks->setIcon(getIcon("bookmark"));
172         OnCheckBoxesChanged();
173 }
174
175
176 void PasswordDialog::OnButtonBrowse()
177 {
178         QString filename=KpxFileDialogs::openExistingFile(this,"PasswordDlg",tr("Select a Key File"),
179                                                       QStringList() << tr("All Files (*)")
180                                                                             << tr("Key Files (*.key)"));
181         if(filename!=QString())
182                 Combo_KeyFile->setEditText(filename);
183 }
184
185 void PasswordDialog::OnCancel()
186 {
187         done(Exit_Cancel);
188 }
189
190 void PasswordDialog::OnOK(){    
191         if(stackedWidget->currentIndex()==1){
192                 if(Password==Edit_PwRepeat->text()){
193                         done(Exit_Ok);
194                 }
195                 Edit_PwRepeat->clear();
196                 Edit_PwRepeat->setFocus(Qt::OtherFocusReason);
197                 Label_Unequal->show();
198                 QTimer::singleShot(2000,Label_Unequal,SLOT(hide()));
199                 return;
200         }
201         
202         Password=Edit_Password->text();
203         KeyFile=Combo_KeyFile->currentText();
204         
205         if(!Check_Password->isChecked() && !Check_KeyFile->isChecked()){
206                 showErrMsg(tr("Please enter a Password or select a key file."),this);
207                 return;
208         }
209         
210         if(Check_Password->isChecked() && Password.isEmpty()){
211                 showErrMsg(tr("Please enter a Password."));
212                 return;
213         }
214         
215         if(Check_KeyFile->isChecked() && KeyFile.isEmpty()){
216                 showErrMsg(tr("Please provide a key file."));
217                 return;
218         }
219
220         if(Check_KeyFile->isChecked()){
221                 /* Check wether key path exists and is readable */
222                 QFileInfo fileinfo(KeyFile);
223                 if(!fileinfo.exists()){
224                         showErrMsg(tr("%1:\nNo such file or directory.").arg(KeyFile),this);
225                         return;
226                 }
227                 if(!fileinfo.isReadable()){
228                         showErrMsg(tr("The selected key file or directory is not readable."),this);
229                         return;
230                 }
231                 
232                 /* If the given path is a directory, we need to find the key file in it */ 
233                 if(fileinfo.isDir()){
234                         if(KeyFile.right(1)!="/")KeyFile+="/";                  
235                         // First, we try to find $path/pwsafe.key
236                         QFile file(KeyFile+"pwsafe.key");
237                         if(file.exists())
238                                 KeyFile+="pwsafe.key";
239                         else{
240                                 // If pwsafe.key does not exist, we try to see if there is exactly one file in the
241                                 // given directory which has the extension *.key.
242                                 QDir dir(KeyFile);
243                                 QStringList files;
244                                 files=dir.entryList(QStringList()<<"*.key",QDir::Files);
245                                 // No Key Files
246                                 if(!files.size()){
247                                         showErrMsg(tr("The given directory does not contain any key files."),this);
248                                         return;
249                                 }
250                                 // More than one key file
251                                 if(files.size()>1){
252                                         showErrMsg(tr("The given directory contains more then one key files.\n"
253                                                       "Please specify the key file directly."),this);
254                                         return;
255                                 }
256                                 KeyFile+=files[0];
257                         }
258                         
259                         // Check again whether the found file exists and is readable
260                         QFileInfo fileinfo(KeyFile);
261                         if(!fileinfo.exists()){
262                                 showErrMsg(tr("%1:\nNo such file or directory.").arg(KeyFile),this);
263                                 return;
264                         }
265                         if(!fileinfo.isReadable()){
266                                 showErrMsg(tr("%1:\nFile is not readable."),this);
267                                 return;
268                         }                       
269                 }               
270
271         }
272         
273         if(Check_Password->isChecked() && (Mode==Mode_Set || Mode==Mode_Change)){
274                 Edit_PwRepeat->clear();
275                 Label_Unequal->hide();
276                 stackedWidget->setCurrentIndex(1);
277                 Edit_PwRepeat->setFocus(Qt::OtherFocusReason);
278                 return;
279         }
280         
281         if((Mode==Mode_Ask || Mode==Mode_Set) && config->rememberLastKey()){
282                 if(Check_Password->isChecked() && Check_KeyFile->isChecked()){
283                         config->setLastKeyType(BOTH);
284                         config->setLastKeyLocation(Combo_KeyFile->currentText());
285                 }
286                 else if(Check_Password->isChecked()){
287                         config->setLastKeyType(PASSWORD);
288                         config->setLastKeyLocation(QString());
289                 }
290                 else if(Check_KeyFile->isChecked()){
291                         config->setLastKeyType(KEYFILE);
292                         config->setLastKeyLocation(Combo_KeyFile->currentText());
293                 }               
294         }
295         
296         done(Exit_Ok);
297 }
298
299 void PasswordDialog::OnCheckBoxesChanged(){
300         Edit_Password->setEnabled(Check_Password->isChecked());
301         Combo_KeyFile->setEnabled(Check_KeyFile->isChecked());
302         Button_Browse->setEnabled(Check_KeyFile->isChecked());
303         Button_GenKeyFile->setEnabled(Check_KeyFile->isChecked());      
304 }
305
306 void PasswordDialog::ChangeEchoModeDatabaseKey(){
307         if(Edit_Password->echoMode()==QLineEdit::Normal){
308                 Edit_Password->setEchoMode(QLineEdit::Password);
309                 Edit_PwRepeat->setEchoMode(QLineEdit::Password);
310                 ButtonChangeEchoMode->setIcon(getIcon("pwd_hide"));
311         }
312         else{
313                 Edit_Password->setEchoMode(QLineEdit::Normal);
314                 Edit_PwRepeat->setEchoMode(QLineEdit::Normal);
315                 ButtonChangeEchoMode->setIcon(getIcon("pwd_show"));
316         }
317 }
318
319 void PasswordDialog::OnButtonQuit(){
320         done(Exit_Quit);
321 }
322
323 void PasswordDialog::paintEvent(QPaintEvent* event){
324         QDialog::paintEvent(event);
325         QPainter painter(this);
326         painter.setClipRegion(event->region());
327         painter.drawPixmap(QPoint(0,0),BannerPixmap);   
328 }
329
330 void PasswordDialog::OnBookmarkTriggered(QAction* action){
331         if(action->data().toString()==QString())
332                 setWindowTitle(Filename);
333         else
334                 setWindowTitle(action->data().toString());
335         Label_Bookmark->setText(action->text());
336         BookmarkFilename=action->data().toString();
337 }
338
339 void PasswordDialog::OnGenKeyFile(){
340         QString filename=KpxFileDialogs::saveFile(this,"PasswordDlg",tr("Create Key File..."),
341                                                   QStringList() << tr("All Files (*)")
342                                                                 << tr("Key Files (*.key)"));
343         if(!filename.isEmpty()){
344                 QString error;
345                 if(!createKeyFile(filename,&error,32,true)){
346                         showErrMsg(error,this);
347                         return;
348                 }
349                 else {
350                         if(Check_KeyFile->isChecked())
351                                 Combo_KeyFile->setEditText(filename);
352                         return;
353                 }
354         }       
355 }
356
357 QString PasswordDialog::password(){
358         if(Check_Password->isChecked())
359                 return Password;
360         else
361                 return QString();
362 }
363
364
365 QString PasswordDialog::keyFile(){
366         if(Check_KeyFile->isChecked())
367                 return Combo_KeyFile->currentText();
368         else
369                 return QString();
370 }
371
372 QString PasswordDialog::selectedBookmark(){
373         return BookmarkFilename;
374 }
375
376 void PasswordDialog::OnButtonBack(){
377         stackedWidget->setCurrentIndex(0);
378         Edit_PwRepeat->clear();
379 }
380
381 void PasswordDialog::done(int r){
382         // workaround for a Qt crash bug
383         Password = Edit_Password->text();
384         Edit_Password->clear();
385         Edit_Password->setEchoMode(QLineEdit::Normal);
386         Edit_PwRepeat->clear();
387         Edit_PwRepeat->setEchoMode(QLineEdit::Normal);
388         
389         QDialog::done(r);
390 }