author | ulf69 <ulf69> | 2004-10-06 00:35:59 (UTC) |
---|---|---|
committer | ulf69 <ulf69> | 2004-10-06 00:35:59 (UTC) |
commit | 904cbf4f2a418d3cadc74a6168a4565ae6ebc3c5 (patch) (side-by-side diff) | |
tree | 22bb491b5886234a0ed21b882df73732ea99bf84 /pwmanager | |
parent | 07fa092b413b7cde1bd4fc797ce0b30adcb8668d (diff) | |
download | kdepimpi-904cbf4f2a418d3cadc74a6168a4565ae6ebc3c5.zip kdepimpi-904cbf4f2a418d3cadc74a6168a4565ae6ebc3c5.tar.gz kdepimpi-904cbf4f2a418d3cadc74a6168a4565ae6ebc3c5.tar.bz2 |
*** empty log message ***
-rw-r--r-- | pwmanager/pwmanager/pwmanagerE.pro | 2 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwmdoc.cpp | 568 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwmdoc.h | 70 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwmdocui.cpp | 2 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwmexception.h | 1 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwmview.cpp | 64 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwmview.h | 22 | ||||
-rw-r--r-- | pwmanager/pwmanager/serializer.cpp | 109 | ||||
-rw-r--r-- | pwmanager/pwmanager/serializer.h | 17 |
9 files changed, 746 insertions, 109 deletions
diff --git a/pwmanager/pwmanager/pwmanagerE.pro b/pwmanager/pwmanager/pwmanagerE.pro index 2558aca..95f5bf3 100644 --- a/pwmanager/pwmanager/pwmanagerE.pro +++ b/pwmanager/pwmanager/pwmanagerE.pro @@ -1,156 +1,156 @@ TEMPLATE = app CONFIG += qt warn_on TARGET = pwmpi OBJECTS_DIR = obj/$(PLATFORM) MOC_DIR = moc/$(PLATFORM) DESTDIR=$(QPEDIR)/bin -INCLUDEPATH += . ../../qtcompat ../../qtcompat/xml ../../libkdepim ../../microkde ../../microkde/kdecore ../../microkde/kdeui ../../microkde/kutils $(QPEDIR)/include +INCLUDEPATH += . ../../ ../../qtcompat ../../qtcompat/xml ../../libkdepim ../../microkde ../../microkde/kdecore ../../microkde/kdeui ../../microkde/kutils $(QPEDIR)/include DEFINES += PWM_EMBEDDED #enable this setting if you want debugoutput for pwmanager #DEFINES += CONFIG_DEBUG LIBS += -lmicrokde LIBS += -lmicroqtcompat LIBS += -lmicrokdepim LIBS += -L$(QPEDIR)/lib LIBS += -lqpe LIBS += -lbz2 LIBS += $(QTOPIALIB) #INTERFACES = \ #addentrywnd.ui \ #configwnd.ui \ #findwnd.ui \ #getmasterpwwnd.ui \ #pwgenwnd.ui \ #setmasterpwwnd.ui \ #subtbledit.ui #INTERFACES = \ #subtbledit.ui \ #HEADERS = \ #configuration_31compat.h \ #configuration.h \ #configwnd.h \ #configwndimpl.h \ #selftest.h #subtbledit.h \ #subtbleditimpl.h \ HEADERS = \ addentrywnd_emb.h \ addentrywndimpl.h \ base64.h \ binentrygen.h \ blowfish.h \ commentbox.h \ compiler.h \ compressbzip2.h \ compressgzip.h \ findwnd_emb.h \ findwndimpl.h \ genpasswd.h \ getkeycardwnd.h \ getmasterpwwnd_emb.h \ getmasterpwwndimpl.h \ globalstuff.h \ gpasmanfile.h \ htmlgen.h \ htmlparse.h \ ipc.h \ listobjselectwnd.h \ listviewpwm.h \ printtext.h \ pwgenwnd_emb.h \ pwgenwndimpl.h \ pwmdoc.h \ pwmdocui.h \ pwmexception.h \ pwm.h \ pwminit.h \ pwmprefs.h \ pwmprint.h \ pwmtray.h \ pwmview.h \ pwmviewstyle_0.h \ pwmviewstyle_1.h \ pwmviewstyle.h \ randomizer.h \ rc2.h \ rencatwnd.h \ serializer.h \ setmasterpwwnd_emb.h \ setmasterpwwndimpl.h \ sha1.h \ waitwnd.h \ kcmconfigs/kcmpwmconfig.h \ kcmconfigs/pwmconfigwidget.h \ #sources that need not be build #SOURCES = \ #advcommeditimpl.cpp \ #configuration.cpp \ #configwnd.cpp \ #configwndimpl.cpp \ #configuration_31compat.cpp \ #htmlparse.cpp \ #printtext.cpp \ #selftest.cpp \ #pwmprint.cpp \ #spinforsignal.cpp #subtbledit.cpp \ #subtbleditimpl.cpp \ SOURCES = \ addentrywnd_emb.cpp \ addentrywndimpl.cpp \ base64.cpp \ binentrygen.cpp \ blowfish.cpp \ commentbox.cpp \ compressbzip2.cpp \ compressgzip.cpp \ findwnd_emb.cpp \ findwndimpl.cpp \ genpasswd.cpp \ getkeycardwnd.cpp \ getmasterpwwnd_emb.cpp \ getmasterpwwndimpl.cpp \ globalstuff.cpp \ gpasmanfile.cpp \ htmlgen.cpp \ ipc.cpp \ listobjselectwnd.cpp \ listviewpwm.cpp \ main.cpp \ pwgenwnd_emb.cpp \ pwgenwndimpl.cpp \ pwm.cpp \ pwmdoc.cpp \ pwmdocui.cpp \ pwmexception.cpp \ pwminit.cpp \ pwmprefs.cpp \ pwmtray.cpp \ pwmview.cpp \ pwmviewstyle_0.cpp \ pwmviewstyle_1.cpp \ pwmviewstyle.cpp \ randomizer.cpp \ rc2.cpp \ rencatwnd.cpp \ serializer.cpp \ setmasterpwwnd_emb.cpp \ setmasterpwwndimpl.cpp \ sha1.cpp \ waitwnd.cpp \ kcmconfigs/kcmpwmconfig.cpp \ kcmconfigs/pwmconfigwidget.cpp \ diff --git a/pwmanager/pwmanager/pwmdoc.cpp b/pwmanager/pwmanager/pwmdoc.cpp index 82fc746..4e8a603 100644 --- a/pwmanager/pwmanager/pwmdoc.cpp +++ b/pwmanager/pwmanager/pwmdoc.cpp @@ -1,229 +1,233 @@ /*************************************************************************** * * * copyright (C) 2003, 2004 by Michael Buesch * * email: mbuesch@freenet.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License version 2 * * as published by the Free Software Foundation. * * * ***************************************************************************/ /*************************************************************************** * copyright (C) 2004 by Ulf Schenk * This file is originaly based on version 2.0 of pwmanager * and was modified to run on embedded devices that run microkde * * $Id$ **************************************************************************/ #include "pwmdoc.h" #include "pwmview.h" #include "blowfish.h" #include "sha1.h" #include "globalstuff.h" #include "gpasmanfile.h" #include "serializer.h" #include "compressgzip.h" #include "compressbzip2.h" #include "randomizer.h" #include "pwminit.h" #ifndef PWM_EMBEDDED //US #include "libgryptif.h" #else #include "pwmprefs.h" #include "kglobal.h" #endif +#include <kmessagebox.h> +#include <libkcal/syncdefines.h> + + #ifdef CONFIG_KWALLETIF # include "kwalletemu.h" #endif // CONFIG_KWALLETIF #include <qdatetime.h> #include <qsize.h> #include <qfileinfo.h> #include <qfile.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> //US#include <iostream> #include <algorithm> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <stdint.h> //TODO: reset to its normal value. #define META_CHECK_TIMER_INTERVAL 10/*300*/ /* sek */ using namespace std; void PwMDocList::add(PwMDoc *doc, const string &id) { #ifdef PWM_DEBUG // check for existance of object in debug mode only. vector<listItem>::iterator begin = docList.begin(), end = docList.end(), i = begin; while (i != end) { if (i->doc == doc) { BUG(); return; } ++i; } #endif listItem newItem; newItem.doc = doc; newItem.docId = id; docList.push_back(newItem); } void PwMDocList::edit(PwMDoc *doc, const string &newId) { vector<listItem>::iterator begin = docList.begin(), end = docList.end(), i = begin; while (i != end) { if (i->doc == doc) { i->docId = newId; return; } ++i; } } void PwMDocList::del(PwMDoc *doc) { vector<listItem>::iterator begin = docList.begin(), end = docList.end(), i = begin; while (i != end) { if (i->doc == doc) { docList.erase(i); return; } ++i; } } bool PwMDocList::find(const string &id, listItem *ret) { vector<listItem>::iterator begin = docList.begin(), end = docList.end(), i = begin; while (i != end) { if (i->docId == id) { if (ret) *ret = *i; return true; } ++i; } return false; } DocTimer::DocTimer(PwMDoc *_doc) : doc (_doc) , mpwLock (0) , autoLockLock (0) , metaCheckLock (0) { mpwTimer = new QTimer; autoLockTimer = new QTimer; metaCheckTimer = new QTimer; connect(mpwTimer, SIGNAL(timeout()), this, SLOT(mpwTimeout())); connect(autoLockTimer, SIGNAL(timeout()), this, SLOT(autoLockTimeout())); connect(metaCheckTimer, SIGNAL(timeout()), this, SLOT(metaCheckTimeout())); } DocTimer::~DocTimer() { delete mpwTimer; delete autoLockTimer; delete metaCheckTimer; } void DocTimer::start(TimerIDs timer) { switch (timer) { case id_mpwTimer: if (mpwTimer->isActive()) mpwTimer->stop(); doc->setDocStatFlag(DOC_STAT_UNLOCK_WITHOUT_PW); mpwTimer->start(conf()->confGlobPwTimeout() * 1000, true); break; case id_autoLockTimer: if (autoLockTimer->isActive()) autoLockTimer->stop(); if (conf()->confGlobLockTimeout() > 0) autoLockTimer->start(conf()->confGlobLockTimeout() * 1000, true); break; case id_metaCheckTimer: if (metaCheckTimer->isActive()) metaCheckTimer->stop(); metaCheckTimer->start(META_CHECK_TIMER_INTERVAL * 1000, true); break; } } void DocTimer::stop(TimerIDs timer) { switch (timer) { case id_mpwTimer: mpwTimer->stop(); break; case id_autoLockTimer: autoLockTimer->stop(); break; case id_metaCheckTimer: metaCheckTimer->stop(); break; } } void DocTimer::getLock(TimerIDs timer) { switch (timer) { case id_mpwTimer: ++mpwLock; break; case id_autoLockTimer: ++autoLockLock; break; case id_metaCheckTimer: ++metaCheckLock; break; } } void DocTimer::putLock(TimerIDs timer) { switch (timer) { case id_mpwTimer: if (mpwLock) --mpwLock; break; case id_autoLockTimer: if (autoLockLock) --autoLockLock; break; case id_metaCheckTimer: if (metaCheckLock) --metaCheckLock; break; } } void DocTimer::mpwTimeout() { if (mpwLock) { mpwTimer->start(1000, true); @@ -818,2061 +822,2447 @@ PwMerror PwMDoc::checkHeader(char *cryptAlgo, QString *pw, char *compress, break; } #endif 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; } #ifndef PWM_EMBEDDED 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; } #endif 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]; #ifndef PWM_EMBEDDED Q_LONG bytesRead, bytesWritten; #else long bytesRead, bytesWritten; #endif while (!srcFd.atEnd()) { #ifndef PWM_EMBEDDED bytesRead = srcFd.readBlock(tmpBuf, static_cast<Q_ULONG>(tmpBuf_size)); #else bytesRead = srcFd.readBlock(tmpBuf, (unsigned long)(tmpBuf_size)); #endif if (bytesRead == -1) { srcFd.close(); dstFd.close(); return false; } #ifndef PWM_EMBEDDED bytesWritten = dstFd.writeBlock(tmpBuf, static_cast<Q_ULONG>(bytesRead)); #else bytesWritten = dstFd.writeBlock(tmpBuf, (unsigned long)(bytesRead)); #endif 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; } - dta[cat].d.push_back(*d); + dti.dta[cat].d.push_back(*d); delAllEmptyCat(true); if (!dontFlagDirty) flagDirty(); return e_success; } PwMerror PwMDoc::addCategory(const QString &category, unsigned int *categoryIndex, bool checkIfExist) { if (isDeepLocked()) { PwMerror ret; ret = deepLock(false); if (ret != e_success) return e_lock; } if (checkIfExist) { if (findCategory(category, categoryIndex)) return e_categoryExists; } PwMCategoryItem item; item.name = category.latin1(); - dta.push_back(item); + dti.dta.push_back(item); if (categoryIndex) - *categoryIndex = dta.size() - 1; + *categoryIndex = dti.dta.size() - 1; return e_success; } bool PwMDoc::delEntry(const QString &category, unsigned int index, bool dontFlagDirty) { unsigned int cat = 0; if (!findCategory(category, &cat)) { BUG(); return false; } return delEntry(cat, index, dontFlagDirty); } bool PwMDoc::delEntry(unsigned int category, unsigned int index, bool dontFlagDirty) { if (isDeepLocked()) return false; - if (index > dta[category].d.size() - 1) + if (index > dti.dta[category].d.size() - 1) return false; getDataChangedLock(); if (!lockAt(category, index, false)) { putDataChangedLock(); return false; } putDataChangedLock(); - int lvPos = dta[category].d[index].listViewPos; + int lvPos = dti.dta[category].d[index].listViewPos; // delete entry - dta[category].d.erase(dta[category].d.begin() + index); + dti.dta[category].d.erase(dti.dta[category].d.begin() + index); unsigned int i, entries = numEntries(category); if (!entries) { // no more entries in this category, so // we can delete it, too. BUG_ON(!delCategory(category)); // delCategory() flags it dirty, so we need not to do so. return true; } for (i = 0; i < entries; ++i) { // decrement all listViewPositions that are greater than the deleted. - if (dta[category].d[i].listViewPos > lvPos) - --dta[category].d[i].listViewPos; + if (dti.dta[category].d[i].listViewPos > lvPos) + --dti.dta[category].d[i].listViewPos; } if (!dontFlagDirty) flagDirty(); return true; } bool PwMDoc::editEntry(const QString &oldCategory, const QString &newCategory, unsigned int index, PwMDataItem *d, bool updateMeta) { PWM_ASSERT(d); unsigned int oldCat = 0; if (!findCategory(oldCategory, &oldCat)) { BUG(); return false; } return editEntry(oldCat, newCategory, index, d, updateMeta); } bool PwMDoc::editEntry(unsigned int oldCategory, const QString &newCategory, unsigned int index, PwMDataItem *d, bool updateMeta) { if (isDeepLocked()) return false; if (updateMeta) { d->meta.update = QDateTime::currentDateTime(); if (d->meta.create.isNull()) { d->meta.create = d->meta.update; } } - if (dta[oldCategory].name != newCategory.latin1()) { + if (dti.dta[oldCategory].name != newCategory.latin1()) { // the user changed the category. PwMerror ret; d->rev = 0; ret = addEntry(newCategory, d, true, false); if (ret != e_success) return false; if (!delEntry(oldCategory, index, true)) return false; } else { - d->rev = dta[oldCategory].d[index].rev + 1; // increment revision counter. - dta[oldCategory].d[index] = *d; + d->rev = dti.dta[oldCategory].d[index].rev + 1; // increment revision counter. + dti.dta[oldCategory].d[index] = *d; } flagDirty(); return true; } unsigned int PwMDoc::numEntries(const QString &category) { unsigned int cat = 0; if (!findCategory(category, &cat)) { BUG(); return 0; } return numEntries(cat); } bool PwMDoc::serializeDta(string *d) { PWM_ASSERT(d); Serializer ser; - if (!ser.serialize(dta)) + if (!ser.serialize(dti)) return false; d->assign(ser.getXml()); if (!d->size()) return false; return true; } bool PwMDoc::deSerializeDta(const string *d, bool entriesLocked) { PWM_ASSERT(d); #ifndef PWM_EMBEDDED try { Serializer ser(d->c_str()); ser.setDefaultLockStat(entriesLocked); - if (!ser.deSerialize(&dta)) + if (!ser.deSerialize(&dti)) return false; } catch (PwMException) { return false; } #else Serializer ser(d->c_str()); ser.setDefaultLockStat(entriesLocked); - if (!ser.deSerialize(&dta)) + if (!ser.deSerialize(&dti)) return false; #endif emitDataChanged(this); return true; } bool PwMDoc::getEntry(const QString &category, unsigned int index, PwMDataItem * d, bool unlockIfLocked) { PWM_ASSERT(d); unsigned int cat = 0; if (!findCategory(category, &cat)) { BUG(); return false; } return getEntry(cat, index, d, unlockIfLocked); } bool PwMDoc::getEntry(unsigned int category, unsigned int index, PwMDataItem *d, bool unlockIfLocked) { - if (index > dta[category].d.size() - 1) + if (index > dti.dta[category].d.size() - 1) return false; bool locked = isLocked(category, index); if (locked) { /* this entry is locked. We don't return a password, * until it's unlocked by the user by inserting * chipcard or entering the mpw */ if (unlockIfLocked) { if (!lockAt(category, index, false)) { return false; } locked = false; } } - *d = dta[category].d[index]; + *d = dti.dta[category].d[index]; if (locked) d->pw = LOCKED_STRING.latin1(); return true; } PwMerror PwMDoc::getCommentByLvp(const QString &category, int listViewPos, string *foundComment) { PWM_ASSERT(foundComment); unsigned int cat = 0; if (!findCategory(category, &cat)) return e_invalidArg; unsigned int i, entries = numEntries(cat); for (i = 0; i < entries; ++i) { - if (dta[cat].d[i].listViewPos == listViewPos) { - *foundComment = dta[cat].d[i].comment; - if (dta[cat].d[i].binary) + if (dti.dta[cat].d[i].listViewPos == listViewPos) { + *foundComment = dti.dta[cat].d[i].comment; + if (dti.dta[cat].d[i].binary) return e_binEntry; return e_normalEntry; } } BUG(); return e_generic; } bool PwMDoc::compressDta(string *d, char algo) { PWM_ASSERT(d); switch (algo) { case PWM_COMPRESS_GZIP: { CompressGzip comp; return comp.compress(d); } case PWM_COMPRESS_BZIP2: { CompressBzip2 comp; return comp.compress(d); } case PWM_COMPRESS_NONE: { return true; } default: { BUG(); } } return false; } bool PwMDoc::decompressDta(string *d, char algo) { PWM_ASSERT(d); switch (algo) { case PWM_COMPRESS_GZIP: { CompressGzip comp; return comp.decompress(d); } case PWM_COMPRESS_BZIP2: { CompressBzip2 comp; return comp.decompress(d); } case PWM_COMPRESS_NONE: { return true; } } return false; } PwMerror PwMDoc::encrypt(string *d, const QString *pw, QFile *f, char algo) { PWM_ASSERT(d); PWM_ASSERT(pw); PWM_ASSERT(f); size_t encSize; byte *encrypted = 0; switch (algo) { case PWM_CRYPT_BLOWFISH: { Blowfish::padNull(d); encSize = d->length(); encrypted = new byte[encSize]; Blowfish bf; if (bf.bf_setkey((byte *) pw->latin1(), pw->length())) { delete [] encrypted; return e_weakPw; } bf.bf_encrypt((byte *) encrypted, (byte *) d->c_str(), encSize); break; } #ifndef PWM_EMBEDDED case PWM_CRYPT_AES128: /*... fall through */ case PWM_CRYPT_AES192: case PWM_CRYPT_AES256: case PWM_CRYPT_3DES: case PWM_CRYPT_TWOFISH: case PWM_CRYPT_TWOFISH128: { if (!LibGCryptIf::available()) return e_cryptNotImpl; LibGCryptIf gc; PwMerror err; unsigned char *plain = new unsigned char[d->length() + 1024]; memcpy(plain, d->c_str(), d->length()); err = gc.encrypt(&encrypted, &encSize, plain, d->length(), reinterpret_cast<const unsigned char *>(pw->latin1()), pw->length(), algo); delete [] plain; if (err != e_success) return e_cryptNotImpl; break; } #endif default: { delete_ifnot_null_array(encrypted); return e_cryptNotImpl; } } // write encrypted data to file #ifndef PWM_EMBEDDED if (f->writeBlock(reinterpret_cast<const char *>(encrypted), static_cast<Q_ULONG>(encSize)) != static_cast<Q_LONG>(encSize)) { delete_ifnot_null_array(encrypted); return e_writeFile; } #else if (f->writeBlock((const char *)(encrypted), (unsigned long)(encSize)) != (long)(encSize)) { delete_ifnot_null_array(encrypted); return e_writeFile; } #endif delete_ifnot_null_array(encrypted); return e_success; } PwMerror PwMDoc::decrypt(string *d, unsigned int pos, const QString *pw, char algo, QFile *f) { PWM_ASSERT(d); PWM_ASSERT(pw); PWM_ASSERT(f); unsigned int cryptLen = f->size() - pos; byte *encrypted = new byte[cryptLen]; byte *decrypted = new byte[cryptLen]; f->at(pos); #ifndef PWM_EMBEDDED if (f->readBlock(reinterpret_cast<char *>(encrypted), static_cast<Q_ULONG>(cryptLen)) != static_cast<Q_LONG>(cryptLen)) { delete [] encrypted; delete [] decrypted; return e_readFile; } #else if (f->readBlock((char *)(encrypted), (unsigned long)(cryptLen)) != (long)(cryptLen)) { delete [] encrypted; delete [] decrypted; return e_readFile; } #endif switch (algo) { case PWM_CRYPT_BLOWFISH: { Blowfish bf; bf.bf_setkey((byte *) pw->latin1(), pw->length()); bf.bf_decrypt(decrypted, encrypted, cryptLen); break; } #ifndef PWM_EMBEDDED case PWM_CRYPT_AES128: /*... fall through */ case PWM_CRYPT_AES192: case PWM_CRYPT_AES256: case PWM_CRYPT_3DES: case PWM_CRYPT_TWOFISH: case PWM_CRYPT_TWOFISH128: { if (!LibGCryptIf::available()) return e_cryptNotImpl; LibGCryptIf gc; PwMerror err; err = gc.decrypt(&decrypted, &cryptLen, encrypted, cryptLen, reinterpret_cast<const unsigned char *>(pw->latin1()), pw->length(), algo); if (err != e_success) { delete [] encrypted; delete [] decrypted; return e_cryptNotImpl; } break; } #endif default: { delete [] encrypted; delete [] decrypted; return e_cryptNotImpl; } } delete [] encrypted; #ifndef PWM_EMBEDDED d->assign(reinterpret_cast<const char *>(decrypted), static_cast<string::size_type>(cryptLen)); #else d->assign((const char *)(decrypted), (string::size_type)(cryptLen)); #endif delete [] decrypted; if (algo == PWM_CRYPT_BLOWFISH) { if (!Blowfish::unpadNull(d)) { BUG(); return e_readFile; } } return e_success; } PwMerror PwMDoc::checkDataHash(char dataHashType, const string *dataHash, const string *dataStream) { PWM_ASSERT(dataHash); PWM_ASSERT(dataStream); switch(dataHashType) { case PWM_HASH_SHA1: { Sha1 hash; hash.sha1_write((byte*)dataStream->c_str(), dataStream->length()); string ret = hash.sha1_read(); if (ret != *dataHash) return e_fileCorrupt; break; } #ifndef PWM_EMBEDDED 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 *>(dataStream->c_str()), dataStream->length(), dataHashType); if (err != e_success) return e_hashNotImpl; string calcHash(reinterpret_cast<const char *>(buf), static_cast<string::size_type>(hashLen)); delete [] buf; if (calcHash != *dataHash) return e_fileCorrupt; break; } #endif default: return e_hashNotImpl; } return e_success; } bool PwMDoc::lockAt(unsigned int category, unsigned int index, bool lock) { if (index >= numEntries(category)) { BUG(); return false; } - if (lock == dta[category].d[index].lockStat) + if (lock == dti.dta[category].d[index].lockStat) return true; if (!lock && currentPw != "") { // "unlocking" and "password is already set" if (!getDocStatFlag(DOC_STAT_UNLOCK_WITHOUT_PW)) { // unlocking without pw not allowed QString pw; pw = requestMpw(getDocStatFlag(DOC_STAT_USE_CHIPCARD)); if (pw != "") { if (pw != currentPw) { wrongMpwMsgBox(getDocStatFlag(DOC_STAT_USE_CHIPCARD)); return false; } else { timer()->start(DocTimer::id_mpwTimer); } } else { return false; } } else { timer()->start(DocTimer::id_mpwTimer); } } - dta[category].d[index].lockStat = lock; - dta[category].d[index].rev++; // increment revision counter. + dti.dta[category].d[index].lockStat = lock; + dti.dta[category].d[index].rev++; // increment revision counter. emitDataChanged(this); if (!lock) timer()->start(DocTimer::id_autoLockTimer); return true; } bool PwMDoc::lockAt(const QString &category,unsigned int index, bool lock) { unsigned int cat = 0; if (!findCategory(category, &cat)) { BUG(); return false; } return lockAt(cat, index, lock); } bool PwMDoc::lockAll(bool lock) { if (!lock && isDeepLocked()) { PwMerror ret; ret = deepLock(false); if (ret != e_success) return false; return true; } if (isDocEmpty()) { return true; } if (!lock && currentPw != "") { // unlocking and password is already set if (!getDocStatFlag(DOC_STAT_UNLOCK_WITHOUT_PW)) { // unlocking without pw not allowed QString pw; pw = requestMpw(getDocStatFlag(DOC_STAT_USE_CHIPCARD)); if (pw != "") { if (pw != currentPw) { wrongMpwMsgBox(getDocStatFlag(DOC_STAT_USE_CHIPCARD)); return false; } else { timer()->start(DocTimer::id_mpwTimer); } } else { return false; } } else { timer()->start(DocTimer::id_mpwTimer); } } - vector<PwMCategoryItem>::iterator catBegin = dta.begin(), - catEnd = dta.end(), + vector<PwMCategoryItem>::iterator catBegin = dti.dta.begin(), + catEnd = dti.dta.end(), catI = catBegin; vector<PwMDataItem>::iterator entrBegin, entrEnd, entrI; while (catI != catEnd) { entrBegin = catI->d.begin(); entrEnd = catI->d.end(); entrI = entrBegin; while (entrI != entrEnd) { entrI->lockStat = lock; entrI->rev++; // increment revision counter. ++entrI; } ++catI; } emitDataChanged(this); if (lock) timer()->stop(DocTimer::id_autoLockTimer); else timer()->start(DocTimer::id_autoLockTimer); return true; } bool PwMDoc::isLocked(const QString &category, unsigned int index) { unsigned int cat = 0; if (!findCategory(category, &cat)) { BUG(); return false; } return isLocked(cat, index); } bool PwMDoc::unlockAll_tempoary(bool revert) { static vector< vector<bool> > *oldLockStates = 0; static bool wasDeepLocked; if (revert) { // revert the unlocking if (oldLockStates) { /* we actually _have_ unlocked something, because * we have allocated space for the oldLockStates. * So, go on and revert them! */ if (wasDeepLocked) { PwMerror ret = deepLock(true); if (ret == e_success) { /* deep-lock succeed. We are save. * (but if it failed, just go on * lock them normally) */ delete_and_null(oldLockStates); timer()->start(DocTimer::id_autoLockTimer); printDebug("tempoary unlocking of dta " "reverted by deep-locking."); return true; } printDebug("deep-lock failed while reverting! " "Falling back to normal-lock."); } if (unlikely(!wasDeepLocked && numCategories() != oldLockStates->size())) { /* DOH! We have modified "dta" while * it was unlocked tempoary. DON'T DO THIS! */ BUG(); delete_and_null(oldLockStates); timer()->start(DocTimer::id_autoLockTimer); return false; } - vector<PwMCategoryItem>::iterator catBegin = dta.begin(), - catEnd = dta.end(), + vector<PwMCategoryItem>::iterator catBegin = dti.dta.begin(), + catEnd = dti.dta.end(), catI = catBegin; vector<PwMDataItem>::iterator entrBegin, entrEnd, entrI; vector< vector<bool> >::iterator oldCatStatI = oldLockStates->begin(); vector<bool>::iterator oldEntrStatBegin, oldEntrStatEnd, oldEntrStatI; while (catI != catEnd) { entrBegin = catI->d.begin(); entrEnd = catI->d.end(); entrI = entrBegin; if (likely(!wasDeepLocked)) { oldEntrStatBegin = oldCatStatI->begin(); oldEntrStatEnd = oldCatStatI->end(); oldEntrStatI = oldEntrStatBegin; if (unlikely(catI->d.size() != oldCatStatI->size())) { /* DOH! We have modified "dta" while * it was unlocked tempoary. DON'T DO THIS! */ BUG(); delete_and_null(oldLockStates); timer()->start(DocTimer::id_autoLockTimer); return false; } } while (entrI != entrEnd) { if (wasDeepLocked) { /* this is an error-fallback if * deeplock didn't succeed */ entrI->lockStat = true; } else { entrI->lockStat = *oldEntrStatI; } ++entrI; if (likely(!wasDeepLocked)) ++oldEntrStatI; } ++catI; if (likely(!wasDeepLocked)) ++oldCatStatI; } delete_and_null(oldLockStates); if (unlikely(wasDeepLocked)) { /* error fallback... */ unsetDocStatFlag(DOC_STAT_DEEPLOCKED); emitDataChanged(this); printDebug("WARNING: unlockAll_tempoary(true) " "deeplock fallback!"); } printDebug("tempoary unlocking of dta reverted."); } else { printDebug("unlockAll_tempoary(true): nothing to do."); } timer()->start(DocTimer::id_autoLockTimer); } else { // unlock all data tempoary if (unlikely(oldLockStates != 0)) { /* DOH! We have already unlocked the data tempoarly. * No need to do it twice. ;) */ BUG(); return false; } wasDeepLocked = false; bool mustUnlock = false; if (isDeepLocked()) { PwMerror ret; while (1) { ret = deepLock(false); if (ret == e_success) { break; } else if (ret == e_wrongPw) { wrongMpwMsgBox(getDocStatFlag(DOC_STAT_USE_CHIPCARD)); } else { printDebug("deep-unlocking failed while " "tempoary unlocking!"); return false; } } wasDeepLocked = true; mustUnlock = true; } else { // first check if it's needed to unlock some entries - vector<PwMCategoryItem>::iterator catBegin = dta.begin(), - catEnd = dta.end(), + vector<PwMCategoryItem>::iterator catBegin = dti.dta.begin(), + catEnd = dti.dta.end(), catI = catBegin; vector<PwMDataItem>::iterator entrBegin, entrEnd, entrI; while (catI != catEnd) { entrBegin = catI->d.begin(); entrEnd = catI->d.end(); entrI = entrBegin; while (entrI != entrEnd) { if (entrI->lockStat == true) { mustUnlock = true; break; } ++entrI; } if (mustUnlock) break; ++catI; } } if (!mustUnlock) { // nothing to do. timer()->stop(DocTimer::id_autoLockTimer); printDebug("unlockAll_tempoary(): nothing to do."); return true; } else if (!wasDeepLocked) { if (!getDocStatFlag(DOC_STAT_UNLOCK_WITHOUT_PW) && currentPw != "") { /* we can't unlock without mpw, so * we need to ask for it. */ QString pw; while (1) { pw = requestMpw(getDocStatFlag(DOC_STAT_USE_CHIPCARD)); if (pw == "") { return false; } else if (pw == currentPw) { break; } wrongMpwMsgBox(getDocStatFlag(DOC_STAT_USE_CHIPCARD)); } } } timer()->stop(DocTimer::id_autoLockTimer); oldLockStates = new vector< vector<bool> >; vector<bool> tmp_vec; - vector<PwMCategoryItem>::iterator catBegin = dta.begin(), - catEnd = dta.end(), + vector<PwMCategoryItem>::iterator catBegin = dti.dta.begin(), + catEnd = dti.dta.end(), catI = catBegin; vector<PwMDataItem>::iterator entrBegin, entrEnd, entrI; while (catI != catEnd) { entrBegin = catI->d.begin(); entrEnd = catI->d.end(); entrI = entrBegin; while (entrI != entrEnd) { if (!wasDeepLocked) { tmp_vec.push_back(entrI->lockStat); } entrI->lockStat = false; ++entrI; } if (!wasDeepLocked) { oldLockStates->push_back(tmp_vec); tmp_vec.clear(); } ++catI; } printDebug("tempoary unlocked dta."); } return true; } PwMerror PwMDoc::deepLock(bool lock, bool saveToFile) { PwMerror ret; if (lock) { if (isDeepLocked()) return e_lock; if (saveToFile) { if (isDocEmpty()) return e_docIsEmpty; ret = saveDoc(conf()->confGlobCompression()); if (ret == e_filename) { /* the doc wasn't saved to a file * by the user, yet. */ cantDeeplock_notSavedMsgBox(); return e_docNotSaved; } else if (ret != e_success) { return e_lock; } } timer()->stop(DocTimer::id_autoLockTimer); clearDoc(); PwMDataItem d; d.desc = IS_DEEPLOCKED_SHORTMSG.latin1(); d.comment = IS_DEEPLOCKED_MSG.latin1(); d.listViewPos = 0; addEntry(DEFAULT_CATEGORY, &d, true); lockAt(DEFAULT_CATEGORY, 0, true); unsetDocStatFlag(DOC_STAT_DISK_DIRTY); setDocStatFlag(DOC_STAT_DEEPLOCKED); } else { if (!isDeepLocked()) return e_lock; ret = openDoc(&filename, (conf()->confGlobUnlockOnOpen()) ? 0 : 1); if (ret == e_wrongPw) { return e_wrongPw; } else if (ret != e_success) { printDebug(string("PwMDoc::deepLock(false): ERR! openDoc() == ") + tostr(static_cast<int>(ret))); return e_lock; } unsetDocStatFlag(DOC_STAT_DEEPLOCKED); timer()->start(DocTimer::id_autoLockTimer); } emitDataChanged(this); return e_success; } void PwMDoc::_deepUnlock() { deepLock(false); } void PwMDoc::clearDoc() { - dta.clear(); + dti.clear(); PwMCategoryItem d; d.name = DEFAULT_CATEGORY.latin1(); - dta.push_back(d); + dti.dta.push_back(d); currentPw = ""; unsetDocStatFlag(DOC_STAT_UNLOCK_WITHOUT_PW); } void PwMDoc::changeCurrentPw() { if (currentPw == "") return; // doc hasn't been saved. No mpw available. bool useChipcard = getDocStatFlag(DOC_STAT_USE_CHIPCARD); QString pw = requestMpwChange(¤tPw, &useChipcard); if (pw == "") return; if (useChipcard) setDocStatFlag(DOC_STAT_USE_CHIPCARD); else unsetDocStatFlag(DOC_STAT_USE_CHIPCARD); setCurrentPw(pw); } void PwMDoc::setListViewPos(const QString &category, unsigned int index, int pos) { unsigned int cat = 0; if (!findCategory(category, &cat)) { BUG(); return; } setListViewPos(cat, index, pos); } void PwMDoc::setListViewPos(unsigned int category, unsigned int index, int pos) { - dta[category].d[index].listViewPos = pos; + dti.dta[category].d[index].listViewPos = pos; /* FIXME workaround: don't flag dirty, because this function sometimes * get's called when it shouldn't. It's because PwMView assumes * the user resorted the UI on behalf of signal layoutChanged(). * This is somewhat broken and incorrect, but I've no other * solution for now. */ // setDocStatFlag(DOC_STAT_DISK_DIRTY); } int PwMDoc::getListViewPos(const QString &category, unsigned int index) { unsigned int cat = 0; if (!findCategory(category, &cat)) { BUG(); return -1; } - return dta[cat].d[index].listViewPos; + return dti.dta[cat].d[index].listViewPos; } void PwMDoc::findEntry(unsigned int category, PwMDataItem find, unsigned int searchIn, vector<unsigned int> *foundPositions, bool breakAfterFound, bool caseSensitive, bool exactWordMatch, bool sortByLvp) { PWM_ASSERT(foundPositions); PWM_ASSERT(searchIn); foundPositions->clear(); unsigned int i, entries = numEntries(category); for (i = 0; i < entries; ++i) { if (searchIn & SEARCH_IN_DESC) { - if (!compareString(find.desc, dta[category].d[i].desc, + if (!compareString(find.desc, dti.dta[category].d[i].desc, caseSensitive, exactWordMatch)) { continue; } } if (searchIn & SEARCH_IN_NAME) { - if (!compareString(find.name, dta[category].d[i].name, + if (!compareString(find.name, dti.dta[category].d[i].name, caseSensitive, exactWordMatch)) { continue; } } if (searchIn & SEARCH_IN_PW) { bool wasLocked = isLocked(category, i); getDataChangedLock(); lockAt(category, i, false); - if (!compareString(find.pw, dta[category].d[i].pw, + if (!compareString(find.pw, dti.dta[category].d[i].pw, caseSensitive, exactWordMatch)) { lockAt(category, i, wasLocked); putDataChangedLock(); continue; } lockAt(category, i, wasLocked); putDataChangedLock(); } if (searchIn & SEARCH_IN_COMMENT) { - if (!compareString(find.comment, dta[category].d[i].comment, + if (!compareString(find.comment, dti.dta[category].d[i].comment, caseSensitive, exactWordMatch)) { continue; } } if (searchIn & SEARCH_IN_URL) { - if (!compareString(find.url, dta[category].d[i].url, + if (!compareString(find.url, dti.dta[category].d[i].url, caseSensitive, exactWordMatch)) { continue; } } if (searchIn & SEARCH_IN_LAUNCHER) { - if (!compareString(find.launcher, dta[category].d[i].launcher, + if (!compareString(find.launcher, dti.dta[category].d[i].launcher, caseSensitive, exactWordMatch)) { continue; } } // all selected "searchIn" matched. foundPositions->push_back(i); if (breakAfterFound) break; } if (sortByLvp && foundPositions->size() > 1) { vector< pair<unsigned int /* foundPosition (real doc pos) */, unsigned int /* lvp-pos */> > tmp_vec; unsigned int i, items = foundPositions->size(); pair<unsigned int, unsigned int> tmp_pair; for (i = 0; i < items; ++i) { tmp_pair.first = (*foundPositions)[i]; - tmp_pair.second = dta[category].d[(*foundPositions)[i]].listViewPos; + tmp_pair.second = dti.dta[category].d[(*foundPositions)[i]].listViewPos; tmp_vec.push_back(tmp_pair); } sort(tmp_vec.begin(), tmp_vec.end(), dta_lvp_greater()); foundPositions->clear(); for (i = 0; i < items; ++i) { foundPositions->push_back(tmp_vec[i].first); } } } void PwMDoc::findEntry(const QString &category, PwMDataItem find, unsigned int searchIn, vector<unsigned int> *foundPositions, bool breakAfterFound, bool caseSensitive, bool exactWordMatch, bool sortByLvp) { PWM_ASSERT(foundPositions); unsigned int cat = 0; if (!findCategory(category, &cat)) { foundPositions->clear(); return; } findEntry(cat, find, searchIn, foundPositions, breakAfterFound, caseSensitive, exactWordMatch, sortByLvp); } bool PwMDoc::compareString(const string &s1, const string &s2, bool caseSensitive, bool exactWordMatch) { QString _s1(s1.c_str()); QString _s2(s2.c_str()); if (!caseSensitive) { _s1 = _s1.lower(); _s2 = _s2.lower(); } if (exactWordMatch ? (_s1 == _s2) : (_s2.find(_s1) != -1)) return true; return false; } bool PwMDoc::findCategory(const QString &name, unsigned int *index) { - vector<PwMCategoryItem>::iterator i = dta.begin(), - end = dta.end(); + vector<PwMCategoryItem>::iterator i = dti.dta.begin(), + end = dti.dta.end(); while (i != end) { if ((*i).name == name.latin1()) { if (index) { - *index = i - dta.begin(); + *index = i - dti.dta.begin(); } return true; } ++i; } return false; } bool PwMDoc::renameCategory(const QString &category, const QString &newName) { unsigned int cat = 0; if (!findCategory(category, &cat)) return false; return renameCategory(cat, newName); } bool PwMDoc::renameCategory(unsigned int category, const QString &newName, bool dontFlagDirty) { if (category > numCategories() - 1) return false; - dta[category].name = newName.latin1(); + dti.dta[category].name = newName.latin1(); if (!dontFlagDirty) flagDirty(); return true; } bool PwMDoc::delCategory(const QString &category) { unsigned int cat = 0; if (!findCategory(category, &cat)) return false; return delCategory(cat); } bool PwMDoc::delCategory(unsigned int category, bool dontFlagDirty) { if (category > numCategories() - 1) return false; // We don't delete it, if it is the last existing // category! Instead we rename it to "Default". if (numCategories() > 1) { - dta.erase(dta.begin() + category); + dti.dta.erase(dti.dta.begin() + category); } else { renameCategory(category, DEFAULT_CATEGORY, dontFlagDirty); return true; } if (!dontFlagDirty) flagDirty(); return true; } void PwMDoc::delAllEmptyCat(bool dontFlagDirty) { - vector<PwMCategoryItem>::iterator begin = dta.begin(), - end = dta.end(), + vector<PwMCategoryItem>::iterator begin = dti.dta.begin(), + end = dti.dta.end(), i = begin; while (i != end) { if (i->d.empty()) { delCategory(begin - i, dontFlagDirty); } ++i; } } void PwMDoc::getCategoryList(vector<string> *list) { PWM_ASSERT(list); list->clear(); - vector<PwMCategoryItem>::iterator i = dta.begin(), - end = dta.end(); + vector<PwMCategoryItem>::iterator i = dti.dta.begin(), + end = dti.dta.end(); while (i != end) { list->push_back(i->name); ++i; } } void PwMDoc::getCategoryList(QStringList *list) { PWM_ASSERT(list); list->clear(); - vector<PwMCategoryItem>::iterator i = dta.begin(), - end = dta.end(); + vector<PwMCategoryItem>::iterator i = dti.dta.begin(), + end = dti.dta.end(); while (i != end) { #ifndef PWM_EMBEDDED list->push_back(i->name.c_str()); #else list->append(i->name.c_str()); #endif ++i; } } void PwMDoc::getEntryList(const QString &category, QStringList *list) { PWM_ASSERT(list); unsigned int cat = 0; if (!findCategory(category, &cat)) { list->clear(); return; } getEntryList(cat, list); } void PwMDoc::getEntryList(const QString &category, vector<string> *list) { PWM_ASSERT(list); unsigned int cat = 0; if (!findCategory(category, &cat)) { list->clear(); return; } getEntryList(cat, list); } void PwMDoc::getEntryList(unsigned int category, vector<string> *list) { PWM_ASSERT(list); list->clear(); - vector<PwMDataItem>::iterator begin = dta[category].d.begin(), - end = dta[category].d.end(), + vector<PwMDataItem>::iterator begin = dti.dta[category].d.begin(), + end = dti.dta[category].d.end(), i = begin; while (i != end) { list->push_back(i->desc); ++i; } } void PwMDoc::getEntryList(unsigned int category, QStringList *list) { PWM_ASSERT(list); list->clear(); - vector<PwMDataItem>::iterator begin = dta[category].d.begin(), - end = dta[category].d.end(), + vector<PwMDataItem>::iterator begin = dti.dta[category].d.begin(), + end = dti.dta[category].d.end(), i = begin; while (i != end) { #ifndef PWM_EMBEDDED list->push_back(i->desc.c_str()); #else list->append(i->desc.c_str()); #endif ++i; } } bool PwMDoc::execLauncher(const QString &category, unsigned int entryIndex) { unsigned int cat = 0; if (!findCategory(category, &cat)) return false; return execLauncher(cat, entryIndex); } bool PwMDoc::execLauncher(unsigned int category, unsigned int entryIndex) { if (geteuid() == 0) { rootAlertMsgBox(); return false; } - QString command(dta[category].d[entryIndex].launcher.c_str()); + QString command(dti.dta[category].d[entryIndex].launcher.c_str()); bool wasLocked = isLocked(category, entryIndex); if (command.find("$p") != -1) { /* the user requested the password to be included * into the command. We have to ask for the password, * if it's locked. We do that by unlocking the entry */ if (!lockAt(category, entryIndex, false)) return false; } #ifndef PWM_EMBEDDED - command.replace("$d", dta[category].d[entryIndex].desc.c_str()); - command.replace("$n", dta[category].d[entryIndex].name.c_str()); - command.replace("$p", dta[category].d[entryIndex].pw.c_str()); - command.replace("$u", dta[category].d[entryIndex].url.c_str()); - command.replace("$c", dta[category].d[entryIndex].comment.c_str()); + command.replace("$d", dti.dta[category].d[entryIndex].desc.c_str()); + command.replace("$n", dti.dta[category].d[entryIndex].name.c_str()); + command.replace("$p", dti.dta[category].d[entryIndex].pw.c_str()); + command.replace("$u", dti.dta[category].d[entryIndex].url.c_str()); + command.replace("$c", dti.dta[category].d[entryIndex].comment.c_str()); #else - command.replace(QRegExp("$d"), dta[category].d[entryIndex].desc.c_str()); - command.replace(QRegExp("$n"), dta[category].d[entryIndex].name.c_str()); - command.replace(QRegExp("$p"), dta[category].d[entryIndex].pw.c_str()); - command.replace(QRegExp("$u"), dta[category].d[entryIndex].url.c_str()); - command.replace(QRegExp("$c"), dta[category].d[entryIndex].comment.c_str()); + command.replace(QRegExp("$d"), dti.dta[category].d[entryIndex].desc.c_str()); + command.replace(QRegExp("$n"), dti.dta[category].d[entryIndex].name.c_str()); + command.replace(QRegExp("$p"), dti.dta[category].d[entryIndex].pw.c_str()); + command.replace(QRegExp("$u"), dti.dta[category].d[entryIndex].url.c_str()); + command.replace(QRegExp("$c"), dti.dta[category].d[entryIndex].comment.c_str()); #endif command.append(" &"); QString customXterm(conf()->confGlobXtermCommand()); if (!customXterm.isEmpty()) command = customXterm + " " + command; system(command.latin1()); lockAt(category, entryIndex, wasLocked); return true; } bool PwMDoc::goToURL(const QString &category, unsigned int entryIndex) { unsigned int cat = 0; if (!findCategory(category, &cat)) return false; return goToURL(cat, entryIndex); } bool PwMDoc::goToURL(unsigned int category, unsigned int entryIndex) { if (geteuid() == 0) { rootAlertMsgBox(); return false; } - QString url(dta[category].d[entryIndex].url.c_str()); + QString url(dti.dta[category].d[entryIndex].url.c_str()); if (url.isEmpty()) return false; QString customBrowser(conf()->confGlobBrowserCommand()); if (!customBrowser.isEmpty()) { browserProc.clearArguments(); browserProc << customBrowser << url; if (browserProc.start(KProcess::DontCare)) return true; } browserProc.clearArguments(); browserProc << "konqueror" << url; if (browserProc.start(KProcess::DontCare)) return true; browserProc.clearArguments(); browserProc << "mozilla" << url; if (browserProc.start(KProcess::DontCare)) return true; browserProc.clearArguments(); browserProc << "opera" << url; if (browserProc.start(KProcess::DontCare)) return true; return false; } PwMerror PwMDoc::exportToText(const QString *file) { PWM_ASSERT(file); if (QFile::exists(*file)) { if (!QFile::remove(*file)) return e_accessFile; } QFile f(*file); if (!f.open(IO_ReadWrite)) return e_openFile; if (!unlockAll_tempoary()) { f.close(); return e_lock; } // write header string header = i18n("Password table generated by\nPwM v").latin1(); header += PACKAGE_VER; header += i18n("\non ").latin1(); QDate currDate = QDate::currentDate(); QTime currTime = QTime::currentTime(); #ifndef PWM_EMBEDDED header += currDate.toString("ddd MMMM d ").latin1(); header += currTime.toString("hh:mm:ss ").latin1(); #else QString dfs = KGlobal::locale()->dateFormatShort(); bool ampm = KGlobal::locale()->use12Clock(); KGlobal::locale()->setDateFormatShort("%A %B %d"); KGlobal::locale()->setHore24Format(true); header += KGlobal::locale()->formatDate(currDate, true, KLocale::Userdefined); header += KGlobal::locale()->formatTime(currTime, true); KGlobal::locale()->setDateFormatShort(dfs); KGlobal::locale()->setHore24Format(!ampm); #endif header += tostr(currDate.year()); header += "\n==============================\n\n"; #ifndef PWM_EMBEDDED if (f.writeBlock(header.c_str(), header.length()) != (Q_LONG)header.length()) { unlockAll_tempoary(true); f.close(); return e_writeFile; } #else if (f.writeBlock(header.c_str(), header.length()) != (long)header.length()) { unlockAll_tempoary(true); f.close(); return e_writeFile; } #endif unsigned int i, numCat = numCategories(); unsigned int j, numEnt; string exp; for (i = 0; i < numCat; ++i) { numEnt = numEntries(i); exp = "\n== Category: "; - exp += dta[i].name; + exp += dti.dta[i].name; exp += " ==\n"; #ifndef PWM_EMBEDDED if (f.writeBlock(exp.c_str(), exp.length()) != (Q_LONG)exp.length()) { unlockAll_tempoary(true); f.close(); return e_writeFile; } #else if (f.writeBlock(exp.c_str(), exp.length()) != (long)exp.length()) { unlockAll_tempoary(true); f.close(); return e_writeFile; } #endif for (j = 0; j < numEnt; ++j) { exp = "\n-- "; - exp += dta[i].d[j].desc; + exp += dti.dta[i].d[j].desc; exp += " --\n"; exp += i18n("Username: ").latin1(); - exp += dta[i].d[j].name; + exp += dti.dta[i].d[j].name; exp += "\n"; exp += i18n("Password: ").latin1(); - exp += dta[i].d[j].pw; + exp += dti.dta[i].d[j].pw; exp += "\n"; exp += i18n("Comment: ").latin1(); - exp += dta[i].d[j].comment; + exp += dti.dta[i].d[j].comment; exp += "\n"; exp += i18n("URL: ").latin1(); - exp += dta[i].d[j].url; + exp += dti.dta[i].d[j].url; exp += "\n"; exp += i18n("Launcher: ").latin1(); - exp += dta[i].d[j].launcher; + exp += dti.dta[i].d[j].launcher; exp += "\n"; #ifndef PWM_EMBEDDED if (f.writeBlock(exp.c_str(), exp.length()) != (Q_LONG)exp.length()) { unlockAll_tempoary(true); f.close(); return e_writeFile; } #else if (f.writeBlock(exp.c_str(), exp.length()) != (long)exp.length()) { unlockAll_tempoary(true); f.close(); return e_writeFile; } #endif } } unlockAll_tempoary(true); f.close(); return e_success; } PwMerror PwMDoc::importFromText(const QString *file, int format) { PWM_ASSERT(file); if (format == 0) return importText_PwM(file); else if (format == -1) { // probe for all formats if (importText_PwM(file) == e_success) return e_success; - dta.clear(); + dti.clear(); emitDataChanged(this); // add next format here... return e_fileFormat; } return e_invalidArg; } PwMerror PwMDoc::importText_PwM(const QString *file) { PWM_ASSERT(file); FILE *f; int tmp; ssize_t ret; string curCat; unsigned int entriesRead = 0; PwMDataItem currItem; f = fopen(file->latin1(), "r"); if (!f) return e_openFile; size_t ch_tmp_size = 1024; char *ch_tmp = (char*)malloc(ch_tmp_size); if (!ch_tmp) { fclose(f); return e_outOfMem; } // - check header if (getline(&ch_tmp, &ch_tmp_size, f) == -1) // skip first line. goto formatError; // check version-string and return version in "ch_tmp". if (fscanf(f, "PwM v%s", ch_tmp) != 1) { // header not recognized as PwM generated header goto formatError; } // set filepointer behind version-string-line previously checked if (getline(&ch_tmp, &ch_tmp_size, f) == -1) goto formatError; // skip next line containing the build-date if (getline(&ch_tmp, &ch_tmp_size, f) == -1) goto formatError; // read header termination line if (getline(&ch_tmp, &ch_tmp_size, f) == -1) goto formatError; if (strcmp(ch_tmp, "==============================\n")) goto formatError; // - read entries do { // find beginning of next category do { tmp = fgetc(f); } while (tmp == '\n' && tmp != EOF); if (tmp == EOF) break; // decrement filepos by one fseek(f, -1, SEEK_CUR); // read cat-name if (getline(&ch_tmp, &ch_tmp_size, f) == -1) goto formatError; // check cat-name format if (memcmp(ch_tmp, "== Category: ", 13) != 0) goto formatError; if (memcmp(ch_tmp + (strlen(ch_tmp) - 1 - 3), " ==", 3) != 0) goto formatError; // copy cat-name curCat.assign(ch_tmp + 13, strlen(ch_tmp) - 1 - 16); do { // find beginning of next entry do { tmp = fgetc(f); } while (tmp == '\n' && tmp != EOF && tmp != '='); if (tmp == EOF) break; if (tmp == '=') { fseek(f, -1, SEEK_CUR); break; } // decrement filepos by one fseek(f, -1, SEEK_CUR); // read desc-line if (getline(&ch_tmp, &ch_tmp_size, f) == -1) goto formatError; // check desc-line format if (memcmp(ch_tmp, "-- ", 3) != 0) goto formatError; if (memcmp(ch_tmp + (strlen(ch_tmp) - 1 - 3), " --", 3) != 0) goto formatError; // add desc-line currItem.desc.assign(ch_tmp + 3, strlen(ch_tmp) - 1 - 6); // read username-line if ((ret = getline(&ch_tmp, &ch_tmp_size, f)) == -1) goto formatError; if (!textExtractEntry_PwM(ch_tmp, ret, &currItem.name)) goto formatError; // read pw-line if ((ret = getline(&ch_tmp, &ch_tmp_size, f)) == -1) goto formatError; if (!textExtractEntry_PwM(ch_tmp, ret, &currItem.pw)) goto formatError; // read comment-line if ((ret = getline(&ch_tmp, &ch_tmp_size, f)) == -1) goto formatError; if (!textExtractEntry_PwM(ch_tmp, ret, &currItem.comment)) goto formatError; // read URL-line if ((ret = getline(&ch_tmp, &ch_tmp_size, f)) == -1) goto formatError; if (!textExtractEntry_PwM(ch_tmp, ret, &currItem.url)) goto formatError; // read launcher-line if ((ret = getline(&ch_tmp, &ch_tmp_size, f)) == -1) goto formatError; if (!textExtractEntry_PwM(ch_tmp, ret, &currItem.launcher)) goto formatError; currItem.lockStat = true; currItem.listViewPos = -1; addEntry(curCat.c_str(), &currItem, true); ++entriesRead; } while (1); } while (1); if (!entriesRead) goto formatError; free(ch_tmp); fclose(f); flagDirty(); return e_success; formatError: free(ch_tmp); fclose(f); return e_fileFormat; } 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 = dta[i].d[j].desc.length(); - nameLen = dta[i].d[j].name.length(); - pwLen = dta[i].d[j].pw.length(); - commentLen = dta[i].d[j].comment.length(); + 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 ? " " : dta[i].d[j].desc.c_str()); - strcpy(entry[1], nameLen == 0 ? " " : dta[i].d[j].name.c_str()); - strcpy(entry[2], pwLen == 0 ? " " : dta[i].d[j].pw.c_str()); - strcpy(entry[3], commentLen == 0 ? " " : dta[i].d[j].comment.c_str()); + 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; vector< vector<PwMDataItem>::iterator > undefined; vector< vector<PwMDataItem>::iterator >::iterator undefBegin, undefEnd, undefI; - vector<PwMCategoryItem>::iterator catBegin = dta.begin(), - catEnd = dta.end(), + 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; ++entrI; } 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()); 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 ) { - bool syncOK = true; 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()); + + //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); + //and remove the found entry here. We will reenter it later again. + 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()); + 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() ); + 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 ]; + qApp->processEvents(); + + inLocal = syncLocal->findEntryByID( uid, &catLocal, &indexLocal ); + inRemote = syncRemote->findEntryByID( uid, &catRemote, &indexRemote ); + 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()); + 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; + //US syncRemote->insertAddressee( inRemote, false ); + //US syncLocal->insertAddressee( inRemote, false ); + syncLocal->addEntry("newcategory", 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 ]; + + inLocal = syncLocal->findEntryByID( uid, &catLocal, &indexLocal ); + inRemote = syncRemote->findEntryByID( uid, &catRemote, &indexRemote ); + 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 ( ! PWMPrefs::instance()->mWriteBackExistingOnly ) { + ++addedPasswordsRemote; + inLocal->meta.update = modifiedSync; + //USsyncLocal->insertAddressee( inLocal, false ); + (*inRemote) = (*inLocal); + //USsyncRemote->insertAddressee( inRemote, false ); + syncRemote->addEntry("newcategory", 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 ); + syncRemote->addSyncDataEntry( syncItemRemote, false ); + 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 ( PWMPrefs::instance()->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 + if ( full ) { + bool equ = true;//US ( (*local) == (*remote) ); + if ( equ ) { + //qDebug("equal "); + if ( mode < SYNC_PREF_FORCE_LOCAL ) + return 0; + + }//else //debug only + //qDebug("not equal %s %s ", local->summary().latin1(), remote->summary().latin1()); + } + + 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(); // construct on the stack = automatic cleanup. PwMDoc syncTarget(this, "synctarget"); PwMerror err = syncTarget.openDoc(&filename, 2 /*== deeplocked*/); if (err != e_success) return false; qDebug("PWM file loaded %s,sync mode %d",filename.latin1(), mode ); err = syncronize(manager, this, &syncTarget, mode ); if (err == e_success) { if ( PWMPrefs::instance()->mWriteBackFile ) { qDebug("Saving remote PWManager file"); err = syncTarget.saveDoc(conf()->confGlobCompression()); if (err != e_success) 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() { - PwMerror ret = saveDoc(conf()->confGlobCompression()); + 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 ); + ++entrI; + } + ++catcounter; + } + + return results; +} #ifndef PWM_EMBEDDED #include "pwmdoc.moc" #endif diff --git a/pwmanager/pwmanager/pwmdoc.h b/pwmanager/pwmanager/pwmdoc.h index ea4d687..91277f6 100644 --- a/pwmanager/pwmanager/pwmdoc.h +++ b/pwmanager/pwmanager/pwmdoc.h @@ -17,708 +17,762 @@ * $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 */ QString uniqueid; void clear() { create = QDateTime(); expire = QDateTime(); update = QDateTime(); updateInt = 0; uniqueid = KApplication::randomString(8); } 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(); } + }; 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 dta[category].d.size(); } + { return dti.dta[category].d.size(); } /** returns number of categories */ unsigned int numCategories() - { return dta.size(); } + { return dti.dta.size(); } /** returns the name of the category at "index" */ const string* getCategory(unsigned int index) - { return (&(dta[index].name)); } + { 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 dta[category].d[index].lockStat; } + { 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 dta[category].d[index].rev; } + { 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 &(dta[category].d[index].meta); } + { 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 dta[category].d[index].binary; } + { 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 */ - vector<PwMCategoryItem> dta; + 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/pwmdocui.cpp b/pwmanager/pwmanager/pwmdocui.cpp index 5e675fc..41afa6a 100644 --- a/pwmanager/pwmanager/pwmdocui.cpp +++ b/pwmanager/pwmanager/pwmdocui.cpp @@ -87,371 +87,371 @@ QString PwMDocUi::requestMpw(bool chipcard) #endif if (pwWnd.exec() != 1) return ""; pw = pwWnd.pwLineEdit->text(); } return pw; } QString PwMDocUi::requestNewMpw(bool *chipcard) { QString pw; SetMasterPwWndImpl pwWnd(currentView); pwWnd.setPwMKeyCard(keyCard); if (!chipcard) { #ifndef PWM_EMBEDDED pwWnd.mainTab->removePage(pwWnd.mainTab->page(1)); #else pwWnd.mainTab->removePage(pwWnd.tab_2); #endif } if (pwWnd.exec() != 1) return ""; pw = pwWnd.getPw(chipcard).c_str(); return pw; } QString PwMDocUi::requestMpwChange(const QString *currentPw, bool *chipcard) { QString pw(requestMpw(*chipcard)); if (pw == "") return ""; if (pw != *currentPw) { wrongMpwMsgBox(*chipcard); return ""; } pw = requestNewMpw(chipcard); if (pw == "") return ""; return pw; } void PwMDocUi::wrongMpwMsgBox(bool chipcard, QString prefix, QString postfix) { QString msg; if (prefix != "") { msg += prefix; msg += "\n"; } if (chipcard) { msg += i18n("Wrong key-card!\n" "Please try again with the\n" "correct key-card."); } else { msg += i18n("Wrong master-password!\n" "Please try again."); } if (postfix != "") { msg += "\n"; msg += postfix; } KMessageBox::error(currentView, msg, (chipcard) ? (i18n("wrong chipcard")) : (i18n("password error"))); } void PwMDocUi::noMpwMsgBox(bool chipcard, QString prefix, QString postfix) { QString msg; if (prefix != "") { msg += prefix; msg += "\n"; } if (chipcard) { msg += i18n("No key-card found!\n" "Please insert the\n" "correct key-card."); } else { msg += i18n("No master-password given!"); } if (postfix != "") { msg += "\n"; msg += postfix; } KMessageBox::error(currentView, msg, (chipcard) ? (i18n("no chipcard")) : (i18n("password error"))); } void PwMDocUi::rootAlertMsgBox() { KMessageBox::error(currentView, i18n("This feature is not available, " "if you execute PwM with \"root\" " "UID 0 privileges, for security reasons!"), i18n("not allowed as root!")); } void PwMDocUi::cantDeeplock_notSavedMsgBox() { KMessageBox::error(currentView, i18n("Can't deep-lock, because the document " "hasn't been saved, yet. Please save " "to a file and try again."), i18n("not saved, yet")); } void PwMDocUi::gpmPwLenErrMsgBox() { KMessageBox::error(currentView, i18n("GPasman does not support passwords " "shorter than 4 characters! Please try " "again with a longer password."), i18n("password too short")); } int PwMDocUi::dirtyAskSave(const QString &docTitle) { int ret; #ifndef PWM_EMBEDDED ret = KMessageBox::questionYesNoCancel(currentView, i18n("The list \"") + docTitle + i18n ("\" has been modified.\n" "Do you want to save it?"), i18n("save?")); if (ret == KMessageBox::Yes) { return 0; } else if (ret == KMessageBox::No) { return 1; } #else ret = KMessageBox::warningYesNoCancel(currentView, i18n("The list \"") + docTitle + i18n ("\" has been modified.\n" "Do you want to save it?"), i18n("save?")); if (ret == KMessageBox::Yes) { return 0; } else if (ret == KMessageBox::No) { return 1; } #endif // cancel return -1; } bool PwMDocUi::saveDocUi(PwMDoc *doc) { PWM_ASSERT(doc); doc->timer()->getLock(DocTimer::id_autoLockTimer); if (doc->isDocEmpty()) { KMessageBox::information(currentView, i18n ("Sorry, there's nothing to save.\n" "Please first add some passwords."), i18n("nothing to do")); doc->timer()->putLock(DocTimer::id_autoLockTimer); return true; } PwMerror ret = doc->saveDoc(conf()->confGlobCompression()); if (ret == e_filename) { doc->timer()->putLock(DocTimer::id_autoLockTimer); return saveAsDocUi(doc); } else if (ret == e_weakPw) { KMessageBox::error(currentView, i18n("Error: This is a weak password.\n" "Please select another password."), i18n("weak password")); doc->timer()->putLock(DocTimer::id_autoLockTimer); return false; } else if (ret == e_fileBackup) { KMessageBox::error(currentView, i18n("Error: Couldn't make backup-file!"), i18n("backup failed")); doc->timer()->putLock(DocTimer::id_autoLockTimer); return false; } else if (ret != e_success) { KMessageBox::error(currentView, i18n("Error: Couldn't write to file.\n" - "Please check if you have permission to " + "Please check if you have permission to\n" "write to the file in that directory."), i18n("error while writing")); doc->timer()->putLock(DocTimer::id_autoLockTimer); return false; } doc->timer()->putLock(DocTimer::id_autoLockTimer); return true; } bool PwMDocUi::saveAsDocUi(PwMDoc *doc) { PWM_ASSERT(doc); doc->timer()->getLock(DocTimer::id_autoLockTimer); if (doc->isDocEmpty()) { KMessageBox::information(currentView, i18n ("Sorry, there's nothing to save.\n" "Please first add some passwords."), i18n("nothing to do")); doc->timer()->putLock(DocTimer::id_autoLockTimer); return true; } #ifndef PWM_EMBEDDED QString fn(KFileDialog::getSaveFileName(QString::null, i18n("*.pwm|PwManager Password file"), currentView)); #else QString fn = locateLocal( "data", KGlobal::getAppName() + "/*.pwm" ); fn = KFileDialog::getSaveFileName(fn, i18n("password filename(*.pwm)"), currentView); #endif if (fn == "") { doc->timer()->putLock(DocTimer::id_autoLockTimer); return false; } if (fn.right(4) != ".pwm") fn += ".pwm"; PwMerror ret = doc->saveDoc(conf()->confGlobCompression(), &fn); if (ret != e_success) { KMessageBox::error(currentView, 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")); doc->timer()->putLock(DocTimer::id_autoLockTimer); return false; } doc->timer()->putLock(DocTimer::id_autoLockTimer); return true; } bool PwMDocUi::openDocUi(PwMDoc *doc, QString filename, bool openDeepLocked) { if (filename.isEmpty()) { #ifndef PWM_EMBEDDED filename = KFileDialog::getOpenFileName(QString::null, i18n("*.pwm|PwManager Password file\n" "*|All files"), getCurrentView()); #else filename = locateLocal( "data", KGlobal::getAppName() + "/*.pwm"); filename = KFileDialog::getOpenFileName(filename, i18n("password filename(*.pwm)"), getCurrentView()); #endif } if (filename.isEmpty()) goto cancelOpen; PwMerror ret; while (true) { int lockStat = -1; if (openDeepLocked) { lockStat = 2; } else { if (conf()->confGlobUnlockOnOpen()) { lockStat = 0; } else { lockStat = 1; } } ret = doc->openDoc(&filename, lockStat); qDebug("pwmdocui::OpenDocui %i", ret); if (ret != e_success) { if (ret == e_readFile || ret == e_openFile) { KMessageBox::error(getCurrentView(), i18n("Could not read file!") + "\n" + filename, i18n("file error")); goto cancelOpen; } if (ret == e_alreadyOpen) { KMessageBox::error(getCurrentView(), i18n("This file is already open."), i18n("already open")); goto cancelOpen; } if (ret == e_fileVer) { KMessageBox::error(getCurrentView(), i18n ("File-version is not supported!\n" "Did you create this file with an older or newer version of PwM?"), i18n ("incompatible version")); goto cancelOpen; } if (ret == e_wrongPw) { continue; } if (ret == e_noPw) { goto cancelOpen; } if (ret == e_fileFormat) { KMessageBox::error(getCurrentView(), i18n ("Sorry, this file has not been recognized " "as a PwM Password file.\n" "Probably you have selected the wrong file."), i18n ("no PwM password-file")); goto cancelOpen; } if (ret == e_fileCorrupt) { KMessageBox::error(getCurrentView(), i18n ("File corrupt!\n" "Maybe the media, you stored this file on, " "had bad sectors?"), i18n ("checksum error")); goto cancelOpen; } } break; } return true; cancelOpen: return false; } QString PwMDocUi::string_defaultCategory() { return i18n("Default"); } QString PwMDocUi::string_locked() { return i18n("<LOCKED>"); } QString PwMDocUi::string_deepLockedShort() { return i18n("DEEP-LOCKED"); } QString PwMDocUi::string_deepLockedLong() { return i18n("This file is DEEP-LOCKED!\n" "That means all data has been encrypted\n" "and written out to the file. If you want\n" "to see the entries, please UNLOCK the file.\n" "While unlocking, you will be prompted for the\n" "master-password or the key-card."); } QString PwMDocUi::string_defaultTitle() { return i18n("Untitled"); } #ifndef PWM_EMBEDDED #include "pwmdocui.moc" #endif diff --git a/pwmanager/pwmanager/pwmexception.h b/pwmanager/pwmanager/pwmexception.h index c8a8c0f..301ebd7 100644 --- a/pwmanager/pwmanager/pwmexception.h +++ b/pwmanager/pwmanager/pwmexception.h @@ -1,216 +1,217 @@ /*************************************************************************** * * * 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 __PWMEXCEPTION_H #define __PWMEXCEPTION_H #include "globalstuff.h" #include <iostream> #include <string> using std::string; using std::cerr; using std::cout; using std::endl; /* This is an internal function to reduce code-overhead * of the BUG(), WARN(), TOD0() and FiXME() macros. Please use * these macros instead of calling this function directly. */ void pwmFatal(const char *id, const char *file, int line); /** Use PWM_ASSERT(condition) for debugging assertions. * "condition" is eaten up and replaced with a NOP * when debugging is disabled. * * PWM_ASSERT_NOEAT(condition) is the same as PWM_ASSERT(condition), * but it does _not_ eat up "condition" and ensures that * condition is always evaluated. */ #ifdef PWM_ASSERT # undef PWM_ASSERT #endif #ifdef PWM_ASSERT_NOEAT # undef PWM_ASSERT_NOEAT #endif #ifdef PWM_DEBUG # define PWM_ASSERT(x) do { \ if (unlikely(!(x))) { \ cerr << "PWM_ASSERT failed: (" << #x \ << ") in " << __FILE__ \ << ":" << __LINE__ \ << endl; \ } \ } while (0) # define PWM_ASSERT_NOEAT(x) do { PWM_ASSERT(x); } while (0) #else // PWM_DEBUG # define PWM_ASSERT(x) do { } while (0) # define PWM_ASSERT_NOEAT(x) do { if (x) ; } while (0) #endif // PWM_DEBUG /** Insert a BUG() into code paths which clearly show * a bug in the code and which should, under normal * circumstances, never execute. */ #ifdef BUG # undef BUG #endif #define BUG() do { pwmFatal("BUG", __FILE__, __LINE__); } while (0) /** Use BUG_ON(condition) to print a bug-message if "condition" * is true. This is also enabled in non-debugging code. */ #ifdef BUG_ON # undef BUG_ON #endif #define BUG_ON(x) do { if (unlikely(x)) BUG(); } while (0) /** Insert a WARN() into code-paths which should not * execute normally, but if they do it's non-fatal. */ #ifdef WARN # undef WARN #endif #define WARN() do { pwmFatal("badness", __FILE__, __LINE__); } while (0) /** Same as BUG_ON() but prints a warning-message */ #ifdef WARN_ON # undef WARN_ON #endif #define WARN_ON(x) do { if (unlikely(x)) WARN(); } while (0) /** Insert this into code which is incomplete */ #ifdef TODO # undef TODO #endif #define TODO() do { pwmFatal("TODO", __FILE__, __LINE__); } while (0) /** Insert this into code which likely contains bugs */ #ifdef FIXME # undef FIXME #endif #define FIXME() do { pwmFatal("FIXME", __FILE__, __LINE__); } while (0) /** PwM error codes */ enum PwMerror { e_success = 0, // file access errors e_filename, e_readFile, e_writeFile, e_openFile, e_accessFile, // permission error, etc... e_fileGeneric, e_alreadyOpen, // other file errors e_fileVer, e_fileFormat, // format error e_unsupportedFormat, // completely unsupported format e_setFilePointer, e_fileBackup, e_fileCorrupt, // file data has correct format, // but is corrupt (checksum error, etc) // password errors e_wrongPw, e_getPw, e_weakPw, e_noPw, // action not implemented errors e_hashNotImpl, e_cryptNotImpl, // argument/parameter errors e_incompleteArg, e_invalidArg, // misc e_writeHeader, e_serializeDta, e_enc, e_entryExists, e_categoryExists, e_maxAllowedEntr, // no more entries can be added. e_outOfMem, e_lock, // error while (un)locking e_docNotSaved, // doc wasn't saved to a file, yet. e_docIsEmpty, e_binEntry, e_normalEntry, + e_syncError, e_generic }; /** can be used for general exception faults */ class PwMException { public: enum exceptionId { EX_GENERIC = 0, EX_OPEN, EX_CLOSE, EX_READ, EX_WRITE, EX_LOAD_MODULE, EX_PARSE }; public: PwMException(exceptionId id = EX_GENERIC, const char *message = "") { exId = id; exMsg = message; } exceptionId getId() { return exId; } const char* getMessage() { return exMsg; } protected: /** ID of this exception */ exceptionId exId; /** additional error-message for this exception */ const char *exMsg; }; void __printInfo(const string &msg); void __printWarn(const string &msg); void __printError(const string &msg); #ifdef PWM_DEBUG void __printDebug(const string &msg); # define printDebug(x) __printDebug(x) #else # define printDebug(x) do { } while (0) #endif #define printInfo(x) __printInfo(x) #define printWarn(x) __printWarn(x) #define printError(x) __printError(x) #endif // __PWMEXCEPTION_H diff --git a/pwmanager/pwmanager/pwmview.cpp b/pwmanager/pwmanager/pwmview.cpp index d192119..e23ce25 100644 --- a/pwmanager/pwmanager/pwmview.cpp +++ b/pwmanager/pwmanager/pwmview.cpp @@ -1,229 +1,230 @@ /*************************************************************************** * * * copyright (C) 2003, 2004 by Michael Buesch * * email: mbuesch@freenet.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License version 2 * * as published by the Free Software Foundation. * * * ***************************************************************************/ /*************************************************************************** * copyright (C) 2004 by Ulf Schenk * This file is originaly based on version 1.0.1 of pwmanager * and was modified to run on embedded devices that run microkde * * $Id$ **************************************************************************/ #include "pwmview.h" #include "pwmexception.h" #include "globalstuff.h" #include "pwm.h" #include "rencatwnd.h" #ifndef PWM_EMBEDDED #include "configuration.h" #else #include "pwmprefs.h" #endif #include "commentbox.h" #include <kmessagebox.h> #include <klocale.h> #include <qlineedit.h> #include <qpoint.h> #include <qapplication.h> +#include <qlayout.h> //US ENH: wouldn't it be a good idea if we could use this consts everywhere else. //US ENH: for examle in listviewpwm.cpp //US ENH: Because of that I transfer them into the headerfile. /* #define COLUMN_DESC 0 #define COLUMN_NAME 1 #define COLUMN_PW 2 #define COLUMN_URL 3 #define COLUMN_LAUNCHER 4 */ PwMView::PwMView(PwM *_mainClass, QWidget *parent, PwMDoc *_doc, const char *name) : PwMViewStyle(parent, name) { PWM_ASSERT(_mainClass); PWM_ASSERT(parent); PWM_ASSERT(_doc); setView(this); doc = _doc; doc->setListViewPointer(this); mainClass = _mainClass; resize(_mainClass->size()); initStyle(conf()->confWndMainViewStyle()); initCtxMenu(); doc->setCurrentView(this); connect(doc, SIGNAL(dataChanged(PwMDoc *)), this, SLOT(updateView())); } PwMView::~PwMView() { } void PwMView::initCtxMenu() { ctxMenu = new QPopupMenu(this); ctxMenu->insertItem(i18n("&Add password"), mainClass, SLOT(addPwd_slot())); ctxMenu->insertSeparator(); ctxMenu->insertItem(i18n("&Edit"), mainClass, SLOT(editPwd_slot())); ctxMenu->insertItem(i18n("&Delete"), mainClass, SLOT(deletePwd_slot())); ctxMenu->insertSeparator(); ctxMenu->insertItem(i18n("copy password to clipboard"), this, SLOT(copyPwToClip())); ctxMenu->insertItem(i18n("copy username to clipboard"), this, SLOT(copyNameToClip())); ctxMenu->insertItem(i18n("copy description to clipboard"), this, SLOT(copyDescToClip())); ctxMenu->insertItem(i18n("copy url to clipboard"), this, SLOT(copyUrlToClip())); ctxMenu->insertItem(i18n("copy launcher to clipboard"), this, SLOT(copyLauncherToClip())); ctxMenu->insertItem(i18n("copy comment to clipboard"), this, SLOT(copyCommentToClip())); ctxMenu->insertSeparator(); ctxMenu->insertItem(i18n("Execute \"Launcher\""), mainClass, SLOT(execLauncher_slot())); ctxMenu->insertItem(i18n("Go to \"URL\""), mainClass, SLOT(goToURL_slot())); } void PwMView::resizeEvent(QResizeEvent *) { resizeView(size()); } void PwMView::refreshCommentTextEdit(QListViewItem *curItem) { PWM_ASSERT(commentBox); if (!curItem) return; string comment; PwMerror ret; ret = document()->getCommentByLvp(getCurrentCategory(), lv->childCount() - lv->itemIndex(curItem) - 1, &comment); if (ret == e_binEntry) { commentBox->setContent(i18n("This is a binary entry.\n" "It is not a normal password-entry, as it contains " "binary data, which PwManager can't display here.")); } else if (ret == e_normalEntry) { commentBox->setContent(comment.c_str()); } else { BUG(); return; } lv->ensureItemVisible(curItem); } void PwMView::keyReleaseEvent(QKeyEvent * /*e*/) { refreshCommentTextEdit(lv->currentItem()); } bool PwMView::getCurEntryIndex(unsigned int *index) { QListViewItem *current = lv->currentItem(); if (!current) return false; return getDocEntryIndex(index, current); } bool PwMView::getDocEntryIndex(unsigned int *index, const QListViewItem *item) { vector<unsigned int> foundPositions; PwMDataItem curItem; curItem.desc = item->text(COLUMN_DESC).latin1(); curItem.name = item->text(COLUMN_NAME).latin1(); document()->getCommentByLvp(getCurrentCategory(), lv->childCount() - lv->itemIndex(item) - 1, &curItem.comment); curItem.url = item->text(COLUMN_URL).latin1(); curItem.launcher = item->text(COLUMN_LAUNCHER).latin1(); document()->findEntry(getCurrentCategory(), curItem, SEARCH_IN_DESC | SEARCH_IN_NAME | SEARCH_IN_COMMENT | SEARCH_IN_URL | SEARCH_IN_LAUNCHER, &foundPositions, true); if (foundPositions.size()) { *index = foundPositions[0]; return true; } return false; } void PwMView::handleToggle(QListViewItem *item) { PWM_ASSERT(doc); if (!item) return; QCheckListItem *clItem = (QCheckListItem *)item; QString curCat(getCurrentCategory()); // find document position of this entry. unsigned int curEntryDocIndex; if (!getDocEntryIndex(&curEntryDocIndex, item)) return; // hack to refresh the comment, if only one item is present if (lv->childCount() == 1) refreshCommentTextEdit(lv->currentItem()); if (doc->isLocked(curCat, curEntryDocIndex) != clItem->isOn()) return; // this is just a click somewhere on the entry if (doc->isDeepLocked()) { PwMerror ret; ret = doc->deepLock(false); if (ret != e_success) clItem->setOn(false); return; } doc->lockAt(curCat, curEntryDocIndex, !clItem->isOn()); } void PwMView::handleRightClick(QListViewItem *item, const QPoint &point, int) { if (!item) return; ctxMenu->move(point); /* don't use ctxMenu->exec() here, as it generates race conditions * with the card interface code. Believe it or not. :) */ ctxMenu->show(); } void PwMView::updateCategories() { QString oldSel(getCurrentCategory()); delAllCategories(); QStringList catList; document()->getCategoryList(&catList); catList.sort(); #ifndef PWM_EMBEDDED QStringList::iterator i = catList.begin(), end = catList.end(); #else QStringList::Iterator i = catList.begin(), end = catList.end(); #endif while (i != end) { addCategory(*i); ++i; } selectCategory(oldSel); } void PwMView::shiftToView() { int cX = lv->contentsX(); int cY = lv->contentsY(); @@ -266,195 +267,258 @@ void PwMView::shiftToView() 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()); } + + + +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 ); + 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 ); + 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 5a326d3..75cce51 100644 --- a/pwmanager/pwmanager/pwmview.h +++ b/pwmanager/pwmanager/pwmview.h @@ -1,150 +1,172 @@ /*************************************************************************** * * * 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 <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 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 a54ba8a..f615082 100644 --- a/pwmanager/pwmanager/serializer.cpp +++ b/pwmanager/pwmanager/serializer.cpp @@ -1,435 +1,451 @@ /*************************************************************************** * * * 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 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(const vector<PwMCategoryItem> &dta) +bool Serializer::serialize(PwMItem &dta) { PWM_ASSERT(domDoc); QDomElement root(genNewRoot()); QDomElement catNode(domDoc->createElement(CAT_ROOT_WR)); - root.appendChild(catNode); - if (!addCategories(&catNode, dta)) + 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(vector<PwMCategoryItem> *dta) +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)) { + 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 true; - } + return false; + } - 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; 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; } #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()); } #else bool ok = true; if (name == META_CREATE_DATE) { dta->create = KGlobal::locale()->readDateTime(val, KLocale::ISODate, &ok); } else if (name == META_VALID_DATE) { dta->valid = KGlobal::locale()->readDateTime(val, KLocale::ISODate, &ok); } else if (name == META_EXPIRE_DATE) { dta->expire = KGlobal::locale()->readDateTime(val, KLocale::ISODate, &ok); } else if (name == META_UPDATE_DATE) { dta->update = KGlobal::locale()->readDateTime(val, KLocale::ISODate, &ok); } 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; } @@ -472,192 +488,269 @@ bool Serializer::addCategories(QDomElement *e, 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); #ifndef PWM_EMBEDDED text = domDoc->createTextNode(dta.create.toString(Qt::ISODate)); #else text = domDoc->createTextNode(KGlobal::locale()->formatDateTime(dta.create, KLocale::ISODate)); #endif tag.appendChild(text); e->appendChild(tag); tag = domDoc->createElement(META_VALID_DATE); #ifndef PWM_EMBEDDED text = domDoc->createTextNode(dta.valid.toString(Qt::ISODate)); #else text = domDoc->createTextNode(KGlobal::locale()->formatDateTime(dta.valid, KLocale::ISODate)); #endif tag.appendChild(text); e->appendChild(tag); tag = domDoc->createElement(META_EXPIRE_DATE); #ifndef PWM_EMBEDDED text = domDoc->createTextNode(dta.expire.toString(Qt::ISODate)); #else text = domDoc->createTextNode(KGlobal::locale()->formatDateTime(dta.expire, KLocale::ISODate)); #endif tag.appendChild(text); e->appendChild(tag); tag = domDoc->createElement(META_UPDATE_DATE); #ifndef PWM_EMBEDDED text = domDoc->createTextNode(dta.update.toString(Qt::ISODate)); #else text = domDoc->createTextNode(KGlobal::locale()->formatDateTime(dta.update, KLocale::ISODate)); #endif tag.appendChild(text); e->appendChild(tag); tag = domDoc->createElement(META_UPDATE_INT); text = domDoc->createTextNode(tostr(dta.updateInt).c_str()); tag.appendChild(text); e->appendChild(tag); tag = domDoc->createElement(META_UNIQUEID); text = domDoc->createTextNode(escapeEntryData(dta.uniqueid)); 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("||>"), "]]>"); #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; + 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); + + e->appendChild(curSync); + + } + return true; +} + diff --git a/pwmanager/pwmanager/serializer.h b/pwmanager/pwmanager/serializer.h index 245fcee..ee61b94 100644 --- a/pwmanager/pwmanager/serializer.h +++ b/pwmanager/pwmanager/serializer.h @@ -1,102 +1,115 @@ /*************************************************************************** * * * 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$ **************************************************************************/ #ifndef __SERIALIZER_H #define __SERIALIZER_H #include "pwmdoc.h" #include <qcstring.h> #include <qdom.h> #include <vector> using std::vector; /** This serializes its input data into * the PwManager-XML-datastream, that becomes * encrypted and maybe compressed */ class Serializer { public: /** construct an empty serializer document */ Serializer(); /** construct a serializer document and parse "buffer" */ Serializer(const QCString &buffer); /** destructor */ virtual ~Serializer(); /** clears all data */ void clear(); /** parse the given data buffer */ bool parseXml(const QCString &buffer); /** returns the current XML data */ QCString getXml(); /** serialize "dta" and store it as XML data */ - bool serialize(const vector<PwMCategoryItem> &dta); + //US ENH: we need to serialize and deserialize not only categories, but also synctargets + bool serialize(PwMItem &dta); /** deserialize the (parsed) XML data and store it in "dta" */ - bool deSerialize(vector<PwMCategoryItem> *dta); + bool deSerialize(PwMItem *dta); /** sets the initial default lockStat we should assign */ void setDefaultLockStat(bool stat) { defaultLockStat = stat; } protected: /** main data holder */ QDomDocument *domDoc; /** default lockStat to assign */ bool defaultLockStat; protected: /** check if this is valid PwManager XML data */ bool checkValid(); /** read the categories in the node "n" */ bool readCategories(const QDomNode &n, vector<PwMCategoryItem> *dta); /** read the entries in the node "n" */ bool readEntries(const QDomNode &n, vector<PwMDataItem> *dta); /** extract the data out of the given item at "n" */ bool extractEntry(const QDomNode &n, PwMDataItem *dta); /** extract the meta-data */ bool extractMeta(const QDomNode &n, PwMMetaData *dta); /** generates a new root node and sets all initial parameters */ QDomElement genNewRoot(); /** add new categories to the XML data stream in e */ bool addCategories(QDomElement *e, const vector<PwMCategoryItem> &dta); /** add the given new entries to the XML data stream in e */ bool addEntries(QDomElement *e, const vector<PwMDataItem> &dta); /** do serialize and write the given entry to the XML stream */ bool writeEntry(QDomElement *e, const PwMDataItem &_dta); /** write the entry meta data to the xml stream */ bool writeMeta(QDomElement *e, const PwMMetaData &dta); /** escape illegal characters out of the given entry data string */ QString escapeEntryData(QString dta); /** un-escape illegal characters out of the given entry data string */ QString unescapeEntryData(QString dta); + + + + //US ENH: the following methods are getting used to write/read sync entries + /** read the syncentries in the node "n" */ + bool readSyncData(const QDomNode &n, + vector<PwMSyncItem> *dta); + + /** add new syncentries to the XML data stream in e */ + bool addSyncData(QDomElement *e, + const vector<PwMSyncItem> &dta); + }; #endif // __SERIALIZER_H |