Index: README.PWMD =================================================================== --- README.PWMD (revision 0) +++ README.PWMD (revision 0) @@ -0,0 +1,41 @@ +Password Manager Daemon (PWMD) stores data in an (encrypted) XML data file +that clients manipulate over a local socket. KeePassX can store its data +there so other PWMD clients can use it. Requires PWMD 1.6, or 1.7 if you want +to use the LOCK/UNLOCK commands. + +I'm not an experienced C++ programmer. This is really my first attempt at it +and it probably could be better and hopefully I didn't break anything. I've +mostly only cut'n'pasted code from other classes/functions. + +There are a few new configuration options in the Extras->Settings->Features +tab. The first is to enable using PWMD on startup rather than opening a +database file like before. Second is whether to use the LOCK command after +opening the database. The connection remains open/locked until another +database is opened or until you quit KeePassX. You should use this option if +you have other clients that use the same data file, if possible. The third is +the PWMD listening socket and the last is the data file on the server to open. +Only the data filename is required. + +Also added are the File->Import from...->PWMD and File->Export to...->PWMD +menu entries. You can also File->Save Database As... an imported or opened +PWMD database to another format like usual. + +The format of the file stored on the server is almost exactly like exporting +to the KeePassX XML format, except that every "group" and "entry" element has +a numeric ID appended. This is so PWMD commands can reach all the elements and +not just the first one found. It also tries to keep these element IDs so any +PWMD "target" attributes pointing to one of these elements remain valid. + +TODO: +Creating "target" attributes within KeePassX. So one group or entry can have +the same value as another. When the target is modified, the entry is too. I +need to figure out how to get DnD working in the EntryView. It works when +dragging a group or entry to another group item though, by Alt-LeftClicking. +Also show an icon next to an entry with a target and a context menu entry to +focus the target item (will only work with elements that are related to +KeePassX). + +Modify the status bar to support PWMD status/progress messages. + +Ben Kibbey +http://bjk.sourceforge.net/pwmd/ Index: src/export/Export_PWMD.cpp =================================================================== --- src/export/Export_PWMD.cpp (revision 0) +++ src/export/Export_PWMD.cpp (revision 0) @@ -0,0 +1,180 @@ +/*************************************************************************** + * Copyright (C) 2008 by Ben Kibbey * + * bjk@luxsci.net * + * * + * Copyright (C) 2007 by Tarek Saidi * + * tarek.saidi@arcor.de * + * * + * 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; version 2 of the License. * + + * * + * 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. * + ***************************************************************************/ + +#include +#include +#include "Export_PWMD.h" +#include "KpxConfig.h" + +struct inquire_s { + QString str; + size_t sent; + unsigned char buf[ASSUAN_LINELENGTH]; +}; + +static gpg_error_t inquire_cb(void *data, const char *keyword, gpg_error_t rc, + char **result, size_t *len) +{ + struct inquire_s *inq = data; + unsigned char *p = inq->buf; + int i = inq->sent, n; + int total = inq->str.length(); + + memset(inq->buf, 0, sizeof(inq->buf)); + + if (rc) + return rc; + + for (n = 0; i < total && n < sizeof(inq->buf); i++, n++, inq->sent++) { + QChar c = inq->str.at(i); + + *p++ = c.cell(); + } + + *p = 0; + *result = inq->buf; + *len = strlen(*result); + return inq->sent >= inq->str.length() ? GPG_ERR_EOF : 0; +} + +bool Export_PWMD::exportDatabase(QWidget* GuiParent,IDatabase* database){ + db=database; + QString str; + gpg_error_t rc; + char *result; + struct inquire_s inq; + + QDomDocument doc(""); + QDomElement root=doc.createElement("database"); + doc.appendChild(root); + QList Groups=db->groups(); + for(int i=0;iparent()==NULL){ + addGroup(Groups[i],root,doc); + } + } + + inq.str = doc.toString(0); + inq.str.prepend("keepassx "); + inq.sent = 0; + rc = db->pwm->openHandle(); + + if (rc) { + QMessageBox::critical(GuiParent, tr("Export Failed"), pwmd_strerror(rc)); + return false; + } + + rc = pwmd_inquire(db->pwm->getHandle(), "IMPORT", inquire_cb, (void *)&inq); + inq.str.clear(); + memset(&inq.buf, 0, sizeof(inq.buf)); + rc = pwmd_save(db->pwm->getHandle()); + + if (rc) { + QMessageBox::critical(GuiParent, tr("Export Failed"), pwmd_strerror(rc)); + return false; + } + + return true; +} + +void Export_PWMD::addGroup(IGroupHandle* group,QDomElement& parent,QDomDocument& doc) { + QDomElement GroupElement=doc.createElement(QString("group%1").arg(group->pwmdId())); + if (!group->pwmdTarget().isNull()) + GroupElement.setAttribute(QString("target"), group->pwmdTarget()); + + parent.appendChild(GroupElement); + QDomElement Title=doc.createElement("title"); + QDomElement Icon=doc.createElement("icon"); + Title.appendChild(doc.createTextNode(group->title())); + Icon.appendChild(doc.createTextNode(QString::number(group->image()))); + GroupElement.appendChild(Title); + GroupElement.appendChild(Icon); + QList childs=group->childs(); + for(int i=0;i entries=db->entries(group); + for(int i=0;ipwmdId())); + + if (!entry->pwmdTarget().isNull()) + GroupElement.setAttribute(QString("target"), entry->pwmdTarget()); + + parent.appendChild(GroupElement); + QDomElement Title=doc.createElement("title"); + QDomElement Username=doc.createElement("username"); + QDomElement Password=doc.createElement("password"); + QDomElement Url=doc.createElement("url"); + QDomElement Comment=doc.createElement("comment"); + QDomElement BinaryDesc=doc.createElement("bindesc"); + QDomElement Binary=doc.createElement("bin"); + QDomElement Icon=doc.createElement("icon"); + QDomElement Creation=doc.createElement("creation"); + QDomElement LastAccess=doc.createElement("lastaccess"); + QDomElement LastMod=doc.createElement("lastmod"); + QDomElement Expire=doc.createElement("expire"); + + Title.appendChild(doc.createTextNode(entry->title())); + Username.appendChild(doc.createTextNode(entry->username())); + SecString password=entry->password(); + password.unlock(); + Password.appendChild(doc.createTextNode(password.string())); + password.lock(); + Url.appendChild(doc.createTextNode(entry->url())); + QStringList CommentLines=entry->comment().split('\n'); + for(int i=0;ibinary().isNull(); + if(HasAttachment){ + BinaryDesc.appendChild(doc.createTextNode(entry->binaryDesc())); + Binary.appendChild(doc.createTextNode(entry->binary().toBase64())); + } + Icon.appendChild(doc.createTextNode(QString::number(entry->image()))); + Creation.appendChild(doc.createTextNode(entry->creation().toString(Qt::ISODate))); + LastAccess.appendChild(doc.createTextNode(entry->lastAccess().toString(Qt::ISODate))); + LastMod.appendChild(doc.createTextNode(entry->lastMod().toString(Qt::ISODate))); + Expire.appendChild(doc.createTextNode(entry->expire().toString(Qt::ISODate))); + GroupElement.appendChild(Title); + GroupElement.appendChild(Username); + GroupElement.appendChild(Password); + GroupElement.appendChild(Url); + GroupElement.appendChild(Comment); + if(HasAttachment){ + GroupElement.appendChild(BinaryDesc); + GroupElement.appendChild(Binary); + } + GroupElement.appendChild(Icon); + GroupElement.appendChild(Creation); + GroupElement.appendChild(LastAccess); + GroupElement.appendChild(LastMod); + GroupElement.appendChild(Expire); +} Index: src/export/Export_PWMD.h =================================================================== --- src/export/Export_PWMD.h (revision 0) +++ src/export/Export_PWMD.h (revision 0) @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2007 by Tarek Saidi * + * tarek.saidi@arcor.de * + * * + * 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; version 2 of the License. * + + * * + * 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. * + ***************************************************************************/ + +#ifndef _EXPORT_PWMD_H_ +#define _EXPORT_PWMD_H_ + +#include +#include +#include "Export.h" + +class Export_PWMD:public IExport, public ExporterBase{ + public: + virtual bool exportDatabase(QWidget* GuiParent, IDatabase* Database); + virtual QString identifier(){return "EXPORT_PWMD";} + virtual QString title(){return "Password Manager Daemon";} + private: + void addGroup(IGroupHandle* group,QDomElement& parent,QDomDocument& doc); + void addEntry(IEntryHandle* group,QDomElement& parent,QDomDocument& doc); + IDatabase* db; +}; + +#endif + Index: src/dialogs/SettingsDlg.cpp =================================================================== --- src/dialogs/SettingsDlg.cpp (revision 148) +++ src/dialogs/SettingsDlg.cpp (working copy) @@ -47,6 +47,7 @@ connect(ButtonTextColor, SIGNAL( clicked() ), this, SLOT( OnTextColor() ) ); connect(CheckBox_OpenLast,SIGNAL(stateChanged(int)),this,SLOT(OnCheckBoxOpenLastChanged(int))); connect(Button_MountDirBrowse,SIGNAL(clicked()),this,SLOT(OnMountDirBrowse())); + connect(Button_PWMDSocketPathBrowse,SIGNAL(clicked()),this,SLOT(OnPWMDSocketPathBrowse())); connect(Radio_IntPlugin_None,SIGNAL(toggled(bool)),this,SLOT(OnIntPluginNone(bool))); connect(Radio_IntPlugin_Gnome,SIGNAL(toggled(bool)),this,SLOT(OnIntPluginGnome(bool))); @@ -140,7 +141,11 @@ CheckBox_BrowserDefault->setChecked(false); } + CheckBox_PWMDEnable->setChecked(config->PWMDEnable()); + CheckBox_PWMDLock->setChecked(config->PWMDLock()); Edit_MountDir->setText(config->mountDir()); + Edit_PWMDSocketPath->setText(config->PWMDSocketPath()); + Edit_PWMDFile->setText(config->PWMDFile()); CheckBox_SaveRelativePaths->setChecked(config->saveRelativePaths()); SpinBox_AutoTypePreGap->setValue(config->autoTypePreGap()); SpinBox_AutoTypeKeyStrokeDelay->setValue(config->autoTypeKeyStrokeDelay()); @@ -219,6 +224,10 @@ //Advanced config->setUrlCmd(Edit_BrowserCmd->text()); config->setMountDir(Edit_MountDir->text()); + config->setPWMDSocketPath(Edit_PWMDSocketPath->text()); + config->setPWMDFile(Edit_PWMDFile->text()); + config->setPWMDEnable(CheckBox_PWMDEnable->isChecked()); + config->setPWMDLock(CheckBox_PWMDLock->isChecked()); if(!config->mountDir().isEmpty() && config->mountDir().right(1)!="/") config->setMountDir(config->mountDir()+"/"); if(CheckBox_BrowserDefault->isChecked())config->setUrlCmd(QString()); @@ -286,6 +295,22 @@ } } +// FIXME: socket file types and non-existant files +void CSettingsDlg::OnPWMDSocketPathBrowse(){ + QDir d = QDir::home(); + QFileDialog f; + QString s; + + f.setFileMode(QFileDialog::AnyFile); + f.setAcceptMode(QFileDialog::AcceptOpen); + f.setReadOnly(true); + s=f.getOpenFileName(this,tr("Select a file..."),d.absolutePath().toUtf8().data(), 0); + + if(s!=QString()){ + Edit_PWMDSocketPath->setText(s); + } +} + void CSettingsDlg::OnIntPluginNone(bool toggled){ Label_IntPlugin_Info->show(); } Index: src/dialogs/PasswordDlg.h =================================================================== --- src/dialogs/PasswordDlg.h (revision 148) +++ src/dialogs/PasswordDlg.h (working copy) @@ -38,9 +38,12 @@ void setStatePasswordOnly(); void setStateKeyFileOnly(); void setStateBoth(); + void setStatePWMD(); + void setStatePWMDPasswordOnly(); bool doAuth(); virtual void paintEvent(QPaintEvent*); QString LastFile; + bool ChangeKey; public: QString keyfile; @@ -59,6 +62,7 @@ void OnButtonExit(); void OnPasswordChanged(const QString &txt); void OnCheckBox_BothChanged(int state); + void OnCheckBox_PWMDChanged(int state); void ChangeEchoModeDatabaseKey(); void OnComboTextChanged(const QString&); void OnBookmarkTriggered(QAction* action); Index: src/dialogs/PasswordDlg.cpp =================================================================== --- src/dialogs/PasswordDlg.cpp (revision 148) +++ src/dialogs/PasswordDlg.cpp (working copy) @@ -29,18 +29,21 @@ #include #include #include +#include #include "main.h" #include "KpxConfig.h" #include "PasswordDlg.h" #include "lib/FileDialogs.h" #include "lib/bookmarks.h" +#include "pwmd.h" CPasswordDialog::CPasswordDialog(QWidget* parent,QString filename,IDatabase* DB,bool IsAuto,bool ChangeKeyMode) : QDialog(parent) { setupUi(this); + ChangeKey=false; createBanner(&BannerPixmap,getPixmap("key"),tr("Database Key"),width()); Button_Bookmarks->setIcon(getIcon("bookmark")); db=DB; @@ -56,6 +59,10 @@ } Combo_Dirs->setEditText(QString()); + + if (ChangeKeyMode && db->is_pwmd) + setStatePWMDPasswordOnly(); + if(config->rememberLastKey() && !ChangeKeyMode){ switch(config->lastKeyType()){ case KEYFILE: @@ -104,6 +111,7 @@ connect(ButtonCancel, SIGNAL( clicked() ), this, SLOT( OnCancel() ) ); connect(Edit_Password, SIGNAL( textChanged(const QString&) ), this, SLOT( OnPasswordChanged(const QString&) ) ); connect(CheckBox_Both, SIGNAL( stateChanged(int) ), this, SLOT( OnCheckBox_BothChanged(int) ) ); + connect(CheckBox_PWMD, SIGNAL( stateChanged(int) ), this, SLOT( OnCheckBox_PWMDChanged(int) ) ); connect(ButtonChangeEchoMode, SIGNAL( clicked() ), this, SLOT( ChangeEchoModeDatabaseKey() ) ); connect(Edit_Password, SIGNAL( returnPressed() ), this, SLOT( OnOK() ) ); connect(Edit_PasswordRep, SIGNAL( returnPressed() ), this, SLOT( OnOK() ) ); @@ -164,7 +172,35 @@ KeyType=BOTH; } +void CPasswordDialog::setStatePWMD(){ + Combo_Dirs->setEnabled(false); + ButtonBrowse->setEnabled(false); + Label_KeyFile->setEnabled(false); + Label_Password->setEnabled(false); + Label_PasswordRep->setEnabled(false); + Edit_Password->setEnabled(false); + Edit_PasswordRep->setEnabled(false); + ButtonChangeEchoMode->setEnabled(false); + CheckBox_Both->setEnabled(false); + KeyType=PWMD; +} +void CPasswordDialog::setStatePWMDPasswordOnly(){ + Combo_Dirs->setEnabled(false); + ButtonBrowse->setEnabled(false); + Label_KeyFile->setEnabled(false); + Label_Password->setEnabled(true); + Label_PasswordRep->setEnabled(true); + Edit_Password->setEnabled(true); + Edit_PasswordRep->setEnabled(true); + ButtonChangeEchoMode->setEnabled(true); + CheckBox_Both->setEnabled(false); + CheckBox_PWMD->setEnabled(false); + CheckBox_PWMD->setChecked(true); + KeyType=PASSWORD; + ChangeKey=true; +} + void CPasswordDialog::OnButtonBrowse() { QString filename=KpxFileDialogs::openExistingFile(this,"PasswordDlg",tr("Select a Key File"), @@ -261,11 +297,28 @@ } void CPasswordDialog::OnOK_Set(){ + if (db->is_pwmd && !ChangeKey) { + db->pwm = new Pwmd(); + done(1); + return; + } + password=Edit_Password->text(); if(password!=Edit_PasswordRep->text()){ QMessageBox::warning(this,tr("Warning"),tr("Password an password repetition are not equal.\nPlease check your input."),tr("OK"),"","",0,0); return; } + + if (db->is_pwmd) { + gpg_error_t rc = db->pwm->saveWithPassword(password); + + if (rc) + QMessageBox::warning(this,tr("PWMD Error"),pwmd_strerror(rc),tr("OK"),"","",0,0); + + done(1); + return; + } + keyfile=Combo_Dirs->currentText(); if(password.isEmpty() && keyfile.isEmpty()){ QMessageBox::warning(this,tr("Error"),tr("Please enter a password or select a key file."),tr("OK"),"","",0,0); @@ -362,6 +415,28 @@ } +void CPasswordDialog::OnCheckBox_PWMDChanged(int state){ +if(state==Qt::Checked) { + setStatePWMD(); + db->is_pwmd = true; +} +if(state==Qt::Unchecked){ + db->is_pwmd = false; + CheckBox_Both->setEnabled(true); + if(!Edit_Password->text().isEmpty() && !Combo_Dirs->currentText().isEmpty()){ + Combo_Dirs->setEditText(QString()); + setStatePasswordOnly(); + } + else{ + if(Edit_Password->text().isEmpty()) + setStateKeyFileOnly(); + else + setStatePasswordOnly(); + } +} + +} + void CPasswordDialog::ChangeEchoModeDatabaseKey(){ if(Edit_Password->echoMode()==QLineEdit::Normal){ Edit_Password->setEchoMode(QLineEdit::Password); Index: src/dialogs/SettingsDlg.h =================================================================== --- src/dialogs/SettingsDlg.h (revision 148) +++ src/dialogs/SettingsDlg.h (working copy) @@ -48,6 +48,7 @@ void OnCheckBoxOpenLastChanged(int state); void OnCheckBoxBrowserDefaultChanged(int state); void OnMountDirBrowse(); + void OnPWMDSocketPathBrowse(); void OnCustomizeEntryDetails(); private: Index: src/Database.cpp =================================================================== --- src/Database.cpp (revision 148) +++ src/Database.cpp (working copy) @@ -112,6 +112,7 @@ CGroup::CGroup(){ + pwmdId=0; Image=0; IsExpanded=false; } Index: src/src.pro =================================================================== --- src/src.pro (revision 148) +++ src/src.pro (working copy) @@ -21,7 +21,7 @@ unix : !macx { target.path = $${PREFIX}/bin data.path = $${PREFIX}/share/keepass - LIBS += -lXtst -lQtDBus + LIBS += -lXtst -lQtDBus -lpwmd SOURCES += lib/AutoType_X11.cpp } @@ -72,9 +72,11 @@ crypto/twofish.h \ import/Import.h \ import/Import_KeePassX_Xml.h \ + import/Import_PWMD.h \ import/Import_PwManager.h \ export/Export_Txt.h \ export/Export_KeePassX_Xml.h \ + export/Export_PWMD.h \ export/Export.h \ import/Import_KWalletXml.h \ dialogs/AboutDlg.h \ @@ -122,7 +124,8 @@ KpxFirefox.h \ dialogs/AddBookmarkDlg.h \ lib/bookmarks.h \ - dialogs/ManageBookmarksDlg.h + dialogs/ManageBookmarksDlg.h \ + pwmd.h SOURCES += lib/UrlLabel.cpp \ main.cpp \ mainwindow.cpp \ @@ -135,8 +138,10 @@ import/Import.cpp \ import/Import_PwManager.cpp \ import/Import_KeePassX_Xml.cpp \ + import/Import_PWMD.cpp \ export/Export_Txt.cpp \ export/Export_KeePassX_Xml.cpp \ + export/Export_PWMD.cpp \ export/Export.cpp \ import/Import_KWalletXml.cpp \ dialogs/AboutDlg.cpp \ @@ -173,7 +178,8 @@ KpxFirefox.cpp \ dialogs/AddBookmarkDlg.cpp \ lib/bookmarks.cpp \ -dialogs/ManageBookmarksDlg.cpp +dialogs/ManageBookmarksDlg.cpp \ +pwmd.cpp RESOURCES += res/resources.qrc MOC_DIR = ../build/moc UI_DIR = ../build/ui Index: src/forms/SettingsDlg.ui =================================================================== --- src/forms/SettingsDlg.ui (revision 148) +++ src/forms/SettingsDlg.ui (working copy) @@ -836,6 +836,126 @@ + + + Password Manager Daemon + + + + 0 + + + 0 + + + 0 + + + 0 + + + 6 + + + 6 + + + + + Open on Startup: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + + + + Lock: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + + + + + 0 + 23 + + + + + 16777215 + 23 + + + + Browse... + + + + + + + The location of the pwmd socket. + + + + + + + Socket Path: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + The data file to use on the server. + + + + + + + Data Filename: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + You can disable several features of KeePassX here according to your needs in order to keep the user interface slim. Index: src/forms/PasswordDlg.ui =================================================================== --- src/forms/PasswordDlg.ui (revision 148) +++ src/forms/PasswordDlg.ui (working copy) @@ -323,6 +323,19 @@ 0 + + + + 0 + 0 + + + + Use Password Manager Daemon + + + + Qt::Horizontal @@ -367,6 +380,7 @@ Combo_Dirs ButtonBrowse CheckBox_Both + CheckBox_PWMD ButtonOK ButtonCancel ButtonExit Index: src/pwmd.cpp =================================================================== --- src/pwmd.cpp (revision 0) +++ src/pwmd.cpp (revision 0) @@ -0,0 +1,168 @@ +#include +#include +#include "KpxConfig.h" +#include "main.h" +#include "pwmd.h" + +static int status_cb(void *data, const char *line) +{ + QString s(line); + + if (s.startsWith("DECRYPT")) { + } + if (s.startsWith("ENCRYPT")) { + } + else if (s.startsWith("DECOMPRESS")) { + } + else if (s.startsWith("COMPRESS")) { + } + else if (s.startsWith("CACHE")) { + } + else if (s.startsWith("LOCKED")) { + } + + return 0; +} + +void Pwmd::closeHandle() +{ + if (handle) { + if (config->PWMDLock()) + gpg_error_t rc = command(QString("UNLOCK")); + + pwmd_close(handle); + } + + handle = NULL; +} + +gpg_error_t Pwmd::command(QString cmd) +{ + gpg_error_t rc; + char *result; // Not used anywhere in this class + + return pwmd_command(handle, &result, "%s", cmd.toUtf8().data()); +} + +gpg_error_t Pwmd::clearCacheEntry() +{ + gpg_error_t rc; + + if (!handle) { + rc = openHandle(); + + if (rc) + return rc; + } + + return command(QString("CLEARCACHE %1").arg(config->PWMDFile())); +} + +gpg_error_t Pwmd::saveWithPassword(QString password) +{ + gpg_error_t rc; + + if (!handle) { + rc = openHandle(); + + if (rc) + return rc; + } + + rc = pwmd_setopt(handle, PWMD_OPTION_PINENTRY, 0); + + if (rc) + return rc; + + rc = pwmd_setopt(handle, PWMD_OPTION_PASSWORD, password.toUtf8().data()); + + if (rc) + return rc; + + rc = clearCacheEntry(); + + if (rc) + return pwmd_setopt(handle, PWMD_OPTION_PINENTRY, 1); + + rc = pwmd_save(handle); + + if (rc) + return rc; + + rc = pwmd_setopt(handle, PWMD_OPTION_PINENTRY, 1); + + if (rc) + return rc; + + return pwmd_setopt(handle, PWMD_OPTION_PASSWORD, NULL); +} + +gpg_error_t Pwmd::openHandle() +{ + QString str, sock = config->PWMDSocketPath(), file = config->PWMDFile(); + gpg_error_t rc; + char *result; + + if (handle) + return 0; + + if (file.isEmpty()) + return -1; + + handle = pwmd_connect(sock.isEmpty() ? NULL : sock.toUtf8().data(), &rc); + + if (!handle) + return rc; + + rc = pwmd_command(handle, &result, "OPTION CLIENT NAME=keepassx"); + + if (rc) { + closeHandle(); + return rc; + } + + rc = pwmd_setopt(handle, PWMD_OPTION_STATUS_FUNC, status_cb); + + if (rc) { + closeHandle(); + return rc; + } + +#if 0 + //FIXME progress bar widget + rc = pwmd_setopt(handle, PWMD_OPTION_STATUS_DATA, Parent); + + if (rc) { + closeHandle(); + return rc; + } +#endif + + rc = pwmd_open(handle, file.toUtf8().data()); + + if (rc) { + closeHandle(); + return rc; + } + + if (config->PWMDLock()) { + rc = command(QString("LOCK")); + + if (rc) { + closeHandle(); + return rc; + } + } + + return 0; +} + +Pwmd::Pwmd() +{ + handle = NULL; +} + +pwm_t *Pwmd::getHandle() +{ + return handle; +} Index: src/Kdb3Database.cpp =================================================================== --- src/Kdb3Database.cpp (revision 148) +++ src/Kdb3Database.cpp (working copy) @@ -859,9 +859,31 @@ Entries.removeAt(j); } +void Kdb3Database::rebuildPwmdEntryIds(IEntryHandle* entry, IGroupHandle* group){ + int i; + quint32 id = entry->pwmdId(); + QList list = entries(group); + +again: + for (i = 0; i < list.size(); i++) { + if (list[i]->pwmdId() == id) { + if (id == entry->pwmdId()) { + entry->setPwmdId(0); + id = 0; + } + + id++; + goto again; + } + } + + entry->setPwmdId(id); +} + void Kdb3Database::moveEntry(IEntryHandle* entry, IGroupHandle* group){ ((EntryHandle*)entry)->Entry->GroupId=((GroupHandle*)group)->Group->Id; ((EntryHandle*)entry)->Entry->Group=((GroupHandle*)group)->Group; + rebuildPwmdEntryIds(entry, group); } @@ -906,7 +928,60 @@ return id; } -IGroupHandle* Kdb3Database::addGroup(const CGroup* group,IGroupHandle* ParentHandle){ +quint32 Kdb3Database::generatePwmdId(IGroupHandle* Parent){ + quint32 i; + quint32 id = 1; + + if (!Parent) { +null_again: + for (i = 0; i < Groups.size(); i++) { + StdGroup g = Groups.at(i); + + if (!g.Handle->parent()) { + if (id == g.Handle->Group->pwmdId) { + id++; + i = 0; + goto null_again; + } + } + } + + return id; + } + + for (i = 0; i < Groups.size(); i++) { + StdGroup g = Groups.at(i); + + if (!g.Handle->parent()) + continue; + + if (g.Handle->parent() == Parent) { + int last = i; +again: + for (; i < Groups.size(); i++) { + g = Groups.at(i); + + if (g.Handle->parent() != Parent) + continue; + + if (id == g.Handle->Group->pwmdId) { + i = last; + id++; + goto again; + } + } + + break; + } + } + + return id; +} + +IGroupHandle* Kdb3Database::addGroup(CGroup* group,IGroupHandle* ParentHandle){ + if (group->pwmdId <=0) + group->pwmdId = generatePwmdId(ParentHandle); + GroupHandles.append(GroupHandle(this)); Groups.append(*group); Groups.back().Id=getNewGroupId(); @@ -926,6 +1001,7 @@ } Kdb3Database::StdGroup::StdGroup(const CGroup& other){ + pwmdId=other.pwmdId; OldImage=0; Index=0; Id=other.Id; @@ -933,6 +1009,9 @@ Title=other.Title; } +QString Kdb3Database::EntryHandle::pwmdTarget(){return Entry->pwmdTarget;} +quint32 Kdb3Database::EntryHandle::pwmdId(){return Entry->pwmdId;} +void Kdb3Database::EntryHandle::setPwmdId(quint32 value){Entry->pwmdId = value;} void Kdb3Database::EntryHandle::setTitle(const QString& Title){Entry->Title=Title; } void Kdb3Database::EntryHandle::setUsername(const QString& Username){Entry->Username=Username;} void Kdb3Database::EntryHandle::setUrl(const QString& Url){Entry->Url=Url;} @@ -1016,12 +1095,80 @@ valid=true; } +void Kdb3Database::EntryHandle::setPwmdEntryTarget(IEntryHandle *entry) +{ + QString str = QString("entry%1").arg(entry->pwmdId()); + IGroupHandle *group = entry->group(); + str.prepend("\t"); + + do { + QString s = QString("group%1").arg(group->pwmdId()); + + str.prepend(s); + group = group->parent(); + str.prepend("\t"); + } while (group); + + str.prepend("keepassx\tdatabase"); + Entry->pwmdTarget.clear; + Entry->pwmdTarget = str; + return str; +} + +void Kdb3Database::EntryHandle::setPwmdEntryTargetString(QString str) +{ + Entry->pwmdTarget.clear; + Entry->pwmdTarget = str; +} + +// FIXME can this be merged into one function (Group/Entry)Handle? +void Kdb3Database::EntryHandle::setPwmdTarget(IGroupHandle *group) +{ + QString str; + + do { + QString s = QString("group%1").arg(group->pwmdId()); + + str.prepend(s); + group = group->parent(); + str.prepend("\t"); + } while (group); + + str.prepend("keepassx\tdatabase"); + setPwmdEntryTargetString(str); +} + +void Kdb3Database::GroupHandle::setPwmdTargetString(QString str) +{ + Group->pwmdTarget.clear; + Group->pwmdTarget = str; +} + +void Kdb3Database::GroupHandle::setPwmdTarget(IGroupHandle *group) +{ + QString str; + + do { + QString s = QString("group%1").arg(group->pwmdId()); + + str.prepend(s); + group = group->parent(); + str.prepend("\t"); + } while (group); + + str.prepend("keepassx\tdatabase"); + setPwmdTargetString(str); +} + bool Kdb3Database::GroupHandle::isValid(){return valid;} void Kdb3Database::GroupHandle::setOldImage(const quint32& s){Group->OldImage=s;} QString Kdb3Database::GroupHandle::title(){return Group->Title;} quint32 Kdb3Database::GroupHandle::oldImage(){return Group->OldImage;} quint32 Kdb3Database::GroupHandle::image(){return Group->Image;} +quint32 Kdb3Database::GroupHandle::pwmdId(){return Group->pwmdId;} +void Kdb3Database::GroupHandle::setPwmdId(quint32 value){Group->pwmdId = value;} +QString Kdb3Database::GroupHandle::pwmdTarget(){return Group->pwmdTarget;} int Kdb3Database::GroupHandle::index(){return Group->Index;} void Kdb3Database::GroupHandle::setTitle(const QString& Title){Group->Title=Title;} void Kdb3Database::GroupHandle::setExpanded(bool IsExpanded){Group->IsExpanded=IsExpanded;} @@ -1519,6 +1666,7 @@ Algorithm=Rijndael_Cipher; KeyTransfRounds=6000; KeyError=false; + is_pwmd=false; } bool Kdb3Database::isKeyError(){ @@ -1534,6 +1682,7 @@ StdEntry dolly; dolly=*((EntryHandle*)entry)->Entry; dolly.Uuid.generate(); + dolly.pwmdId = generatePwmdEntryId(entry->group()); Entries.append(dolly); EntryHandles.append(EntryHandle(this)); EntryHandles.back().Entry=&Entries.back(); @@ -1544,6 +1693,7 @@ IEntryHandle* Kdb3Database::newEntry(IGroupHandle* group){ StdEntry Entry; Entry.Uuid.generate(); + Entry.pwmdId = generatePwmdEntryId(group); Entry.Group=((GroupHandle*)group)->Group; Entry.GroupId=Entry.Group->Id; Entries.append(Entry); @@ -1553,6 +1703,36 @@ return &EntryHandles.back(); } +quint32 Kdb3Database::generatePwmdEntryId(IGroupHandle* Group){ + int i; + quint32 id = 1; + + for (i = 0; i < Entries.size(); i++) { + StdEntry e = Entries.at(i); + + if (e.Handle->group() == Group) { + int last = i; +again: + for (; i < Entries.size(); i++) { + e = Entries.at(i); + + if (e.Handle->group() != Group) + continue; + + if (id == e.pwmdId) { + i = last; + id++; + goto again; + } + } + + break; + } + } + + return id; +} + IEntryHandle* Kdb3Database::addEntry(const CEntry* NewEntry, IGroupHandle* Group){ StdEntry Entry(*((StdEntry*)NewEntry)); Entry.Uuid.generate(); @@ -1673,6 +1853,29 @@ } +/* + * This is needed to change the moved elements ID to an unused one of the new + * parent after moveGroup(). + */ +void Kdb3Database::rebuildPwmdIds(StdGroup *orig, QList& list){ + int i; + quint32 id = orig->pwmdId; + +again: + for (i = 0; i < list.size(); i++) { + if (list[i]->Parent == orig->Parent && + list[i]->pwmdId == id) { + if (id == orig->pwmdId) + orig->pwmdId = id = 0; + + id++; + goto again; + } + } + + orig->pwmdId = id; +} + void Kdb3Database::moveGroup(IGroupHandle* groupHandle,IGroupHandle* NewParent,int Pos){ StdGroup* Parent; StdGroup* Group=((GroupHandle*)groupHandle)->Group; @@ -1692,6 +1895,7 @@ Parent->Childs.insert(Pos,Group); } rebuildIndices(Parent->Childs); + rebuildPwmdIds(Group, Parent->Childs); } bool Kdb3Database::changeFile(const QString& filename){ Index: src/Database.h =================================================================== --- src/Database.h (revision 148) +++ src/Database.h (working copy) @@ -26,7 +26,9 @@ #include #include #include +#include #include "lib/SecString.h" +#include "pwmd.h" using namespace std; extern const QDateTime Date_Never; @@ -93,6 +95,8 @@ KpxDateTime LastAccess; KpxDateTime Expire; QByteArray Binary; + quint32 pwmdId; + QString pwmdTarget; bool operator==(const CEntry& other) const; }; @@ -104,11 +108,14 @@ quint32 Id; quint32 Image; QString Title; + quint32 pwmdId; + QString pwmdTarget; bool operator==(const CGroup& other) const; bool IsExpanded; }; +class Pwmd; class IGroupHandle; class IEntryHandle; //! Handle class interface for accessing entries @@ -167,6 +174,11 @@ \return TRUE if the handle is valid and FALSE if the handle is invalid e.g. because the associated entry was deleted.*/ virtual bool isValid()const=0; + virtual void setPwmdId(quint32 value)=0; + virtual quint32 pwmdId()=0; + virtual void setPwmdEntryTarget(IEntryHandle *entry)=0; + virtual void setPwmdEntryTargetString(QString string)=0; + virtual QString pwmdTarget()=0; }; @@ -227,6 +239,12 @@ \param index The new index of the group. The indices of the other groups which are affected by this operation will be automatically adjusted.*/ virtual void setIndex(int index)=0; + virtual void setPwmdId(quint32 value)=0; + virtual quint32 pwmdId()=0; + virtual void setPwmdTarget(IGroupHandle* group)=0; + virtual void setPwmdTargetString(QString string)=0; + virtual QString pwmdTarget()=0; + /*! Tests the validity of the handle. \return TRUE if the handle is valid and FALSE if the handle is invalid e.g. because the associated group was deleted.*/ virtual bool isValid()=0; @@ -354,7 +372,7 @@ \param Group A pointer to a CGroup object. Id and ParentId of the object are ignored. \param Parent A pointer to the handle of parent of the group. Can be NULL if the group is a top-level group. \return a pointer to the handle of the added group.*/ - virtual IGroupHandle* addGroup(const CGroup* Group,IGroupHandle* Parent)=0; + virtual IGroupHandle* addGroup(CGroup* Group,IGroupHandle* Parent)=0; /*! Moves a group. \param Group The group which should be moved. @@ -407,6 +425,8 @@ //! Empty the recycle bin. virtual void emptyTrash()=0; + bool is_pwmd; + Pwmd *pwm; }; Index: src/pwmd.h =================================================================== --- src/pwmd.h (revision 0) +++ src/pwmd.h (revision 0) @@ -0,0 +1,20 @@ +#ifndef PWMD_H +#define PWMD_H + +#include + +class Pwmd:public QObject { + public: + Pwmd(); + virtual gpg_error_t openHandle(); + virtual gpg_error_t clearCacheEntry(); + virtual void closeHandle(); + virtual gpg_error_t saveWithPassword(QString password); + virtual pwm_t *getHandle(); + + private: + gpg_error_t command(QString cmd); + pwm_t *handle; +}; + +#endif Index: src/mainwindow.cpp =================================================================== --- src/mainwindow.cpp (revision 148) +++ src/mainwindow.cpp (working copy) @@ -46,8 +46,10 @@ #include "import/Import_PwManager.h" #include "import/Import_KWalletXml.h" #include "import/Import_KeePassX_Xml.h" +#include "import/Import_PWMD.h" #include "export/Export_Txt.h" #include "export/Export_KeePassX_Xml.h" +#include "export/Export_PWMD.h" #include "dialogs/AboutDlg.h" #include "dialogs/SearchDlg.h" @@ -66,10 +68,14 @@ #include Import_KeePassX_Xml import_KeePassX_Xml; +Import_PWMD import_PWMD; Import_PwManager import_PwManager; Import_KWalletXml import_KWalletXml; Export_Txt export_Txt; Export_KeePassX_Xml export_KeePassX_Xml; +Export_PWMD export_PWMD; +QAction *actionPWMDExport; +QAction *actionPWMDImport; KeepassMainWindow::KeepassMainWindow(const QString& ArgFile,QWidget *parent, Qt::WFlags flags):QMainWindow(parent,flags){ @@ -106,6 +112,10 @@ FileOpen=false; if(!ArgFile.isEmpty()) openDatabase(QDir::cleanPath(QDir::current().absoluteFilePath(ArgFile)),false); + else if (config->PWMDEnable()) { + actionPWMDImport->trigger(); + goto done; + } else if(config->openLastFile() && !config->lastFile().isEmpty()){ QFileInfo file(config->lastFile()); if(file.exists()) @@ -113,6 +123,7 @@ else config->setLastFile(QString()); } +done: HelpBrowser = new QAssistantClient(QString(),this); HelpBrowser->setArguments(QStringList()<< "-profile" << "/home/tarek/Documents/KeePassX/share/keepass/doc/keepassx.adp"); @@ -307,17 +318,33 @@ import->setText(name.title());\ menuImport->addAction(import);} + #define _add_pwmd_import(name){\ + QAction* import=new QAction(this);\ + import->setData(qVariantFromValue(dynamic_cast(&name)));\ + import->setText(name.title());\ + menuImport->addAction(import);\ + actionPWMDImport = import;} + #define _add_export(name){\ QAction* Export=new QAction(this);\ Export->setData(qVariantFromValue(dynamic_cast(&name)));\ Export->setText(name.title());\ menuExport->addAction(Export);} + #define _add_pwmd_export(name){\ + QAction* Export=new QAction(this);\ + Export->setData(qVariantFromValue(dynamic_cast(&name)));\ + Export->setText(name.title());\ + menuExport->addAction(Export);\ + actionPWMDExport = Export;} + _add_import(import_KeePassX_Xml) + _add_pwmd_import(import_PWMD); _add_import(import_PwManager) _add_import(import_KWalletXml) _add_export(export_Txt); _add_export(export_KeePassX_Xml); + _add_pwmd_export(export_PWMD); //FileNewMenu->setShortcut(tr("Ctrl+N")); FileOpenAction->setShortcut(tr("Ctrl+O")); @@ -367,6 +394,7 @@ if(PasswordDlg.BookmarkFilename!=QString()) filename=PasswordDlg.BookmarkFilename; + db->is_pwmd = false; GroupView->db=db; EntryView->db=db; setupDatabaseConnections(db); @@ -408,6 +436,12 @@ if(!OnFileSave())return false; } db->close(); + + if (db->is_pwmd) { + db->pwm->closeHandle(); + delete db->pwm; + } + delete db; db=NULL; EntryView->db=NULL; @@ -432,7 +466,7 @@ if(FileOpen) if(!closeDatabase())return; db=dynamic_cast(db_new); - setWindowTitle(tr("%1 - KeePassX").arg(tr("[new]"))); + setWindowTitle(tr("%1 - KeePassX").arg(db->is_pwmd ? "PWMD" : tr("[new]"))); GroupView->db=db; EntryView->db=db; GroupView->createItems(); @@ -719,6 +753,11 @@ bool KeepassMainWindow::OnFileSave(){ + if (db->is_pwmd) { + actionPWMDExport->trigger(); + return false; + } + if(!db->file()) return OnFileSaveAs(); saveLastFilename(db->file()->fileName()); @@ -763,7 +802,8 @@ void KeepassMainWindow::OnExport(QAction* action){ - dynamic_cast(action->data().value())->exportDatabase(this,db); + if (dynamic_cast(action->data().value())->exportDatabase(this,db) && db->is_pwmd) + setStateFileModified(false); } void KeepassMainWindow::OnImport(QAction* action){ @@ -772,25 +812,42 @@ IDatabase* tmpdb=dynamic_cast(new Kdb3Database()); tmpdb->create(); if(dynamic_cast(action->data().value())->importDatabase(this,tmpdb)){ + if (!tmpdb->is_pwmd) { CPasswordDialog dlg(this,QString(),tmpdb,false,true); dlg.setWindowTitle(tr("Set Master Key")); if(!dlg.exec()){ delete tmpdb; return; } - db=tmpdb; - GroupView->db=db; - EntryView->db=db; - setupDatabaseConnections(db); - setWindowTitle(tr("* - KeePassX")); - GroupView->createItems(); - EntryView->showGroup(NULL); - setStateFileOpen(true); - setStateFileModified(true); + } + + db=tmpdb; + GroupView->db=db; + EntryView->db=db; + setupDatabaseConnections(db); + setWindowTitle(db->is_pwmd ? tr("PWMD - KeePassX") : tr("* - KeePassX")); + GroupView->createItems(); + EntryView->showGroup(NULL); + setStateFileOpen(true); + + if (db->is_pwmd) + setStateFileModified(false); + else + setStateFileModified(true); } - else + else { delete tmpdb; + return; + } + if (db->is_pwmd) { + menuBookmarks->menuAction()->setEnabled(false); + FileSettingsAction->setEnabled(false); + } + else { + FileSettingsAction->setEnabled(true); + menuBookmarks->menuAction()->setVisible(config->featureBookmarks()); + } } Index: src/Kdb3Database.h =================================================================== --- src/Kdb3Database.h (revision 148) +++ src/Kdb3Database.h (working copy) @@ -59,7 +59,13 @@ friend class Kdb3Database; public: EntryHandle(Kdb3Database* db); + virtual quint32 pwmdId(); + virtual void setPwmdId(quint32 value); virtual void setImage(const quint32& ImageID); + virtual void setPwmdTarget(IGroupHandle *group); + virtual void setPwmdEntryTarget(IEntryHandle *entry); + virtual void setPwmdEntryTargetString(QString string); + virtual QString pwmdTarget(); void setOldImage(const quint32& OldImgID); virtual void setTitle(const QString& Title); virtual void setUrl(const QString& URL); @@ -116,6 +122,11 @@ virtual QList childs(); virtual int index(); virtual void setIndex(int index); + virtual quint32 pwmdId(); + virtual void setPwmdId(quint32 value); + virtual void setPwmdTarget(IGroupHandle *group); + virtual void setPwmdTargetString(QString string); + virtual QString pwmdTarget(); virtual int level(); virtual bool expanded(); virtual void setExpanded(bool IsExpanded); @@ -202,7 +213,9 @@ virtual QList sortedGroups(); virtual void deleteGroup(IGroupHandle* group); virtual void moveGroup(IGroupHandle* Group,IGroupHandle* NewParent,int Position); - virtual IGroupHandle* addGroup(const CGroup* Group,IGroupHandle* Parent); + virtual IGroupHandle* addGroup(CGroup* Group,IGroupHandle* Parent); + virtual quint32 generatePwmdId(IGroupHandle* Parent); + virtual quint32 generatePwmdEntryId(IGroupHandle* Parent); virtual bool isParent(IGroupHandle* parent, IGroupHandle* child); @@ -234,6 +247,8 @@ bool searchStringContains(const QString& search, const QString& string,bool Cs, bool RegExp); void getEntriesRecursive(IGroupHandle* Group, QList& EntryList); void rebuildIndices(QList& list); + void rebuildPwmdIds(StdGroup* orig, QList& list); + void rebuildPwmdEntryIds(IEntryHandle *entry, IGroupHandle *group); void restoreGroupTreeState(); StdEntry* getEntry(const KpxUuid& uuid); Index: src/lib/EntryView.h =================================================================== --- src/lib/EntryView.h (revision 148) +++ src/lib/EntryView.h (working copy) @@ -52,6 +52,7 @@ QMenu *ContextMenu; QBitArray Columns; void setCurrentEntry(IEntryHandle* entry); + QString generatePwmdPathToolTip(IEntryHandle *entry); private: void setEntry(IEntryHandle* entry); void updateEntry(EntryViewItem*); Index: src/lib/GroupView.cpp =================================================================== --- src/lib/GroupView.cpp (revision 148) +++ src/lib/GroupView.cpp (working copy) @@ -61,6 +61,8 @@ if(groups[i]->parent()==NULL){ Items.append(new GroupViewItem(this)); Items.back()->setText(0,groups[i]->title()); + if (db->is_pwmd) + Items.back()->setToolTip(0, generatePwmdPathToolTip(groups[i])); Items.back()->GroupHandle=groups[i]; addChilds(Items.back()); } @@ -94,6 +96,8 @@ for(int i=0; isetText(0,childs[i]->title()); + if (db->is_pwmd) + Items.back()->setToolTip(0, generatePwmdPathToolTip(childs[i])); Items.back()->GroupHandle=childs[i]; addChilds(Items.back()); } @@ -118,6 +122,24 @@ takeTopLevelItem(topLevelItemCount()-1); } +QString KeepassGroupView::generatePwmdPathToolTip(IGroupHandle *group) +{ + QString str; + + do { + QString s = QString("group%1").arg(group->pwmdId()); + + str.prepend(s); + group = group->parent(); + + if (group) + str.prepend("->"); + } while (group); + + str.prepend("keepassx->database->"); + return str; +} + void KeepassGroupView::OnNewGroup(){ GroupViewItem* parent=(GroupViewItem*)currentItem(); CGroup NewGroup; @@ -141,6 +163,10 @@ } Items.back()->GroupHandle=group; Items.back()->setText(0,group->title()); + + if (db->is_pwmd) + Items.back()->setToolTip(0, generatePwmdPathToolTip(group)); + Items.back()->setIcon(0,db->icon(group->image())); } emit fileModified(); @@ -226,7 +252,39 @@ LastHoverItem->setBackgroundColor(0,QApplication::palette().color(QPalette::Base)); LastHoverItem->setForeground(0,QBrush(QApplication::palette().color(QPalette::Text))); } + +#if 0 + //FIXME the entry needs to be able to be dropped in the entry + //viewport and not only to the group viewport + if (db->is_pwmd) { GroupViewItem* Item=(GroupViewItem*)itemAt(event->pos()); + if (event->source == EntryView) + EntryViewItem* Item=(EntryViewItem*)itemAt(event->pos()); + else + GroupViewItem* Item=(GroupViewItem*)itemAt(event->pos()); +#endif + + if (db->is_pwmd) { + GroupViewItem* Item=(GroupViewItem*)itemAt(event->pos()); + if (!Item) { + event->ignore(); + return; + } + + Qt::KeyboardModifiers m = QApplication::keyboardModifiers(); + if (m & Qt::AltModifier) { + for(int i=0;isize();i++){ + EntryViewItem *e = EntryDragItems->at(i); + //e->setPwmdTarget(event->source == EntryView ? Item->EntryHandle : Item->GroupHandle); + //e->EntryHandle->setPwmdEntryTarget(Item->GroupHandle); + } + emit fileModified(); + emit entriesDropped(); + return; + } + } + + GroupViewItem* Item=(GroupViewItem*)itemAt(event->pos()); if(!Item){ event->ignore(); return; @@ -261,6 +319,16 @@ viewport()->update(QRegion(0,RemoveLine-2,viewport()->width(),4)); } GroupViewItem* Item=(GroupViewItem*)itemAt(event->pos()); + + if (Item && db->is_pwmd) { + Qt::KeyboardModifiers m = QApplication::keyboardModifiers(); + if (m & Qt::AltModifier) { + DragItem->GroupHandle->setPwmdTarget(Item->GroupHandle); + emit fileModified(); + return; + } + } + if(!Item){ qDebug("Append at the end"); db->moveGroup(DragItem->GroupHandle,NULL,-1); @@ -344,6 +412,7 @@ void KeepassGroupView::entryDragMoveEvent( QDragMoveEvent * event ){ GroupViewItem* Item=(GroupViewItem*)itemAt(event->pos()); + if(!Item){ if(LastHoverItem){ LastHoverItem->setBackgroundColor(0,QApplication::palette().color(QPalette::Base)); @@ -370,6 +439,13 @@ Item->setBackgroundColor(0,QApplication::palette().color(QPalette::Highlight)); Item->setForeground(0,QBrush(QApplication::palette().color(QPalette::HighlightedText))); LastHoverItem=Item; + + if (db->is_pwmd) { + Qt::KeyboardModifiers m = QApplication::keyboardModifiers(); + + if (m & Qt::AltModifier) + emit groupChanged(((GroupViewItem*)Item)->GroupHandle); + } } event->accept(); return; @@ -381,6 +457,17 @@ entryDragMoveEvent(event); return; } + + if (DragItem && db->is_pwmd) { + Qt::KeyboardModifiers m = QApplication::keyboardModifiers(); + if (m & Qt::AltModifier) { + GroupViewItem* Item=(GroupViewItem*)itemAt(event->pos()); + if (Item) + emit groupChanged(((GroupViewItem*)Item)->GroupHandle); + return; + } + } + if(DragItem){ GroupViewItem* Item=(GroupViewItem*)itemAt(event->pos()); if(!Item){ @@ -467,10 +554,10 @@ if ((event->pos() - DragStartPos).manhattanLength() < QApplication::startDragDistance()) return; - + DragItem=(GroupViewItem*)itemAt(event->pos()); if(!DragItem)return; - + if(DragItem==SearchResultItem){ qDebug("SearchGroup"); DragItem=NULL; Index: src/lib/GroupView.h =================================================================== --- src/lib/GroupView.h (revision 148) +++ src/lib/GroupView.h (working copy) @@ -39,6 +39,7 @@ void createItems(); void showSearchResults(); void setCurrentGroup(IGroupHandle* group); + QString generatePwmdPathToolTip(IGroupHandle *group); private: virtual void dragEnterEvent(QDragEnterEvent* event); Index: src/lib/EntryView.cpp =================================================================== --- src/lib/EntryView.cpp (revision 148) +++ src/lib/EntryView.cpp (working copy) @@ -174,6 +174,8 @@ int j=0; if(Columns.at(0)){ item->setText(j++,entry->title()); + if (db->is_pwmd) + item->setToolTip(0, generatePwmdPathToolTip(entry)); item->setIcon(0,db->icon(entry->image())); } if (Columns.at(1)){ @@ -359,6 +361,26 @@ createItems(entries); } +QString KeepassEntryView::generatePwmdPathToolTip(IEntryHandle *entry) +{ + QString str = QString("->entry%1").arg(entry->pwmdId()); + IGroupHandle *group = entry->group(); + + do { + QString s = QString("group%1").arg(group->pwmdId()); + + str.prepend(s); + group = group->parent(); + + if (group) + str.prepend("->"); + } while (group); + + str.prepend("keepassx->database->"); + return str; +} + + void KeepassEntryView::createItems(QList& entries){ header()->setSortIndicatorShown(false); for(int i=0;isetText(j++,entries[i]->title()); + if (db->is_pwmd) + item->setToolTip(0, generatePwmdPathToolTip(entries[i])); item->setIcon(0,db->icon(entries[i]->image()));} if (Columns.at(1)){ if(config->hideUsernames()) Index: src/import/Import_PWMD.cpp =================================================================== --- src/import/Import_PWMD.cpp (revision 0) +++ src/import/Import_PWMD.cpp (revision 0) @@ -0,0 +1,215 @@ +/*************************************************************************** + * Copyright (C) 2008 by Ben Kibbey * + * bjk@luxsci.net * + * * + * Copyright (C) 2007 by Tarek Saidi * + * tarek.saidi@arcor.de * + * * + * 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; version 2 of the License. * + + * * + * 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. * + ***************************************************************************/ + +#include +#include +#include +#include +#include "Import_PWMD.h" +#include "KpxConfig.h" + +bool Import_PWMD::importDatabase(QWidget* Parent, IDatabase* database){ + db=database; + GuiParent=Parent; + QDomDocument doc; + QString ErrMsg, str; + int ErrLine; + int ErrCol; + gpg_error_t rc; + char *result; + + db->is_pwmd = true; + db->pwm = new Pwmd(); + rc = db->pwm->openHandle(); + + if (rc == -1) { + QMessageBox::critical(Parent, tr("PWMD Error"), tr("The data filename needs to be specified in Extras->Settings->Features.")); + return false; + } + else if (rc) { + QMessageBox::critical(GuiParent, tr("PWMD Import Failed"), pwmd_strerror(rc)); + return false; + } + + rc = pwmd_command(db->pwm->getHandle(), &result, + "XPATH //account[@name=\"keepassx\"]/database"); + + if (rc) { + QMessageBox::critical(GuiParent, tr("PWMD Import Failed"), pwmd_strerror(rc)); + return false; + } + + str = result; + + if(!doc.setContent(str,&ErrMsg,&ErrLine,&ErrCol)){ + pwmd_free_result(result); + QMessageBox::critical(GuiParent,tr("Import Failed"),tr("XML parsing error on line %1 column %2:\n%3").arg(ErrLine).arg(ErrCol).arg(ErrMsg)); + return false; + } + + pwmd_free_result(result); + QDomElement root=doc.documentElement(); + if(root.tagName()!="database"){ + QMessageBox::critical(GuiParent,tr("Import Failed"),tr("Parsing error: File is no valid KeePassX XML file.")); + return false; + } + QDomNodeList TopLevelGroupNodes=root.childNodes(); + QStringList GroupNames; + for(int i=0;iaddGroup(&Group,ParentGroup); + GroupHandle->setPwmdId(pwmdId); + + if (GroupElement.hasAttribute(QString("target"))) + GroupHandle->setPwmdTargetString(GroupElement.attribute(QString("target"))); + + for(int i=0;inewEntry(Group); + entry->setPwmdId(id); + QDomNodeList ChildNodes=EntryElement.childNodes(); + for(int i=0;isetTitle(ChildNodes.item(i).toElement().text()); + else if(ChildNodes.item(i).toElement().tagName()=="username") + entry->setUsername(ChildNodes.item(i).toElement().text()); + else if(ChildNodes.item(i).toElement().tagName()=="password"){ + SecString pw; + QString cpw=ChildNodes.item(i).toElement().text(); + pw.setString(cpw,true); + entry->setPassword(pw); + } + else if(ChildNodes.item(i).toElement().tagName()=="url") + entry->setUrl(ChildNodes.item(i).toElement().text()); + else if(ChildNodes.item(i).toElement().tagName()=="icon") + entry->setImage(ChildNodes.item(i).toElement().text().toInt()); + else if(ChildNodes.item(i).toElement().tagName()=="creation") + entry->setCreation(KpxDateTime::fromString(ChildNodes.item(i).toElement().text(),Qt::ISODate)); + else if(ChildNodes.item(i).toElement().tagName()=="lastaccess") + entry->setLastAccess(KpxDateTime::fromString(ChildNodes.item(i).toElement().text(),Qt::ISODate)); + else if(ChildNodes.item(i).toElement().tagName()=="lastmod") + entry->setLastMod(KpxDateTime::fromString(ChildNodes.item(i).toElement().text(),Qt::ISODate)); + else if(ChildNodes.item(i).toElement().tagName()=="expire") + entry->setExpire(KpxDateTime::fromString(ChildNodes.item(i).toElement().text(),Qt::ISODate)); + else if(ChildNodes.item(i).toElement().tagName()=="bindesc") + entry->setBinaryDesc(ChildNodes.item(i).toElement().text()); + else if(ChildNodes.item(i).toElement().tagName()=="bin") + entry->setBinary(QByteArray::fromBase64(ChildNodes.item(i).toElement().text().toAscii())); + else if(ChildNodes.item(i).toElement().tagName()=="comment"){ + QDomNodeList Lines=ChildNodes.item(i).childNodes(); + QString comment; + for(int i=0;isetComment(comment); + } + } + return true; +} Index: src/import/Import_PWMD.h =================================================================== --- src/import/Import_PWMD.h (revision 0) +++ src/import/Import_PWMD.h (revision 0) @@ -0,0 +1,41 @@ +/*************************************************************************** + * Copyright (C) 2007 by Tarek Saidi * + * tarek.saidi@arcor.de * + * * + * 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; version 2 of the License. * + + * * + * 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. * + ***************************************************************************/ + +#ifndef _IMPORT_PWMD_H_ +#define _IMPORT_PWMD_H_ + +#include +#include "Import.h" + + +class Import_PWMD:public IImport, public ImporterBase{ + public: + virtual bool importDatabase(QWidget* GuiParent, IDatabase* Database); + virtual QString identifier(){return "PWMD";} + virtual QString title(){return "Password Manager Daemon";} + private: + bool parseGroup(const QDomElement& GroupElement,IGroupHandle* ParentGroup, quint32 pwmdId); + bool parseEntry(const QDomElement& EntryElement,IGroupHandle* Group); + IDatabase* db; + QWidget* GuiParent; +}; + + +#endif Index: src/main.h =================================================================== --- src/main.h (revision 148) +++ src/main.h (working copy) @@ -37,7 +37,7 @@ #define BUILTIN_ICONS 65 -typedef enum tKeyType {PASSWORD=0,KEYFILE=1,BOTH=2}; +typedef enum tKeyType {PASSWORD=0,KEYFILE=1,BOTH=2,PWMD=3}; class KpxConfig; void createBanner(QLabel *Banner,const QPixmap* symbol,QString text); Index: src/KpxConfig.h =================================================================== --- src/KpxConfig.h (revision 148) +++ src/KpxConfig.h (working copy) @@ -41,6 +41,11 @@ # define DEFAULT_MOUNT_DIR QString() #endif +#define DEFAULT_PWMD_SOCKET_PATH QString() +#define DEFAULT_PWMD_FILE QString() +#define DEFAULT_PWMD_ENABLE false +#define DEFAULT_PWMD_LOCK true + class KpxConfig{ public: enum IntegrPluginType{NoIntegr,KDE,Gnome}; @@ -69,6 +74,10 @@ QRect mainWindowGeometry(const QRect& defaultValue){return settings.value("UI/MainWindowGeometry",defaultValue).toRect();} bool minimizeToTray(){return settings.value("Options/MinimizeToTray",false).toBool();} QString mountDir(){return settings.value("Options/MountDir",DEFAULT_MOUNT_DIR).toString();} + bool PWMDEnable(){return settings.value("Options/PWMDEnable",DEFAULT_PWMD_ENABLE).toBool();} + bool PWMDLock(){return settings.value("Options/PWMDLock",DEFAULT_PWMD_LOCK).toBool();} + QString PWMDSocketPath(){return settings.value("Options/PWMDSocketPath",DEFAULT_PWMD_SOCKET_PATH).toString();} + QString PWMDFile(){return settings.value("Options/PWMDFile",DEFAULT_PWMD_FILE).toString();} bool openLastFile(){return settings.value("Options/OpenLastFile",true).toBool();} QString pwGenCharList(){return settings.value("Options/PwGenCharList").toString();} int pwGenLength(){return settings.value("Options/PwGenLength",25).toInt();} @@ -112,6 +121,10 @@ void setMainWindowGeometry(const QRect& value){settings.setValue("UI/MainWindowGeometry",value);} void setMinimizeToTray(bool value){settings.setValue("Options/MinimizeToTray",value);} void setMountDir(const QString& value){settings.setValue("Options/MountDir",value);} + void setPWMDSocketPath(const QString& value){settings.setValue("Options/PWMDSocketPath",value);} + void setPWMDFile(const QString& value){settings.setValue("Options/PWMDFile",value);} + void setPWMDEnable(bool value){settings.setValue("Options/PWMDEnable",value);} + void setPWMDLock(bool value){settings.setValue("Options/PWMDLock",value);} void setOpenLastFile(bool value){settings.setValue("Options/OpenLastFile",value);} void setPwGenCharList(const QString& value){settings.setValue("Options/PwGenCharList",value);} void setPwGenLength(int value){settings.setValue("Options/PwGenLength",value);} Index: keepass.pro =================================================================== --- keepass.pro (revision 148) +++ keepass.pro (working copy) @@ -25,4 +25,4 @@ message("Install Prefix:" $$PREFIX) message("KDE Prefix:" $$KDEDIR) message("*** Makefile successfully generated.") -message("*** Start make now.") \ No newline at end of file +message("*** Start make now.")