-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 | 39 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwmview.cpp | 92 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwmview.h | 25 | ||||
-rw-r--r-- | pwmanager/pwmanager/serializer.cpp | 126 |
7 files changed, 287 insertions, 145 deletions
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(); + + //US curDoc()->sync sets the dirtyFlag in case the sync was successfull. + save(); } 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(); -} - -//called by the syncmanager to indicate that the work has to be saved. -void PwM::sync_save() -{ - PWM_ASSERT(curDoc()); - return curDoc()->sync_save(); -} - - - #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 @@ -106,887 +106,890 @@ void PwMDocList::edit(PwMDoc *doc, const string &newId) 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; } @@ -2423,989 +2426,1007 @@ PwMerror PwMDoc::importText_PwM(const QString *file) // 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 @@ -75,450 +75,530 @@ 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; - tag = domDoc->createElement(META_CREATE_DATE); + //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)); + text = domDoc->createTextNode(dta.create.toString(Qt::ISODate)); #else - text = domDoc->createTextNode(KGlobal::locale()->formatDateTime(dta.create, KLocale::ISODate)); + text = domDoc->createTextNode(KGlobal::locale()->formatDateTime(dta.create, KLocale::ISODate)); #endif - tag.appendChild(text); - e->appendChild(tag); + tag.appendChild(text); + e->appendChild(tag); + } - tag = domDoc->createElement(META_VALID_DATE); + //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)); + text = domDoc->createTextNode(dta.valid.toString(Qt::ISODate)); #else - text = domDoc->createTextNode(KGlobal::locale()->formatDateTime(dta.valid, KLocale::ISODate)); + text = domDoc->createTextNode(KGlobal::locale()->formatDateTime(dta.valid, KLocale::ISODate)); #endif - tag.appendChild(text); - e->appendChild(tag); + tag.appendChild(text); + e->appendChild(tag); + } - tag = domDoc->createElement(META_EXPIRE_DATE); + //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)); + text = domDoc->createTextNode(dta.expire.toString(Qt::ISODate)); #else - text = domDoc->createTextNode(KGlobal::locale()->formatDateTime(dta.expire, KLocale::ISODate)); + text = domDoc->createTextNode(KGlobal::locale()->formatDateTime(dta.expire, KLocale::ISODate)); #endif - tag.appendChild(text); - e->appendChild(tag); + tag.appendChild(text); + e->appendChild(tag); + } - tag = domDoc->createElement(META_UPDATE_DATE); + //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)); + text = domDoc->createTextNode(dta.update.toString(Qt::ISODate)); #else - text = domDoc->createTextNode(KGlobal::locale()->formatDateTime(dta.update, KLocale::ISODate)); + text = domDoc->createTextNode(KGlobal::locale()->formatDateTime(dta.update, KLocale::ISODate)); #endif - tag.appendChild(text); - e->appendChild(tag); + 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; } |