author | ulf69 <ulf69> | 2004-10-18 02:55:13 (UTC) |
---|---|---|
committer | ulf69 <ulf69> | 2004-10-18 02:55:13 (UTC) |
commit | 2fd3f09238a624b1a91793d43b5f3653e2b34763 (patch) (side-by-side diff) | |
tree | 07cff893e261ad594ff44d7ab2e8e457a88d6390 | |
parent | 4e7fac5fdb4c0dace10cada64f036c56bb29fe58 (diff) | |
download | kdepimpi-2fd3f09238a624b1a91793d43b5f3653e2b34763.zip kdepimpi-2fd3f09238a624b1a91793d43b5f3653e2b34763.tar.gz kdepimpi-2fd3f09238a624b1a91793d43b5f3653e2b34763.tar.bz2 |
*** empty log message ***
-rw-r--r-- | bin/kdepim/pwmanager/pwmanagerFAQ.txt | 38 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwm.cpp | 57 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwm.h | 8 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwmdoc.cpp | 85 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwmdoc.h | 37 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwmview.cpp | 92 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwmview.h | 25 | ||||
-rw-r--r-- | pwmanager/pwmanager/serializer.cpp | 86 |
8 files changed, 300 insertions, 128 deletions
diff --git a/bin/kdepim/pwmanager/pwmanagerFAQ.txt b/bin/kdepim/pwmanager/pwmanagerFAQ.txt index 7bfe368..a28f07b 100644 --- a/bin/kdepim/pwmanager/pwmanagerFAQ.txt +++ b/bin/kdepim/pwmanager/pwmanagerFAQ.txt @@ -1,41 +1,71 @@ Q: -What is PWM/Pi +What is PWM/Pi? Q: For which platform is PWM/Pi available? Q: -Can I exchange the password files from PWM/Pi and PwManager +Can I exchange the password files from PWM/Pi and PwManager? +Q: +Does Export/Import keep sync information in place? +Q: +Can PWM/Pi sync categories? +Q: +Which crypto, hash and compress algorithm is applied to the remote file +while syncing? + ************************************************************************* Q: What is PWM/Pi A: PWM/Pi is the platform-independend version of PwManager 1.0.1, written by Michael Buesch and the PwManager Team (http://passwordmanager.sourceforge.net) ************************************************************************* Q: For which platform is PWM/Pi available? A: PWM/Pi is the platform-independend version of PWManager and it includes a replacement for the KDE libraries called microkde. It can be compiled to any platform, where Qt is available. The source code compiles without modifications on Windows, Linux Desktop and Sharp Zaurus PDA. Precompiled versions are available on www.pi-sync.net for Windows and Sharp Zaurus PDA. Latest versions and the source code cvs can be found at: http://sourceforge.net/projects/kdepimpi/ ************************************************************************* Q: Can I exchange the password files from PWM/Pi and PwManager A: The password files of PWM/Pi can not be exchanged with all versions up to 1.0.1 of PwManager. However, Michael will integrate our changes into a PwManager release 1.1, and the password files of that release will then be interchangable with PWM/Pi - - +************************************************************************* +Q: +Does Export/Import keep sync information in place +A: +Exporting data from PwManager removes all sync related information +(Meta information) from the data. Because of that, a subsequent import +results in "new" entries that will be handled as new entries when +syncing them with an existing password file. +************************************************************************* +Q: +Can PWM/Pi sync categories? +A: +No. PWM/Pi does not sync categories. It syncs all pw entries of the file +without checking for the entries categories. +A sync operation does not move modified entries from one category to another. +Only if the sync operation has to create a new pw entry, it checks for the +existance of the category and creates it if not existent. +************************************************************************* +Q: +Which crypto, hash and compress algorithm is applied to the remote file +while syncing? +A: The sync operation applies the local crypt, hash and compress algorithm +to both, the local and remote copy of the passwordfile and with thus +overwrites the settings of the remote PwManager application. diff --git a/pwmanager/pwmanager/pwm.cpp b/pwmanager/pwmanager/pwm.cpp index 014e809..57b4432 100644 --- a/pwmanager/pwmanager/pwm.cpp +++ b/pwmanager/pwmanager/pwm.cpp @@ -1,1365 +1,1364 @@ /*************************************************************************** * * * copyright (C) 2003, 2004 by Michael Buesch * * email: mbuesch@freenet.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License version 2 * * as published by the Free Software Foundation. * * * ***************************************************************************/ /*************************************************************************** * copyright (C) 2004 by Ulf Schenk * This file is originaly based on version 1.0.1 of pwmanager * and was modified to run on embedded devices that run microkde * * $Id$ **************************************************************************/ #include <klocale.h> #include <klistview.h> #include <ktoolbar.h> #include <kfiledialog.h> #include <kiconloader.h> #include <kmessagebox.h> #ifndef PWM_EMBEDDED #include <kmenubar.h> #include <kstatusbar.h> #include <dcopclient.h> #include "configwndimpl.h" #include "configuration.h" #else #include <qmenubar.h> #include <qmessagebox.h> #include <pwmprefs.h> #include <kpimglobalprefs.h> #include <kcmconfigs/kcmpwmconfig.h> #include <kcmconfigs/kcmkdepimconfig.h> #include <kcmultidialog.h> #endif #include <qpixmap.h> #include <qcheckbox.h> #include <qspinbox.h> #include <qlineedit.h> #include <qfileinfo.h> #include <qclipboard.h> #include <stdio.h> #include "pwm.h" #include "pwminit.h" #include "pwmprint.h" #include "addentrywndimpl.h" #include "globalstuff.h" #include "findwndimpl.h" #ifdef CONFIG_KWALLETIF # include "kwalletif.h" # include "kwalletemu.h" #endif #ifdef CONFIG_KEYCARD # include "pwmkeycard.h" #endif #define DEFAULT_SIZE (QSize(700, 400)) // Button IDs for "file" popup menu enum { BUTTON_POPUP_FILE_NEW = 0, BUTTON_POPUP_FILE_OPEN, BUTTON_POPUP_FILE_CLOSE, BUTTON_POPUP_FILE_SAVE, BUTTON_POPUP_FILE_SAVEAS, BUTTON_POPUP_FILE_EXPORT, BUTTON_POPUP_FILE_IMPORT, BUTTON_POPUP_FILE_PRINT, BUTTON_POPUP_FILE_QUIT }; // Button IDs for "manage" popup menu enum { BUTTON_POPUP_MANAGE_ADD = 0, BUTTON_POPUP_MANAGE_EDIT, BUTTON_POPUP_MANAGE_DEL, BUTTON_POPUP_MANAGE_CHANGEMP }; // Button IDs for chipcard popup menu enum { #ifdef CONFIG_KEYCARD BUTTON_POPUP_CHIPCARD_GENNEW = 0, BUTTON_POPUP_CHIPCARD_DEL, BUTTON_POPUP_CHIPCARD_READID, BUTTON_POPUP_CHIPCARD_SAVEBACKUP, BUTTON_POPUP_CHIPCARD_REPLAYBACKUP #else // CONFIG_KEYCARD BUTTON_POPUP_CHIPCARD_NO = 0 #endif // CONFIG_KEYCARD }; // Button IDs for "view" popup menu enum { BUTTON_POPUP_VIEW_FIND = 0, BUTTON_POPUP_VIEW_LOCK, BUTTON_POPUP_VIEW_DEEPLOCK, BUTTON_POPUP_VIEW_UNLOCK }; // Button IDs for "options" popup menu enum { BUTTON_POPUP_OPTIONS_CONFIG = 0 }; // Button IDs for "export" popup menu (in "file" popup menu) enum { BUTTON_POPUP_EXPORT_TEXT = 0, BUTTON_POPUP_EXPORT_GPASMAN #ifdef CONFIG_KWALLETIF ,BUTTON_POPUP_EXPORT_KWALLET #endif }; // Button IDs for "import" popup menu (in "file" popup menu) enum { BUTTON_POPUP_IMPORT_TEXT = 0, BUTTON_POPUP_IMPORT_GPASMAN #ifdef CONFIG_KWALLETIF ,BUTTON_POPUP_IMPORT_KWALLET #endif }; #ifdef PWM_EMBEDDED // Button IDs for "help" popup menu enum { BUTTON_POPUP_HELP_LICENSE = 0, BUTTON_POPUP_HELP_FAQ, - BUTTON_POPUP_HELP_ABOUT + BUTTON_POPUP_HELP_ABOUT, + BUTTON_POPUP_HELP_SYNC }; #endif // Button IDs for toolbar enum { BUTTON_TOOL_NEW = 0, BUTTON_TOOL_OPEN, BUTTON_TOOL_SAVE, BUTTON_TOOL_SAVEAS, BUTTON_TOOL_PRINT, BUTTON_TOOL_ADD, BUTTON_TOOL_EDIT, BUTTON_TOOL_DEL, BUTTON_TOOL_FIND, BUTTON_TOOL_LOCK, BUTTON_TOOL_DEEPLOCK, BUTTON_TOOL_UNLOCK }; PwM::PwM(PwMInit *_init, PwMDoc *doc, bool virginity, QWidget *parent, const char *name) - : KMainWindow(parent, name) + : KMainWindow(parent, "HALLO") , forceQuit (false) , forceMinimizeToTray (false) { init = _init; connect(doc, SIGNAL(docClosed(PwMDoc *)), this, SLOT(docClosed(PwMDoc *))); initMenubar(); initToolbar(); initMetrics(); setVirgin(virginity); setFocusPolicy(QWidget::WheelFocus); #ifndef PWM_EMBEDDED statusBar()->show(); #endif view = makeNewListView(doc); setCentralWidget(view); updateCaption(); showStatMsg(i18n("Ready.")); } PwM::~PwM() { disconnect(curDoc(), SIGNAL(docClosed(PwMDoc *)), this, SLOT(docClosed(PwMDoc *))); conf()->confWndMainWndSize(size()); emit closed(this); delete view; } void PwM::initMenubar() { KIconLoader* picons; #ifndef PWM_EMBEDDED KIconLoader icons; picons = &icons; #else picons = KGlobal::iconLoader(); syncPopup = new KPopupMenu(this); syncManager = new KSyncManager((QWidget*)this, (KSyncInterface*)this, KSyncManager::PWMPI, PWMPrefs::instance(), syncPopup); syncManager->setBlockSave(false); connect ( syncPopup, SIGNAL( activated ( int ) ), syncManager, SLOT (slotSyncMenu( int ) ) ); syncManager->fillSyncMenu(); #endif filePopup = new KPopupMenu(this); importPopup = new KPopupMenu(filePopup); exportPopup = new KPopupMenu(filePopup); managePopup = new KPopupMenu(this); #ifdef CONFIG_KEYCARD chipcardPopup = new KPopupMenu(this); #endif // CONFIG_KEYCARD viewPopup = new KPopupMenu(this); optionsPopup = new KPopupMenu(this); // "file" popup menu filePopup->insertItem(QIconSet(picons->loadIcon("filenew", KIcon::Small)), i18n("&New"), this, SLOT(new_slot()), 0, BUTTON_POPUP_FILE_NEW); filePopup->insertItem(QIconSet(picons->loadIcon("fileopen", KIcon::Small)), i18n("&Open"), this, SLOT(open_slot()), 0, BUTTON_POPUP_FILE_OPEN); filePopup->insertItem(QIconSet(picons->loadIcon("fileclose", KIcon::Small)), i18n("&Close"), this, SLOT(close_slot()), 0, BUTTON_POPUP_FILE_CLOSE); filePopup->insertSeparator(); filePopup->insertItem(QIconSet(picons->loadIcon("filesave", KIcon::Small)), i18n("&Save"), this, SLOT(save_slot()), 0, BUTTON_POPUP_FILE_SAVE); filePopup->insertItem(QIconSet(picons->loadIcon("filesaveas", KIcon::Small)), i18n("Save &as..."), this, SLOT(saveAs_slot()), 0, BUTTON_POPUP_FILE_SAVEAS); filePopup->insertSeparator(); // "file/export" popup menu exportPopup->insertItem(i18n("&Text-file..."), this, SLOT(exportToText()), 0, BUTTON_POPUP_EXPORT_TEXT); exportPopup->insertItem(i18n("&Gpasman / Kpasman ..."), this, SLOT(exportToGpasman()), 0, BUTTON_POPUP_EXPORT_GPASMAN); #ifdef CONFIG_KWALLETIF exportPopup->insertItem(i18n("&KWallet..."), this, SLOT(exportToKWallet()), 0, BUTTON_POPUP_EXPORT_KWALLET); #endif filePopup->insertItem(QIconSet(picons->loadIcon("fileexport", KIcon::Small)), i18n("E&xport"), exportPopup, BUTTON_POPUP_FILE_EXPORT); // "file/import" popup menu importPopup->insertItem(i18n("&Text-file..."), this, SLOT(importFromText()), 0, BUTTON_POPUP_IMPORT_TEXT); importPopup->insertItem(i18n("&Gpasman / Kpasman ..."), this, SLOT(importFromGpasman()), 0, BUTTON_POPUP_IMPORT_GPASMAN); #ifdef CONFIG_KWALLETIF importPopup->insertItem(i18n("&KWallet..."), this, SLOT(importKWallet()), 0, BUTTON_POPUP_IMPORT_KWALLET); #endif filePopup->insertItem(QIconSet(picons->loadIcon("fileimport", KIcon::Small)), i18n("I&mport"), importPopup, BUTTON_POPUP_FILE_IMPORT); filePopup->insertSeparator(); filePopup->insertItem(QIconSet(picons->loadIcon("fileprint", KIcon::Small)), i18n("&Print..."), this, SLOT(print_slot()), 0, BUTTON_POPUP_FILE_PRINT); filePopup->insertSeparator(); filePopup->insertItem(QIconSet(picons->loadIcon("exit", KIcon::Small)), i18n("&Quit"), this, SLOT(quitButton_slot()), 0, BUTTON_POPUP_FILE_QUIT); menuBar()->insertItem(i18n("&File"), filePopup); // "manage" popup menu managePopup->insertItem(QIconSet(picons->loadIcon("pencil", KIcon::Small)), i18n("&Add password"), this, SLOT(addPwd_slot()), 0, BUTTON_POPUP_MANAGE_ADD); managePopup->insertItem(QIconSet(picons->loadIcon("edit", KIcon::Small)), i18n("&Edit"), this, SLOT(editPwd_slot()), 0, BUTTON_POPUP_MANAGE_EDIT); managePopup->insertItem(QIconSet(picons->loadIcon("editdelete", KIcon::Small)), i18n("&Delete"), this, SLOT(deletePwd_slot()), 0, BUTTON_POPUP_MANAGE_DEL); managePopup->insertSeparator(); managePopup->insertItem(QIconSet(picons->loadIcon("rotate", KIcon::Small)), i18n("Change &Master Password"), this, SLOT(changeMasterPwd_slot()), 0, BUTTON_POPUP_MANAGE_CHANGEMP); menuBar()->insertItem(i18n("&Manage"), managePopup); // "chipcard" popup menu #ifdef CONFIG_KEYCARD chipcardPopup->insertItem(QIconSet(picons->loadIcon("filenew", KIcon::Small)), i18n("&Generate new key-card"), this, SLOT(genNewCard_slot()), 0, BUTTON_POPUP_CHIPCARD_GENNEW); chipcardPopup->insertItem(QIconSet(picons->loadIcon("editdelete", KIcon::Small)), i18n("&Erase key-card"), this, SLOT(eraseCard_slot()), 0, BUTTON_POPUP_CHIPCARD_DEL); chipcardPopup->insertItem(QIconSet(picons->loadIcon("", KIcon::Small)), i18n("Read card-&ID"), this, SLOT(readCardId_slot()), 0, BUTTON_POPUP_CHIPCARD_READID); chipcardPopup->insertSeparator(); chipcardPopup->insertItem(QIconSet(picons->loadIcon("2rightarrow", KIcon::Small)), i18n("&Make card backup-image"), this, SLOT(makeCardBackup_slot()), 0, BUTTON_POPUP_CHIPCARD_SAVEBACKUP); chipcardPopup->insertItem(QIconSet(picons->loadIcon("2leftarrow", KIcon::Small)), i18n("&Replay card backup-image"), this, SLOT(replayCardBackup_slot()), 0, BUTTON_POPUP_CHIPCARD_REPLAYBACKUP); menuBar()->insertItem(i18n("&Chipcard manager"), chipcardPopup); #endif // CONFIG_KEYCARD // "view" popup menu viewPopup->insertItem(QIconSet(picons->loadIcon("find", KIcon::Small)), i18n("&Find"), this, SLOT(find_slot()), 0, BUTTON_POPUP_VIEW_FIND); viewPopup->insertSeparator(); viewPopup->insertItem(QIconSet(picons->loadIcon("halfencrypted", KIcon::Small)), i18n("&Lock all entries"), this, SLOT(lockWnd_slot()), 0, BUTTON_POPUP_VIEW_LOCK); viewPopup->insertItem(QIconSet(picons->loadIcon("encrypted", KIcon::Small)), i18n("&Deep-lock all entries"), this, SLOT(deepLockWnd_slot()), 0, BUTTON_POPUP_VIEW_DEEPLOCK); viewPopup->insertItem(QIconSet(picons->loadIcon("decrypted", KIcon::Small)), i18n("&Unlock all entries"), this, SLOT(unlockWnd_slot()), 0, BUTTON_POPUP_VIEW_UNLOCK); menuBar()->insertItem(i18n("&View"), viewPopup); // "options" popup menu optionsPopup->insertItem(QIconSet(picons->loadIcon("configure", KIcon::Small)), i18n("&Configure..."), this, SLOT(config_slot()), BUTTON_POPUP_OPTIONS_CONFIG); menuBar()->insertItem(i18n("&Options"), optionsPopup); // "help" popup menu #ifndef PWM_EMBEDDED helpPopup = helpMenu(QString::null, false); #else menuBar()->insertItem(i18n("&Sync"), syncPopup); helpPopup = new KPopupMenu(this); helpPopup->insertItem(i18n("&License"), this, SLOT(showLicense_slot()), 0, BUTTON_POPUP_HELP_LICENSE); helpPopup->insertItem(i18n("&Faq"), this, SLOT(faq_slot()), 0, BUTTON_POPUP_HELP_FAQ); helpPopup->insertItem(i18n("&About PwManager"), this, SLOT(createAboutData_slot()), 0, BUTTON_POPUP_HELP_ABOUT); + helpPopup->insertItem(i18n("&Sync HowTo"), this, + SLOT(syncHowTo_slot()), 0, + BUTTON_POPUP_HELP_SYNC); + #endif menuBar()->insertItem(i18n("&Help"), helpPopup); } void PwM::initToolbar() { KIconLoader* picons; #ifndef PWM_EMBEDDED KIconLoader icons; picons = &icons; #else picons = KGlobal::iconLoader(); #endif #ifdef PWM_EMBEDDED if ( QApplication::desktop()->width() > 320 ) #endif { toolBar()->insertButton(picons->loadIcon("filenew", KIcon::Toolbar), BUTTON_TOOL_NEW, SIGNAL(clicked(int)), this, SLOT(new_slot()), true, i18n("New")); toolBar()->insertButton(picons->loadIcon("fileopen", KIcon::Toolbar), BUTTON_TOOL_OPEN, SIGNAL(clicked(int)), this, SLOT(open_slot()), true, i18n("Open")); toolBar()->insertSeparator(); } toolBar()->insertButton(picons->loadIcon("filesave", KIcon::Toolbar), BUTTON_TOOL_SAVE, SIGNAL(clicked(int)), this, SLOT(save_slot()), true, i18n("Save")); toolBar()->insertButton(picons->loadIcon("filesaveas", KIcon::Toolbar), BUTTON_TOOL_SAVEAS, SIGNAL(clicked(int)), this, SLOT(saveAs_slot()), true, i18n("Save as")); toolBar()->insertButton(picons->loadIcon("fileprint", KIcon::Toolbar), BUTTON_TOOL_PRINT, SIGNAL(clicked(int)), this, SLOT(print_slot()), true, i18n("Print...")); toolBar()->insertSeparator(); toolBar()->insertButton(picons->loadIcon("pencil", KIcon::Toolbar), BUTTON_TOOL_ADD, SIGNAL(clicked(int)), this, SLOT(addPwd_slot()), true, i18n("Add password")); toolBar()->insertButton(picons->loadIcon("edit", KIcon::Toolbar), BUTTON_TOOL_EDIT, SIGNAL(clicked(int)), this, SLOT(editPwd_slot()), true, i18n("Edit password")); toolBar()->insertButton(picons->loadIcon("editdelete", KIcon::Toolbar), BUTTON_TOOL_DEL, SIGNAL(clicked(int)), this, SLOT(deletePwd_slot()), true, i18n("Delete password")); toolBar()->insertSeparator(); toolBar()->insertButton(picons->loadIcon("find", KIcon::Toolbar), BUTTON_TOOL_FIND, SIGNAL(clicked(int)), this, SLOT(find_slot()), true, i18n("Find entry")); toolBar()->insertSeparator(); toolBar()->insertButton(picons->loadIcon("halfencrypted", KIcon::Toolbar), BUTTON_TOOL_LOCK, SIGNAL(clicked(int)), this, SLOT(lockWnd_slot()), true, i18n("Lock all entries")); toolBar()->insertButton(picons->loadIcon("encrypted", KIcon::Toolbar), BUTTON_TOOL_DEEPLOCK, SIGNAL(clicked(int)), this, SLOT(deepLockWnd_slot()), true, i18n("Deep-Lock all entries")); toolBar()->insertButton(picons->loadIcon("decrypted", KIcon::Toolbar), BUTTON_TOOL_UNLOCK, SIGNAL(clicked(int)), this, SLOT(unlockWnd_slot()), true, i18n("Unlock all entries")); } void PwM::initMetrics() { QSize s = conf()->confWndMainWndSize(); if (s.isValid()) resize(s); else resize(DEFAULT_SIZE); } void PwM::updateCaption() { setPlainCaption(curDoc()->getTitle() + " - " PROG_NAME " " PACKAGE_VER); } void PwM::hideEvent(QHideEvent *) { if (isMinimized()) { if (init->tray()) { forceMinimizeToTray = true; close(); } int mmlock = conf()->confGlobMinimizeLock(); switch (mmlock) { case 0: // don't lock anything break; case 1: { // normal lock curDoc()->lockAll(true); break; } case 2: { // deep-lock curDoc()->deepLock(); break; } default: WARN(); } } } void PwM::setVirgin(bool v) { if (virgin == v) return; virgin = v; filePopup->setItemEnabled(BUTTON_POPUP_FILE_SAVE, !v); filePopup->setItemEnabled(BUTTON_POPUP_FILE_SAVEAS, !v); filePopup->setItemEnabled(BUTTON_POPUP_FILE_EXPORT, !v); filePopup->setItemEnabled(BUTTON_POPUP_FILE_PRINT, !v); managePopup->setItemEnabled(BUTTON_POPUP_MANAGE_EDIT, !v); managePopup->setItemEnabled(BUTTON_POPUP_MANAGE_DEL, !v); managePopup->setItemEnabled(BUTTON_POPUP_MANAGE_CHANGEMP, !v); viewPopup->setItemEnabled(BUTTON_POPUP_VIEW_LOCK, !v); viewPopup->setItemEnabled(BUTTON_POPUP_VIEW_DEEPLOCK, !v); viewPopup->setItemEnabled(BUTTON_POPUP_VIEW_UNLOCK, !v); viewPopup->setItemEnabled(BUTTON_POPUP_VIEW_FIND, !v); toolBar()->setItemEnabled(BUTTON_TOOL_SAVE, !v); toolBar()->setItemEnabled(BUTTON_TOOL_SAVEAS, !v); toolBar()->setItemEnabled(BUTTON_TOOL_PRINT, !v); toolBar()->setItemEnabled(BUTTON_TOOL_EDIT, !v); toolBar()->setItemEnabled(BUTTON_TOOL_DEL, !v); toolBar()->setItemEnabled(BUTTON_TOOL_LOCK, !v); toolBar()->setItemEnabled(BUTTON_TOOL_DEEPLOCK, !v); toolBar()->setItemEnabled(BUTTON_TOOL_UNLOCK, !v); toolBar()->setItemEnabled(BUTTON_TOOL_FIND, !v); } void PwM::new_slot() { init->createMainWnd(); } //US ENH void PwM::open_slot() { open_slot(""); } void PwM::open_slot(QString fn) { openDoc(fn); } PwMDoc * PwM::openDoc(QString filename, bool openDeepLocked) { if (!isVirgin()) { // open the document in a new window. PwM *newInstance = init->createMainWnd(); PwMDoc *newDoc = newInstance->openDoc(filename, openDeepLocked); if (!newDoc) { newInstance->setForceQuit(true); delete_and_null(newInstance); } return newDoc; } if (!curDoc()->openDocUi(curDoc(), filename, openDeepLocked)) return 0; showStatMsg(i18n("Successfully opened file.")); updateCaption(); setVirgin(false); return curDoc(); } PwMView * PwM::makeNewListView(PwMDoc *doc) { PwMView *ret = new PwMView(this, this, doc); ret->setFont(conf()->confGlobEntryFont()); ret->show(); return ret; } void PwM::close_slot() { close(); } void PwM::quitButton_slot() { init->shutdownApp(0); } void PwM::save_slot() { save(); } bool PwM::save() { if (!curDoc()->saveDocUi(curDoc())) return false; showStatMsg(i18n("Successfully saved data.")); updateCaption(); return true; } void PwM::saveAs_slot() { saveAs(); } bool PwM::saveAs() { if (!curDoc()->saveAsDocUi(curDoc())) return false; showStatMsg(i18n("Successfully saved data.")); updateCaption(); return true; } //US ENH : changed code to run with older MOC void PwM::addPwd_slot() { addPwd_slot(0, 0); } void PwM::addPwd_slot(QString *pw, PwMDoc *_doc) { PwMDoc *doc; if (_doc) { doc = _doc; } else { doc = curDoc(); } PWM_ASSERT(doc); doc->timer()->getLock(DocTimer::id_autoLockTimer); #ifndef PWM_EMBEDDED AddEntryWndImpl w; #else AddEntryWndImpl w(this, "addentrywndimpl"); #endif vector<string> catList; doc->getCategoryList(&catList); unsigned i, size = catList.size(); for (i = 0; i < size; ++i) { w.addCategory(catList[i].c_str()); } w.setCurrCategory(view->getCurrentCategory()); if (pw) w.pwLineEdit->setText(*pw); tryAgain: if (w.exec() == 1) { PwMDataItem d; + + //US BUG: to initialize all values of curEntr with meaningfulldata, + // we call clear on it. Reason: Metadata will be uninitialized otherwise. + // another option would be to create a constructor for PwMDataItem + d.clear(true); + d.desc = w.getDescription().latin1(); d.name = w.getUsername().latin1(); d.pw = w.getPassword().latin1(); d.comment = w.getComment().latin1(); d.url = w.getUrl().latin1(); d.launcher = w.getLauncher().latin1(); PwMerror ret = doc->addEntry(w.getCategory(), &d); if (ret == e_entryExists) { KMessageBox::error(this, i18n - ("An entry with this \"Description\", " + ("An entry with this \"Description\",\n" "does already exist.\n" "Please select another description."), i18n("entry already exists.")); goto tryAgain; } else if (ret == e_maxAllowedEntr) { - KMessageBox::error(this, i18n("The maximum possible number of entries " - "has been reached. You can't add more entries."), + KMessageBox::error(this, i18n("The maximum possible number of\nentries" + "has been reached.\nYou can't add more entries."), i18n("maximum number of entries")); doc->timer()->putLock(DocTimer::id_autoLockTimer); return; } } setVirgin(false); doc->timer()->putLock(DocTimer::id_autoLockTimer); } //US ENH : changed code to run with older MOC void PwM::editPwd_slot() { editPwd_slot(0,0,0); } void PwM::editPwd_slot(const QString *category) { editPwd_slot(category, 0, 0); } void PwM::editPwd_slot(const QString *category, const int *index, PwMDoc *_doc) { PwMDoc *doc; if (_doc) { doc = _doc; } else { doc = curDoc(); } PWM_ASSERT(doc); if (doc->isDocEmpty()) return; if (doc->isDeepLocked()) return; doc->timer()->getLock(DocTimer::id_autoLockTimer); unsigned int curEntryIndex; if (index) { curEntryIndex = *index; } else { if (!(view->getCurEntryIndex(&curEntryIndex))) { printDebug("couldn't get index. Maybe we have a binary entry here."); doc->timer()->putLock(DocTimer::id_autoLockTimer); return; } } QString curCategory; if (category) { curCategory = *category; } else { curCategory = view->getCurrentCategory(); } PwMDataItem currItem; if (!doc->getEntry(curCategory, curEntryIndex, &currItem, true)) { doc->timer()->putLock(DocTimer::id_autoLockTimer); return; } BUG_ON(currItem.binary); AddEntryWndImpl w; vector<string> catList; doc->getCategoryList(&catList); unsigned i, size = catList.size(); for (i = 0; i < size; ++i) { w.addCategory(catList[i].c_str()); } w.setCurrCategory(curCategory); w.setDescription(currItem.desc.c_str()); w.setUsername(currItem.name.c_str()); w.setPassword(currItem.pw.c_str()); w.setUrl(currItem.url.c_str()); w.setLauncher(currItem.launcher.c_str()); w.setComment(currItem.comment.c_str()); if (w.exec() == 1) { currItem.desc = w.getDescription().latin1(); currItem.name = w.getUsername().latin1(); currItem.pw = w.getPassword().latin1(); currItem.comment = w.getComment().latin1(); currItem.url = w.getUrl().latin1(); currItem.launcher = w.getLauncher().latin1(); if (!doc->editEntry(curCategory, w.getCategory(), curEntryIndex, &currItem)) { KMessageBox::error(this, i18n("Couldn't edit the entry.\n" "Maybe you changed the category and " "this entry is already present in the new " "category?"), i18n("couldn't edit entry.")); doc->timer()->putLock(DocTimer::id_autoLockTimer); return; } } doc->timer()->putLock(DocTimer::id_autoLockTimer); } void PwM::deletePwd_slot() { PWM_ASSERT(curDoc()); if (curDoc()->isDocEmpty()) return; if (curDoc()->isDeepLocked()) return; curDoc()->timer()->getLock(DocTimer::id_autoLockTimer); unsigned int curEntryIndex = 0; if (!(view->getCurEntryIndex(&curEntryIndex))) { printDebug("couldn't get index"); curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); return; } PwMDataItem currItem; QString curCategory = view->getCurrentCategory(); if (!curDoc()->getEntry(curCategory, curEntryIndex, &currItem)) { printDebug("couldn't get entry"); curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); return; } if (KMessageBox:: questionYesNo(this, i18n ("Do you really want to delete\nthe selected entry") + " \n\"" + QString(currItem.desc.c_str()) + "\" ?", i18n("delete?")) == KMessageBox::Yes) { curDoc()->delEntry(curCategory, curEntryIndex); } curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); } void PwM::changeMasterPwd_slot() { PWM_ASSERT(curDoc()); curDoc()->changeCurrentPw(); } void PwM::lockWnd_slot() { PWM_ASSERT(curDoc()); curDoc()->lockAll(true); } void PwM::deepLockWnd_slot() { PWM_ASSERT(curDoc()); curDoc()->deepLock(); } void PwM::unlockWnd_slot() { PWM_ASSERT(curDoc()); curDoc()->lockAll(false); } void PwM::config_slot() { int oldStyle = conf()->confWndMainViewStyle(); #ifdef PWM_EMBEDDED KCMultiDialog* ConfigureDialog = new KCMultiDialog( "PIM", this ,"pwmconfigdialog", true ); KCMPwmConfig* pwmcfg = new KCMPwmConfig( ConfigureDialog->getNewVBoxPage(i18n( "PwManager")) , "KCMPwmConfig" ); ConfigureDialog->addModule(pwmcfg ); KCMKdePimConfig* kdelibcfg = new KCMKdePimConfig( ConfigureDialog->getNewVBoxPage(i18n( "Global")) , "KCMKdeLibConfig" ); ConfigureDialog->addModule(kdelibcfg ); #ifndef DESKTOP_VERSION ConfigureDialog->showMaximized(); #endif if ( ConfigureDialog->exec() ) KMessageBox::information( this, i18n("Some changes are only\neffective after a restart!\n") ); delete ConfigureDialog; #else //PWM_EMBEDDED // display the configuration window (modal mode) if (!conf()->showConfWnd(this)) return; #endif int newStyle = conf()->confWndMainViewStyle(); // reinitialize tray init->initTray(); // reinitialize KWallet emulation init->initKWalletEmu(); PwMDocList *_dl = PwMDoc::getOpenDocList(); const vector<PwMDocList::listItem> *dl = _dl->getList(); vector<PwMDocList::listItem>::const_iterator i = dl->begin(), end = dl->end(); PwMDoc *doc; while (i != end) { doc = (*i).doc; // unlock-without-mpw timeout doc->timer()->start(DocTimer::id_mpwTimer); // auto-lock timeout doc->timer()->start(DocTimer::id_autoLockTimer); ++i; } const QValueList<PwM *> *ml = init->mainWndList(); #ifndef PWM_EMBEDDED QValueList<PwM *>::const_iterator i2 = ml->begin(), end2 = ml->end(); #else QValueList<PwM *>::ConstIterator i2 = ml->begin(), end2 = ml->end(); #endif PwM *pwm; while (i2 != end2) { pwm = *i2; // reinitialize the window style. if (oldStyle != newStyle) pwm->curView()->initStyle(newStyle); // set the new font pwm->curView()->setFont(conf()->confGlobEntryFont()); ++i2; } } void PwM::activateMpButton(bool activate) { managePopup->setItemEnabled(BUTTON_POPUP_MANAGE_CHANGEMP, activate); } void PwM::closeEvent(QCloseEvent *e) { e->accept(); } void PwM::docClosed(PwMDoc *doc) { PARAM_UNUSED(doc); PWM_ASSERT(doc == curDoc()); close(); } void PwM::find_slot() { PWM_ASSERT(curDoc()); if (curDoc()->isDocEmpty()) return; if (curDoc()->isDeepLocked()) return; curDoc()->timer()->getLock(DocTimer::id_autoLockTimer); FindWndImpl findWnd(view); findWnd.exec(); curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); } void PwM::exportToText() { PWM_ASSERT(curDoc()); if (curDoc()->isDocEmpty()) { KMessageBox::information(this, i18n ("Sorry, there's nothing to export.\n" "Please first add some passwords."), i18n("nothing to do")); return; } curDoc()->timer()->getLock(DocTimer::id_autoLockTimer); QString fn(KFileDialog::getSaveFileName(QString::null, i18n("*|plain-text file"), this)); if (fn == "") { curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); return; } PwMerror ret = curDoc()->exportToText(&fn); if (ret != e_success) { KMessageBox::error(this, i18n("Error: Couldn't write to file.\n" "Please check if you have permission to write " "to the file in that directory."), i18n("error while writing")); } else showStatMsg(i18n("Successfully exported data.")); curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); } bool PwM::importFromText() { if (!isVirgin()) { if (KMessageBox::questionYesNo(this, i18n("Do you want to import the data " "into the current document? (If you " "select \"no\", a new document will be " "opened.)"), i18n("import into this document?")) == KMessageBox::No) { // import the data to a new window. PwM *newInstance = init->createMainWnd(); bool ok = newInstance->importFromText(); if (!ok) { newInstance->setForceQuit(true); delete_and_null(newInstance); } return ok; } } curDoc()->timer()->getLock(DocTimer::id_autoLockTimer); PwMerror ret; QString path(KFileDialog::getOpenFileName(QString::null, i18n("*|PWM-exported text file"), this)); if (path == "") goto cancelImport; ret = curDoc()->importFromText(&path, 0); if (ret == e_fileFormat) { KMessageBox::error(this, i18n("Could not read file-format.\n" "This seems to be _not_ a valid file " "exported by PwM."), i18n("invalid file-format")); goto cancelImport; } else if (ret == e_invalidArg) { BUG(); goto cancelImport; } else if (ret != e_success) { KMessageBox::error(this, i18n("Could not import file!\n" "Do you have permission to read this file? " "Do you have enough free memory?"), i18n("import failed")); goto cancelImport; } setVirgin(false); curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); return true; cancelImport: curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); return false; } void PwM::exportToGpasman() { PWM_ASSERT(curDoc()); if (curDoc()->isDocEmpty()) { KMessageBox::information(this, i18n ("Sorry, there's nothing to export.\n" "Please first add some passwords."), i18n("nothing to do")); return; } curDoc()->timer()->getLock(DocTimer::id_autoLockTimer); QString fn(KFileDialog::getSaveFileName(QString::null, i18n("*|Gpasman or Kpasman file"), this)); if (fn == "") { curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); return; } PwMerror ret = curDoc()->exportToGpasman(&fn); if (ret != e_success) { if (ret == e_noPw) { curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); return; } KMessageBox::error(this, i18n("Error: Couldn't write to file.\n" "Please check if you have permission to write " "to the file in that directory."), i18n("error while writing")); } else showStatMsg(i18n("Successfully exported data.")); curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); } void PwM::exportToKWallet() { #ifdef CONFIG_KWALLETIF if (!checkAndAskForKWalletEmu()) return; PWM_ASSERT(curDoc()); if (curDoc()->isDocEmpty()) { KMessageBox::information(this, i18n ("Sorry, there's nothing to export.\n" "Please first add some passwords."), i18n("nothing to do")); init->initKWalletEmu(); return; } curDoc()->timer()->getLock(DocTimer::id_autoLockTimer); KWalletIf walletIf(this); if (walletIf.kwalletExport(curDoc())) { KMessageBox::information(this, i18n("Successfully exported the data of the current " "document to KWallet."), i18n("Successfully exported data.")); showStatMsg(i18n("Successfully exported data.")); } init->initKWalletEmu(); curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); #endif // CONFIG_KWALLETIF } bool PwM::importFromGpasman() { if (!isVirgin()) { if (KMessageBox::questionYesNo(this, i18n("Do you want to import the data " "into the current document? (If you " "select \"no\", a new document will be " "opened.)"), i18n("import into this document?")) == KMessageBox::No) { // import the data to a new window. PwM *newInstance = init->createMainWnd(); bool ok = newInstance->importFromGpasman(); if (!ok) { newInstance->setForceQuit(true); delete_and_null(newInstance); } return ok; } } curDoc()->timer()->getLock(DocTimer::id_autoLockTimer); PwMerror ret; QString path(KFileDialog::getOpenFileName(QString::null, i18n("*|Gpasman or Kpasman file"), this)); if (path == "") goto cancelImport; ret = curDoc()->importFromGpasman(&path); if (ret == e_wrongPw) { if (KMessageBox::questionYesNo(this, i18n ("This is probably the wrong master-password" "you have typed in.\n" "There is no real way to determine the " "correctness of the password in the Gpasman " "file-format. But I think this " "password ist wrong.\n" "Do you want to continue nevertheless?"), i18n("password error")) == KMessageBox::No) { goto cancelImport; } } else if (ret != e_success) { KMessageBox::error(this, i18n("Could not import file!\n" "Do you have permission to read this file?"), i18n("import failed")); goto cancelImport; } setVirgin(false); curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); return true; cancelImport: curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); return false; } #ifdef CONFIG_KWALLETIF bool PwM::checkAndAskForKWalletEmu() { if (init->kwalletEmu()) { /* KWallet emulation is enabled. We can't import/export * data from/to it, while emulation is active. */ if (KMessageBox::questionYesNo(this, i18n("KWallet emulation is enabled.\n" "You can't import or export data from/to " "the original KWallet, while the emulation " "is active.\n" "Do you want to tempoarly disable the KWallet emulation?"), i18n("Tempoarly disable KWallet emulation?")) == KMessageBox::Yes) { init->initKWalletEmu(true); PWM_ASSERT(!init->kwalletEmu()); return true; } return false; } return true; } #endif // CONFIG_KWALLETIF bool PwM::importKWallet() { #ifdef CONFIG_KWALLETIF if (!checkAndAskForKWalletEmu()) return false; KWalletIf walletIf(this); if (!isVirgin()) { if (KMessageBox::questionYesNo(this, i18n("Do you want to import the data " "into the current document? (If you " "select \"no\", a new document will be " "opened.)"), i18n("import into this document?")) == KMessageBox::No) { // import the data to a new window. PwM *newInstance = init->createMainWnd(); bool ok = newInstance->importKWallet(); if (!ok) { newInstance->setForceQuit(true); delete_and_null(newInstance); goto exit_fail; } else { goto exit_ok; } } } curDoc()->timer()->getLock(DocTimer::id_autoLockTimer); if (!walletIf.kwalletImport(curDoc())) { curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); showStatMsg(i18n("KWallet import failed")); goto exit_fail; } KMessageBox::information(this, i18n("Successfully imported the KWallet data " "into the current document."), i18n("successfully imported")); showStatMsg(i18n("successfully imported")); setVirgin(false); curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); exit_ok: init->initKWalletEmu(); return true; exit_fail: init->initKWalletEmu(); #endif // CONFIG_KWALLETIF return false; } void PwM::print_slot() { curDoc()->timer()->getLock(DocTimer::id_autoLockTimer); #ifndef PWM_EMBEDDED PwMPrint p(curDoc(), this); p.printNow(); #else qDebug("PwM::print_slot , PRINTING IS NOT IMPLEMENTED"); #endif curDoc()->timer()->putLock(DocTimer::id_autoLockTimer); } void PwM::genNewCard_slot() { #ifdef CONFIG_KEYCARD init->keycard()->genNewCard(); #endif } void PwM::eraseCard_slot() { #ifdef CONFIG_KEYCARD init->keycard()->eraseCard(); #endif } void PwM::readCardId_slot() { #ifdef CONFIG_KEYCARD init->keycard()->displayKey(); #endif } void PwM::makeCardBackup_slot() { #ifdef CONFIG_KEYCARD init->keycard()->makeBackupImage(); #endif } void PwM::replayCardBackup_slot() { #ifdef CONFIG_KEYCARD init->keycard()->replayBackupImage(); #endif } void PwM::execLauncher_slot() { PWM_ASSERT(curDoc()); if (curDoc()->isDeepLocked()) return; unsigned int curEntryIndex; if (!view->getCurEntryIndex(&curEntryIndex)) return; bool ret = curDoc()->execLauncher(view->getCurrentCategory(), curEntryIndex); if (ret) showStatMsg(i18n("Executed the \"Launcher\".")); else showStatMsg(i18n("ERROR: Couldn't execute the \"Launcher\"!")); } void PwM::goToURL_slot() { PWM_ASSERT(curDoc()); if (curDoc()->isDeepLocked()) return; unsigned int curEntryIndex; if (!view->getCurEntryIndex(&curEntryIndex)) return; bool ret = curDoc()->goToURL(view->getCurrentCategory(), curEntryIndex); if (ret) showStatMsg(i18n("started browser with current URL.")); else showStatMsg(i18n("ERROR: Couldn't start browser! Maybe invalid URL?")); } void PwM::copyToClipboard(const QString &s) { QClipboard *cb = QApplication::clipboard(); #ifndef PWM_EMBEDDED if (cb->supportsSelection()) cb->setText(s, QClipboard::Selection); cb->setText(s, QClipboard::Clipboard); #else cb->setText(s); #endif } void PwM::showStatMsg(const QString &msg) { #ifndef PWM_EMBEDDED KStatusBar *statBar = statusBar(); statBar->message(msg, STATUSBAR_MSG_TIMEOUT * 1000); #else qDebug("Statusbar : %s",msg.latin1()); #endif } void PwM::focusInEvent(QFocusEvent *e) { if (e->gotFocus()) { emit gotFocus(this); } else if (e->lostFocus()) { emit lostFocus(this); } } #ifdef PWM_EMBEDDED void PwM::showLicense_slot() { KApplication::showLicence(); } void PwM::faq_slot() { KApplication::showFile( "PWM/Pi FAQ", "kdepim/pwmanager/pwmanagerFAQ.txt" ); } +void PwM::syncHowTo_slot() +{ + qDebug("PwM::syncHowTo_slot"); + KApplication::showFile( "KDE-Pim/Pi Synchronization HowTo", "kdepim/SyncHowto.txt" ); +} + + void PwM::createAboutData_slot() { QString version; #include <../version> QMessageBox::about( this, "About PwManager/Pi", "PwManager/Platform-independent\n" "(PWM/Pi) " +version + " - " + #ifdef DESKTOP_VERSION "Desktop Edition\n" #else "PDA-Edition\n" "for: Zaurus 5500 / 7x0 / 8x0\n" #endif "(c) 2004 Ulf Schenk\n" "(c) 2004 Lutz Rogowski\n" "(c) 1997-2004, The KDE PIM Team\n" "(c) Michael Buesch - main programming\nand current maintainer\nmbuesch@freenet.de\n" "Matt Scifo - mscifo@o1.com\n" "Elias Probst - elias.probst@gmx.de\n" "George Staikos - staikos@kde.org\n" "Matthew Palmer - mjp16@uow.edu.au\n" "Olivier Sessink - gpasman@nl.linux.org\n" "The libgcrypt developers -\nBlowfish and SHA1 algorithms\nftp://ftp.gnupg.org/gcrypt/alpha/libgcrypt/\n" "Troy Engel - tengel@sonic.net\n" "Wickey - wickey@gmx.at\n" "Ian MacGregor - original documentation author.\n" ); } //this are the overwritten callbackmethods from the syncinterface bool PwM::sync(KSyncManager* manager, QString filename, int mode) { PWM_ASSERT(curDoc()); bool ret = curDoc()->sync(manager, filename, mode); + qDebug("PwM::sync save now: ret=%i", ret); + if (ret == true) { //US BUG: what can we call here to update the view of the current doc? //mViewManager->refreshView(); - } - - return ret; -} -//called by the syncmanager to indicate that the work has to be marked as dirty. -void PwM::sync_setModified() -{ - PWM_ASSERT(curDoc()); - curDoc()->sync_setModified(); -} - -//called by the syncmanager to ask if the dirty flag is set. -bool PwM::sync_isModified() -{ - PWM_ASSERT(curDoc()); - return curDoc()->sync_isModified(); + //US curDoc()->sync sets the dirtyFlag in case the sync was successfull. + save(); } -//called by the syncmanager to indicate that the work has to be saved. -void PwM::sync_save() -{ - PWM_ASSERT(curDoc()); - return curDoc()->sync_save(); + return ret; } - - - #endif #ifndef PWM_EMBEDDED #include "pwm.moc" #endif diff --git a/pwmanager/pwmanager/pwm.h b/pwmanager/pwmanager/pwm.h index 7c6bf0d..6ed9d34 100644 --- a/pwmanager/pwmanager/pwm.h +++ b/pwmanager/pwmanager/pwm.h @@ -1,297 +1,291 @@ /*************************************************************************** * * * copyright (C) 2003, 2004 by Michael Buesch * * email: mbuesch@freenet.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License version 2 * * as published by the Free Software Foundation. * * * ***************************************************************************/ /*************************************************************************** * copyright (C) 2004 by Ulf Schenk * This file is originaly based on version 1.0.1 of pwmanager * and was modified to run on embedded devices that run microkde * * $Id$ **************************************************************************/ #ifndef __PWM_H #define __PWM_H #include <kpopupmenu.h> #include <klistview.h> #include <kmainwindow.h> #ifndef PWM_EMBEDDED #include <kwin.h> #include <kapp.h> #include <kdeversion.h> #else #include <ksyncmanager.h> #endif #include <kaction.h> #include <qglobal.h> #include "pwmview.h" #include "pwmexception.h" /** timeout for displaying a message on the status-bar (in seconds) */ #define STATUSBAR_MSG_TIMEOUT 5 class PwMInit; class KSyncManager; /** PwM is the base class of the project */ #ifndef PWM_EMBEDDED //MOC_SKIP_BEGIN class PwM : public KMainWindow //MOC_SKIP_END #else class PwM : public KMainWindow, public KSyncInterface #endif { Q_OBJECT public: friend class PwMView; /** construtor */ PwM(PwMInit *_init, PwMDoc *doc, bool virginity = true, QWidget* parent = 0, const char *name = 0); /** destructor */ ~PwM(); /** copy some text to the global clipboard */ static void copyToClipboard(const QString &s); /** returns pointer to the view */ PwMView * curView() { return view; } /** returns pointer to the currently using document. */ PwMDoc * curDoc() { return curView()->document(); } /** open a new doc with the given filename */ PwMDoc * openDoc(QString filename, bool openDeepLocked = false); /** show a message on the global status bar. * The message times out after some seconds. */ void showStatMsg(const QString &msg); /** ask the user where to save the doc (if it has not been saved, yet) * and write the data to disk. */ bool save(); /** ask the user where to save the doc * and write the data to disk. */ bool saveAs(); /** force quit. Quit this window, always! Don't minimize it */ bool isForceQuit() { return forceQuit; } /** set forceQuit */ void setForceQuit(bool force) { forceQuit = force; } /** force minimize this window */ bool isForceMinimizeToTray() { return forceMinimizeToTray; } /** set forceMinimizeToTray */ void setForceMinimizeToTray(bool force) { forceMinimizeToTray = force; } public slots: /** file/new triggered */ void new_slot(); /** file/open triggered */ //US ENH void open_slot(); void open_slot(QString fn); /** file/close triggered */ void close_slot(); /** file/quit triggered */ void quitButton_slot(); /** file/save triggered */ void save_slot(); /** file/saveAs triggered */ void saveAs_slot(); /** file/export/text triggered */ void exportToText(); /** file/export/gpasman triggered */ void exportToGpasman(); /** file/export/kwallet triggered */ void exportToKWallet(); /** file/import/text triggered */ bool importFromText(); /** file/import/gpasman triggered */ bool importFromGpasman(); /** file/import/kwallet triggered */ bool importKWallet(); /** file/print triggered */ void print_slot(); /** manage/add triggered */ //US ENH : changed code to run with older MOC void addPwd_slot(); void addPwd_slot(QString *pw, PwMDoc *_doc); /** manage/edit triggered */ //US ENH : changed code to run with older MOC void editPwd_slot(); void editPwd_slot(const QString *category); void editPwd_slot(const QString *category = 0, const int *index = 0, PwMDoc *_doc = 0); /** manage/delete triggered */ void deletePwd_slot(); /** execute the "Launcher" entry */ void execLauncher_slot(); /** open browser with URL entry */ void goToURL_slot(); /** manage/changeMasterPwd triggered */ void changeMasterPwd_slot(); /** lock current document */ void lockWnd_slot(); /** deeplock current document */ void deepLockWnd_slot(); /** window/unlock triggered */ void unlockWnd_slot(); /** find item */ void find_slot(); /** configure clicked */ void config_slot(); /** (de)activate the "change master pw" button in the menu-bar */ void activateMpButton(bool activate = true); /** generate a new chipcard */ void genNewCard_slot(); /** completely erase the current card */ void eraseCard_slot(); /** returns the ID number of the current card */ void readCardId_slot(); /** make backup image of the current card */ void makeCardBackup_slot(); /** write backup image to current card */ void replayCardBackup_slot(); #ifdef PWM_EMBEDDED void showLicense_slot(); void faq_slot(); void createAboutData_slot(); + void syncHowTo_slot(); #endif protected: /** is this window virgin? */ bool isVirgin() { return virgin; } /** add/remove virginity */ void setVirgin(bool v); /** initialize the menubar */ void initMenubar(); /** initialize the toolbar */ void initToolbar(); /** initialize the window-metrics */ void initMetrics(); /** close-event */ void closeEvent(QCloseEvent *e); /** creates a new PwM-ListView and returns it */ PwMView * makeNewListView(PwMDoc *doc); /** Window hide-event */ void hideEvent(QHideEvent *); /** is this window minimized? */ bool isMinimized() { #ifndef PWM_EMBEDDED #if KDE_VERSION >= KDE_MAKE_VERSION(3, 2, 0) return KWin::windowInfo(winId()).isMinimized(); #else // KDE_VERSION return KWin::info(winId()).isIconified(); #endif // KDE_VERSION #else return false; #endif } /** window got the focus */ void focusInEvent(QFocusEvent *e); /** update the caption string */ void updateCaption(); #ifdef CONFIG_KWALLETIF /** check if kwalletemu is enabled and ask the user what to do */ bool checkAndAskForKWalletEmu(); #endif // CONFIG_KWALLETIF protected slots: /** doc got closed */ void docClosed(PwMDoc *doc); signals: /** window got closed (by user or someone else) */ void closed(PwM *wnd); /** window got the focus (was brought to foreground) */ void gotFocus(PwM *wnd); /** window lost the focus */ void lostFocus(PwM *wnd); protected: /** pointer to the view active in this KMainWindow */ PwMView *view; /** pointer to the init class */ PwMInit *init; /** has this window already lost its virginity? * Means is there an open working document */ bool virgin; /** "file" popup-menu */ KPopupMenu *filePopup; /** "manage" popup-menu */ KPopupMenu *managePopup; #ifdef CONFIG_KEYCARD /** "chipcard" popup-menu */ KPopupMenu *chipcardPopup; #endif // CONFIG_KEYCARD /** "view" popup-menu */ KPopupMenu *viewPopup; /** "options" popup-menu */ KPopupMenu *optionsPopup; /** "help" popup-menu */ KPopupMenu *helpPopup; /** "export" popup-menu */ KPopupMenu *exportPopup; /** "import" popup-menu */ KPopupMenu *importPopup; /** force quit this window? */ bool forceQuit; /** force minimize this window to the tray */ bool forceMinimizeToTray; private: #ifdef PWM_EMBEDDED //this are the overwritten callbackmethods from the syncinterface virtual bool sync(KSyncManager* manager, QString filename, int mode); - //called by the syncmanager to indicate that the work has to marked as dirty. - virtual void sync_setModified(); - //called by the syncmanager to ask if the dirty flag is set. - virtual bool sync_isModified(); - //called by the syncmanager to indicate that the work has to be saved. - virtual void sync_save(); - // LR ******************************* // sync stuff! QPopupMenu *syncPopup; KSyncManager* syncManager; #endif }; #endif diff --git a/pwmanager/pwmanager/pwmdoc.cpp b/pwmanager/pwmanager/pwmdoc.cpp index 0ac5517..2a7b11d 100644 --- a/pwmanager/pwmanager/pwmdoc.cpp +++ b/pwmanager/pwmanager/pwmdoc.cpp @@ -1,1120 +1,1123 @@ /*************************************************************************** * * * copyright (C) 2003, 2004 by Michael Buesch * * email: mbuesch@freenet.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License version 2 * * as published by the Free Software Foundation. * * * ***************************************************************************/ /*************************************************************************** * copyright (C) 2004 by Ulf Schenk * This file is originaly based on version 2.0 of pwmanager * and was modified to run on embedded devices that run microkde * * $Id$ **************************************************************************/ #include "pwmdoc.h" #include "pwmview.h" #include "blowfish.h" #include "sha1.h" #include "globalstuff.h" #include "gpasmanfile.h" #include "serializer.h" #include "compressgzip.h" //US#include "compressbzip2.h" #include "randomizer.h" #include "pwminit.h" #include "libgcryptif.h" #ifdef PWM_EMBEDDED #include "pwmprefs.h" #include "kglobal.h" #endif #include <kmessagebox.h> #include <libkcal/syncdefines.h> #ifdef CONFIG_KWALLETIF # include "kwalletemu.h" #endif // CONFIG_KWALLETIF #include <qdatetime.h> #include <qsize.h> #include <qfileinfo.h> #include <qfile.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> //US#include <iostream> #include <algorithm> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <stdint.h> #ifdef PWM_EMBEDDED #ifndef Q_LONG #define Q_LONG long #endif #ifndef Q_ULONG #define Q_ULONG unsigned long #endif #endif //PWM_EMBEDDED //TODO: reset to its normal value. #define META_CHECK_TIMER_INTERVAL 10/*300*/ /* sek */ using namespace std; void PwMDocList::add(PwMDoc *doc, const string &id) { #ifdef PWM_DEBUG // check for existance of object in debug mode only. vector<listItem>::iterator begin = docList.begin(), end = docList.end(), i = begin; while (i != end) { if (i->doc == doc) { BUG(); return; } ++i; } #endif listItem newItem; newItem.doc = doc; newItem.docId = id; docList.push_back(newItem); } void PwMDocList::edit(PwMDoc *doc, const string &newId) { vector<listItem>::iterator begin = docList.begin(), end = docList.end(), i = begin; while (i != end) { if (i->doc == doc) { i->docId = newId; return; } ++i; } } void PwMDocList::del(PwMDoc *doc) { vector<listItem>::iterator begin = docList.begin(), end = docList.end(), i = begin; while (i != end) { if (i->doc == doc) { docList.erase(i); return; } ++i; } } bool PwMDocList::find(const string &id, listItem *ret) { vector<listItem>::iterator begin = docList.begin(), end = docList.end(), i = begin; while (i != end) { if (i->docId == id) { if (ret) *ret = *i; return true; } ++i; } return false; } DocTimer::DocTimer(PwMDoc *_doc) : doc (_doc) , mpwLock (0) , autoLockLock (0) , metaCheckLock (0) { mpwTimer = new QTimer; autoLockTimer = new QTimer; metaCheckTimer = new QTimer; connect(mpwTimer, SIGNAL(timeout()), this, SLOT(mpwTimeout())); connect(autoLockTimer, SIGNAL(timeout()), this, SLOT(autoLockTimeout())); connect(metaCheckTimer, SIGNAL(timeout()), this, SLOT(metaCheckTimeout())); } DocTimer::~DocTimer() { delete mpwTimer; delete autoLockTimer; delete metaCheckTimer; } void DocTimer::start(TimerIDs timer) { switch (timer) { case id_mpwTimer: if (mpwTimer->isActive()) mpwTimer->stop(); doc->setDocStatFlag(DOC_STAT_UNLOCK_WITHOUT_PW); mpwTimer->start(conf()->confGlobPwTimeout() * 1000, true); break; case id_autoLockTimer: if (autoLockTimer->isActive()) autoLockTimer->stop(); if (conf()->confGlobLockTimeout() > 0) autoLockTimer->start(conf()->confGlobLockTimeout() * 1000, true); break; case id_metaCheckTimer: if (metaCheckTimer->isActive()) metaCheckTimer->stop(); metaCheckTimer->start(META_CHECK_TIMER_INTERVAL * 1000, true); break; } } void DocTimer::stop(TimerIDs timer) { switch (timer) { case id_mpwTimer: mpwTimer->stop(); break; case id_autoLockTimer: autoLockTimer->stop(); break; case id_metaCheckTimer: metaCheckTimer->stop(); break; } } void DocTimer::getLock(TimerIDs timer) { switch (timer) { case id_mpwTimer: ++mpwLock; break; case id_autoLockTimer: ++autoLockLock; break; case id_metaCheckTimer: ++metaCheckLock; break; } } void DocTimer::putLock(TimerIDs timer) { switch (timer) { case id_mpwTimer: if (mpwLock) --mpwLock; break; case id_autoLockTimer: if (autoLockLock) --autoLockLock; break; case id_metaCheckTimer: if (metaCheckLock) --metaCheckLock; break; } } void DocTimer::mpwTimeout() { if (mpwLock) { mpwTimer->start(1000, true); return; } doc->unsetDocStatFlag(DOC_STAT_UNLOCK_WITHOUT_PW); } void DocTimer::autoLockTimeout() { if (autoLockLock) { autoLockTimer->start(1000, true); return; } if (conf()->confGlobAutoDeepLock() && doc->filename != QString::null && doc->filename != "") { doc->deepLock(true); } else { doc->lockAll(true); } } void DocTimer::metaCheckTimeout() { if (metaCheckLock) { // check again in one second. metaCheckTimer->start(1000, true); return; } if (doc->isDeepLocked()) { metaCheckTimer->start(META_CHECK_TIMER_INTERVAL * 1000, true); return; } if (doc->isDocEmpty()) { metaCheckTimer->start(META_CHECK_TIMER_INTERVAL * 1000, true); return; } #ifdef CONFIG_KWALLETIF KWalletEmu *kwlEmu = doc->init->kwalletEmu(); if (kwlEmu) kwlEmu->suspendDocSignals(); #endif // CONFIG_KWALLETIF /* We simply trigger all views to update their * displayed values. This way they have a chance * to get notified when some meta changes over time. * (for example an entry expired). * The _view_ is responsive for not updating its * contents if nothing really changed! */ emit doc->dataChanged(doc); #ifdef CONFIG_KWALLETIF if (kwlEmu) kwlEmu->resumeDocSignals(); #endif // CONFIG_KWALLETIF metaCheckTimer->start(META_CHECK_TIMER_INTERVAL * 1000, true); } PwMDocList PwMDoc::openDocList; unsigned int PwMDocList::unnamedDocCnt = 1; PwMDoc::PwMDoc(QObject *parent, const char *name) : PwMDocUi(parent, name) , dataChangedLock (0) { deleted = false; unnamedNum = 0; getOpenDocList()->add(this, getTitle().latin1()); curDocStat = 0; setMaxNumEntries(); _timer = new DocTimer(this); timer()->start(DocTimer::id_mpwTimer); timer()->start(DocTimer::id_autoLockTimer); timer()->start(DocTimer::id_metaCheckTimer); addCategory(DEFAULT_CATEGORY, 0, false); listView = 0; emit docCreated(this); } PwMDoc::~PwMDoc() { emit docClosed(this); getOpenDocList()->del(this); delete _timer; } PwMerror PwMDoc::saveDoc(char compress, const QString *file) { PwMerror ret, e; if (!file) { if (filename == "") return e_filename; } else { if (*file == "" && filename == "") return e_filename; if (*file != "") filename = *file; } bool wasDeepLocked = isDeepLocked(); if (wasDeepLocked) { if (deepLock(false) != e_success) return e_noPw; } if (!isPwAvailable()) { /* password is not available. This means, the * document wasn't saved, yet. */ bool useChipcard = getDocStatFlag(DOC_STAT_USE_CHIPCARD); QString pw(requestNewMpw(&useChipcard)); if (pw != "") { currentPw = pw; } else { return e_noPw; } if (useChipcard) { setDocStatFlag(DOC_STAT_USE_CHIPCARD); } else { unsetDocStatFlag(DOC_STAT_USE_CHIPCARD); } } int _cryptAlgo = conf()->confGlobCryptAlgo(); int _hashAlgo = conf()->confGlobHashAlgo(); // sanity check for the selected algorithms if (_cryptAlgo < PWM_CRYPT_BLOWFISH || _cryptAlgo > PWM_CRYPT_TWOFISH128) { printWarn("Invalid Crypto-Algorithm selected! " "Config-file seems to be corrupt. " "Falling back to Blowfish."); _cryptAlgo = PWM_CRYPT_BLOWFISH; } if (_hashAlgo < PWM_HASH_SHA1 || _hashAlgo > PWM_HASH_TIGER) { printWarn("Invalid Hash-Algorithm selected! " "Config-file seems to be corrupt. " "Falling back to SHA1."); _hashAlgo = PWM_HASH_SHA1; } char cryptAlgo = static_cast<char>(_cryptAlgo); char hashAlgo = static_cast<char>(_hashAlgo); if (conf()->confGlobMakeFileBackup()) { if (!backupFile(filename)) return e_fileBackup; } QString tmpFileMoved(QString::null); if (QFile::exists(filename)) { /* Move the existing file to some tmp file. * When saving file succeeds, delete tmp file. Otherwise * move tmp file back. See below. */ Randomizer *rnd = Randomizer::obj(); char rnd_buf[5]; sprintf(rnd_buf, "%X%X%X%X", rnd->genRndChar() & 0xFF, rnd->genRndChar() & 0xFF, rnd->genRndChar() & 0xFF, rnd->genRndChar() & 0xFF); tmpFileMoved = filename + "." + rnd_buf + ".mv"; if (!copyFile(filename, tmpFileMoved)) return e_openFile; if (!QFile::remove(filename)) { printWarn(string("removing orig file ") + filename.latin1() + " failed!"); } } QFile f(filename); string serialized; if (!f.open(IO_ReadWrite)) { ret = e_openFile; goto out_moveback; } e = writeFileHeader(hashAlgo, hashAlgo, cryptAlgo, compress, ¤tPw, &f); if (e == e_hashNotImpl) { printDebug("PwMDoc::saveDoc(): writeFileHeader() failed: e_hashNotImpl"); f.close(); ret = e_hashNotImpl; goto out_moveback; } else if (e != e_success) { printDebug("PwMDoc::saveDoc(): writeFileHeader() failed"); f.close(); ret = e_writeHeader; goto out_moveback; } if (!serializeDta(&serialized)) { printDebug("PwMDoc::saveDoc(): serializeDta() failed"); f.close(); ret = e_serializeDta; goto out_moveback; } e = writeDataHash(hashAlgo, &serialized, &f); if (e == e_hashNotImpl) { printDebug("PwMDoc::saveDoc(): writeDataHash() failed: e_hashNotImpl"); f.close(); ret = e_hashNotImpl; goto out_moveback; } else if (e != e_success) { printDebug("PwMDoc::saveDoc(): writeDataHash() failed"); f.close(); ret = e_writeHeader; goto out_moveback; } if (!compressDta(&serialized, compress)) { printDebug("PwMDoc::saveDoc(): compressDta() failed"); f.close(); ret = e_enc; goto out_moveback; } e = encrypt(&serialized, ¤tPw, &f, cryptAlgo); if (e == e_weakPw) { printDebug("PwMDoc::saveDoc(): encrypt() failed: e_weakPw"); f.close(); ret = e_weakPw; goto out_moveback; } else if (e == e_cryptNotImpl) { printDebug("PwMDoc::saveDoc(): encrypt() failed: e_cryptNotImpl"); f.close(); ret = e_cryptNotImpl; goto out_moveback; } else if (e != e_success) { printDebug("PwMDoc::saveDoc(): encrypt() failed"); f.close(); ret = e_enc; goto out_moveback; } unsetDocStatFlag(DOC_STAT_DISK_DIRTY); f.close(); if (chmod(filename.latin1(), conf()->confGlobFilePermissions())) { printWarn(string("chmod failed: ") + strerror(errno)); } openDocList.edit(this, getTitle().latin1()); if (wasDeepLocked) deepLock(true); if (tmpFileMoved != QString::null) { // now remove the moved file. if (!QFile::remove(tmpFileMoved)) { printWarn(string("removing file ") + tmpFileMoved.latin1() + " failed!"); } } ret = e_success; - printDebug(string("writing file { compress: ") + printDebug(string("writing file { name: ") + + filename.latin1() + " compress: " + tostr(static_cast<int>(compress)) + " cryptAlgo: " + tostr(static_cast<int>(cryptAlgo)) + " hashAlgo: " + tostr(static_cast<int>(hashAlgo)) + " }"); goto out; out_moveback: if (tmpFileMoved != QString::null) { if (copyFile(tmpFileMoved, filename)) { if (!QFile::remove(tmpFileMoved)) { printWarn(string("removing tmp file ") + filename.latin1() + " failed!"); } } else { printWarn(string("couldn't copy file ") + tmpFileMoved.latin1() + " back to " + filename.latin1()); } } out: return ret; } PwMerror PwMDoc::openDoc(const QString *file, int openLocked) { PWM_ASSERT(file); PWM_ASSERT(openLocked == 0 || openLocked == 1 || openLocked == 2); string decrypted, dataHash; PwMerror ret; char cryptAlgo, dataHashType, compress; unsigned int headerLen; if (*file == "") return e_readFile; filename = *file; /* check if this file is already open. * This does not catch symlinks! */ if (!isDeepLocked()) { if (getOpenDocList()->find(filename.latin1())) return e_alreadyOpen; } QFile f(filename); if (openLocked == 2) { // open deep-locked if (!QFile::exists(filename)) return e_openFile; if (deepLock(true, false) != e_success) return e_openFile; goto out_success; } if (!f.open(IO_ReadOnly)) return e_openFile; ret = checkHeader(&cryptAlgo, ¤tPw, &compress, &headerLen, &dataHashType, &dataHash, &f); if (ret != e_success) { printDebug("PwMDoc::openDoc(): checkHeader() failed"); f.close(); if (ret == e_wrongPw) { wrongMpwMsgBox(getDocStatFlag(DOC_STAT_USE_CHIPCARD)); return ret; } else if (ret == e_noPw || ret == e_fileVer || ret == e_fileFormat || ret == e_hashNotImpl) { return ret; } else return e_readFile; } ret = decrypt(&decrypted, headerLen, ¤tPw, cryptAlgo, &f); if (ret == e_cryptNotImpl) { printDebug("PwMDoc::openDoc(): decrypt() failed: e_cryptNotImpl"); f.close(); return e_cryptNotImpl; } else if (ret != e_success) { printDebug("PwMDoc::openDoc(): decrypt() failed"); f.close(); return e_readFile; } if (!decompressDta(&decrypted, compress)) { printDebug("PwMDoc::openDoc(): decompressDta() failed"); f.close(); return e_fileCorrupt; } ret = checkDataHash(dataHashType, &dataHash, &decrypted); if (ret == e_hashNotImpl) { printDebug("PwMDoc::openDoc(): checkDataHash() failed: e_hashNotImpl"); f.close(); return e_hashNotImpl; } else if (ret != e_success) { printDebug("PwMDoc::openDoc(): checkDataHash() failed"); f.close(); return e_fileCorrupt; } if (!deSerializeDta(&decrypted, openLocked == 1)) { printDebug("PwMDoc::openDoc(): deSerializeDta() failed"); f.close(); return e_readFile; } f.close(); timer()->start(DocTimer::id_mpwTimer); timer()->start(DocTimer::id_autoLockTimer); out_success: openDocList.edit(this, getTitle().latin1()); emit docOpened(this); return e_success; } PwMerror PwMDoc::writeFileHeader(char keyHash, char dataHash, char crypt, char compress, QString *pw, QFile *f) { PWM_ASSERT(pw); PWM_ASSERT(f); - PWM_ASSERT(listView); + //US ENH: or maybe a bug: checking here for listView does not make sense because we do not check anywhere else + //Wenn I sync, I open a doc without a view => listView is 0 => Assertion + //US PWM_ASSERT(listView); if (f->writeBlock(FILE_ID_HEADER, strlen(FILE_ID_HEADER)) != static_cast<Q_LONG>(strlen(FILE_ID_HEADER))) { return e_writeFile; } if (f->putch(PWM_FILE_VER) == -1 || f->putch(keyHash) == -1 || f->putch(dataHash) == -1 || f->putch(crypt) == -1 || f->putch(compress) == -1 || f->putch((getDocStatFlag(DOC_STAT_USE_CHIPCARD)) ? (static_cast<char>(0x01)) : (static_cast<char>(0x00))) == -1) { return e_writeFile; } // write bytes of NUL-data. These bytes are reserved for future-use. const int bufSize = 64; char tmp_buf[bufSize]; memset(tmp_buf, 0x00, bufSize); if (f->writeBlock(tmp_buf, bufSize) != bufSize) return e_writeFile; switch (keyHash) { case PWM_HASH_SHA1: { const int hashlen = SHA1_HASH_LEN_BYTE; Sha1 hash; hash.sha1_write(reinterpret_cast<const byte *>(pw->latin1()), pw->length()); string ret = hash.sha1_read(); if (f->writeBlock(ret.c_str(), hashlen) != hashlen) return e_writeFile; break; } case PWM_HASH_SHA256: /*... fall through */ case PWM_HASH_SHA384: case PWM_HASH_SHA512: case PWM_HASH_MD5: case PWM_HASH_RMD160: case PWM_HASH_TIGER: { if (!LibGCryptIf::available()) return e_hashNotImpl; LibGCryptIf gc; PwMerror err; unsigned char *buf; size_t hashLen; err = gc.hash(&buf, &hashLen, reinterpret_cast<const unsigned char *>(pw->latin1()), pw->length(), keyHash); if (err != e_success) return e_hashNotImpl; if (f->writeBlock(reinterpret_cast<const char *>(buf), hashLen) != static_cast<Q_LONG>(hashLen)) { delete [] buf; return e_hashNotImpl; } delete [] buf; break; } default: { return e_hashNotImpl; } } return e_success; } PwMerror PwMDoc::checkHeader(char *cryptAlgo, QString *pw, char *compress, unsigned int *headerLength, char *dataHashType, string *dataHash, QFile *f) { PWM_ASSERT(cryptAlgo); PWM_ASSERT(pw); PWM_ASSERT(headerLength); PWM_ASSERT(dataHashType); PWM_ASSERT(dataHash); PWM_ASSERT(f); int tmpRet; // check "magic" header const char magicHdr[] = FILE_ID_HEADER; const int hdrLen = array_size(magicHdr) - 1; char tmp[hdrLen]; if (f->readBlock(tmp, hdrLen) != hdrLen) return e_readFile; if (memcmp(tmp, magicHdr, hdrLen) != 0) return e_fileFormat; // read and check file ver int fileV = f->getch(); if (fileV == -1) return e_fileFormat; if (fileV != PWM_FILE_VER) return e_fileVer; // read hash hash type int keyHash = f->getch(); if (keyHash == -1) return e_fileFormat; // read data hash type tmpRet = f->getch(); if (tmpRet == -1) return e_fileFormat; *dataHashType = tmpRet; // read crypt algo tmpRet = f->getch(); if (tmpRet == -1) return e_fileFormat; *cryptAlgo = tmpRet; // get compression-algo tmpRet = f->getch(); if (tmpRet == -1) return e_fileFormat; *compress = tmpRet; // get the MPW-flag int mpw_flag = f->getch(); if (mpw_flag == -1) return e_fileFormat; if (mpw_flag == 0x01) setDocStatFlag(DOC_STAT_USE_CHIPCARD); else unsetDocStatFlag(DOC_STAT_USE_CHIPCARD); // skip the "RESERVED"-bytes if (!(f->at(f->at() + 64))) return e_fileFormat; *pw = requestMpw(getDocStatFlag(DOC_STAT_USE_CHIPCARD)); if (*pw == "") { /* the user didn't give a master-password * or didn't insert a chipcard */ return e_noPw; } // verify key-hash switch (keyHash) { case PWM_HASH_SHA1: { // read hash from header const int hashLen = SHA1_HASH_LEN_BYTE; string readHash; int i; for (i = 0; i < hashLen; ++i) readHash.push_back(f->getch()); Sha1 hash; hash.sha1_write(reinterpret_cast<const byte *>(pw->latin1()), pw->length()); string ret = hash.sha1_read(); if (ret != readHash) return e_wrongPw; // hash doesn't match (wrong key) break; } case PWM_HASH_SHA256: /*... fall through */ case PWM_HASH_SHA384: case PWM_HASH_SHA512: case PWM_HASH_MD5: case PWM_HASH_RMD160: case PWM_HASH_TIGER: { if (!LibGCryptIf::available()) return e_hashNotImpl; LibGCryptIf gc; PwMerror err; unsigned char *buf; size_t hashLen; err = gc.hash(&buf, &hashLen, reinterpret_cast<const unsigned char *>(pw->latin1()), pw->length(), keyHash); if (err != e_success) return e_hashNotImpl; string calcHash(reinterpret_cast<const char *>(buf), static_cast<string::size_type>(hashLen)); delete [] buf; // read hash from header string readHash; size_t i; for (i = 0; i < hashLen; ++i) readHash.push_back(f->getch()); if (calcHash != readHash) return e_wrongPw; // hash doesn't match (wrong key) break; } default: { return e_hashNotImpl; } } // read the data-hash from the file unsigned int hashLen, i; switch (*dataHashType) { case PWM_HASH_SHA1: hashLen = SHA1_HASH_LEN_BYTE; break; case PWM_HASH_SHA256: /*... fall through */ case PWM_HASH_SHA384: case PWM_HASH_SHA512: case PWM_HASH_MD5: case PWM_HASH_RMD160: case PWM_HASH_TIGER: { if (!LibGCryptIf::available()) return e_hashNotImpl; LibGCryptIf gc; hashLen = gc.hashLength(*dataHashType); if (hashLen == 0) return e_hashNotImpl; break; } default: return e_hashNotImpl; } *dataHash = ""; for (i = 0; i < hashLen; ++i) { tmpRet = f->getch(); if (tmpRet == -1) return e_fileFormat; dataHash->push_back(static_cast<char>(tmpRet)); } *headerLength = f->at(); #ifndef PWM_EMBEDDED printDebug(string("opening file { compress: ") + tostr(static_cast<int>(*compress)) + " cryptAlgo: " + tostr(static_cast<int>(*cryptAlgo)) + " keyHashAlgo: " + tostr(static_cast<int>(keyHash)) + " }"); #else printDebug(string("opening file { compress: ") + tostr((int)(*compress)) + " cryptAlgo: " + tostr((int)(*cryptAlgo)) + " keyHashAlgo: " + tostr((int)(keyHash)) + " }"); #endif return e_success; } PwMerror PwMDoc::writeDataHash(char dataHash, string *d, QFile *f) { PWM_ASSERT(d); PWM_ASSERT(f); switch (dataHash) { case PWM_HASH_SHA1: { const int hashLen = SHA1_HASH_LEN_BYTE; Sha1 h; h.sha1_write(reinterpret_cast<const byte *>(d->c_str()), d->size()); string hRet = h.sha1_read(); if (f->writeBlock(hRet.c_str(), hashLen) != hashLen) return e_writeFile; break; } case PWM_HASH_SHA256: /*... fall through */ case PWM_HASH_SHA384: case PWM_HASH_SHA512: case PWM_HASH_MD5: case PWM_HASH_RMD160: case PWM_HASH_TIGER: { if (!LibGCryptIf::available()) return e_hashNotImpl; LibGCryptIf gc; PwMerror err; unsigned char *buf; size_t hashLen; err = gc.hash(&buf, &hashLen, reinterpret_cast<const unsigned char *>(d->c_str()), d->size(), dataHash); if (err != e_success) return e_hashNotImpl; if (f->writeBlock(reinterpret_cast<const char *>(buf), hashLen) != static_cast<Q_LONG>(hashLen)) { delete [] buf; return e_hashNotImpl; } delete [] buf; break; } default: { return e_hashNotImpl; } } return e_success; } bool PwMDoc::backupFile(const QString &filePath) { QFileInfo fi(filePath); if (!fi.exists()) return true; // Yes, true is correct. QString pathOnly(fi.dirPath(true)); QString nameOnly(fi.fileName()); QString backupPath = pathOnly + "/~" + nameOnly + ".backup"; return copyFile(filePath, backupPath); } bool PwMDoc::copyFile(const QString &src, const QString &dst) { QFileInfo fi(src); if (!fi.exists()) return false; if (QFile::exists(dst)) { if (!QFile::remove(dst)) return false; } QFile srcFd(src); if (!srcFd.open(IO_ReadOnly)) return false; QFile dstFd(dst); if (!dstFd.open(IO_ReadWrite)) { srcFd.close(); return false; } const int tmpBuf_size = 512; char tmpBuf[tmpBuf_size]; Q_LONG bytesRead, bytesWritten; while (!srcFd.atEnd()) { bytesRead = srcFd.readBlock(tmpBuf, static_cast<Q_ULONG>(tmpBuf_size)); if (bytesRead == -1) { srcFd.close(); dstFd.close(); return false; } bytesWritten = dstFd.writeBlock(tmpBuf, static_cast<Q_ULONG>(bytesRead)); if (bytesWritten != bytesRead) { srcFd.close(); dstFd.close(); return false; } } srcFd.close(); dstFd.close(); return true; } PwMerror PwMDoc::addEntry(const QString &category, PwMDataItem *d, bool dontFlagDirty, bool updateMeta) { PWM_ASSERT(d); unsigned int cat = 0; if (isDeepLocked()) { PwMerror ret; ret = deepLock(false); if (ret != e_success) return e_lock; } addCategory(category, &cat); if (numEntries(category) >= maxEntries) return e_maxAllowedEntr; vector<unsigned int> foundPositions; /* historically this was: * const int searchIn = SEARCH_IN_DESC | SEARCH_IN_NAME | * SEARCH_IN_URL | SEARCH_IN_LAUNCHER; * But for now we only search in desc. * That's a tweak to be KWallet compatible. But it should not add * usability-drop onto PwManager, does it? * (And yes, "int" was a bug. Correct is "unsigned int") */ const unsigned int searchIn = SEARCH_IN_DESC; findEntry(cat, *d, searchIn, &foundPositions, true); if (foundPositions.size()) { // DOH! We found this entry. return e_entryExists; } d->listViewPos = -1; d->lockStat = conf()->confGlobNewEntrLockStat(); if (updateMeta) { d->meta.create = QDateTime::currentDateTime(); d->meta.update = d->meta.create; } dti.dta[cat].d.push_back(*d); delAllEmptyCat(true); if (!dontFlagDirty) flagDirty(); return e_success; } PwMerror PwMDoc::addCategory(const QString &category, unsigned int *categoryIndex, bool checkIfExist) { if (isDeepLocked()) { PwMerror ret; ret = deepLock(false); if (ret != e_success) return e_lock; } if (checkIfExist) { if (findCategory(category, categoryIndex)) return e_categoryExists; } PwMCategoryItem item; item.name = category.latin1(); dti.dta.push_back(item); if (categoryIndex) *categoryIndex = dti.dta.size() - 1; return e_success; } bool PwMDoc::delEntry(const QString &category, unsigned int index, bool dontFlagDirty) { unsigned int cat = 0; if (!findCategory(category, &cat)) { BUG(); return false; } return delEntry(cat, index, dontFlagDirty); } bool PwMDoc::delEntry(unsigned int category, unsigned int index, bool dontFlagDirty) { if (isDeepLocked()) return false; if (index > dti.dta[category].d.size() - 1) return false; getDataChangedLock(); if (!lockAt(category, index, false)) { putDataChangedLock(); return false; } putDataChangedLock(); int lvPos = dti.dta[category].d[index].listViewPos; // delete entry dti.dta[category].d.erase(dti.dta[category].d.begin() + index); unsigned int i, entries = numEntries(category); if (!entries) { // no more entries in this category, so // we can delete it, too. BUG_ON(!delCategory(category)); // delCategory() flags it dirty, so we need not to do so. return true; } for (i = 0; i < entries; ++i) { // decrement all listViewPositions that are greater than the deleted. if (dti.dta[category].d[i].listViewPos > lvPos) --dti.dta[category].d[i].listViewPos; } if (!dontFlagDirty) flagDirty(); return true; } bool PwMDoc::editEntry(const QString &oldCategory, const QString &newCategory, unsigned int index, PwMDataItem *d, bool updateMeta) { PWM_ASSERT(d); unsigned int oldCat = 0; if (!findCategory(oldCategory, &oldCat)) { BUG(); return false; } return editEntry(oldCat, newCategory, index, d, updateMeta); } bool PwMDoc::editEntry(unsigned int oldCategory, const QString &newCategory, unsigned int index, PwMDataItem *d, bool updateMeta) { if (isDeepLocked()) return false; if (updateMeta) { d->meta.update = QDateTime::currentDateTime(); if (d->meta.create.isNull()) { d->meta.create = d->meta.update; } } if (dti.dta[oldCategory].name != newCategory.latin1()) { // the user changed the category. PwMerror ret; d->rev = 0; ret = addEntry(newCategory, d, true, false); if (ret != e_success) return false; if (!delEntry(oldCategory, index, true)) return false; } else { d->rev = dti.dta[oldCategory].d[index].rev + 1; // increment revision counter. dti.dta[oldCategory].d[index] = *d; } flagDirty(); return true; } unsigned int PwMDoc::numEntries(const QString &category) { unsigned int cat = 0; if (!findCategory(category, &cat)) { BUG(); return 0; } return numEntries(cat); } bool PwMDoc::serializeDta(string *d) { PWM_ASSERT(d); Serializer ser; if (!ser.serialize(dti)) @@ -2295,1117 +2298,1135 @@ PwMerror PwMDoc::exportToText(const QString *file) if (f.writeBlock(header.c_str(), header.length()) != (Q_LONG)header.length()) { unlockAll_tempoary(true); f.close(); return e_writeFile; } #else if (f.writeBlock(header.c_str(), header.length()) != (long)header.length()) { unlockAll_tempoary(true); f.close(); return e_writeFile; } #endif unsigned int i, numCat = numCategories(); unsigned int j, numEnt; string exp; for (i = 0; i < numCat; ++i) { numEnt = numEntries(i); exp = "\n== Category: "; exp += dti.dta[i].name; exp += " ==\n"; #ifndef PWM_EMBEDDED if (f.writeBlock(exp.c_str(), exp.length()) != (Q_LONG)exp.length()) { unlockAll_tempoary(true); f.close(); return e_writeFile; } #else if (f.writeBlock(exp.c_str(), exp.length()) != (long)exp.length()) { unlockAll_tempoary(true); f.close(); return e_writeFile; } #endif for (j = 0; j < numEnt; ++j) { exp = "\n-- "; exp += dti.dta[i].d[j].desc; exp += " --\n"; exp += i18n("Username: ").latin1(); exp += dti.dta[i].d[j].name; exp += "\n"; exp += i18n("Password: ").latin1(); exp += dti.dta[i].d[j].pw; exp += "\n"; exp += i18n("Comment: ").latin1(); exp += dti.dta[i].d[j].comment; exp += "\n"; exp += i18n("URL: ").latin1(); exp += dti.dta[i].d[j].url; exp += "\n"; exp += i18n("Launcher: ").latin1(); exp += dti.dta[i].d[j].launcher; exp += "\n"; #ifndef PWM_EMBEDDED if (f.writeBlock(exp.c_str(), exp.length()) != (Q_LONG)exp.length()) { unlockAll_tempoary(true); f.close(); return e_writeFile; } #else if (f.writeBlock(exp.c_str(), exp.length()) != (long)exp.length()) { unlockAll_tempoary(true); f.close(); return e_writeFile; } #endif } } unlockAll_tempoary(true); f.close(); return e_success; } PwMerror PwMDoc::importFromText(const QString *file, int format) { PWM_ASSERT(file); if (format == 0) return importText_PwM(file); else if (format == -1) { // probe for all formats if (importText_PwM(file) == e_success) return e_success; dti.clear(); emitDataChanged(this); // add next format here... return e_fileFormat; } return e_invalidArg; } PwMerror PwMDoc::importText_PwM(const QString *file) { #ifndef PWM_EMBEDDED PWM_ASSERT(file); FILE *f; int tmp; ssize_t ret; string curCat; unsigned int entriesRead = 0; PwMDataItem currItem; f = fopen(file->latin1(), "r"); if (!f) return e_openFile; size_t ch_tmp_size = 1024; char *ch_tmp = (char*)malloc(ch_tmp_size); if (!ch_tmp) { fclose(f); return e_outOfMem; } // - check header if (getline(&ch_tmp, &ch_tmp_size, f) == -1) // skip first line. goto formatError; // check version-string and return version in "ch_tmp". if (fscanf(f, "PwM v%s", ch_tmp) != 1) { // header not recognized as PwM generated header goto formatError; } // set filepointer behind version-string-line previously checked if (getline(&ch_tmp, &ch_tmp_size, f) == -1) goto formatError; // skip next line containing the build-date if (getline(&ch_tmp, &ch_tmp_size, f) == -1) goto formatError; // read header termination line if (getline(&ch_tmp, &ch_tmp_size, f) == -1) goto formatError; if (strcmp(ch_tmp, "==============================\n")) goto formatError; // - read entries do { // find beginning of next category do { tmp = fgetc(f); } while (tmp == '\n' && tmp != EOF); if (tmp == EOF) break; // decrement filepos by one fseek(f, -1, SEEK_CUR); // read cat-name if (getline(&ch_tmp, &ch_tmp_size, f) == -1) goto formatError; // check cat-name format if (memcmp(ch_tmp, "== Category: ", 13) != 0) goto formatError; if (memcmp(ch_tmp + (strlen(ch_tmp) - 1 - 3), " ==", 3) != 0) goto formatError; // copy cat-name curCat.assign(ch_tmp + 13, strlen(ch_tmp) - 1 - 16); do { // find beginning of next entry do { tmp = fgetc(f); } while (tmp == '\n' && tmp != EOF && tmp != '='); if (tmp == EOF) break; if (tmp == '=') { fseek(f, -1, SEEK_CUR); break; } // decrement filepos by one fseek(f, -1, SEEK_CUR); // read desc-line if (getline(&ch_tmp, &ch_tmp_size, f) == -1) goto formatError; // check desc-line format if (memcmp(ch_tmp, "-- ", 3) != 0) goto formatError; if (memcmp(ch_tmp + (strlen(ch_tmp) - 1 - 3), " --", 3) != 0) goto formatError; // add desc-line currItem.desc.assign(ch_tmp + 3, strlen(ch_tmp) - 1 - 6); // read username-line if ((ret = getline(&ch_tmp, &ch_tmp_size, f)) == -1) goto formatError; if (!textExtractEntry_PwM(ch_tmp, ret, &currItem.name)) goto formatError; // read pw-line if ((ret = getline(&ch_tmp, &ch_tmp_size, f)) == -1) goto formatError; if (!textExtractEntry_PwM(ch_tmp, ret, &currItem.pw)) goto formatError; // read comment-line if ((ret = getline(&ch_tmp, &ch_tmp_size, f)) == -1) goto formatError; if (!textExtractEntry_PwM(ch_tmp, ret, &currItem.comment)) goto formatError; // read URL-line if ((ret = getline(&ch_tmp, &ch_tmp_size, f)) == -1) goto formatError; if (!textExtractEntry_PwM(ch_tmp, ret, &currItem.url)) goto formatError; // read launcher-line if ((ret = getline(&ch_tmp, &ch_tmp_size, f)) == -1) goto formatError; if (!textExtractEntry_PwM(ch_tmp, ret, &currItem.launcher)) goto formatError; currItem.lockStat = true; currItem.listViewPos = -1; addEntry(curCat.c_str(), &currItem, true); ++entriesRead; } while (1); } while (1); if (!entriesRead) goto formatError; free(ch_tmp); fclose(f); flagDirty(); return e_success; formatError: free(ch_tmp); fclose(f); return e_fileFormat; #else PWM_ASSERT(file); QFile f(file->latin1()); int tmp; ssize_t ret; string curCat; unsigned int entriesRead = 0; PwMDataItem currItem; bool res = f.open(IO_ReadOnly); if (res == false) return e_openFile; unsigned int ch_tmp_size = 1024; char *ch_tmp = (char*)malloc(ch_tmp_size); if (!ch_tmp) { f.close(); return e_outOfMem; } // - check header if (f.readLine(ch_tmp, ch_tmp_size) == -1) // skip first line. goto formatError; //US read fileversion first, then check if ok. if (f.readLine(ch_tmp, ch_tmp_size) == -1) goto formatError; // check version-string and return version in "ch_tmp". //US if (fscanf(f, "PwM v%s", ch_tmp) != 1) { //US // header not recognized as PwM generated header //US goto formatError; //US } //US set filepointer behind version-string-line previously checked //US if (f.readLine(ch_tmp, ch_tmp_size) == -1) //US goto formatError; // skip next line containing the build-date if (f.readLine(ch_tmp, ch_tmp_size) == -1) goto formatError; // read header termination line if (f.readLine(ch_tmp, ch_tmp_size) == -1) goto formatError; if (strcmp(ch_tmp, "==============================\n")) goto formatError; // - read entries do { // find beginning of next category do { tmp = f.getch(); } while (tmp == '\n' && tmp != EOF); if (tmp == EOF) break; // decrement filepos by one f.at(f.at()-1); // read cat-name if (f.readLine(ch_tmp, ch_tmp_size) == -1) goto formatError; // check cat-name format if (memcmp(ch_tmp, "== Category: ", 13) != 0) goto formatError; if (memcmp(ch_tmp + (strlen(ch_tmp) - 1 - 3), " ==", 3) != 0) goto formatError; // copy cat-name curCat.assign(ch_tmp + 13, strlen(ch_tmp) - 1 - 16); do { // find beginning of next entry do { tmp = f.getch(); } while (tmp == '\n' && tmp != EOF && tmp != '='); if (tmp == EOF) break; if (tmp == '=') { f.at(f.at()-1); break; } // decrement filepos by one f.at(f.at()-1); // read desc-line if (f.readLine(ch_tmp, ch_tmp_size) == -1) goto formatError; // check desc-line format if (memcmp(ch_tmp, "-- ", 3) != 0) goto formatError; if (memcmp(ch_tmp + (strlen(ch_tmp) - 1 - 3), " --", 3) != 0) goto formatError; // add desc-line currItem.desc.assign(ch_tmp + 3, strlen(ch_tmp) - 1 - 6); // read username-line if ((ret = f.readLine(ch_tmp, ch_tmp_size)) == -1) goto formatError; if (!textExtractEntry_PwM(ch_tmp, ret, &currItem.name)) goto formatError; // read pw-line if ((ret = f.readLine(ch_tmp, ch_tmp_size)) == -1) goto formatError; if (!textExtractEntry_PwM(ch_tmp, ret, &currItem.pw)) goto formatError; // read comment-line if ((ret = f.readLine(ch_tmp, ch_tmp_size)) == -1) goto formatError; if (!textExtractEntry_PwM(ch_tmp, ret, &currItem.comment)) goto formatError; // read URL-line if ((ret = f.readLine(ch_tmp, ch_tmp_size)) == -1) goto formatError; if (!textExtractEntry_PwM(ch_tmp, ret, &currItem.url)) goto formatError; // read launcher-line if ((ret = f.readLine(ch_tmp, ch_tmp_size)) == -1) goto formatError; if (!textExtractEntry_PwM(ch_tmp, ret, &currItem.launcher)) goto formatError; currItem.lockStat = true; currItem.listViewPos = -1; addEntry(curCat.c_str(), &currItem, true); ++entriesRead; } while (1); } while (1); if (!entriesRead) goto formatError; free(ch_tmp); f.close(); flagDirty(); return e_success; formatError: free(ch_tmp); f.close(); return e_fileFormat; #endif } bool PwMDoc::textExtractEntry_PwM(const char *in, ssize_t in_size, string *out) { PWM_ASSERT(in && out); ssize_t i = 0, len = in_size - 1; while (i < len) { if (in[i] == ':') break; ++i; } i += 2; *out = ""; out->append(in + i, in_size - i - 1); return true; } PwMerror PwMDoc::exportToGpasman(const QString *file) { PWM_ASSERT(file); GpasmanFile gp; int ret; if (!unlockAll_tempoary()) return e_lock; QString gpmPassword; while (1) { gpmPassword = requestNewMpw(0); if (gpmPassword == "") { unlockAll_tempoary(true); return e_noPw; } if (gpmPassword.length() < 4) { gpmPwLenErrMsgBox(); } else { break; } } ret = gp.save_init(file->latin1(), gpmPassword.latin1()); if (ret != 1) { unlockAll_tempoary(true); return e_accessFile; } char *entry[4]; unsigned int numCat = numCategories(), i; unsigned int numEntr, j; int descLen, nameLen, pwLen, commentLen; for (i = 0; i < numCat; ++i) { numEntr = numEntries(i); for (j = 0; j < numEntr; ++j) { descLen = dti.dta[i].d[j].desc.length(); nameLen = dti.dta[i].d[j].name.length(); pwLen = dti.dta[i].d[j].pw.length(); commentLen = dti.dta[i].d[j].comment.length(); entry[0] = new char[descLen + 1]; entry[1] = new char[nameLen + 1]; entry[2] = new char[pwLen + 1]; entry[3] = new char[commentLen + 1]; strcpy(entry[0], descLen == 0 ? " " : dti.dta[i].d[j].desc.c_str()); strcpy(entry[1], nameLen == 0 ? " " : dti.dta[i].d[j].name.c_str()); strcpy(entry[2], pwLen == 0 ? " " : dti.dta[i].d[j].pw.c_str()); strcpy(entry[3], commentLen == 0 ? " " : dti.dta[i].d[j].comment.c_str()); entry[0][descLen == 0 ? descLen + 1 : descLen] = '\0'; entry[1][nameLen == 0 ? nameLen + 1 : nameLen] = '\0'; entry[2][pwLen == 0 ? pwLen + 1 : pwLen] = '\0'; entry[3][commentLen == 0 ? commentLen + 1 : commentLen] = '\0'; ret = gp.save_entry(entry); if (ret == -1){ delete [] entry[0]; delete [] entry[1]; delete [] entry[2]; delete [] entry[3]; gp.save_finalize(); unlockAll_tempoary(true); return e_writeFile; } delete [] entry[0]; delete [] entry[1]; delete [] entry[2]; delete [] entry[3]; } } unlockAll_tempoary(true); if (gp.save_finalize() == -1) return e_writeFile; return e_success; } PwMerror PwMDoc::importFromGpasman(const QString *file) { PWM_ASSERT(file); QString pw = requestMpw(false); if (pw == "") return e_noPw; GpasmanFile gp; int ret, i; PwMerror ret2; char *entry[4]; PwMDataItem tmpData; ret = gp.load_init(file->latin1(), pw.latin1()); if (ret != 1) return e_accessFile; do { ret = gp.load_entry(entry); if(ret != 1) break; tmpData.desc = entry[0]; tmpData.name = entry[1]; tmpData.pw = entry[2]; tmpData.comment = entry[3]; tmpData.lockStat = true; tmpData.listViewPos = -1; ret2 = addEntry(DEFAULT_CATEGORY, &tmpData, true); for (i = 0; i < 4; ++i) free(entry[i]); if (ret2 == e_maxAllowedEntr) { gp.load_finalize(); return e_maxAllowedEntr; } } while (1); gp.load_finalize(); if (isDocEmpty()) return e_wrongPw; // we assume this. flagDirty(); return e_success; } void PwMDoc::ensureLvp() { if (isDocEmpty()) return; + //US ENH BUG: when using syncronizing, this way of sorting + //is not sufficient, because there might be empty spaces + // at the beginning. But this algorythm only can add elements + //to the end.The result are crashes because of listoverflows + //we need something to fill all gaps. vector< vector<PwMDataItem>::iterator > undefined; + vector< vector<PwMDataItem>::iterator > sorted; vector< vector<PwMDataItem>::iterator >::iterator undefBegin, undefEnd, undefI; + vector< vector<PwMDataItem>::iterator >::iterator sortedBegin, + sortedEnd, + sortedI; vector<PwMCategoryItem>::iterator catBegin = dti.dta.begin(), catEnd = dti.dta.end(), catI = catBegin; vector<PwMDataItem>::iterator entrBegin, entrEnd, entrI; int lvpTop, tmpLvp; while (catI != catEnd) { lvpTop = -1; undefined.clear(); entrBegin = catI->d.begin(); entrEnd = catI->d.end(); entrI = entrBegin; while (entrI != entrEnd) { tmpLvp = entrI->listViewPos; if (tmpLvp == -1) undefined.push_back(entrI); - else if (tmpLvp > lvpTop) - lvpTop = tmpLvp; + else + sorted[tmpLvp] = entrI; + //US else if (tmpLvp > lvpTop) + //US lvpTop = tmpLvp; ++entrI; } + + //now we have all undefied in the collection. Now insert the existing + sortedBegin = sorted.begin(); + sortedEnd = sorted.end(); + sortedI = sortedBegin; + + while (sortedI != sortedEnd) { + tmpLvp = (*sortedI)->listViewPos; + undefined[tmpLvp] = *sortedI; + ++sortedI; + } + undefBegin = undefined.begin(); undefEnd = undefined.end(); undefI = undefBegin; while (undefI != undefEnd) { (*undefI)->listViewPos = ++lvpTop; ++undefI; } ++catI; } } QString PwMDoc::getTitle() { /* NOTE: We have to ensure, that the returned title * is unique and not reused somewhere else while * this document is valid (open). */ QString title(getFilename()); + + //US ENH: The whole filename on PDAs is too long. So use only the last characters + if (QApplication::desktop()->width() < 640) + { + if (title.length() > 30) + title = "..." + title.right(30); + + } + + if (title.isEmpty()) { if (unnamedNum == 0) { unnamedNum = PwMDocList::getNewUnnamedNumber(); PWM_ASSERT(unnamedNum != 0); } title = DEFAULT_TITLE; title += " "; title += tostr(unnamedNum).c_str(); } return title; } bool PwMDoc::tryDelete() { if (deleted) return true; int ret; if (isDirty()) { ret = dirtyAskSave(getTitle()); if (ret == 0) { // save to disk if (!saveDocUi(this)) goto out_ignore; } else if (ret == 1) { // don't save and delete goto out_accept; } else { // cancel operation goto out_ignore; } } out_accept: deleted = true; delete this; return true; out_ignore: return false; } #ifdef PWM_EMBEDDED //US ENH: this is the magic function that syncronizes the this doc with the remote doc //US it could have been defined as static, but I did not want to. PwMerror PwMDoc::syncronize(KSyncManager* manager, PwMDoc* syncLocal , PwMDoc* syncRemote, int mode ) { int addedPasswordsLocal = 0; int addedPasswordsRemote = 0; int deletedPasswordsRemote = 0; int deletedPasswordsLocal = 0; int changedLocal = 0; int changedRemote = 0; PwMSyncItem* syncItemLocal; PwMSyncItem* syncItemRemote; QString mCurrentSyncName = manager->getCurrentSyncName(); QString mCurrentSyncDevice = manager->getCurrentSyncDevice(); bool fullDateRange = false; int take; // local->resetTempSyncStat(); QDateTime mLastSync = QDateTime::currentDateTime(); QDateTime modifiedSync = mLastSync; unsigned int index; //Step 1. Find syncinfo in Local file and create if not existent. bool found = syncLocal->findSyncData(mCurrentSyncDevice, &index); if (found == false) { PwMSyncItem newSyncItemLocal; newSyncItemLocal.syncName = mCurrentSyncDevice; newSyncItemLocal.lastSyncDate = mLastSync; syncLocal->addSyncDataEntry(&newSyncItemLocal, true); found = syncLocal->findSyncData(mCurrentSyncDevice, &index); if (found == false) { qDebug("PwMDoc::syncronize : newly created local sync data could not be found"); return e_syncError; } } syncItemLocal = syncLocal->getSyncDataEntry(index); - qDebug("Last Sync %s ", syncItemLocal->lastSyncDate.toString().latin1()); + qDebug("Last Sync Local %s ", syncItemLocal->lastSyncDate.toString().latin1()); //Step 2. Find syncinfo in remote file and create if not existent. found = syncRemote->findSyncData(mCurrentSyncName, &index); if (found == false) { qDebug("FULLDATE 1"); fullDateRange = true; PwMSyncItem newSyncItemRemote; newSyncItemRemote.syncName = mCurrentSyncName; newSyncItemRemote.lastSyncDate = mLastSync; syncRemote->addSyncDataEntry(&newSyncItemRemote, true); found = syncRemote->findSyncData(mCurrentSyncName, &index); if (found == false) { qDebug("PwMDoc::syncronize : newly created remote sync data could not be found"); return e_syncError; } } syncItemRemote = syncRemote->getSyncDataEntry(index); + qDebug("Last Sync Remote %s ", syncItemRemote->lastSyncDate.toString().latin1()); //and remove the found entry here. We will reenter it later again. //US syncRemote->delSyncDataEntry(index, true); if ( syncItemLocal->lastSyncDate == mLastSync ) { qDebug("FULLDATE 2"); fullDateRange = true; } if ( ! fullDateRange ) { if ( syncItemLocal->lastSyncDate != syncItemRemote->lastSyncDate ) { - // qDebug("set fulldate to true %s %s" ,addresseeLSync->dtStart().toString().latin1(), addresseeRSync->dtStart().toString().latin1() ); - //qDebug("%d %d %d %d ", addresseeLSync->dtStart().time().second(), addresseeLSync->dtStart().time().msec() , addresseeRSync->dtStart().time().second(), addresseeRSync->dtStart().time().msec()); + // qDebug("set fulldate to true %s %s" ,syncItemLocal->lastSyncDate.toString().latin1(), syncItemRemote->lastSyncDate.toString().latin1() ); + // qDebug("%d %d %d %d ", syncItemLocal->lastSyncDate.time().second(), addresseeLSync->dtStart().time().msec() , addresseeRSync->dtStart().time().second(), addresseeRSync->dtStart().time().msec()); fullDateRange = true; qDebug("FULLDATE 3 %s %s", syncItemLocal->lastSyncDate.toString().latin1() , syncItemRemote->lastSyncDate.toString().latin1() ); } } // fullDateRange = true; // debug only! if ( fullDateRange ) mLastSync = QDateTime::currentDateTime().addDays( -100*365); else mLastSync = syncItemLocal->lastSyncDate; qDebug("*************************** "); - // qDebug("mLastAddressbookSync %s ",mLastAddressbookSync.toString().latin1() ); + qDebug("mLastSync %s ",mLastSync.toString().latin1() ); QStringList er = syncRemote->getIDEntryList(); PwMDataItem* inRemote ;//= er.first(); PwMDataItem* inLocal; unsigned int catLocal, indexLocal; unsigned int catRemote, indexRemote; QString uid; manager->showProgressBar(0, i18n("Syncing - close to abort!"), er.count()); int modulo = (er.count()/10)+1; unsigned int incCounter = 0; while ( incCounter < er.count()) { if (manager->isProgressBarCanceled()) return e_syncError; if ( incCounter % modulo == 0 ) manager->showProgressBar(incCounter); uid = er[ incCounter ]; qDebug("sync uid %s from remote file", uid.latin1()); qApp->processEvents(); inLocal = syncLocal->findEntryByID( uid, &catLocal, &indexLocal ); inRemote = syncRemote->findEntryByID( uid, &catRemote, &indexRemote ); PWM_ASSERT(inRemote); if ( inLocal != 0 ) { // maybe conflict - same uid in both files if ( (take = takePwMDataItem( inLocal, inRemote, mLastSync, mode, fullDateRange) ) ) { - //qDebug("take %d %s ", take, inL.summary().latin1()); + qDebug("take %d %s ", take, inLocal->desc.c_str()); if ( take == 3 ) return e_syncError; if ( take == 1 ) {// take local //US syncRemote->removeAddressee( inRemote ); (*inRemote) = (*inLocal); //US syncRemote->insertAddressee( inRemote , false); ++changedRemote; } else { // take == 2 take remote //US syncLocal->removeAddressee( inLocal ); (*inLocal) = (*inRemote); //US syncLocal->insertAddressee( inLocal , false ); ++changedLocal; } } } else { // no conflict if ( inRemote->meta.update > mLastSync || mode == 5 ) { inRemote->meta.update = modifiedSync; //first check if we have a matching category in the local file const string* remotecat = syncRemote->getCategory(catRemote); //US syncRemote->insertAddressee( inRemote, false ); //US syncLocal->insertAddressee( inRemote, false ); syncLocal->addEntry(remotecat->c_str(), inRemote, true, false); ++addedPasswordsLocal; } else { // pending checkExternSyncAddressee(addresseeRSyncSharp, inR); syncRemote->delEntry(catRemote, indexRemote, true); //USsyncRemote->removeAddressee( inRemote ); ++deletedPasswordsRemote; } } ++incCounter; } er.clear(); QStringList el = syncLocal->getIDEntryList(); modulo = (el.count()/10)+1; manager->showProgressBar(0, i18n("Add / remove addressees"), el.count()); incCounter = 0; while ( incCounter < el.count()) { qApp->processEvents(); if (manager->isProgressBarCanceled()) return e_syncError; if ( incCounter % modulo == 0 ) manager->showProgressBar(incCounter); uid = el[ incCounter ]; + qDebug("sync uid %s from local file", uid.latin1()); inLocal = syncLocal->findEntryByID( uid, &catLocal, &indexLocal ); inRemote = syncRemote->findEntryByID( uid, &catRemote, &indexRemote ); PWM_ASSERT(inLocal); if ( inRemote == 0 ) { if ( inLocal->meta.update < mLastSync && mode != 4 ) { // pending checkExternSyncAddressee(addresseeLSyncSharp, inL); syncLocal->delEntry(catLocal, indexLocal, true); //USsyncLocal->removeAddressee( inLocal ); ++deletedPasswordsLocal; } else { if ( ! manager->mWriteBackExistingOnly ) { ++addedPasswordsRemote; inLocal->meta.update = modifiedSync; //first check if we have a matching category in the remote file const string* localcat = syncLocal->getCategory(catLocal); //USsyncLocal->insertAddressee( inLocal, false ); PwMDataItem newEntry; newEntry = *inLocal; inRemote = &newEntry; //USsyncRemote->insertAddressee( inRemote, false ); syncRemote->addEntry(localcat->c_str(), inRemote, true, false); } } } ++incCounter; } el.clear(); manager->hideProgressBar(); // Now write the info back into the sync data space of the files mLastSync = QDateTime::currentDateTime().addSecs( 1 ); // get rid of micro seconds QTime t = mLastSync.time(); mLastSync.setTime( QTime (t.hour (), t.minute (), t.second () ) ); syncItemLocal->lastSyncDate = mLastSync; syncItemRemote->lastSyncDate = mLastSync; // addresseeRSync.setRole( i18n("!Remote from: ")+mCurrentSyncName ) ; // addresseeLSync.setRole(i18n("!Local from: ") + mCurrentSyncName ); //US syncRemote->addSyncDataEntry( syncItemRemote, false ); //US syncLocal->addSyncDataEntry( syncItemLocal, false ); QString mes; mes .sprintf( i18n("Synchronization summary:\n\n %d items added to local\n %d items added to remote\n %d items updated on local\n %d items updated on remote\n %d items deleted on local\n %d items deleted on remote\n"),addedPasswordsLocal, addedPasswordsRemote, changedLocal, changedRemote, deletedPasswordsLocal, deletedPasswordsRemote ); if ( manager->mShowSyncSummary ) { KMessageBox::information(0, mes, i18n("PWM/Pi Synchronization") ); } qDebug( mes ); return e_success; } int PwMDoc::takePwMDataItem( PwMDataItem* local, PwMDataItem* remote, QDateTime lastSync, int mode , bool full ) { // 0 equal // 1 take local // 2 take remote // 3 cancel QDateTime localMod = local->meta.update; QDateTime remoteMod = remote->meta.update; //US QString mCurrentSyncDevice = syncManager->getCurrentSyncDevice(); if ( localMod == remoteMod ) return 0; qDebug(" %d %d conflict on %s %s ", mode, full, local->desc.c_str(), remote->desc.c_str() ); //qDebug("%s %d %s %d", local->lastModified().toString().latin1() , localMod, remote->lastModified().toString().latin1(), remoteMod); //qDebug("%d %d %d %d ", local->lastModified().time().second(), local->lastModified().time().msec(), remote->lastModified().time().second(), remote->lastModified().time().msec() ); - //full = true; //debug only + full = true; //debug only if ( full ) { - bool equ = true;//US ( (*local) == (*remote) ); + bool equ = ( (*local) == (*remote) ); if ( equ ) { - //qDebug("equal "); + qDebug("equal "); if ( mode < SYNC_PREF_FORCE_LOCAL ) return 0; - }//else //debug only - //qDebug("not equal %s %s ", local->summary().latin1(), remote->summary().latin1()); + }else //debug only + qDebug("not equal %s %s ", local->desc.c_str(), remote->desc.c_str()); } int result; bool localIsNew; //qDebug("%s -- %s mLastCalendarSync %s lastsync %s --- local %s remote %s ",local->summary().latin1(), remote->summary().latin1(),mLastCalendarSync.toString().latin1() ,lastSync.toString().latin1() , local->lastModified().toString().latin1() , remote->lastModified().toString().latin1() ); if ( full && mode < SYNC_PREF_NEWEST ) mode = SYNC_PREF_ASK; switch( mode ) { case SYNC_PREF_LOCAL: if ( lastSync > remoteMod ) return 1; if ( lastSync > localMod ) return 2; return 1; break; case SYNC_PREF_REMOTE: if ( lastSync > remoteMod ) return 1; if ( lastSync > localMod ) return 2; return 2; break; case SYNC_PREF_NEWEST: if ( localMod > remoteMod ) return 1; else return 2; break; case SYNC_PREF_ASK: //qDebug("lsy %s --- lo %s --- re %s ", lastSync.toString().latin1(), localMod.toString().latin1(), remoteMod.toString().latin1() ); if ( lastSync > remoteMod ) return 1; if ( lastSync > localMod ) return 2; localIsNew = localMod >= remoteMod; //qDebug("conflict! ************************************** "); { PwMDataItemChooser acd ( *local,*remote, localIsNew , 0/*this*/ ); result = acd.executeD(localIsNew); return result; } break; case SYNC_PREF_FORCE_LOCAL: return 1; break; case SYNC_PREF_FORCE_REMOTE: return 2; break; default: // SYNC_PREF_TAKE_BOTH not implemented break; } return 0; } //this are the overwritten callbackmethods from the syncinterface bool PwMDoc::sync(KSyncManager* manager, QString filename, int mode) { QString mCurrentSyncDevice = manager->getCurrentSyncDevice(); //1) unlock local file first if necessary (ask for password) if (this->isDeepLocked()) { PwMerror ret = this->deepLock(false); if (ret != e_success) return false; } - //2) construct and open a new doc on the stack(automatic cleanup) for remote file. + //2) construct and open a new doc on the stack(automatic cleanup of remote file). PwMDoc syncTarget(this, "synctarget"); PwMDoc* pSyncTarget = &syncTarget; PwMerror err = pSyncTarget->openDoc(&filename, 1 /*== open with all entries locked*/); if (err == e_alreadyOpen) { PwMDocList::listItem li; if (getOpenDocList()->find(filename.latin1(), &li)) pSyncTarget = li.doc; else { qDebug("PwmDoc::sync: sync failed. Error %i while opening file %s",err, filename.latin1()); return false; } } else if (err != e_success) { qDebug("PwmDoc::sync: sync failed. Error %i while opening file %s",err, filename.latin1()); return false; } qDebug("PWM file loaded %s,sync mode %d",filename.latin1(), mode ); //3) unlock remote file first if necessary (ask for password) if (pSyncTarget->isDeepLocked()) { PwMerror ret = pSyncTarget->deepLock(false); if (ret != e_success) return false; } err = syncronize(manager, this, pSyncTarget, mode ); if (err == e_success) { if ( manager->mWriteBackFile ) { qDebug("Saving remote PWManager file"); err = pSyncTarget->saveDoc(conf()->confGlobCompression()); if (err != e_success) { qDebug("PwmDoc::sync: Sync failed. Error %i while storing file %s",err, filename.latin1()); return false; } } flagDirty(); return true; } else { return false; } } -//called by the syncmanager to indicate that the work has to marked as dirty. -void PwMDoc::sync_setModified() -{ - flagDirty(); -} - -//called by the syncmanager to ask if the dirty flag is set. -bool PwMDoc::sync_isModified() -{ - return isDirty(); -} - -//called by the syncmanager to indicate that the work has to be saved. -void PwMDoc::sync_save() -{ - saveDoc(conf()->confGlobCompression()); -} #endif bool PwMDoc::findSyncData(const QString &syncname, unsigned int *index) { vector<PwMSyncItem>::iterator i = dti.syncDta.begin(), end = dti.syncDta.end(); while (i != end) { if ((*i).syncName == syncname.latin1()) { if (index) { *index = i - dti.syncDta.begin(); } return true; } ++i; } return false; }; /** add new syncdataentry */ PwMerror PwMDoc::addSyncDataEntry(PwMSyncItem *d, bool dontFlagDirty) { PWM_ASSERT(d); if (isDeepLocked()) { PwMerror ret; ret = deepLock(false); if (ret != e_success) return e_lock; } unsigned int index; const QString tmp = d->syncName.c_str(); bool exists = findSyncData(d->syncName.c_str(), &index); if (exists == true) { // DOH! We found this entry. return e_entryExists; } dti.syncDta.push_back(*d); if (!dontFlagDirty) flagDirty(); return e_success; } /** delete syncdata entry */ bool PwMDoc::delSyncDataEntry(unsigned int index, bool dontFlagDirty) { if (isDeepLocked()) return false; if (index > dti.syncDta.size() - 1) return false; // delete entry dti.syncDta.erase(dti.syncDta.begin() + index); if (!dontFlagDirty) flagDirty(); return true; } PwMDataItem* PwMDoc::findEntryByID(const QString &uid, unsigned int *category, unsigned int *index) { vector<PwMCategoryItem>::iterator catcounter = dti.dta.begin(), catend = dti.dta.end(); vector<PwMDataItem>::iterator entrBegin, entrEnd, entrI; while (catcounter != catend) { entrBegin = catcounter->d.begin(); entrEnd = catcounter->d.end(); entrI = entrBegin; while (entrI != entrEnd) { if ((*entrI).meta.uniqueid == uid.latin1()) { if (category) *category = catcounter - dti.dta.begin(); if (index) *index = entrI - entrBegin; return &(*entrI); } ++entrI; } ++catcounter; } return 0; } QStringList PwMDoc::getIDEntryList() { QStringList results; vector<PwMCategoryItem>::iterator catcounter = dti.dta.begin(), catend = dti.dta.end(); vector<PwMDataItem>::iterator entrBegin, entrEnd, entrI; while (catcounter != catend) { entrBegin = catcounter->d.begin(); entrEnd = catcounter->d.end(); entrI = entrBegin; while (entrI != entrEnd) { results.append( (*entrI).meta.uniqueid.c_str() ); ++entrI; } ++catcounter; } return results; } #ifndef PWM_EMBEDDED #include "pwmdoc.moc" #endif diff --git a/pwmanager/pwmanager/pwmdoc.h b/pwmanager/pwmanager/pwmdoc.h index 2e9547e..6a1dd30 100644 --- a/pwmanager/pwmanager/pwmdoc.h +++ b/pwmanager/pwmanager/pwmdoc.h @@ -1,806 +1,805 @@ /*************************************************************************** * * * copyright (C) 2003, 2004 by Michael Buesch * * email: mbuesch@freenet.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License version 2 * * as published by the Free Software Foundation. * * * ***************************************************************************/ /*************************************************************************** * copyright (C) 2004 by Ulf Schenk * This file is originaly based on version 2.0 of pwmanager * and was modified to run on embedded devices that run microkde * * $Id$ **************************************************************************/ #ifndef __PWMDOC_H #define __PWMDOC_H #define PWM_FILE_VER (static_cast<char>(0x05)) #define PWM_HASH_SHA1 (static_cast<char>(0x01)) #define PWM_HASH_SHA256 (static_cast<char>(0x02)) #define PWM_HASH_SHA384 (static_cast<char>(0x03)) #define PWM_HASH_SHA512 (static_cast<char>(0x04)) #define PWM_HASH_MD5 (static_cast<char>(0x05)) #define PWM_HASH_RMD160 (static_cast<char>(0x06)) #define PWM_HASH_TIGER (static_cast<char>(0x07)) #define PWM_CRYPT_BLOWFISH (static_cast<char>(0x01)) #define PWM_CRYPT_AES128 (static_cast<char>(0x02)) #define PWM_CRYPT_AES192 (static_cast<char>(0x03)) #define PWM_CRYPT_AES256 (static_cast<char>(0x04)) #define PWM_CRYPT_3DES (static_cast<char>(0x05)) #define PWM_CRYPT_TWOFISH (static_cast<char>(0x06)) #define PWM_CRYPT_TWOFISH128 (static_cast<char>(0x07)) #define PWM_COMPRESS_NONE (static_cast<char>(0x00)) #define PWM_COMPRESS_GZIP (static_cast<char>(0x01)) #define PWM_COMPRESS_BZIP2 (static_cast<char>(0x02)) #define DEFAULT_MAX_ENTRIES (~(static_cast<unsigned int>(0))) #define FILE_ID_HEADER "PWM_PASSWORD_FILE" #include "pwmexception.h" #include "pwmdocui.h" #include <qobject.h> #include <qtimer.h> #include <qdatetime.h> #include <kprocess.h> #ifndef PWM_EMBEDDED #include "configuration.h" #else #include <kapplication.h> #include <ksyncmanager.h> #endif #include <string> #include <vector> #include <utility> using std::vector; using std::string; using std::pair; /* used in findEntry() function */ #define SEARCH_IN_DESC (1) #define SEARCH_IN_NAME (1 << 1) #define SEARCH_IN_PW (1 << 2) #define SEARCH_IN_COMMENT (1 << 3) #define SEARCH_IN_URL (1 << 4) #define SEARCH_IN_LAUNCHER (1 << 5) #define SEARCH_IN_ALL (SEARCH_IN_DESC | SEARCH_IN_NAME | \ SEARCH_IN_PW | SEARCH_IN_COMMENT | \ SEARCH_IN_URL | SEARCH_IN_LAUNCHER) /** document deeplocked. Data is out for lunch to disk */ #define DOC_STAT_DEEPLOCKED (1) /** encrypted document on disk is dirty. data has to go to disk. */ #define DOC_STAT_DISK_DIRTY (1 << 1) /** we are using a chipcard to encrypt the data */ #define DOC_STAT_USE_CHIPCARD (1 << 2) /** use "currentPw" to unlock. (This flag is set/unset by a timer) */ #define DOC_STAT_UNLOCK_WITHOUT_PW (1 << 3) class PwMDoc; class PwMView; class QFile; /* meta data for a PwMDataItem */ struct PwMMetaData { PwMMetaData() : updateInt (0) { } /** creation date of the PwMDataItem to which * this meta data belongs. */ QDateTime create; /** becomes valid on this date */ QDateTime valid; /** expire date */ QDateTime expire; /** update date (last updated at this date) */ QDateTime update; /** update interval (in minutes). Time since the * last update to remind the user to update the item. * 0 disables. */ unsigned long updateInt; //US ENH: enhancements of the filestructure /* each entry gets a unique id assigned */ string uniqueid; void clear() { create = QDateTime(); expire = QDateTime(); update = QDateTime(); updateInt = 0; uniqueid = KApplication::randomString(8); } - PwMMetaData& operator = (const PwMMetaData& x) - { - create = x.create; - expire = x.expire; - update = x.update; - updateInt = x.updateInt; - uniqueid = x.uniqueid; - return *this; - } - inline bool isValid() const { if (valid.isNull()) return true; return (valid < QDateTime::currentDateTime()); } inline bool isExpired() const { if (expire.isNull()) return false; return (expire < QDateTime::currentDateTime()); } inline bool isUpdateIntOver() const { if (updateInt == 0 || update.isNull()) return false; QDateTime d(update); return (d.addSecs(updateInt * 60) < QDateTime::currentDateTime()); } }; struct PwMDataItem { PwMDataItem() : lockStat (true) , listViewPos (-1) , binary (false) , rev (0) { } /** password description */ string desc; /** user-name */ string name; /** the password itself */ string pw; /** some comment */ string comment; /** an URL string */ string url; /** launcher. Can be executed as a system() command */ string launcher; /** locking status. If locked (true), pw is not emitted through getEntry() */ bool lockStat; /** position of this item in main "list-view" * If -1, the position is not yet specified and should be appended to the list */ int listViewPos; /** does this entry contain binary data? */ bool binary; /** meta data for this data item. */ PwMMetaData meta; /** data revision counter. This counter can be used * to easily, efficiently determine if this data item * has changed since some time. * This counter is incremented on every update. */ unsigned int rev; void clear(bool clearMeta = true) { /* NOTE: Don't use .clear() here to be * backward compatible with gcc-2 (Debian Woody) */ desc = ""; name = ""; pw = ""; comment = ""; url = ""; launcher = ""; lockStat = true; listViewPos = -1; binary = false; if (clearMeta) meta.clear(); } + //US ENH: we need this operator to compare two items if we have no unique ids + //available. Generaly this happens before the first sync + bool PwMDataItem::operator==( const PwMDataItem &a ) const + { + qDebug("oper==%s", a.desc.c_str()); + if ( desc != a.desc ) return false; + if ( name != a.name ) return false; + if ( pw != a.pw ) return false; + if ( comment != a.comment ) return false; + if ( url != a.url ) return false; + if ( launcher != a.launcher ) return false; + //all other field will not be checked. + return true; + } + //US ENH:this operator is used to copy an elements data during syncronization + //Attention: listViewPos will not be copied. So the position will stay the same. PwMDataItem& operator = (const PwMDataItem& x) { - qDebug("oper=%s", x.desc.c_str()); + // qDebug("oper=%s", x.desc.c_str()); desc = x.desc; name = x.name; pw = x.pw; comment = x.comment; url = x.url; launcher = x.launcher; lockStat = x.lockStat; - listViewPos = x.listViewPos; + //Do not copy listViewPos!!! listViewPos = x.listViewPos; binary = x.binary; meta = x.meta; rev = x.rev; return *this; } }; struct PwMCategoryItem { /** all PwMDataItems (all passwords) within this category */ vector<PwMDataItem> d; /** category name/description */ string name; void clear() { d.clear(); name = ""; } }; struct PwMSyncItem { string syncName; QDateTime lastSyncDate; void clear() { lastSyncDate = QDateTime(); syncName = ""; } }; struct PwMItem { vector<PwMCategoryItem> dta; vector<PwMSyncItem> syncDta; void clear() { dta.clear(); syncDta.clear(); } }; /** "Function Object" for sort()ing PwMDataItem::listViewPos */ class dta_lvp_greater { public: bool operator() (const pair<unsigned int, unsigned int> &d1, const pair<unsigned int, unsigned int> &d2) { return d1.second > d2.second; } }; /** list of PwMDoc documents and it's IDs */ class PwMDocList { public: struct listItem { /** document filename (known as ID, here) */ string docId; /** pointer to the document class */ PwMDoc *doc; }; PwMDocList() {} /** add a new item to the list */ void add(PwMDoc *doc, const string &id); /** changes the contents of an existing item */ void edit(PwMDoc *doc, const string &newId); /** remove the given item */ void del(PwMDoc *doc); /** get the item at index */ listItem getAt(int index) { return docList[index]; } /** find an entry with this id */ bool find(const string &id, listItem *ret = 0); /** returns a copy of the list */ const vector<listItem>* getList() const { return &docList; } /** returns a new unique number to extend the name of * an unnamed document. */ static unsigned int getNewUnnamedNumber() { return unnamedDocCnt++; } protected: /* Hm, I think we shouldn't really use a "list" here, should we? * So I decided to actually use a vector. */ vector<listItem> docList; /** This value is used to get a new number for yet unnamed * documents. It is incremented on every request. So it's * theoretically possible to overflow it, but... :) */ static unsigned int unnamedDocCnt; }; /** implements timers for the document */ class DocTimer : public QObject { Q_OBJECT public: enum TimerIDs { id_mpwTimer, id_autoLockTimer, id_metaCheckTimer }; public: DocTimer(PwMDoc *_doc); ~DocTimer(); /** start the timer */ void start(TimerIDs timer); /** stop the timer */ void stop(TimerIDs timer); /** get the lock for a timer. * This lock is a recursive lock. When a lock is * held, the timer will be stopped and timeout is * guaranteed to not happen */ void getLock(TimerIDs timer); /** put a recursive timer lock */ void putLock(TimerIDs timer); protected slots: /** timeout slot for the mpw timer */ void mpwTimeout(); /** timeout slot for the autoLock timer */ void autoLockTimeout(); /** timeout slot for the metaCheck timer */ void metaCheckTimeout(); protected: /** pointer to the document associated with this timer. */ PwMDoc *doc; /** timer object for mpw timer */ QTimer *mpwTimer; /** timer object for the autoLock timer */ QTimer *autoLockTimer; /** timer object for the metaCheck timer */ QTimer *metaCheckTimer; /** lock counter for the mpw timer */ unsigned int mpwLock; /** lock counter for the autoLock timer */ unsigned int autoLockLock; /** lock counter for the metaCheck timer */ unsigned int metaCheckLock; }; /** Document class for PwM */ //US ENH: derived from KSyncInterfaces, to get called by PwM when a sync is required. // But PwMDoc is handling the sync by itself. class PwMDoc : public PwMDocUi, public KSyncInterface { Q_OBJECT friend class DocTimer; public: /** construtor */ PwMDoc(QObject* parent = 0, const char *name = 0); /** destructor */ ~PwMDoc(); /** returns a pointer to a list of all open documents */ static PwMDocList* getOpenDocList() { return &openDocList; } /** flag document dirty. dta changed */ void flagDirty() { setDocStatFlag(DOC_STAT_DISK_DIRTY); emitDataChanged(this); } /** modified? */ bool isDirty() { return getDocStatFlag(DOC_STAT_DISK_DIRTY); } /** save document to disk */ PwMerror saveDoc(char compress, const QString *file = 0); /** read document from file. * "openLocked is must be set to either of these values: * 0 == open with all entries unlocked * 1 == open with all entries locked * 2 == open deep-locked */ PwMerror openDoc(const QString *file, int openLocked); /** export document to ascii-textfile */ PwMerror exportToText(const QString *file); /** export document to gpasman / kpasman file */ PwMerror exportToGpasman(const QString *file); /** import document from ascii-textfile */ PwMerror importFromText(const QString *file, int format = -1); /** import document from gpasman / kpasman file */ PwMerror importFromGpasman(const QString *file); /** add new entry */ PwMerror addEntry(const QString &category, PwMDataItem *d, bool dontFlagDirty = false, bool updateMeta = true); /** add new category. This function doesn't flag the document dirty! */ PwMerror addCategory(const QString &category, unsigned int *categoryIndex, bool checkIfExist = true); /** rename an existing category */ bool renameCategory(const QString &category, const QString &newName); /** rename an existing category */ bool renameCategory(unsigned int category, const QString &newName, bool dontFlagDirty = false); /** delete an existing category */ bool delCategory(const QString &category); /** delete an existing category */ bool delCategory(unsigned int category, bool dontFlagDirty = false); /** returns a list of all category-names */ void getCategoryList(vector<string> *list); /** returns a list of all category-names */ void getCategoryList(QStringList *list); /** returns a list of all entry-descs in the given category */ void getEntryList(const QString &category, QStringList *list); /** returns a list of all entry-descs in the given category */ void getEntryList(const QString &category, vector<string> *list); /** returns a list of all entry-descs in the given category */ void getEntryList(unsigned int category, vector<string> *list); /** returns a list of all entry-descs in the given category */ void getEntryList(unsigned int category, QStringList *list); /** delete entry */ bool delEntry(const QString &category, unsigned int index, bool dontFlagDirty = false); /** delete entry */ bool delEntry(unsigned int category, unsigned int index, bool dontFlagDirty = false); /** edit entry */ bool editEntry(const QString &oldCategory, const QString &newCategory, unsigned int index, PwMDataItem *d, bool updateMeta = true); /** edit entry */ bool editEntry(unsigned int oldCategory, const QString &newCategory, unsigned int index, PwMDataItem *d, bool updateMeta = true); /** finds the category with the "name" and return it's index */ bool findCategory(const QString &name, unsigned int *index); /** search for an entry "find" and check while searching only for * the data-fields specified by "searchIn". To set the "searchIn" * value, we may use one or more of the SEARCH_IN_* defines at * the top of this header-file. It returns the positions of all * matched entries in "foundPositions". If "breakAfterFound" is true, * the function terminates after the first occurence of the entry * and doesn't go on searching. So foundPositions->size() is never * > 1 if breakAfterFound is true. */ void findEntry(unsigned int category, PwMDataItem find, unsigned int searchIn, vector<unsigned int> *foundPositions, bool breakAfterFound = false, bool caseSensitive = true, bool exactWordMatch = true, bool sortByLvp = false); /** see the above funtion. This function allows to set the category by name. */ void findEntry(const QString &category, PwMDataItem find, unsigned int searchIn, vector<unsigned int> *foundPositions, bool breakAfterFound = false, bool caseSensitive = true, bool exactWordMatch = true, bool sortByLvp = false); /** returns number of entries */ unsigned int numEntries(const QString &category); unsigned int numEntries(unsigned int category) { return dti.dta[category].d.size(); } /** returns number of categories */ unsigned int numCategories() { return dti.dta.size(); } /** returns the name of the category at "index" */ const string* getCategory(unsigned int index) { return (&(dti.dta[index].name)); } /** returns the data of item at "index". * It unlocks the entry if it's locked and unlockIfLocked is true. * If the entry is locked, but unlockIfLocked is false, it'll not return * the pw. */ bool getEntry(const QString &category, unsigned int index, PwMDataItem *d, bool unlockIfLocked = false); bool getEntry(unsigned int category, unsigned int index, PwMDataItem *d, bool unlockIfLocked = false); /** returns the comment-string by looking at the category * and the listViewPos */ PwMerror getCommentByLvp(const QString &category, int listViewPos, string *foundComment); /** checks if a password is already available. (currentPw) */ bool isPwAvailable() { return (currentPw != ""); } /** un/lock entry at "index". If needed, ask for password. */ bool lockAt(const QString &category, unsigned int index, bool lock = true); bool lockAt(unsigned int category, unsigned int index, bool lock = true); /** returns the lock-status at "index" */ bool isLocked(const QString &category, unsigned int index); bool isLocked(unsigned int category, unsigned int index) { return dti.dta[category].d[index].lockStat; } /** returns the deeplock status */ bool isDeepLocked() { return getDocStatFlag(DOC_STAT_DEEPLOCKED); } /** (un)lock all entries */ bool lockAll(bool lock); /** unlocks all entries tempoarly. * 1st NOTE: Be very careful with this function! :) * 2nd NOTE: After you have called unlockAll_Tempoary(); , * please DON'T forget to call unlockAll_Tempoary(true); * _before_ the user (or someone else) is able to change * the document! * 3rd NOTE: Please DON'T change "dta" while the data is tempoary * unlocked! This will cause corruption. */ bool unlockAll_tempoary(bool revert = false); /** deep-(un)locks the document. * deep-locking writes all data to the file, deletes all data * in memory, but doesn't close the document. * deep-locking is only available, if the user previously saved * the doc to a file (with a password). * If "saveToFile" is false, it does NOT write the data to the file! */ PwMerror deepLock(bool lock = true, bool saveToFile = true); /** is unlockable without pw? */ bool unlockWoPw() { return getDocStatFlag(DOC_STAT_UNLOCK_WITHOUT_PW); } /** get the "currentPassword" */ const QString& getCurrentPw() { return currentPw; } /** open a window and request the user to change the mpw */ void changeCurrentPw(); /** set the "listViewPos" variable of "dta" */ void setListViewPos(const QString &category, unsigned int index, int pos); /** set the "listViewPos" variable of "dta" */ void setListViewPos(unsigned int category, unsigned int index, int pos); /** get the "listViewPos" variable of "dta" */ int getListViewPos(const QString &category, unsigned int index); /** set the maximum number of entries allowed */ void setMaxNumEntries(unsigned int num = DEFAULT_MAX_ENTRIES) { maxEntries = num; } /** get the maximum number of entries allowed */ unsigned int getMaxNumEntries() { return maxEntries; } /** ensure all listViewPos of all dta items are set. (are ! -1). * If there are some undefined entries, add them to the end of * the listViewPos(itions). */ void ensureLvp(); /** execute the "launcher" of this entry */ bool execLauncher(const QString &category, unsigned int entryIndex); /** see above */ bool execLauncher(unsigned int category, unsigned int entryIndex); /** open a browser with the URL-section of the given entry */ bool goToURL(const QString &category, unsigned int entryIndex); /** see above */ bool goToURL(unsigned int category, unsigned int entryIndex); /** returns true if there is no entry present in the document. * Note: The "default" Category is present everytime, so * it's checked for it's entries. */ bool isDocEmpty() { if (numCategories() > 1) return false; if (numEntries(0)) return false; return true; } /** returns the filename of this doc */ const QString& getFilename() { return filename; } /** returns the title of the doc */ QString getTitle(); /** sets the list-view-pointer hold in the doc */ void setListViewPointer(PwMView *_listView) { listView = _listView; } /** returns the list-view-pointer */ PwMView * getListViewPointer() { return listView; } /** try to delete the doc. The user may be asked to save * the data. The user may cancel the whole operation. * false is returned, then. */ bool tryDelete(); /** is the doc deleted? (with tryDelete() ) */ bool isDeleted() { return deleted; } /** returns the document timer object */ DocTimer * timer() { return _timer; } /** get a lock on the dataChanged signal. * If someone is holding a lock, the signal is not emitted. */ void getDataChangedLock() { ++dataChangedLock; } /** put the dataChanged lock */ void putDataChangedLock() { --dataChangedLock; } /** returns the revision count of the item at cat/index */ unsigned int getEntryRevCnt(unsigned int category, unsigned int index) { return dti.dta[category].d[index].rev; } /** returns a const pointer to the entries meta */ const PwMMetaData * getEntryMeta(unsigned int category, unsigned int index) { return &(dti.dta[category].d[index].meta); } /** is the entry at "category" "index" a binary entry? */ bool isBinEntry(unsigned int category, unsigned int index) { return dti.dta[category].d[index].binary; } public slots: /** wrapper for PwMTray */ void _deepUnlock(); signals: /** the data of the document has changed and must be updated * in all views. * NOTE: use emitDataChanged(PwMDoc *document) to emit this signal! */ void dataChanged(PwMDoc *document); /** the document class is going to close. This signal may be * used to nofify all views, that the user closed the document, * so the views can go down, too. */ void docClosed(PwMDoc *document); /** somebody just opened the document */ void docOpened(PwMDoc *document); /** this document object just got created */ void docCreated(PwMDoc *document); public: /** emit the dataChanged signal after checking for a lock */ void emitDataChanged(PwMDoc *document) { if (!dataChangedLock) emit dataChanged(document); } protected: /** current file for this doc */ QString filename; //US ENH: we need a place where we keep the syncentries. So I invented // struct PwMItem, that has a vector of PwMCategoryItem and vector of PwMSyncItem /** holds all data */ PwMItem dti; /** maximum number of entries */ unsigned int maxEntries; /** currently used password to encrypt data */ QString currentPw; /** current global document status flags */ unsigned int curDocStat; /** browser process for goToURL() */ KProcess browserProc; /** pointer to the list-view, using this document. * As there can only be one list-view per doc, we * don't need a list here. */ PwMView *listView; /** unnamedNum is used to store the "unnamed counter" * for this document, while it's unnamed. If it's 0, * we have to get a new unique one. */ unsigned int unnamedNum; /** is this doc going to be deleted (executing in destructor context) */ bool deleted; /** document timer */ DocTimer *_timer; /** lock counter for the "dataChanged" signal */ unsigned int dataChangedLock; /** list of all open documents */ static PwMDocList openDocList; protected: /** serialize "dta" and return it in "d". */ bool serializeDta(string *d); /** de-serialize "d" and overwrite "dta" */ bool deSerializeDta(const string *d, bool entriesLocked); /** write header to file */ PwMerror writeFileHeader(char keyHash, char dataHash, char crypt, char compress, QString *pw, QFile *f); /** write data-hash to file */ PwMerror writeDataHash(char dataHash, string *d, QFile *f); /** check header. Read header info and verify key-hash and filever. * returns length of header in "headerLength" */ PwMerror checkHeader(char *cryptAlgo, QString *pw, char *compress, unsigned int *headerLength, char *dataHashType, string *dataHash, QFile *f); /** check the data-hash */ PwMerror checkDataHash(char dataHashType, const string *dataHash, const string *dataStream); /** encrypt data "d" and write to "filename" */ PwMerror encrypt(string *d, const QString *pw, QFile *f, char algo); /** read data from file beginning at "pos", decrypt and return it */ PwMerror decrypt(string *d, unsigned int pos, const QString *pw, char algo, QFile *f); /** compress the data */ bool compressDta(string *d, char algo); /** uncompress the data */ bool decompressDta(string *d, char algo); /** internal import function for a text-file generated by PwM. * If this is not a valid PwM-exported file, it returns e_fileFormat */ PwMerror importText_PwM(const QString *file); /** PwM-text-import helper function to extract the name/pw/comment out * of one entry-line */ bool textExtractEntry_PwM(const char *in, ssize_t in_size, string *out); /** compare two strings */ bool compareString(const string &s1, const string &s2, bool caseSensitive, bool exactWordMatch); /** clears all document-data */ void clearDoc(); /** delete all empty categories */ void delAllEmptyCat(bool dontFlagDirty); /** set a document status flag */ void setDocStatFlag(unsigned int statFlag) { curDocStat |= statFlag; } /** unset a document status flag */ void unsetDocStatFlag(unsigned int statFlag) { curDocStat &= ~statFlag; } /** get a document status flag */ bool getDocStatFlag(unsigned int statFlag) const { return (curDocStat & statFlag); } /** set the "currentPassword" */ void setCurrentPw(const QString &pw) { currentPw = pw; setDocStatFlag(DOC_STAT_DISK_DIRTY); } /** make a backup-copy of the given file */ bool backupFile(const QString &filePath); /** copy a file from src to dst */ bool copyFile(const QString &src, const QString &dst); public: #ifdef PWM_EMBEDDED //US ENH: this is the magic function that syncronizes the local doc with the remote doc. PwMerror syncronize(KSyncManager* manager, PwMDoc* syncLocal, PwMDoc* syncRemote, int mode ); //takePwMDataItem returns the following values // 0 equal // 1 take local // 2 take remote // 3 cancel int takePwMDataItem( PwMDataItem* local, PwMDataItem* remote, QDateTime lastSync, int mode , bool full ); //the following methods are the overwritten callbackmethods from the syncinterface virtual bool sync(KSyncManager* manager, QString filename, int mode); - //called by the syncmanager to indicate that the work has to be marked as dirty. - virtual void sync_setModified(); - //called by the syncmanager to ask if the dirty flag is set. - virtual bool sync_isModified(); - //called by the syncmanager to indicate that the work has to be saved. - virtual void sync_save(); - #endif private: //US ENH: helpermethods to access the sync data for a certain syncname. // It returns the syncdatas index bool findSyncData(const QString &syncname, unsigned int *index); /** add new syncdataentry */ PwMerror addSyncDataEntry(PwMSyncItem *d, bool dontFlagDirty = false); /** returns a pointer to the syncdata */ PwMSyncItem* getSyncDataEntry(unsigned int index) { return &(dti.syncDta[index]); } /** delete entry */ bool delSyncDataEntry(unsigned int index, bool dontFlagDirty = false); PwMDataItem* findEntryByID(const QString &uid, unsigned int *category, unsigned int *index); QStringList getIDEntryList(); }; #endif diff --git a/pwmanager/pwmanager/pwmview.cpp b/pwmanager/pwmanager/pwmview.cpp index e23ce25..e53124f 100644 --- a/pwmanager/pwmanager/pwmview.cpp +++ b/pwmanager/pwmanager/pwmview.cpp @@ -1,524 +1,604 @@ /*************************************************************************** * * * copyright (C) 2003, 2004 by Michael Buesch * * email: mbuesch@freenet.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License version 2 * * as published by the Free Software Foundation. * * * ***************************************************************************/ /*************************************************************************** * copyright (C) 2004 by Ulf Schenk * This file is originaly based on version 1.0.1 of pwmanager * and was modified to run on embedded devices that run microkde * * $Id$ **************************************************************************/ #include "pwmview.h" #include "pwmexception.h" #include "globalstuff.h" #include "pwm.h" #include "rencatwnd.h" #ifndef PWM_EMBEDDED #include "configuration.h" #else #include "pwmprefs.h" #endif #include "commentbox.h" #include <kmessagebox.h> #include <klocale.h> #include <qlineedit.h> #include <qpoint.h> #include <qapplication.h> #include <qlayout.h> //US ENH: wouldn't it be a good idea if we could use this consts everywhere else. //US ENH: for examle in listviewpwm.cpp //US ENH: Because of that I transfer them into the headerfile. /* #define COLUMN_DESC 0 #define COLUMN_NAME 1 #define COLUMN_PW 2 #define COLUMN_URL 3 #define COLUMN_LAUNCHER 4 */ PwMView::PwMView(PwM *_mainClass, QWidget *parent, PwMDoc *_doc, const char *name) : PwMViewStyle(parent, name) { PWM_ASSERT(_mainClass); PWM_ASSERT(parent); PWM_ASSERT(_doc); setView(this); doc = _doc; doc->setListViewPointer(this); mainClass = _mainClass; resize(_mainClass->size()); initStyle(conf()->confWndMainViewStyle()); initCtxMenu(); doc->setCurrentView(this); connect(doc, SIGNAL(dataChanged(PwMDoc *)), this, SLOT(updateView())); } PwMView::~PwMView() { } void PwMView::initCtxMenu() { ctxMenu = new QPopupMenu(this); ctxMenu->insertItem(i18n("&Add password"), mainClass, SLOT(addPwd_slot())); ctxMenu->insertSeparator(); ctxMenu->insertItem(i18n("&Edit"), mainClass, SLOT(editPwd_slot())); ctxMenu->insertItem(i18n("&Delete"), mainClass, SLOT(deletePwd_slot())); ctxMenu->insertSeparator(); ctxMenu->insertItem(i18n("copy password to clipboard"), this, SLOT(copyPwToClip())); ctxMenu->insertItem(i18n("copy username to clipboard"), this, SLOT(copyNameToClip())); ctxMenu->insertItem(i18n("copy description to clipboard"), this, SLOT(copyDescToClip())); ctxMenu->insertItem(i18n("copy url to clipboard"), this, SLOT(copyUrlToClip())); ctxMenu->insertItem(i18n("copy launcher to clipboard"), this, SLOT(copyLauncherToClip())); ctxMenu->insertItem(i18n("copy comment to clipboard"), this, SLOT(copyCommentToClip())); ctxMenu->insertSeparator(); ctxMenu->insertItem(i18n("Execute \"Launcher\""), mainClass, SLOT(execLauncher_slot())); ctxMenu->insertItem(i18n("Go to \"URL\""), mainClass, SLOT(goToURL_slot())); } void PwMView::resizeEvent(QResizeEvent *) { resizeView(size()); } void PwMView::refreshCommentTextEdit(QListViewItem *curItem) { PWM_ASSERT(commentBox); if (!curItem) return; string comment; PwMerror ret; ret = document()->getCommentByLvp(getCurrentCategory(), lv->childCount() - lv->itemIndex(curItem) - 1, &comment); if (ret == e_binEntry) { commentBox->setContent(i18n("This is a binary entry.\n" "It is not a normal password-entry, as it contains " "binary data, which PwManager can't display here.")); } else if (ret == e_normalEntry) { commentBox->setContent(comment.c_str()); } else { BUG(); return; } lv->ensureItemVisible(curItem); } void PwMView::keyReleaseEvent(QKeyEvent * /*e*/) { refreshCommentTextEdit(lv->currentItem()); } bool PwMView::getCurEntryIndex(unsigned int *index) { QListViewItem *current = lv->currentItem(); if (!current) return false; return getDocEntryIndex(index, current); } bool PwMView::getDocEntryIndex(unsigned int *index, const QListViewItem *item) { vector<unsigned int> foundPositions; PwMDataItem curItem; curItem.desc = item->text(COLUMN_DESC).latin1(); curItem.name = item->text(COLUMN_NAME).latin1(); document()->getCommentByLvp(getCurrentCategory(), lv->childCount() - lv->itemIndex(item) - 1, &curItem.comment); curItem.url = item->text(COLUMN_URL).latin1(); curItem.launcher = item->text(COLUMN_LAUNCHER).latin1(); document()->findEntry(getCurrentCategory(), curItem, SEARCH_IN_DESC | SEARCH_IN_NAME | SEARCH_IN_COMMENT | SEARCH_IN_URL | SEARCH_IN_LAUNCHER, &foundPositions, true); if (foundPositions.size()) { *index = foundPositions[0]; return true; } return false; } void PwMView::handleToggle(QListViewItem *item) { PWM_ASSERT(doc); if (!item) return; QCheckListItem *clItem = (QCheckListItem *)item; QString curCat(getCurrentCategory()); // find document position of this entry. unsigned int curEntryDocIndex; if (!getDocEntryIndex(&curEntryDocIndex, item)) return; // hack to refresh the comment, if only one item is present if (lv->childCount() == 1) refreshCommentTextEdit(lv->currentItem()); if (doc->isLocked(curCat, curEntryDocIndex) != clItem->isOn()) return; // this is just a click somewhere on the entry if (doc->isDeepLocked()) { PwMerror ret; ret = doc->deepLock(false); if (ret != e_success) clItem->setOn(false); return; } doc->lockAt(curCat, curEntryDocIndex, !clItem->isOn()); } void PwMView::handleRightClick(QListViewItem *item, const QPoint &point, int) { if (!item) return; ctxMenu->move(point); /* don't use ctxMenu->exec() here, as it generates race conditions * with the card interface code. Believe it or not. :) */ ctxMenu->show(); } void PwMView::updateCategories() { QString oldSel(getCurrentCategory()); delAllCategories(); QStringList catList; document()->getCategoryList(&catList); catList.sort(); #ifndef PWM_EMBEDDED QStringList::iterator i = catList.begin(), end = catList.end(); #else QStringList::Iterator i = catList.begin(), end = catList.end(); #endif while (i != end) { addCategory(*i); ++i; } selectCategory(oldSel); } void PwMView::shiftToView() { int cX = lv->contentsX(); int cY = lv->contentsY(); commentBox->clear(); unsigned int catDocIndex; if (unlikely( !(document()->findCategory(getCurrentCategory(), &catDocIndex)))) { BUG(); } // ensure all listViewPos are set doc->ensureLvp(); // clear all tmp-data vectors unsigned int i, entries = doc->numEntries(catDocIndex); if (entries) { mainClass->setVirgin(false); } vector<PwMDataItem> tmpSorted; PwMDataItem currItem; currItem.clear(); tmpSorted.insert(tmpSorted.begin(), entries, currItem); // Sort items and store them in tempoary tmpSorted. for (i = 0; i < entries; ++i) { doc->getEntry(catDocIndex, i, &currItem); tmpSorted[currItem.listViewPos] = currItem; } // shift tempoary data to ListView. tmpDisableSort(); lv->clear(); QCheckListItem *newItem; vector<PwMDataItem>::iterator it = tmpSorted.begin(), end = tmpSorted.end(); while (it != end) { newItem = new ListViewItemPwM(lv); newItem->setText(COLUMN_DESC, (*it).desc.c_str()); if ((*it).binary) { newItem->setText(COLUMN_NAME, ""); newItem->setText(COLUMN_PW, i18n("<BINARY ENTRY>")); newItem->setText(COLUMN_URL, ""); newItem->setText(COLUMN_LAUNCHER, (*it).launcher.c_str()); } else { newItem->setText(COLUMN_NAME, (*it).name.c_str()); if ((*it).lockStat) { newItem->setText(COLUMN_PW, QString((*it).pw.c_str()) + " " + i18n("To unlock click the icon on the left.")); } else { newItem->setText(COLUMN_PW, (*it).pw.c_str()); } newItem->setText(COLUMN_URL, (*it).url.c_str()); newItem->setText(COLUMN_LAUNCHER, (*it).launcher.c_str()); } newItem->setOn(!((*it).lockStat)); lv->insertItem(newItem); ++it; } tmpReEnableSort(); if (cY || cX) lv->setContentsPos(cX, cY); } void PwMView::reorgLp() { if (!lv->childCount()) return; PWM_ASSERT(doc); PWM_ASSERT(!doc->isDocEmpty()); QListViewItem *currItem; vector<unsigned int> foundPos; /* This searchIn _should_ be: * const unsigned int searchIn = SEARCH_IN_DESC; * But we want backward compatibility (see comment in PwMDoc::addEntry()). * So we need to search again, if we don't find the entry. (see below) */ const unsigned int searchIn = SEARCH_IN_DESC | SEARCH_IN_NAME | SEARCH_IN_URL | SEARCH_IN_LAUNCHER; QString curCat(getCurrentCategory()); PwMDataItem findThis; unsigned int i, cnt = lv->childCount(); for (i = 0; i < cnt; ++i) { currItem = lv->itemAtIndex(i); findThis.desc = currItem->text(COLUMN_DESC).latin1(); findThis.name = currItem->text(COLUMN_NAME).latin1(); findThis.url = currItem->text(COLUMN_URL).latin1(); findThis.launcher = currItem->text(COLUMN_LAUNCHER).latin1(); doc->findEntry(curCat, findThis, searchIn, &foundPos, true); if (!foundPos.size()) { /* Did not find the entry. We seem to have a binary * entry here (pray for it!). So search again with * the "correct" searchIn flags. */ const unsigned int searchIn2 = SEARCH_IN_DESC; doc->findEntry(curCat, findThis, searchIn2, &foundPos, true); if (unlikely(!foundPos.size())) { BUG(); continue; } /* We assert that it's a binary entry, now. * No chance to efficiently verify it here. */ } doc->setListViewPos(curCat, foundPos[0], cnt - i - 1); } } void PwMView::selAt(int index) { QListViewItem *item = lv->itemAtIndex(index); if (!item) return; lv->setCurrentItem(item); lv->ensureItemVisible(item); } void PwMView::renCatButton_slot() { if (doc->isDeepLocked()) return; RenCatWnd wnd(this); if (wnd.exec() == 1) { QString newName(wnd.getNewName()); if (newName == "") return; document()->renameCategory(getCurrentCategory(), newName); } } void PwMView::delCatButton_slot() { if (doc->isDeepLocked()) return; if (numCategories() <= 1) { mainClass->showStatMsg(i18n("Can't remove the last category.")); return; } if (KMessageBox::questionYesNo(this, i18n("Do you really want to\n" "delete the selected\n" "category? All password-\n" "entries will be lost in\n" "this category!\n"), i18n("Delete category?")) == KMessageBox::No) { return; } document()->delCategory(getCurrentCategory()); } void PwMView::copyPwToClip() { if (doc->isDeepLocked()) return; unsigned int curIndex = 0; if (!getCurEntryIndex(&curIndex)) return; PwMDataItem d; document()->getDataChangedLock(); document()->getEntry(getCurrentCategory(), curIndex, &d, true); document()->putDataChangedLock(); PwM::copyToClipboard(d.pw.c_str()); } void PwMView::copyNameToClip() { if (doc->isDeepLocked()) return; unsigned int curIndex = 0; if (!getCurEntryIndex(&curIndex)) return; PwMDataItem d; document()->getEntry(getCurrentCategory(), curIndex, &d); PwM::copyToClipboard(d.name.c_str()); } void PwMView::copyDescToClip() { if (doc->isDeepLocked()) return; unsigned int curIndex = 0; if (!getCurEntryIndex(&curIndex)) return; PwMDataItem d; document()->getEntry(getCurrentCategory(), curIndex, &d); PwM::copyToClipboard(d.desc.c_str()); } void PwMView::copyUrlToClip() { if (doc->isDeepLocked()) return; unsigned int curIndex = 0; if (!getCurEntryIndex(&curIndex)) return; PwMDataItem d; document()->getEntry(getCurrentCategory(), curIndex, &d); PwM::copyToClipboard(d.url.c_str()); } void PwMView::copyLauncherToClip() { if (doc->isDeepLocked()) return; unsigned int curIndex = 0; if (!getCurEntryIndex(&curIndex)) return; PwMDataItem d; document()->getEntry(getCurrentCategory(), curIndex, &d); PwM::copyToClipboard(d.launcher.c_str()); } void PwMView::copyCommentToClip() { if (doc->isDeepLocked()) return; unsigned int curIndex = 0; if (!getCurEntryIndex(&curIndex)) return; PwMDataItem d; document()->getEntry(getCurrentCategory(), curIndex, &d); PwM::copyToClipboard(d.comment.c_str()); } +/************************************************************************ + * + * + * + ************************************************************************/ + + +PwMDataItemView::PwMDataItemView( QWidget *parent, const char *name ) + : QTextBrowser( parent, name ) + + +{ +//US setWrapPolicy( QTextEdit::AtWordBoundary ); + setLinkUnderline( false ); + // setVScrollBarMode( QScrollView::AlwaysOff ); + //setHScrollBarMode( QScrollView::AlwaysOff ); + +//US QStyleSheet *sheet = styleSheet(); +//US QStyleSheetItem *link = sheet->item( "a" ); +//US link->setColor( KGlobalSettings::linkColor() ); + +} + +void PwMDataItemView::setPwMDataItem( const PwMDataItem& a ) + +{ + mItem = a; + // clear view + setText( QString::null ); + + + QString dynamicPart; + QString format = "<tr><td align=\"right\"><b>%1</b></td>" + "<td align=\"left\">%2</td></tr>"; + + dynamicPart += format + .arg( i18n("Description") ) + .arg( mItem.desc.c_str() ); + dynamicPart += format + .arg( i18n("Name") ) + .arg( mItem.name.c_str() ); + + dynamicPart += format + .arg( i18n("Password") ) + .arg( mItem.pw.c_str() ); + + QString comment(mItem.pw.c_str()); + dynamicPart += format + .arg( i18n("Comment") ) + .arg( comment.replace( QRegExp("\n"), "<br>" ) ); + + dynamicPart += format + .arg( i18n("URL") ) + .arg( mItem.url.c_str() ); + + dynamicPart += format + .arg( i18n("Launcher") ) + .arg( mItem.launcher.c_str() ); + + QString mText = "<table><td colspan=\"2\"> </td>"; + + mText += dynamicPart; + mText += "</table>"; + + // at last display it... + setText( mText ); + +} + +PwMDataItem PwMDataItemView::pwmdataitem() const +{ + return mItem; +} + +/************************************************************************ + * + * + * + ************************************************************************/ -PwMDataItemChooser::PwMDataItemChooser( PwMDataItem loc, PwMDataItem rem, bool takeloc, QWidget *parent, const char *name ) : KDialogBase(parent,name, - true ,i18n("Conflict! Please choose Entry!"),Ok|User1|Close,Close, false) +PwMDataItemChooser::PwMDataItemChooser( PwMDataItem loc, PwMDataItem rem, bool takeloc, QWidget *parent, const char *name ) + : KDialogBase(parent, name, true , + i18n("Conflict! Please choose Entry!"),Ok|User1|Close,Close, false) { findButton( Close )->setText( i18n("Cancel Sync")); findButton( Ok )->setText( i18n("Remote")); findButton( User1 )->setText( i18n("Local")); QWidget* topframe = new QWidget( this ); setMainWidget( topframe ); QBoxLayout* bl; if ( QApplication::desktop()->width() < 640 ) { bl = new QVBoxLayout( topframe ); } else { bl = new QHBoxLayout( topframe ); } QVBox* subframe = new QVBox( topframe ); bl->addWidget(subframe ); QLabel* lab = new QLabel( i18n("Local Entry"), subframe ); if ( takeloc ) lab->setBackgroundColor(Qt::green.light() ); - // AddresseeView * av = new AddresseeView( subframe ); - // av->setAddressee( loc ); + PwMDataItemView * av = new PwMDataItemView( subframe ); + av->setPwMDataItem( loc ); subframe = new QVBox( topframe ); bl->addWidget(subframe ); lab = new QLabel( i18n("Remote Entry"), subframe ); if ( !takeloc ) lab->setBackgroundColor(Qt::green.light() ); - // av = new AddresseeView( subframe ); - // av->setAddressee( rem ); + av = new PwMDataItemView( subframe ); + av->setPwMDataItem( rem ); QObject::connect(findButton( Ok ),SIGNAL(clicked()),this, SLOT(slot_remote())); QObject::connect(this,SIGNAL(user1Clicked()),this, SLOT(slot_local())); #ifndef DESKTOP_VERSION showMaximized(); #else resize ( 640, 400 ); #endif } int PwMDataItemChooser::executeD( bool local ) { mSyncResult = 3; if ( local ) findButton( User1 )->setFocus(); else findButton( Ok )->setFocus(); exec(); return mSyncResult; } void PwMDataItemChooser::slot_remote() { mSyncResult = 2; accept(); } void PwMDataItemChooser::slot_local() { mSyncResult = 1; accept(); } #ifndef PWM_EMBEDDED #include "pwmview.moc" #endif diff --git a/pwmanager/pwmanager/pwmview.h b/pwmanager/pwmanager/pwmview.h index 75cce51..e42b17a 100644 --- a/pwmanager/pwmanager/pwmview.h +++ b/pwmanager/pwmanager/pwmview.h @@ -1,172 +1,197 @@ /*************************************************************************** * * * copyright (C) 2003, 2004 by Michael Buesch * * email: mbuesch@freenet.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License version 2 * * as published by the Free Software Foundation. * * * ***************************************************************************/ /*************************************************************************** * copyright (C) 2004 by Ulf Schenk * This file is originaly based on version 1.0.1 of pwmanager * and was modified to run on embedded devices that run microkde * * $Id$ **************************************************************************/ #ifndef PWMVIEW_H #define PWMVIEW_H //US ENH: wouldn't it be a good idea if we could use this consts everywhere else. //US ENH: for examle in listviewpwm.cpp //US ENH: Because of that I transfer them into the headerfile. #define COLUMN_DESC 0 #define COLUMN_NAME 1 #define COLUMN_PW 2 #define COLUMN_URL 3 #define COLUMN_LAUNCHER 4 #include "listviewpwm.h" #include "pwmdoc.h" #include "pwmviewstyle.h" #include <kconfig.h> #include <klocale.h> #include <kdialogbase.h> #include <qevent.h> #include <qfont.h> #include <qobject.h> +#include <qtextbrowser.h> #include <vector> #include <string> using std::string; using std::vector; class PwM; class ConfFile; class PwMStatusBar; /** View class for PwM */ class PwMView : public PwMViewStyle { Q_OBJECT friend class PwMViewStyle; public: /** construtor */ PwMView(PwM *_mainClass, QWidget* parent, PwMDoc *_doc, const char *name = 0); /** destructor */ ~PwMView(); /** returns pointer to the document */ PwMDoc* document() { return doc; } /** returns the index of the currently selected entry. * (index as represented in PwMDoc !) */ bool getCurEntryIndex(unsigned int *index); /** returns the position of the given item in the document * Note: This func only serches in the current category. */ bool getDocEntryIndex(unsigned int *index, const QListViewItem *item); public slots: /** update the view (call if dirty) */ void updateView() { updateCategories(); shiftToView(); } /** (re)sort all items and (re)shift them to listView. */ void shiftToView(); /** handle clicking on an item */ void handleToggle(QListViewItem *item); /** handle right-clicking on an item */ void handleRightClick(QListViewItem *item, const QPoint &point, int); /** selects the item at "index" */ void selAt(int index); /** rename category button pressed */ void renCatButton_slot(); /** delete category button pressed */ void delCatButton_slot(); protected: /** right-click context-menu */ QPopupMenu *ctxMenu; protected: /** update the categories from document */ void updateCategories(); /** widget resize event */ void resizeEvent(QResizeEvent *); /** initialize context-menu */ void initCtxMenu(); /** tempoarly disable auto-sorting and user-sorting */ void tmpDisableSort() { lv->setSorting(-1); } /** re-enable tempoarly disabled sorting */ void tmpReEnableSort() { lv->setSorting(lv->columns() + 1, true/*lv->sortOrder() == Qt::Ascending*/); } /** The user pressed and released a key. */ void keyReleaseEvent(QKeyEvent *e); protected slots: /** changes the comment text-edit, because a new item has been selected */ void refreshCommentTextEdit(QListViewItem *curItem); /** copy pw to clipboard */ void copyPwToClip(); /** copy name to clipboard */ void copyNameToClip(); /** copy desc to clipboard */ void copyDescToClip(); /** copy url to clipboard */ void copyUrlToClip(); /** copy launcher to clipboard */ void copyLauncherToClip(); /** copy comment to clipboard */ void copyCommentToClip(); /** reorganize the "listViewPos" positions in the document * (for the current category only!) */ void reorgLp(); private: /** document */ PwMDoc *doc; /** pointer to the main class "PwM" */ PwM *mainClass; }; +//US ENH basic widget to view an password entry. We need it for the sync stuff. +//But might be oif interest for other functionalities as well. +class PwMDataItemView : public QTextBrowser +{ + public: + PwMDataItemView( QWidget *parent = 0, const char *name = 0 ); + + /** + Sets the PwMDataItem object. It is displayed immediately. + + @param a The PwMDataItem object. + */ + void setPwMDataItem( const PwMDataItem& a ); + + /** + Returns the current PwMDataItem object. + */ + PwMDataItem pwmdataitem() const; + + private: + PwMDataItem mItem; +}; + + //US ENH we need this chooser when syncing results in a conflict class PwMDataItemChooser : public KDialogBase { Q_OBJECT public: PwMDataItemChooser( PwMDataItem loc, PwMDataItem rem, bool takeloc, QWidget *parent = 0, const char *name = 0 ); int executeD( bool local ); private: int mSyncResult; private slots: void slot_remote(); void slot_local(); }; #endif diff --git a/pwmanager/pwmanager/serializer.cpp b/pwmanager/pwmanager/serializer.cpp index 203f82c..5c6568f 100644 --- a/pwmanager/pwmanager/serializer.cpp +++ b/pwmanager/pwmanager/serializer.cpp @@ -1,756 +1,780 @@ /*************************************************************************** * * * copyright (C) 2004 by Michael Buesch * * email: mbuesch@freenet.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License version 2 * * as published by the Free Software Foundation. * * * ***************************************************************************/ /*************************************************************************** * copyright (C) 2004 by Ulf Schenk * This file is originaly based on version 2.0 of pwmanager * and was modified to run on embedded devices that run microkde * * $Id$ **************************************************************************/ #include "serializer.h" #include "pwmexception.h" #ifdef PWM_EMBEDDED #include <kglobal.h> #include <klocale.h> #endif /* enable/disable serializer debugging (0/1) */ -#define SERIALIZER_DEBUG 0 +#define SERIALIZER_DEBUG 1 /* use the old xml tags for writing (0/1) */ #define USE_OLD_TAGS 0 /* write a CDATA section (0/1) */ #define WRITE_CDATA_SEC 0 #define META_CREATE_DATE "c" #define META_VALID_DATE "v" #define META_EXPIRE_DATE "e" #define META_UPDATE_DATE "u" #define META_UPDATE_INT "i" //US ENH : uniqueid #define META_UNIQUEID "n" #define SYNC_ROOT "s" #define SYNC_TARGET_PREFIX "t" #define SYNC_TARGET_NAME "n" /* This is compatibility stuff. * The names of the entries have changed and here are the * new and old ones */ #define ROOT_MAGIC_OLD "PwM-xml-dat" #define VER_STR_OLD "ver" #define COMPAT_VER_OLD "0x02" #define CAT_ROOT_OLD "categories" #define CAT_PREFIX_OLD "cat_" #define CAT_NAME_OLD "name" #define ENTRY_PREFIX_OLD "entry_" #define ENTRY_DESC_OLD "desc" #define ENTRY_NAME_OLD "name" #define ENTRY_PW_OLD "pw" #define ENTRY_COMMENT_OLD "comment" #define ENTRY_URL_OLD "url" #define ENTRY_LAUNCHER_OLD "launcher" #define ENTRY_LVP_OLD "listViewPos" #define ENTRY_BIN_OLD "b" #define ENTRY_META_OLD "m" #define ROOT_MAGIC_NEW "P" #define VER_STR_NEW "v" #define COMPAT_VER_NEW "2" #define CAT_ROOT_NEW "c" #define CAT_PREFIX_NEW "c" #define CAT_NAME_NEW "n" #define ENTRY_PREFIX_NEW "e" #define ENTRY_DESC_NEW "d" #define ENTRY_NAME_NEW "n" #define ENTRY_PW_NEW "p" #define ENTRY_COMMENT_NEW "c" #define ENTRY_URL_NEW "u" #define ENTRY_LAUNCHER_NEW "l" #define ENTRY_LVP_NEW "v" #define ENTRY_BIN_NEW ENTRY_BIN_OLD #define ENTRY_META_NEW ENTRY_META_OLD #if USE_OLD_TAGS != 0 # define ROOT_MAGIC_WR ROOT_MAGIC_OLD # define VER_STR_WR VER_STR_OLD # define COMPAT_VER_WR COMPAT_VER_OLD # define CAT_ROOT_WR CAT_ROOT_OLD # define CAT_PREFIX_WR CAT_PREFIX_OLD # define CAT_NAME_WR CAT_NAME_OLD # define ENTRY_PREFIX_WR ENTRY_PREFIX_OLD # define ENTRY_DESC_WR ENTRY_DESC_OLD # define ENTRY_NAME_WR ENTRY_NAME_OLD # define ENTRY_PW_WR ENTRY_PW_OLD # define ENTRY_COMMENT_WR ENTRY_COMMENT_OLD # define ENTRY_URL_WR ENTRY_URL_OLD # define ENTRY_LAUNCHER_WR ENTRY_LAUNCHER_OLD # define ENTRY_LVP_WR ENTRY_LVP_OLD # define ENTRY_BIN_WR ENTRY_BIN_OLD # define ENTRY_META_WR ENTRY_META_OLD #else # define ROOT_MAGIC_WR ROOT_MAGIC_NEW # define VER_STR_WR VER_STR_NEW # define COMPAT_VER_WR COMPAT_VER_NEW # define CAT_ROOT_WR CAT_ROOT_NEW # define CAT_PREFIX_WR CAT_PREFIX_NEW # define CAT_NAME_WR CAT_NAME_NEW # define ENTRY_PREFIX_WR ENTRY_PREFIX_NEW # define ENTRY_DESC_WR ENTRY_DESC_NEW # define ENTRY_NAME_WR ENTRY_NAME_NEW # define ENTRY_PW_WR ENTRY_PW_NEW # define ENTRY_COMMENT_WR ENTRY_COMMENT_NEW # define ENTRY_URL_WR ENTRY_URL_NEW # define ENTRY_LAUNCHER_WR ENTRY_LAUNCHER_NEW # define ENTRY_LVP_WR ENTRY_LVP_NEW # define ENTRY_BIN_WR ENTRY_BIN_NEW # define ENTRY_META_WR ENTRY_META_NEW #endif Serializer::Serializer() { defaultLockStat = true; //US BUG: I needed to specify a document name. Otherwise impl will not be created for serializing #ifndef PWM_EMBEDDED domDoc = new QDomDocument; #else domDoc = new QDomDocument("mydoc"); #endif } Serializer::Serializer(const QCString &buffer) { defaultLockStat = true; //US BUG: I needed to specify a document name. Otherwise impl will not be created for serializing #ifndef PWM_EMBEDDED domDoc = new QDomDocument; #else domDoc = new QDomDocument("mydoc"); #endif if (!parseXml(buffer)) { delete domDoc; #ifndef PWM_EMBEDDED throw PwMException(PwMException::EX_PARSE); #else qDebug("Serializer::Serializer : Parse Exception "); #endif } } Serializer::~Serializer() { delete_ifnot_null(domDoc); } void Serializer::clear() { delete_ifnot_null(domDoc); domDoc = new QDomDocument; } bool Serializer::parseXml(const QCString &buffer) { PWM_ASSERT(domDoc); #ifndef PWM_EMBEDDED if (!domDoc->setContent(buffer, true)) return false; #else if (!domDoc->setContent(buffer)) return false; #endif if (!checkValid()) return false; return true; } QCString Serializer::getXml() { PWM_ASSERT(domDoc); #ifndef PWM_EMBEDDED #if defined(PWM_DEBUG) && SERIALIZER_DEBUG != 0 QCString tmp(domDoc->toCString(8)); printDebug("<BEGIN Serializer::getXml() dump>\n"); cout << tmp << endl; printDebug("<END Serializer::getXml() dump>"); #endif // DEBUG QCString ret(domDoc->toCString(0)); ret.replace('\n', ""); return ret; #else #if defined(PWM_DEBUG) && SERIALIZER_DEBUG != 0 QCString tmp(" " + domDoc->toCString()); printDebug("<BEGIN Serializer::getXml() dump>\n"); qDebug(tmp); cout << tmp << endl; printDebug("<END Serializer::getXml() dump>"); #endif // DEBUG QCString ret(domDoc->toCString()); ret.replace(QRegExp("\n"), ""); return ret; #endif } bool Serializer::serialize(PwMItem &dta) { PWM_ASSERT(domDoc); QDomElement root(genNewRoot()); QDomElement catNode(domDoc->createElement(CAT_ROOT_WR)); QDomElement syncNode(domDoc->createElement(SYNC_ROOT)); if (!addSyncData(&syncNode, dta.syncDta)) return false; root.appendChild(syncNode); if (!addCategories(&catNode, dta.dta)) return false; root.appendChild(catNode); return true; } bool Serializer::deSerialize(PwMItem *dta) { PWM_ASSERT(domDoc); PWM_ASSERT(dta); QDomElement root(domDoc->documentElement()); QDomNode n; dta->clear(); for (n = root.firstChild(); !n.isNull(); n = n.nextSibling()) { // find <categories> ... </categories> // <c> ... </c> if (n.nodeName() == CAT_ROOT_NEW || n.nodeName() == CAT_ROOT_OLD) { if (!readCategories(n, &(dta->dta))) { return false; } continue; } else if (n.nodeName() == SYNC_ROOT) { if (!readSyncData(n, &(dta->syncDta))) { return false; } continue; } /* NOTE: We can stop processing here, as we * don't have more nodes in root, yet. */ return false; } return true; } bool Serializer::readCategories(const QDomNode &n, vector<PwMCategoryItem> *dta) { QDomNodeList nl(n.childNodes()); QDomNode cur; QString name; unsigned int numCat = nl.count(), i; PwMCategoryItem curCat; vector<PwMDataItem> curEntr; if (!numCat) { printDebug("Serializer::readCategories(): empty"); return false; } for (i = 0; i < numCat; ++i) { cur = nl.item(i); if (cur.nodeName().left(1) == CAT_PREFIX_NEW || cur.nodeName().left(4) == CAT_PREFIX_OLD) { name = cur.toElement().attribute(CAT_NAME_NEW); if (name == QString::null) name = cur.toElement().attribute(CAT_NAME_OLD); PWM_ASSERT(name != QString::null); PWM_ASSERT(name != ""); curCat.clear(); curCat.name = name.latin1(); if (!readEntries(cur, &curEntr)) { dta->clear(); return false; } curCat.d = curEntr; dta->push_back(curCat); } else { printDebug("Serializer::readCategories(): uh? not a category?"); } } return true; } bool Serializer::readEntries(const QDomNode &n, vector<PwMDataItem> *dta) { QDomNodeList nl(n.childNodes()); QDomNode cur; unsigned int numEntr = nl.count(), i; PwMDataItem curEntr; + //US BUG: to initialize all values of curEntr with meaningfulldata, + // we call clear on it. Reason: Information in the file we will read might be incomplete. + // e.g. the metadata is missing. + curEntr.clear(true); dta->clear(); for (i = 0; i < numEntr; ++i) { cur = nl.item(i); if (cur.nodeName().left(1) == ENTRY_PREFIX_NEW || cur.nodeName().left(6) == ENTRY_PREFIX_OLD) { if (!extractEntry(cur, &curEntr)) { return false; } dta->push_back(curEntr); } else { printDebug("Serializer::readEntries(): hm? not an entry?"); } } return true; } bool Serializer::extractEntry(const QDomNode &n, PwMDataItem *dta) { QDomNodeList nl(n.childNodes()); QDomNode cur, cdata; unsigned int cnt = nl.count(), i; QString name, text; if (!cnt) { printDebug("Serializer::extractEntry(): empty"); return false; } dta->clear(); for (i = 0; i < cnt; ++i) { cur = nl.item(i); name = cur.nodeName(); cdata = cur.firstChild(); if (unlikely(cdata.isCDATASection())) { text = cdata.toCDATASection().data(); } else if (likely(cur.isElement())) { text = cur.toElement().text(); } else { printDebug("Serializer::extractEntry(): neither CDATA nor element."); return false; } if (text == " ") text = ""; // for backward compatibility. if (name == ENTRY_DESC_NEW || name == ENTRY_DESC_OLD) { dta->desc = unescapeEntryData(text).latin1(); } else if (name == ENTRY_NAME_NEW || name == ENTRY_NAME_OLD) { dta->name = unescapeEntryData(text).latin1(); } else if (name == ENTRY_PW_NEW || name == ENTRY_PW_OLD) { dta->pw = unescapeEntryData(text).latin1(); } else if (name == ENTRY_COMMENT_NEW || name == ENTRY_COMMENT_OLD) { dta->comment = unescapeEntryData(text).latin1(); } else if (name == ENTRY_URL_NEW || name == ENTRY_URL_OLD) { dta->url = unescapeEntryData(text).latin1(); } else if (name == ENTRY_LAUNCHER_NEW || name == ENTRY_LAUNCHER_OLD) { dta->launcher = unescapeEntryData(text).latin1(); } else if (name == ENTRY_LVP_NEW || name == ENTRY_LVP_OLD) { dta->listViewPos = strtol(text.latin1(), 0, 10); } else if (name == ENTRY_BIN_NEW) { // ENTRY_BIN_NEW == ENTRY_BIN_OLD if (text == "0") { dta->binary = false; } else { dta->binary = true; } } else if (name == ENTRY_META_NEW) { // ENTRY_META_NEW == ENTRY_META_OLD if (!extractMeta(cur, &dta->meta)) return false; } else { printDebug(string("Serializer::extractEntry(): invalid: ") + name.latin1()); } } dta->lockStat = defaultLockStat; return true; } bool Serializer::extractMeta(const QDomNode &n, PwMMetaData *dta) { QDomNode cur(n.firstChild()); QString name, val; while (!cur.isNull()) { name = cur.nodeName(); val = cur.toElement().text(); if (val == "") { cur = cur.nextSibling(); continue; } + + //US BUG: The transformation of an empty date into an ISO date and back is different on different systems/compilers. + //because of that it is possible that here some values are not set, which means they are null. + //US ENH: at the same moment we need backwardcompatibility. So older versions might have stored invalid dates. + + QDateTime dtval; //dtval should be invalid by definition. + + if ((name == META_CREATE_DATE) || + (name == META_VALID_DATE) || + (name == META_EXPIRE_DATE) || + (name == META_UPDATE_DATE)) + { + //qDebug("Serializer::extractMeta:: val:%s, empty:%i, length:%i",val.utf8(), val.isEmpty(), val.length()); + #ifndef PWM_EMBEDDED - if (name == META_CREATE_DATE) { - dta->create = QDateTime::fromString(val, Qt::ISODate); - } else if (name == META_VALID_DATE) { - dta->valid = QDateTime::fromString(val, Qt::ISODate); - } else if (name == META_EXPIRE_DATE) { - dta->expire = QDateTime::fromString(val, Qt::ISODate); - } else if (name == META_UPDATE_DATE) { - dta->update = QDateTime::fromString(val, Qt::ISODate); - } else if (name == META_UPDATE_INT) { - dta->updateInt = strtoul(val.latin1(), 0, 10); - } else if (name == META_UNIQUEID) { - dta->uniqueid = unescapeEntryData(val).latin1(); - } else { - printDebug(string("extractMeta(): invalid: ") - + name.latin1()); - } + dtval = QDateTime::fromString(val, Qt::ISODate); #else + bool ok; + dtval = KGlobal::locale()->readDateTime(val, KLocale::ISODate, &ok); + + if (ok == false) + qDebug("Serializer::extractMeta invalid date or time !!!!!!!!!!!!!"); +#endif + //if the parsed data is wrong, dtval should be invalid at this time. - bool ok = true; + } if (name == META_CREATE_DATE) { - dta->create = KGlobal::locale()->readDateTime(val, KLocale::ISODate, &ok); + dta->create = dtval; } else if (name == META_VALID_DATE) { - dta->valid = KGlobal::locale()->readDateTime(val, KLocale::ISODate, &ok); + dta->valid = dtval; } else if (name == META_EXPIRE_DATE) { - dta->expire = KGlobal::locale()->readDateTime(val, KLocale::ISODate, &ok); + dta->expire = dtval; } else if (name == META_UPDATE_DATE) { - dta->update = KGlobal::locale()->readDateTime(val, KLocale::ISODate, &ok); + dta->update = dtval; } else if (name == META_UPDATE_INT) { dta->updateInt = strtoul(val.latin1(), 0, 10); } else if (name == META_UNIQUEID) { dta->uniqueid = unescapeEntryData(val).latin1(); } else { printDebug(string("extractMeta(): invalid: ") + name.latin1()); } - if (ok == false) - qDebug("Serializer::extractMeta invalid date or time !!!!!!!!!!!!!"); - - -#endif cur = cur.nextSibling(); } return true; } bool Serializer::checkValid() { PWM_ASSERT(domDoc); QDomElement root(domDoc->documentElement()); if (root.nodeName() != ROOT_MAGIC_NEW && root.nodeName() != ROOT_MAGIC_OLD) { printDebug("Serializer: wrong magic"); return false; } if (root.attribute(VER_STR_NEW) != COMPAT_VER_NEW && root.attribute(VER_STR_OLD) != COMPAT_VER_OLD) { printDebug("Serializer: wrong version"); return false; } return true; } QDomElement Serializer::genNewRoot() { PWM_ASSERT(domDoc); QDomElement root(domDoc->createElement(ROOT_MAGIC_WR)); root.setAttribute(VER_STR_WR, COMPAT_VER_WR); domDoc->appendChild(root); return root; } bool Serializer::addCategories(QDomElement *e, const vector<PwMCategoryItem> &dta) { unsigned int numCat = dta.size(), i; QString curId, curName; QDomElement curCat; for (i = 0; i < numCat; ++i) { curId = CAT_PREFIX_WR; curId += tostr(i).c_str(); curName = dta[i].name.c_str(); curCat = domDoc->createElement(curId); curCat.setAttribute(CAT_NAME_WR, curName); if (!addEntries(&curCat, dta[i].d)) { return false; } e->appendChild(curCat); } return true; } bool Serializer::addEntries(QDomElement *e, const vector<PwMDataItem> &dta) { unsigned int numEntr = dta.size(), i; QString curId; QDomElement curEntr; for (i = 0; i < numEntr; ++i) { curId = ENTRY_PREFIX_WR; curId += tostr(i).c_str(); curEntr = domDoc->createElement(curId); if (!writeEntry(&curEntr, dta[i])) { return false; } e->appendChild(curEntr); } return true; } bool Serializer::writeEntry(QDomElement *e, const PwMDataItem &_dta) { #if WRITE_CDATA_SEC != 0 # define new_text(x) domDoc->createCDATASection(x) QDomCDATASection curText; #else # define new_text(x) domDoc->createTextNode(x) QDomText curText; #endif QDomText plainText; QDomElement tag; // begin -- This is for compatibility with the old serializer PwMDataItem dta = _dta; if (!dta.desc.size()) dta.desc = " "; if (!dta.name.size()) dta.name = " "; if (!dta.pw.size()) dta.pw = " "; if (!dta.comment.size()) dta.comment = " "; if (!dta.url.size()) dta.url = " "; if (!dta.launcher.size()) dta.launcher = " "; // end -- This is for compatibility with the old serializer tag = domDoc->createElement(ENTRY_DESC_WR); curText = new_text(escapeEntryData(dta.desc.c_str())); tag.appendChild(curText); e->appendChild(tag); tag = domDoc->createElement(ENTRY_NAME_WR); curText = new_text(escapeEntryData(dta.name.c_str())); tag.appendChild(curText); e->appendChild(tag); tag = domDoc->createElement(ENTRY_PW_WR); curText = new_text(escapeEntryData(dta.pw.c_str())); tag.appendChild(curText); e->appendChild(tag); tag = domDoc->createElement(ENTRY_COMMENT_WR); curText = new_text(escapeEntryData(dta.comment.c_str())); tag.appendChild(curText); e->appendChild(tag); tag = domDoc->createElement(ENTRY_URL_WR); curText = new_text(escapeEntryData(dta.url.c_str())); tag.appendChild(curText); e->appendChild(tag); tag = domDoc->createElement(ENTRY_LAUNCHER_WR); curText = new_text(escapeEntryData(dta.launcher.c_str())); tag.appendChild(curText); e->appendChild(tag); tag = domDoc->createElement(ENTRY_LVP_WR); plainText = domDoc->createTextNode(tostr(dta.listViewPos).c_str()); tag.appendChild(plainText); e->appendChild(tag); tag = domDoc->createElement(ENTRY_BIN_WR); if (dta.binary) plainText = domDoc->createTextNode("1"); else plainText = domDoc->createTextNode("0"); tag.appendChild(plainText); e->appendChild(tag); tag = domDoc->createElement(ENTRY_META_WR); if (!writeMeta(&tag, dta.meta)) return false; e->appendChild(tag); #undef new_text return true; } bool Serializer::writeMeta(QDomElement *e, const PwMMetaData &dta) { QDomText text; QDomElement tag; + //US BUG!!!: The transformation of an empty date into an ISO date is different on different systems/compilers. + //So do not transform an empty value at all. + if (dta.create.isValid()) + { tag = domDoc->createElement(META_CREATE_DATE); #ifndef PWM_EMBEDDED text = domDoc->createTextNode(dta.create.toString(Qt::ISODate)); #else text = domDoc->createTextNode(KGlobal::locale()->formatDateTime(dta.create, KLocale::ISODate)); #endif tag.appendChild(text); e->appendChild(tag); + } + //US BUG!!!: The transformation of an empty date into an ISO date is different on different systems/compilers. + //So do not transform an empty value at all. + if (dta.valid.isValid()) + { tag = domDoc->createElement(META_VALID_DATE); #ifndef PWM_EMBEDDED text = domDoc->createTextNode(dta.valid.toString(Qt::ISODate)); #else text = domDoc->createTextNode(KGlobal::locale()->formatDateTime(dta.valid, KLocale::ISODate)); #endif tag.appendChild(text); e->appendChild(tag); + } + //US BUG!!!: The transformation of an empty date into an ISO date is different on different systems/compilers. + //So do not transform an empty value at all. + if (dta.expire.isValid()) + { tag = domDoc->createElement(META_EXPIRE_DATE); #ifndef PWM_EMBEDDED text = domDoc->createTextNode(dta.expire.toString(Qt::ISODate)); #else text = domDoc->createTextNode(KGlobal::locale()->formatDateTime(dta.expire, KLocale::ISODate)); #endif tag.appendChild(text); e->appendChild(tag); + } + //US BUG!!!: The transformation of an empty date into an ISO date is different on different systems/compilers. + //So do not transform an empty value at all. + if (dta.update.isValid()) + { tag = domDoc->createElement(META_UPDATE_DATE); #ifndef PWM_EMBEDDED text = domDoc->createTextNode(dta.update.toString(Qt::ISODate)); #else text = domDoc->createTextNode(KGlobal::locale()->formatDateTime(dta.update, KLocale::ISODate)); #endif tag.appendChild(text); e->appendChild(tag); + } tag = domDoc->createElement(META_UPDATE_INT); text = domDoc->createTextNode(tostr(dta.updateInt).c_str()); tag.appendChild(text); e->appendChild(tag); tag = domDoc->createElement(META_UNIQUEID); text = domDoc->createTextNode(escapeEntryData(dta.uniqueid.c_str())); tag.appendChild(text); e->appendChild(tag); #undef new_text return true; } QString Serializer::escapeEntryData(QString dta) { #ifndef PWM_EMBEDDED dta.replace('\n', "$>--endl--<$"); dta.replace("]]>", "||>"); #else dta.replace(QRegExp("\n"), "$>--endl--<$"); dta.replace(QRegExp("]]>"), "||>"); #endif return dta; } QString Serializer::unescapeEntryData(QString dta) { #ifndef PWM_EMBEDDED dta.replace("$>--endl--<$", "\n"); dta.replace("||>", "]]>"); #else - dta.replace(QRegExp("$>--endl--<$"), "\n"); + dta.replace(QRegExp("\\$>--endl--<\\$"), "\n"); dta.replace(QRegExp("||>"), "]]>"); #endif return dta; } //US ENH: the following methods are getting used to write/read sync entries /** read the syncentries in the node "n" */ bool Serializer::readSyncData(const QDomNode &n, vector<PwMSyncItem> *dta) { QDomNodeList nl(n.childNodes()); QDomNode cur; QString devicename, val; unsigned int numSync = nl.count(), i; PwMSyncItem curSync; bool ok = true; if (!numSync) { //no sync entries is a possible result printDebug("Serializer::readSyncData(): empty"); return true; } for (i = 0; i < numSync; ++i) { cur = nl.item(i); if (cur.nodeName().left(1) == SYNC_TARGET_PREFIX) { devicename = cur.toElement().attribute(SYNC_TARGET_NAME); val = cur.toElement().text(); if ((val == "") || (devicename == QString::null)) { printDebug("Serializer::readSyncData(): empty synctarget name or syncdate"); continue; } curSync.syncName = devicename; #ifndef PWM_EMBEDDED curSync.lastSyncDate = QDateTime::fromString(val, Qt::ISODate); #else curSync.lastSyncDate = KGlobal::locale()->readDateTime(val, KLocale::ISODate, &ok); if (ok == false) qDebug("Serializer::readSyncData(): could not parse syncdate:%s",val.latin1()); #endif dta->push_back(curSync); } } return true; } bool Serializer::addSyncData(QDomElement *e, const vector<PwMSyncItem> &dta) { unsigned int numSync = dta.size(), i; QString curId, curDeviceName; - QDomElement curSync, curSyncDate; + QDomElement curSync; QDomText text; for (i = 0; i < numSync; ++i) { curId = SYNC_TARGET_PREFIX; curId += tostr(i).c_str(); curDeviceName = dta[i].syncName.c_str(); curSync = domDoc->createElement(curId); curSync.setAttribute(SYNC_TARGET_NAME, curDeviceName); #ifndef PWM_EMBEDDED text = domDoc->createTextNode(dta[i].lastSyncDate.toString(Qt::ISODate)); #else text = domDoc->createTextNode(KGlobal::locale()->formatDateTime(dta[i].lastSyncDate, KLocale::ISODate)); #endif - curSyncDate.appendChild(text); - curSync.appendChild(curSyncDate); + curSync.appendChild(text); e->appendChild(curSync); } return true; } |