author | ulf69 <ulf69> | 2004-10-06 06:18:43 (UTC) |
---|---|---|
committer | ulf69 <ulf69> | 2004-10-06 06:18:43 (UTC) |
commit | 8e5089d2f2011e38d811ae0fc6b6d4edaeaf89b8 (patch) (side-by-side diff) | |
tree | 8d8ca7401ce699ee3aca98cace5561beb4104710 | |
parent | 904cbf4f2a418d3cadc74a6168a4565ae6ebc3c5 (diff) | |
download | kdepimpi-8e5089d2f2011e38d811ae0fc6b6d4edaeaf89b8.zip kdepimpi-8e5089d2f2011e38d811ae0fc6b6d4edaeaf89b8.tar.gz kdepimpi-8e5089d2f2011e38d811ae0fc6b6d4edaeaf89b8.tar.bz2 |
*** empty log message ***
-rw-r--r-- | pwmanager/pwmanager/pwmdoc.cpp | 46 |
1 files changed, 39 insertions, 7 deletions
diff --git a/pwmanager/pwmanager/pwmdoc.cpp b/pwmanager/pwmanager/pwmdoc.cpp index 4e8a603..6c1a9c0 100644 --- a/pwmanager/pwmanager/pwmdoc.cpp +++ b/pwmanager/pwmanager/pwmdoc.cpp @@ -848,2421 +848,2453 @@ PwMerror PwMDoc::checkHeader(char *cryptAlgo, QString *pw, char *compress, #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; } dti.dta[cat].d.push_back(*d); delAllEmptyCat(true); if (!dontFlagDirty) flagDirty(); return e_success; } PwMerror PwMDoc::addCategory(const QString &category, unsigned int *categoryIndex, bool checkIfExist) { if (isDeepLocked()) { PwMerror ret; ret = deepLock(false); if (ret != e_success) return e_lock; } if (checkIfExist) { if (findCategory(category, categoryIndex)) return e_categoryExists; } PwMCategoryItem item; item.name = category.latin1(); dti.dta.push_back(item); if (categoryIndex) *categoryIndex = dti.dta.size() - 1; return e_success; } bool PwMDoc::delEntry(const QString &category, unsigned int index, bool dontFlagDirty) { unsigned int cat = 0; if (!findCategory(category, &cat)) { BUG(); return false; } return delEntry(cat, index, dontFlagDirty); } bool PwMDoc::delEntry(unsigned int category, unsigned int index, bool dontFlagDirty) { if (isDeepLocked()) return false; if (index > dti.dta[category].d.size() - 1) return false; getDataChangedLock(); if (!lockAt(category, index, false)) { putDataChangedLock(); return false; } putDataChangedLock(); int lvPos = dti.dta[category].d[index].listViewPos; // delete entry dti.dta[category].d.erase(dti.dta[category].d.begin() + index); unsigned int i, entries = numEntries(category); if (!entries) { // no more entries in this category, so // we can delete it, too. BUG_ON(!delCategory(category)); // delCategory() flags it dirty, so we need not to do so. return true; } for (i = 0; i < entries; ++i) { // decrement all listViewPositions that are greater than the deleted. if (dti.dta[category].d[i].listViewPos > lvPos) --dti.dta[category].d[i].listViewPos; } if (!dontFlagDirty) flagDirty(); return true; } bool PwMDoc::editEntry(const QString &oldCategory, const QString &newCategory, unsigned int index, PwMDataItem *d, bool updateMeta) { PWM_ASSERT(d); unsigned int oldCat = 0; if (!findCategory(oldCategory, &oldCat)) { BUG(); return false; } return editEntry(oldCat, newCategory, index, d, updateMeta); } bool PwMDoc::editEntry(unsigned int oldCategory, const QString &newCategory, unsigned int index, PwMDataItem *d, bool updateMeta) { if (isDeepLocked()) return false; if (updateMeta) { d->meta.update = QDateTime::currentDateTime(); if (d->meta.create.isNull()) { d->meta.create = d->meta.update; } } if (dti.dta[oldCategory].name != newCategory.latin1()) { // the user changed the category. PwMerror ret; d->rev = 0; ret = addEntry(newCategory, d, true, false); if (ret != e_success) return false; if (!delEntry(oldCategory, index, true)) return false; } else { d->rev = dti.dta[oldCategory].d[index].rev + 1; // increment revision counter. dti.dta[oldCategory].d[index] = *d; } flagDirty(); return true; } unsigned int PwMDoc::numEntries(const QString &category) { unsigned int cat = 0; if (!findCategory(category, &cat)) { BUG(); return 0; } return numEntries(cat); } bool PwMDoc::serializeDta(string *d) { PWM_ASSERT(d); Serializer ser; if (!ser.serialize(dti)) 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(&dti)) return false; } catch (PwMException) { return false; } #else Serializer ser(d->c_str()); ser.setDefaultLockStat(entriesLocked); 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 > 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 = 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 (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 == 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); } } 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 = 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 = 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 = 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 = 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() { dti.clear(); PwMCategoryItem d; d.name = DEFAULT_CATEGORY.latin1(); 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) { 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 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, dti.dta[category].d[i].desc, caseSensitive, exactWordMatch)) { continue; } } if (searchIn & SEARCH_IN_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, 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, dti.dta[category].d[i].comment, caseSensitive, exactWordMatch)) { continue; } } if (searchIn & SEARCH_IN_URL) { if (!compareString(find.url, dti.dta[category].d[i].url, caseSensitive, exactWordMatch)) { continue; } } if (searchIn & SEARCH_IN_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 = 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 = dti.dta.begin(), end = dti.dta.end(); while (i != end) { if ((*i).name == name.latin1()) { if (index) { *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; 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) { 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 = 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 = 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 = 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 = 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 = 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(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", 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"), 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(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 += dti.dta[i].name; exp += " ==\n"; #ifndef PWM_EMBEDDED if (f.writeBlock(exp.c_str(), exp.length()) != (Q_LONG)exp.length()) { unlockAll_tempoary(true); f.close(); return e_writeFile; } #else if (f.writeBlock(exp.c_str(), exp.length()) != (long)exp.length()) { unlockAll_tempoary(true); f.close(); return e_writeFile; } #endif for (j = 0; j < numEnt; ++j) { exp = "\n-- "; exp += dti.dta[i].d[j].desc; exp += " --\n"; exp += i18n("Username: ").latin1(); exp += dti.dta[i].d[j].name; exp += "\n"; exp += i18n("Password: ").latin1(); exp += dti.dta[i].d[j].pw; exp += "\n"; exp += i18n("Comment: ").latin1(); exp += dti.dta[i].d[j].comment; exp += "\n"; exp += i18n("URL: ").latin1(); exp += dti.dta[i].d[j].url; exp += "\n"; exp += i18n("Launcher: ").latin1(); exp += dti.dta[i].d[j].launcher; exp += "\n"; #ifndef PWM_EMBEDDED if (f.writeBlock(exp.c_str(), exp.length()) != (Q_LONG)exp.length()) { unlockAll_tempoary(true); f.close(); return e_writeFile; } #else if (f.writeBlock(exp.c_str(), exp.length()) != (long)exp.length()) { unlockAll_tempoary(true); f.close(); return e_writeFile; } #endif } } unlockAll_tempoary(true); f.close(); return e_success; } PwMerror PwMDoc::importFromText(const QString *file, int format) { PWM_ASSERT(file); if (format == 0) return importText_PwM(file); else if (format == -1) { // probe for all formats if (importText_PwM(file) == e_success) return e_success; dti.clear(); emitDataChanged(this); // add next format here... return e_fileFormat; } return e_invalidArg; } PwMerror PwMDoc::importText_PwM(const QString *file) { 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 = dti.dta[i].d[j].desc.length(); nameLen = dti.dta[i].d[j].name.length(); pwLen = dti.dta[i].d[j].pw.length(); commentLen = dti.dta[i].d[j].comment.length(); entry[0] = new char[descLen + 1]; entry[1] = new char[nameLen + 1]; entry[2] = new char[pwLen + 1]; entry[3] = new char[commentLen + 1]; strcpy(entry[0], descLen == 0 ? " " : dti.dta[i].d[j].desc.c_str()); strcpy(entry[1], nameLen == 0 ? " " : dti.dta[i].d[j].name.c_str()); strcpy(entry[2], pwLen == 0 ? " " : dti.dta[i].d[j].pw.c_str()); strcpy(entry[3], commentLen == 0 ? " " : dti.dta[i].d[j].comment.c_str()); entry[0][descLen == 0 ? descLen + 1 : descLen] = '\0'; entry[1][nameLen == 0 ? nameLen + 1 : nameLen] = '\0'; entry[2][pwLen == 0 ? pwLen + 1 : pwLen] = '\0'; entry[3][commentLen == 0 ? commentLen + 1 : commentLen] = '\0'; ret = gp.save_entry(entry); if (ret == -1){ delete [] entry[0]; delete [] entry[1]; delete [] entry[2]; delete [] entry[3]; gp.save_finalize(); unlockAll_tempoary(true); return e_writeFile; } delete [] entry[0]; delete [] entry[1]; delete [] entry[2]; delete [] entry[3]; } } unlockAll_tempoary(true); if (gp.save_finalize() == -1) return e_writeFile; return e_success; } PwMerror PwMDoc::importFromGpasman(const QString *file) { PWM_ASSERT(file); QString pw = requestMpw(false); if (pw == "") return e_noPw; GpasmanFile gp; int ret, i; PwMerror ret2; char *entry[4]; PwMDataItem tmpData; ret = gp.load_init(file->latin1(), pw.latin1()); if (ret != 1) return e_accessFile; do { ret = gp.load_entry(entry); if(ret != 1) break; tmpData.desc = entry[0]; tmpData.name = entry[1]; tmpData.pw = entry[2]; tmpData.comment = entry[3]; tmpData.lockStat = true; tmpData.listViewPos = -1; ret2 = addEntry(DEFAULT_CATEGORY, &tmpData, true); for (i = 0; i < 4; ++i) free(entry[i]); if (ret2 == e_maxAllowedEntr) { gp.load_finalize(); return e_maxAllowedEntr; } } while (1); gp.load_finalize(); if (isDocEmpty()) return e_wrongPw; // we assume this. flagDirty(); return e_success; } void PwMDoc::ensureLvp() { if (isDocEmpty()) return; vector< vector<PwMDataItem>::iterator > undefined; vector< vector<PwMDataItem>::iterator >::iterator undefBegin, undefEnd, undefI; 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 ) { 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 ]; + qDebug("sync uid %s from remote file", uid.latin1()); + qApp->processEvents(); inLocal = syncLocal->findEntryByID( uid, &catLocal, &indexLocal ); inRemote = syncRemote->findEntryByID( uid, &catRemote, &indexRemote ); + PWM_ASSERT(inRemote); if ( inLocal != 0 ) { // maybe conflict - same uid in both files if ( (take = takePwMDataItem( inLocal, inRemote, mLastSync, mode, fullDateRange) ) ) { //qDebug("take %d %s ", take, inL.summary().latin1()); 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. + //1) unlock local file first if necessary (ask for password) + if (this->isDeepLocked()) { + PwMerror ret = this->deepLock(false); + if (ret != e_success) + return false; + } + + //2) construct and open a new doc on the stack(automatic cleanup) for remote file. PwMDoc syncTarget(this, "synctarget"); + PwMDoc* pSyncTarget = &syncTarget; - PwMerror err = syncTarget.openDoc(&filename, 2 /*== deeplocked*/); - if (err != e_success) + PwMerror err = pSyncTarget->openDoc(&filename, 1 /*== open with all entries locked*/); + + if (err == e_alreadyOpen) { + PwMDocList::listItem li; + if (getOpenDocList()->find(filename.latin1(), &li)) + pSyncTarget = li.doc; + else { + qDebug("PwmDoc::sync: sync failed. Error %i while opening file %s",err, filename.latin1()); + return false; + } + } + else if (err != e_success) { + qDebug("PwmDoc::sync: sync failed. Error %i while opening file %s",err, filename.latin1()); return false; + } qDebug("PWM file loaded %s,sync mode %d",filename.latin1(), mode ); - err = syncronize(manager, this, &syncTarget, mode ); + //3) unlock remote file first if necessary (ask for password) + if (pSyncTarget->isDeepLocked()) { + PwMerror ret = pSyncTarget->deepLock(false); + if (ret != e_success) + return false; + } + + + err = syncronize(manager, this, pSyncTarget, mode ); if (err == e_success) { if ( PWMPrefs::instance()->mWriteBackFile ) { qDebug("Saving remote PWManager file"); - err = syncTarget.saveDoc(conf()->confGlobCompression()); - if (err != e_success) + err = pSyncTarget->saveDoc(conf()->confGlobCompression()); + if (err != e_success) { + qDebug("PwmDoc::sync: Sync failed. Error %i while storing file %s",err, filename.latin1()); return false; - + } } flagDirty(); return true; } else { return false; } } //called by the syncmanager to indicate that the work has to marked as dirty. void PwMDoc::sync_setModified() { flagDirty(); } //called by the syncmanager to ask if the dirty flag is set. bool PwMDoc::sync_isModified() { return isDirty(); } //called by the syncmanager to indicate that the work has to be saved. void PwMDoc::sync_save() { saveDoc(conf()->confGlobCompression()); } #endif bool PwMDoc::findSyncData(const QString &syncname, unsigned int *index) { vector<PwMSyncItem>::iterator i = dti.syncDta.begin(), end = dti.syncDta.end(); while (i != end) { if ((*i).syncName == syncname.latin1()) { if (index) { *index = i - dti.syncDta.begin(); } return true; } ++i; } return false; }; /** add new syncdataentry */ PwMerror PwMDoc::addSyncDataEntry(PwMSyncItem *d, bool dontFlagDirty) { PWM_ASSERT(d); if (isDeepLocked()) { PwMerror ret; ret = deepLock(false); if (ret != e_success) return e_lock; } unsigned int index; const QString tmp = d->syncName.c_str(); bool exists = findSyncData(d->syncName.c_str(), &index); if (exists == true) { // DOH! We found this entry. return e_entryExists; } dti.syncDta.push_back(*d); if (!dontFlagDirty) flagDirty(); return e_success; } /** delete syncdata entry */ bool PwMDoc::delSyncDataEntry(unsigned int index, bool dontFlagDirty) { if (isDeepLocked()) return false; if (index > dti.syncDta.size() - 1) return false; // delete entry dti.syncDta.erase(dti.syncDta.begin() + index); if (!dontFlagDirty) flagDirty(); return true; } PwMDataItem* PwMDoc::findEntryByID(const QString &uid, unsigned int *category, unsigned int *index) { vector<PwMCategoryItem>::iterator catcounter = dti.dta.begin(), catend = dti.dta.end(); vector<PwMDataItem>::iterator entrBegin, entrEnd, entrI; while (catcounter != catend) { entrBegin = catcounter->d.begin(); entrEnd = catcounter->d.end(); entrI = entrBegin; while (entrI != entrEnd) { if ((*entrI).meta.uniqueid == uid.latin1()) { if (category) *category = catcounter - dti.dta.begin(); if (index) *index = entrI - entrBegin; return &(*entrI); } ++entrI; } ++catcounter; } return 0; } QStringList PwMDoc::getIDEntryList() { QStringList results; vector<PwMCategoryItem>::iterator catcounter = dti.dta.begin(), catend = dti.dta.end(); vector<PwMDataItem>::iterator entrBegin, entrEnd, entrI; while (catcounter != catend) { entrBegin = catcounter->d.begin(); entrEnd = catcounter->d.end(); entrI = entrBegin; while (entrI != entrEnd) { results.append( (*entrI).meta.uniqueid ); ++entrI; } ++catcounter; } return results; } #ifndef PWM_EMBEDDED #include "pwmdoc.moc" #endif |