summaryrefslogtreecommitdiffabout
Side-by-side diff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--kabc/plugins/file/resourcefile.cpp49
-rw-r--r--kabc/plugins/file/resourcefile.h1
-rw-r--r--pwmanager/pwmanager/pwmdoc.cpp45
3 files changed, 93 insertions, 2 deletions
diff --git a/kabc/plugins/file/resourcefile.cpp b/kabc/plugins/file/resourcefile.cpp
index 2bd9e71..c89939d 100644
--- a/kabc/plugins/file/resourcefile.cpp
+++ b/kabc/plugins/file/resourcefile.cpp
@@ -1,433 +1,478 @@
/*
This file is part of libkabc.
Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
/*
Enhanced Version of the file for platform independent KDE tools.
Copyright (c) 2004 Ulf Schenk
$Id$
*/
#include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32_
#include <unistd.h>
#endif
#include <qfile.h>
#include <qfileinfo.h>
#include <qregexp.h>
#include <qtimer.h>
#include <kapplication.h>
#include <kconfig.h>
#include <kdebug.h>
#include <klocale.h>
//US #include <ksavefile.h>
#include <kstandarddirs.h>
#include <kmessagebox.h>
+#include <kglobalsettings.h>
#include "formatfactory.h"
#include "resource.h"
#include "resourcefileconfig.h"
#include "stdaddressbook.h"
#define NO_DIRWATCH
#include "resourcefile.h"
//#define ALLOW_LOCKING
using namespace KABC;
extern "C"
#ifdef _WIN32_
__declspec(dllexport)
#else
{
#endif
//US void *init_kabc_file()
void *init_microkabc_file()
{
return new KRES::PluginFactory<ResourceFile,ResourceFileConfig>();
}
#ifndef _WIN32_
}
#endif
ResourceFile::ResourceFile( const KConfig *config )
: Resource( config ) , mFormat( 0 )
{
QString fileName, formatName, default_fileName;
default_fileName = StdAddressBook::fileName();
-
+ mLastBackupDate = -1;
KConfig *cfg = (KConfig *)config;
if ( cfg ) {
fileName = cfg->readEntry( "FileName", default_fileName );
formatName = cfg->readEntry( "FileFormat", "vcard" );
mFamily = cfg->readEntry( "ResourceName", "std" );
+ mLastBackupDate = cfg->readNumEntry( "LastBackupDate", 0 );
} else {
fileName = default_fileName;
formatName = "vcard";
}
init( fileName, formatName );
}
ResourceFile::ResourceFile( const QString &fileName ,
const QString &formatName )
: Resource( 0 )
{
// qDebug("ResourceFile::ResourceFile : 3 %s, %s", fileName.latin1(), formatName.latin1());
-
+ mLastBackupDate = -1;
init( fileName, formatName );
}
void ResourceFile::init( const QString &fileName, const QString &formatName )
{
mFormatName = formatName;
FormatFactory *factory = FormatFactory::self();
mFormat = factory->format( mFormatName );
if ( !mFormat ) {
mFormatName = "vcard";
mFormat = factory->format( mFormatName );
}
#ifndef NO_DIRWATCH
connect( &mDirWatch, SIGNAL( dirty(const QString&) ), SLOT( fileChanged() ) );
connect( &mDirWatch, SIGNAL( created(const QString&) ), SLOT( fileChanged() ) );
connect( &mDirWatch, SIGNAL( deleted(const QString&) ), SLOT( fileChanged() ) );
#endif
QString localKdeDir;
localKdeDir = readEnvPath("LOCALMICROKDEHOME");
if ( ! localKdeDir.isEmpty() ) {
qDebug("LOCALMICROKDEHOME is set to: %s",localKdeDir.latin1() );
QFileInfo fi ( fileName );
QString localname = localKdeDir + "/apps/kabc/" + fi.fileName ();
QFileInfo fi2 ( localname );
if ( ! fi2.exists() || mFamily == "sync_res" ) {
if ( fi.exists() && mFamily == "sync_res") {
qDebug("LOCAL mode SYNC mode using absolute file path ");
setFileName( fileName );
return;
} else {
KMessageBox::error(0,i18n("Addressbook resource file not found:\n '%1'.\nIn LOCAL mode only resource files in\n'%2'\nare supported.\n(i.e. in the dir ./apps/kabc/ relative to the kapi(.exe) binary.)\n\nIf you are starting KA/Pi for the very first time\nyou will get this error message as well.\nIt will create the missing file automatically for you.").arg(localname).arg(localKdeDir+"/apps/kabc/") );
setFileName( localname );
return;
}
} else {
qDebug("Local resource file found. Changing filename to: %s",localname.latin1() );
setFileName( localname );
return;
}
}
setFileName( fileName );
}
ResourceFile::~ResourceFile()
{
delete mFormat;
mFormat = 0;
}
void ResourceFile::writeConfig( KConfig *config )
{
config->setGroup( "Resource_" + identifier() );
Resource::writeConfig( config );
config->writeEntry( "FileName", fileName() );
config->writeEntry( "FileFormat", mFormatName );
// qDebug("ResourceFile::writeConfig format %s, %s", mFileName.latin1(), mFormatName.latin1());
}
Ticket *ResourceFile::requestSaveTicket()
{
kdDebug(5700) << "ResourceFile::requestSaveTicket()" << endl;
if ( !addressBook() ) return 0;
#ifdef ALLOW_LOCKING
if ( !lock( mFileName ) ) {
qDebug("unablt to lock file ");
return 0;
}
#endif
return createTicket( this );
}
bool ResourceFile::doOpen()
{
QFile file( fileName() );
qDebug("ResourceFile::openfile %s ", fileName().latin1());
if ( !file.exists() ) {
// try to create the file
bool ok = file.open( IO_WriteOnly );
if ( ok )
file.close();
return ok;
} else {
if ( !file.open( IO_ReadWrite ) )
return false;
if ( file.size() < 10 ) {
file.close();
return true;
}
bool ok = mFormat->checkFormat( &file );
file.close();
return ok;
}
}
void ResourceFile::doClose()
{
}
bool ResourceFile::load()
{
QFile file( fileName() );
if ( !file.open( IO_ReadOnly ) ) {
addressBook()->error( i18n( "Unable to open file '%1'." ).arg( fileName() ) );
return false;
}
// qDebug("ResourceFile::load format %s, %s", mFileName.latin1(), mFormatName.latin1());
return mFormat->loadAll( addressBook(), this, &file );
}
bool ResourceFile::save( Ticket *ticket )
{
// qDebug("ResourceFile::save format %s, %s", mFileName.latin1(), mFormatName.latin1());
// create backup file
QString extension = "_" + QString::number( QDate::currentDate().dayOfWeek() );
/*US we use a simpler method to create a backupfile
(void) KSaveFile::backupFile( mFileName, QString::null
,extension );
KSaveFile saveFile( mFileName );
bool ok = false;
if ( saveFile.status() == 0 && saveFile.file() )
{
mFormat->saveAll( addressBook(), this, saveFile.file() );
ok = saveFile.close();
}
*/
//US ToDo: write backupfile
#ifndef NO_DIRWATCH
mDirWatch.stopScan();
#endif
+ if ( mLastBackupDate >= 0 && mFamily != "sync_res") {
+ KConfig conf (locateLocal("config","microkdeglobalrc"));
+ conf.setGroup( "BackupSettings" );
+ bool b_enabled = conf.readBoolEntry( "BackupEnabled" );
+ if ( b_enabled ) {
+ int num = conf.readNumEntry( "BackupNumbers" );
+ int d_count = conf.readNumEntry( "BackupDayCount" );
+ bool stdDir = conf.readBoolEntry( "BackupUseDefaultDir" );
+ QString bupDir = conf.readEntry( "BackupDatadir" );
+ QDate reference ( 2000,1,1 );
+ int daysTo = reference.daysTo ( QDate::currentDate() );
+ bool saveDate = false;
+ if ( daysTo - d_count >= mLastBackupDate ) {
+ qDebug("KA: Last backup was %d days ago ", daysTo - mLastBackupDate );
+ if ( stdDir )
+ bupDir = KGlobalSettings::backupDataDir();
+ int retval = KApplication::createBackup( fileName(), bupDir, num );
+ if ( retval == 0 ) {
+ qDebug("KO: Backup cancelled. Will try again tomorrow ");
+ // retval == 0 : backup skipped for today, try again tomorrow
+ mLastBackupDate = daysTo - d_count+1;
+ saveDate = true;
+ } else if ( retval == 1 ){
+ qDebug("KO: Backup created.");
+ // backup ok
+ mLastBackupDate = daysTo;
+ saveDate = true;
+ } else if ( retval == 2 ){
+ qDebug("KO: Backup globally cancelled.");
+ // backup globally cancelled
+ b_enabled = false;
+ }
+ if ( !b_enabled ) {
+ conf.writeEntry( "mBackupEnabled", false );
+ }
+ if ( saveDate ) {
+ KConfig config ( locateLocal("config","kabcrc") );
+ config.setGroup( "Resource_" + identifier() );
+ config.writeEntry( "LastBackupDate", mLastBackupDate );
+ }
+ }
+ }
+ }
QFile info;
info.setName( fileName() );
bool ok = info.open( IO_WriteOnly );
if ( ok ) {
mFormat->saveAll( addressBook(), this, &info );
info.close();
ok = true;
}
else {
}
if ( !ok )
addressBook()->error( i18n( "Unable to save file '%1'." ).arg( fileName() ) );
#ifndef NO_DIRWATCH
mDirWatch.startScan();
#endif
delete ticket;
#ifdef ALLOW_LOCKING
unlock( mFileName );
#endif
return ok;
}
bool ResourceFile::lock( const QString &fileName )
{
#ifdef ALLOW_LOCKING
QString fn = fileName;
//US change the implementation how the lockfilename is getting created
//US fn.replace( QRegExp("/"), "_" );
//US QString lockName = locateLocal( "data", "kabc/lock/" + fn + ".lock" );
KURL url(fn);
QString lockName = locateLocal( "data", "kabc/lock/" + url.fileName() + ".lock" );
if (QFile::exists( lockName )) return false;
QString lockUniqueName;
lockUniqueName = fn + KApplication::randomString( 8 );
url = lockUniqueName;
//US mLockUniqueName = locateLocal( "data", "kabc/lock/" + lockUniqueName );
mLockUniqueName = locateLocal( "data", "kabc/lock/" + url.fileName() );
kdDebug(5700) << "-- lock unique name: " << mLockUniqueName << endl;
// Create unique file
QFile file( mLockUniqueName );
file.open( IO_WriteOnly );
file.close();
// Create lock file
int result = 0;
#ifndef _WIN32_
result = ::link( QFile::encodeName( mLockUniqueName ),
QFile::encodeName( lockName ) );
#endif
if ( result == 0 ) {
addressBook()->emitAddressBookLocked();
return true;
}
// TODO: check stat
return false;
#else
return true;
#endif
}
void ResourceFile::unlock( const QString &fileName )
{
#ifdef ALLOW_LOCKING
QString fn = fileName;
//US change the implementation how the lockfilename is getting created
//US fn.replace( QRegExp( "/" ), "_" );
//US QString lockName = locateLocal( "data", "kabc/lock/" + fn + ".lock" );
//US QString lockName = fn + ".lock";
KURL url(fn);
QString lockName = locateLocal( "data", "kabc/lock/" + url.fileName() + ".lock" );
QFile::remove( lockName );
QFile::remove( mLockUniqueName );
addressBook()->emitAddressBookUnlocked();
#else
return;
#endif
}
void ResourceFile::setFileName( const QString &fileName )
{
#ifndef NO_DIRWATCH
mDirWatch.stopScan();
mDirWatch.removeFile( mFileName );
mFileName = fileName;
mDirWatch.addFile( mFileName );
mDirWatch.startScan();
#else
mFileName2 = fileName;
#endif
//US simulate KDirWatch event
//US fileChanged();
}
QString ResourceFile::fileName() const
{
return mFileName2;
}
void ResourceFile::setFormat( const QString &format )
{
mFormatName = format;
delete mFormat;
FormatFactory *factory = FormatFactory::self();
mFormat = factory->format( mFormatName );
/*US
//qDebug("ResourceFile::setFormat initialized with format %s ", format.latin1());
if (mFormatName == "vcard") {
mFormat = new VCardFormatPlugin2();
// qDebug("ResourceFile::setFormat format %s", mFormatName.latin1());
}
else if (mFormatName == "binary") {
mFormat = new BinaryFormat();
// qDebug("ResourceFile::setFormat format %s", mFormatName.latin1());
}
else
qDebug("ResourceFile::setFormat format unknown !!! %s ", format.latin1());
*/
}
QString ResourceFile::format() const
{
return mFormatName;
}
void ResourceFile::fileChanged()
{
// There is a small theoretical chance that KDirWatch calls us before
// we are fully constructed
if (!addressBook())
return;
QString text( i18n( "File resource '%1'<br> has been changed by third party.<br>Do you want to reload?").arg( fileName() ) );
if ( readOnly() || KMessageBox::questionYesNo( 0, text ) == KMessageBox::Yes ) {
load();
addressBook()->emitAddressBookChanged();
}
}
void ResourceFile::removeAddressee( const Addressee &addr )
{
QFile::remove( QFile::encodeName( locateLocal( "data", "kabc/photos/" ) + addr.uid() ) );
QFile::remove( QFile::encodeName( locateLocal( "data", "kabc/logos/" ) + addr.uid() ) );
QFile::remove( QFile::encodeName( locateLocal( "data", "kabc/sounds/" ) + addr.uid() ) );
}
void ResourceFile::cleanUp()
{
unlock( fileName() );
}
//US #include "resourcefile.moc"
diff --git a/kabc/plugins/file/resourcefile.h b/kabc/plugins/file/resourcefile.h
index 3e9edfc..61da154 100644
--- a/kabc/plugins/file/resourcefile.h
+++ b/kabc/plugins/file/resourcefile.h
@@ -1,164 +1,165 @@
/*
This file is part of libkabc.
Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
/*
Enhanced Version of the file for platform independent KDE tools.
Copyright (c) 2004 Ulf Schenk
$Id$
*/
#ifndef KABC_RESOURCEFILE_H
#define KABC_RESOURCEFILE_H
#include <kconfig.h>
#include <kdirwatch.h>
#include <sys/types.h>
#include <resource.h>
class QTimer;
class FormatPlugin;
namespace KABC {
//US class FormatPlugin;
class ResourceConfigWidget;
/**
@internal
*/
class ResourceFile : public Resource
{
Q_OBJECT
public:
/**
Constructor.
@param cfg The config object where custom resource settings are stored.
*/
ResourceFile( const KConfig *cfg );
/**
Construct file resource on file @arg fileName using format @arg formatName.
*/
ResourceFile( const QString &fileName , const QString &formatName = "vcard" );
/**
* Destructor.
*/
~ResourceFile();
/**
Writes the config back.
*/
virtual void writeConfig( KConfig *cfg );
/**
* Tries to open the file and checks for the proper format.
* This method should be called before @ref load().
*/
virtual bool doOpen();
/**
* Closes the file again.
*/
virtual void doClose();
/**
* Requests a save ticket, that is used by @ref save()
*/
virtual Ticket *requestSaveTicket();
/**
* Loads all addressees from file to the address book.
* Returns true if all addressees could be loaded otherwise false.
*/
virtual bool load();
/**
* Saves all addresses from address book to file.
* Returns true if all addressees could be saved otherwise false.
*
* @param ticket The ticket returned by @ref requestSaveTicket()
*/
virtual bool save( Ticket *ticket );
/**
* Set name of file to be used for saving.
*/
void setFileName( const QString & );
/**
* Return name of file used for loading and saving the address book.
*/
QString fileName() const;
/**
Sets a new format by name.
*/
void setFormat( const QString &name );
/**
Returns the format name.
*/
QString format() const;
/**
* Remove a addressee from its source.
* This method is mainly called by KABC::AddressBook.
*/
virtual void removeAddressee( const Addressee& addr );
/**
* This method is called by an error handler if the application
* crashed
*/
virtual void cleanUp();
protected slots:
void fileChanged();
protected:
void init( const QString &fileName, const QString &format );
bool lock( const QString &fileName );
void unlock( const QString &fileName );
private:
+ int mLastBackupDate;
QString mFamily;
QString mFileName2;
QString mFormatName;
FormatPlugin *mFormat;
QString mLockUniqueName;
#ifndef NO_DIRWATCH
KDirWatch mDirWatch;
#endif
};
}
#endif
diff --git a/pwmanager/pwmanager/pwmdoc.cpp b/pwmanager/pwmanager/pwmdoc.cpp
index 61f2616..36b0df5 100644
--- a/pwmanager/pwmanager/pwmdoc.cpp
+++ b/pwmanager/pwmanager/pwmdoc.cpp
@@ -1,1965 +1,2010 @@
/***************************************************************************
* *
* 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.1 of pwmanager
* and was modified to run on embedded devices that run microkde
*
* $Id$
**************************************************************************/
#include "pwmdoc.h"
#include "pwmview.h"
#include "blowfish.h"
#include "sha1.h"
#include "globalstuff.h"
#include "gpasmanfile.h"
#include "serializer.h"
#include "compressgzip.h"
//US#include "compressbzip2.h"
#include "randomizer.h"
#include "pwminit.h"
#include "libgcryptif.h"
#ifdef PWM_EMBEDDED
#include "pwmprefs.h"
#include "kglobal.h"
#endif
#include <kmessagebox.h>
+#include <kconfig.h>
+#include <kglobalsettings.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>
#ifndef _WIN32_
#include <unistd.h>
#include <stdint.h>
#endif
#ifdef PWM_EMBEDDED
#ifndef Q_LONG
#define Q_LONG long
#endif
#ifndef Q_ULONG
#define Q_ULONG unsigned long
#endif
#endif //PWM_EMBEDDED
//TODO: reset to its normal value.
//LR set to 5 min
#define META_CHECK_TIMER_INTERVAL 300 /* 10 300*/ /* sek */
using namespace std;
void PwMDocList::add(PwMDoc *doc, const string &id)
{
#ifdef PWM_DEBUG
// check for existance of object in debug mode only.
vector<listItem>::iterator begin = docList.begin(),
end = docList.end(),
i = begin;
while (i != end) {
if (i->doc == doc) {
BUG();
return;
}
++i;
}
#endif
listItem newItem;
newItem.doc = doc;
newItem.docId = id;
docList.push_back(newItem);
}
void PwMDocList::edit(PwMDoc *doc, const string &newId)
{
vector<listItem>::iterator begin = docList.begin(),
end = docList.end(),
i = begin;
while (i != end) {
if (i->doc == doc) {
i->docId = newId;
return;
}
++i;
}
}
void PwMDocList::del(PwMDoc *doc)
{
vector<listItem>::iterator begin = docList.begin(),
end = docList.end(),
i = begin;
while (i != end) {
if (i->doc == doc) {
docList.erase(i);
return;
}
++i;
}
}
bool PwMDocList::find(const string &id, listItem *ret)
{
vector<listItem>::iterator begin = docList.begin(),
end = docList.end(),
i = begin;
while (i != end) {
if (i->docId == id) {
if (ret)
*ret = *i;
return true;
}
++i;
}
return false;
}
DocTimer::DocTimer(PwMDoc *_doc)
: doc (_doc)
, mpwLock (0)
, autoLockLock (0)
, metaCheckLock (0)
{
mpwTimer = new QTimer;
autoLockTimer = new QTimer;
metaCheckTimer = new QTimer;
connect(mpwTimer, SIGNAL(timeout()),
this, SLOT(mpwTimeout()));
connect(autoLockTimer, SIGNAL(timeout()),
this, SLOT(autoLockTimeout()));
connect(metaCheckTimer, SIGNAL(timeout()),
this, SLOT(metaCheckTimeout()));
}
DocTimer::~DocTimer()
{
delete mpwTimer;
delete autoLockTimer;
delete metaCheckTimer;
}
void DocTimer::start(TimerIDs timer)
{
switch (timer) {
case id_mpwTimer:
if (mpwTimer->isActive())
mpwTimer->stop();
doc->setDocStatFlag(DOC_STAT_UNLOCK_WITHOUT_PW);
mpwTimer->start(conf()->confGlobPwTimeout() * 1000, true);
break;
case id_autoLockTimer:
if (autoLockTimer->isActive())
autoLockTimer->stop();
if (conf()->confGlobLockTimeout() > 0)
autoLockTimer->start(conf()->confGlobLockTimeout() * 1000, true);
break;
case id_metaCheckTimer:
if (metaCheckTimer->isActive())
metaCheckTimer->stop();
metaCheckTimer->start(META_CHECK_TIMER_INTERVAL * 1000, true);
break;
}
}
void DocTimer::stop(TimerIDs timer)
{
switch (timer) {
case id_mpwTimer:
mpwTimer->stop();
break;
case id_autoLockTimer:
autoLockTimer->stop();
break;
case id_metaCheckTimer:
metaCheckTimer->stop();
break;
}
}
void DocTimer::getLock(TimerIDs timer)
{
switch (timer) {
case id_mpwTimer:
++mpwLock;
break;
case id_autoLockTimer:
++autoLockLock;
break;
case id_metaCheckTimer:
++metaCheckLock;
break;
}
}
void DocTimer::putLock(TimerIDs timer)
{
switch (timer) {
case id_mpwTimer:
if (mpwLock)
--mpwLock;
break;
case id_autoLockTimer:
if (autoLockLock)
--autoLockLock;
break;
case id_metaCheckTimer:
if (metaCheckLock)
--metaCheckLock;
break;
}
}
void DocTimer::mpwTimeout()
{
if (mpwLock) {
mpwTimer->start(1000, true);
return;
}
doc->unsetDocStatFlag(DOC_STAT_UNLOCK_WITHOUT_PW);
}
void DocTimer::autoLockTimeout()
{
if (autoLockLock) {
autoLockTimer->start(1000, true);
return;
}
if (conf()->confGlobAutoDeepLock() &&
doc->filename != QString::null &&
doc->filename != "") {
doc->deepLock(true);
} else {
doc->lockAll(true);
}
}
void DocTimer::metaCheckTimeout()
{
if (metaCheckLock) {
// check again in one second.
metaCheckTimer->start(1000, true);
return;
}
if (doc->isDeepLocked()) {
metaCheckTimer->start(META_CHECK_TIMER_INTERVAL * 1000, true);
return;
}
if (doc->isDocEmpty()) {
metaCheckTimer->start(META_CHECK_TIMER_INTERVAL * 1000, true);
return;
}
#ifdef CONFIG_KWALLETIF
KWalletEmu *kwlEmu = doc->init->kwalletEmu();
if (kwlEmu)
kwlEmu->suspendDocSignals();
#endif // CONFIG_KWALLETIF
/* We simply trigger all views to update their
* displayed values. This way they have a chance
* to get notified when some meta changes over time.
* (for example an entry expired).
* The _view_ is responsive for not updating its
* contents if nothing really changed!
*/
emit doc->dataChanged(doc);
#ifdef CONFIG_KWALLETIF
if (kwlEmu)
kwlEmu->resumeDocSignals();
#endif // CONFIG_KWALLETIF
metaCheckTimer->start(META_CHECK_TIMER_INTERVAL * 1000, true);
}
PwMDocList PwMDoc::openDocList;
unsigned int PwMDocList::unnamedDocCnt = 1;
PwMDoc::PwMDoc(QObject *parent, const char *name)
: PwMDocUi(parent, name)
, dataChangedLock (0)
{
deleted = false;
unnamedNum = 0;
getOpenDocList()->add(this, getTitle().latin1());
curDocStat = 0;
setMaxNumEntries();
_timer = new DocTimer(this);
timer()->start(DocTimer::id_mpwTimer);
timer()->start(DocTimer::id_autoLockTimer);
timer()->start(DocTimer::id_metaCheckTimer);
addCategory(DEFAULT_CATEGORY, 0, false);
listView = 0;
emit docCreated(this);
}
PwMDoc::~PwMDoc()
{
emit docClosed(this);
getOpenDocList()->del(this);
delete _timer;
}
PwMerror PwMDoc::saveDoc(char compress, const QString *file)
{
PwMerror ret, e;
string serialized;
QFile f;
QString tmpFileMoved(QString::null);
bool wasDeepLocked;
QString savedFilename(filename);
if (!file) {
if (filename == "")
return e_filename;
if (isDeepLocked()) {
/* We don't need to save any data.
* It's already all on disk, because
* we are deeplocked.
*/
unsetDocStatFlag(DOC_STAT_DISK_DIRTY);
ret = e_success;
return ret;
}
} else {
if (*file == "" && filename == "")
return e_filename;
if (*file != "")
filename = *file;
}
wasDeepLocked = isDeepLocked();
if (wasDeepLocked) {
/* We are deeplocked. That means all data is already
* on disk. BUT we need to do saving procedure,
* because *file != savedFilename.
* Additionally we need to tempoarly restore
* the old "filename", because deepLock() references it.
*/
QString newFilename(filename);
filename = savedFilename;
getDataChangedLock();
e = deepLock(false);
putDataChangedLock();
filename = newFilename;
switch (e) {
case e_success:
break;
case e_wrongPw:
case e_noPw:
emitDataChanged(this);
return e;
default:
emitDataChanged(this);
return e_openFile;
}
}
if (!isPwAvailable()) {
/* password is not available. This means, the
* document wasn't saved, yet.
*/
bool useChipcard = getDocStatFlag(DOC_STAT_USE_CHIPCARD);
QString pw(requestNewMpw(&useChipcard));
if (pw != "") {
currentPw = pw;
} else {
return e_noPw;
}
if (useChipcard) {
setDocStatFlag(DOC_STAT_USE_CHIPCARD);
} else {
unsetDocStatFlag(DOC_STAT_USE_CHIPCARD);
}
}
int _cryptAlgo = conf()->confGlobCryptAlgo();
int _hashAlgo = conf()->confGlobHashAlgo();
// sanity check for the selected algorithms
if (_cryptAlgo < PWM_CRYPT_BLOWFISH ||
_cryptAlgo > PWM_CRYPT_TWOFISH128) {
printWarn("Invalid Crypto-Algorithm selected! "
"Config-file seems to be corrupt. "
"Falling back to Blowfish.");
_cryptAlgo = PWM_CRYPT_BLOWFISH;
}
if (_hashAlgo < PWM_HASH_SHA1 ||
_hashAlgo > PWM_HASH_TIGER) {
printWarn("Invalid Hash-Algorithm selected! "
"Config-file seems to be corrupt. "
"Falling back to SHA1.");
_hashAlgo = PWM_HASH_SHA1;
}
char cryptAlgo = static_cast<char>(_cryptAlgo);
char hashAlgo = static_cast<char>(_hashAlgo);
if (conf()->confGlobMakeFileBackup()) {
if (!backupFile(filename))
return e_fileBackup;
}
+ int mLastBackupDate = 0;
+ KConfig configGlobal (locateLocal("config","pwmanagerbuprc"));
+ QFileInfo fileInfo ( filename );
+ mLastBackupDate = configGlobal.readNumEntry( "LastBackupDate-"+ fileInfo.fileName (), 0 );
+ KConfig config (locateLocal("config","microkdeglobalrc"));
+ config.setGroup( "BackupSettings" );
+ bool b_enabled = config.readBoolEntry( "BackupEnabled" );
+ if ( b_enabled ) {
+ int num = config.readNumEntry( "BackupNumbers" );
+ int d_count = config.readNumEntry( "BackupDayCount" );
+ bool stdDir = config.readBoolEntry( "BackupUseDefaultDir" );
+ QString bupDir = config.readEntry( "BackupDatadir" );
+ QDate reference ( 2000,1,1 );
+ int daysTo = reference.daysTo ( QDate::currentDate() );
+ bool saveDate = false;
+ if ( daysTo - d_count >= mLastBackupDate ) {
+ qDebug("KA: Last backup was %d days ago ", daysTo - mLastBackupDate );
+ if ( stdDir )
+ bupDir = KGlobalSettings::backupDataDir();
+ int retval = KApplication::createBackup( filename, bupDir, num );
+ if ( retval == 0 ) {
+ qDebug("KO: Backup cancelled. Will try again tomorrow ");
+ // retval == 0 : backup skipped for today, try again tomorrow
+ mLastBackupDate = daysTo - d_count+1;
+ saveDate = true;
+ } else if ( retval == 1 ){
+ qDebug("KO: Backup created.");
+ // backup ok
+ mLastBackupDate = daysTo;
+ saveDate = true;
+ } else if ( retval == 2 ){
+ qDebug("KO: Backup globally cancelled.");
+ // backup globally cancelled
+ b_enabled = false;
+ }
+ if ( !b_enabled ) {
+ config.writeEntry( "mBackupEnabled", false );
+ }
+ if ( saveDate ) {
+ configGlobal.writeEntry( "LastBackupDate-"+ fileInfo.fileName (), mLastBackupDate );
+ }
+ }
+ }
if (QFile::exists(filename)) {
/* Move the existing file to some tmp file.
* When saving file succeeds, delete tmp file. Otherwise
* move tmp file back. See below.
*/
Randomizer *rnd = Randomizer::obj();
char rnd_buf[5];
sprintf(rnd_buf, "%X%X%X%X", rnd->genRndChar() & 0xFF, rnd->genRndChar() & 0xFF,
rnd->genRndChar() & 0xFF, rnd->genRndChar() & 0xFF);
tmpFileMoved = filename + "." + rnd_buf + ".mv";
if (!copyFile(filename, tmpFileMoved))
return e_openFile;
if (!QFile::remove(filename)) {
printWarn(string("removing orig file ")
+ filename.latin1()
+ " failed!");
}
}
f.setName(filename);
if (!f.open(IO_ReadWrite)) {
ret = e_openFile;
goto out_moveback;
}
e = writeFileHeader(hashAlgo, hashAlgo,
cryptAlgo, compress,
&currentPw, &f);
if (e == e_hashNotImpl) {
printDebug("PwMDoc::saveDoc(): writeFileHeader() failed: e_hashNotImpl");
f.close();
ret = e_hashNotImpl;
goto out_moveback;
} else if (e != e_success) {
printDebug("PwMDoc::saveDoc(): writeFileHeader() failed");
f.close();
ret = e_writeHeader;
goto out_moveback;
}
if (!serializeDta(&serialized)) {
printDebug("PwMDoc::saveDoc(): serializeDta() failed");
f.close();
ret = e_serializeDta;
goto out_moveback;
}
e = writeDataHash(hashAlgo, &serialized, &f);
if (e == e_hashNotImpl) {
printDebug("PwMDoc::saveDoc(): writeDataHash() failed: e_hashNotImpl");
f.close();
ret = e_hashNotImpl;
goto out_moveback;
} else if (e != e_success) {
printDebug("PwMDoc::saveDoc(): writeDataHash() failed");
f.close();
ret = e_writeHeader;
goto out_moveback;
}
if (!compressDta(&serialized, compress)) {
printDebug("PwMDoc::saveDoc(): compressDta() failed");
f.close();
ret = e_enc;
goto out_moveback;
}
e = encrypt(&serialized, &currentPw, &f, cryptAlgo, hashAlgo);
if (e == e_weakPw) {
printDebug("PwMDoc::saveDoc(): encrypt() failed: e_weakPw");
f.close();
ret = e_weakPw;
goto out_moveback;
} else if (e == e_cryptNotImpl) {
printDebug("PwMDoc::saveDoc(): encrypt() failed: e_cryptNotImpl");
f.close();
ret = e_cryptNotImpl;
goto out_moveback;
} else if (e != e_success) {
printDebug("PwMDoc::saveDoc(): encrypt() failed");
f.close();
ret = e_enc;
goto out_moveback;
}
unsetDocStatFlag(DOC_STAT_DISK_DIRTY);
f.close();
#ifndef _WIN32_
if (chmod(filename.latin1(),
conf()->confGlobFilePermissions())) {
printWarn(string("chmod failed: ") + strerror(errno));
}
#endif
openDocList.edit(this, getTitle().latin1());
if (wasDeepLocked) {
/* Do _not_ save the data with the deepLock()
* call, because this will recurse
* into saveDoc()
*/
deepLock(true, false);
/* We don't check return value here, because
* it won't fail. See NOTE in deepLock()
*/
}
if (tmpFileMoved != QString::null) {
// now remove the moved file.
if (!QFile::remove(tmpFileMoved)) {
printWarn(string("removing file ")
+ tmpFileMoved.latin1()
+ " failed!");
}
}
ret = e_success;
printDebug(string("writing file { name: ")
+ filename.latin1() + " compress: "
+ tostr(static_cast<int>(compress)) + " cryptAlgo: "
+ tostr(static_cast<int>(cryptAlgo)) + " hashAlgo: "
+ tostr(static_cast<int>(hashAlgo))
+ " }");
goto out;
out_moveback:
if (tmpFileMoved != QString::null) {
if (copyFile(tmpFileMoved, filename)) {
if (!QFile::remove(tmpFileMoved)) {
printWarn(string("removing tmp file ")
+ filename.latin1()
+ " failed!");
}
} else {
printWarn(string("couldn't copy file ")
+ tmpFileMoved.latin1()
+ " back to "
+ filename.latin1());
}
}
out:
return ret;
}
PwMerror PwMDoc::openDoc(const QString *file, int openLocked)
{
PWM_ASSERT(file);
PWM_ASSERT(openLocked == 0 || openLocked == 1 || openLocked == 2);
string decrypted, dataHash;
PwMerror ret;
char cryptAlgo, dataHashType, compress;
unsigned int headerLen;
if (*file == "")
return e_readFile;
filename = *file;
/* check if this file is already open.
* This does not catch symlinks!
*/
if (!isDeepLocked()) {
if (getOpenDocList()->find(filename.latin1()))
return e_alreadyOpen;
}
QFile f(filename);
if (openLocked == 2) {
// open deep-locked
if (!QFile::exists(filename))
return e_openFile;
if (deepLock(true, false) != e_success)
return e_openFile;
goto out_success;
}
if (!f.open(IO_ReadOnly))
return e_openFile;
ret = checkHeader(&cryptAlgo, &currentPw, &compress, &headerLen,
&dataHashType, &dataHash, &f);
if (ret != e_success) {
printDebug("PwMDoc::openDoc(): checkHeader() failed");
f.close();
if (ret == e_wrongPw) {
wrongMpwMsgBox(getDocStatFlag(DOC_STAT_USE_CHIPCARD));
return ret;
} else if (ret == e_noPw ||
ret == e_fileVer ||
ret == e_fileFormat ||
ret == e_hashNotImpl) {
return ret;
} else
return e_readFile;
}
ret = decrypt(&decrypted, headerLen, &currentPw, cryptAlgo, dataHashType, &f);
if (ret == e_cryptNotImpl) {
printDebug("PwMDoc::openDoc(): decrypt() failed: e_cryptNotImpl");
f.close();
return e_cryptNotImpl;
} else if (ret != e_success) {
printDebug("PwMDoc::openDoc(): decrypt() failed");
f.close();
return e_readFile;
}
if (!decompressDta(&decrypted, compress)) {
printDebug("PwMDoc::openDoc(): decompressDta() failed");
f.close();
return e_fileCorrupt;
}
ret = checkDataHash(dataHashType, &dataHash, &decrypted);
if (ret == e_hashNotImpl) {
printDebug("PwMDoc::openDoc(): checkDataHash() failed: e_hashNotImpl");
f.close();
return e_hashNotImpl;
} else if (ret != e_success) {
printDebug("PwMDoc::openDoc(): checkDataHash() failed");
f.close();
return e_fileCorrupt;
}
if (!deSerializeDta(&decrypted, openLocked == 1)) {
printDebug("PwMDoc::openDoc(): deSerializeDta() failed");
f.close();
return e_readFile;
}
f.close();
timer()->start(DocTimer::id_mpwTimer);
timer()->start(DocTimer::id_autoLockTimer);
out_success:
openDocList.edit(this, getTitle().latin1());
emit docOpened(this);
return e_success;
}
PwMerror PwMDoc::writeFileHeader(char keyHash, char dataHash, char crypt, char compress,
QString *pw, QFile *f)
{
PWM_ASSERT(pw);
PWM_ASSERT(f);
//US ENH: or maybe a bug: checking here for listView does not make sense because we do not check anywhere else
//Wenn I sync, I open a doc without a view => listView is 0 => Assertion
//US PWM_ASSERT(listView);
if (f->writeBlock(FILE_ID_HEADER, strlen(FILE_ID_HEADER)) !=
static_cast<Q_LONG>(strlen(FILE_ID_HEADER))) {
return e_writeFile;
}
if (f->putch(PWM_FILE_VER) == -1 ||
f->putch(keyHash) == -1 ||
f->putch(dataHash) == -1 ||
f->putch(crypt) == -1 ||
f->putch(compress) == -1 ||
f->putch((getDocStatFlag(DOC_STAT_USE_CHIPCARD)) ?
(static_cast<char>(0x01)) : (static_cast<char>(0x00))) == -1) {
return e_writeFile;
}
// write bytes of NUL-data. These bytes are reserved for future-use.
const int bufSize = 64;
char tmp_buf[bufSize];
memset(tmp_buf, 0x00, bufSize);
if (f->writeBlock(tmp_buf, bufSize) != bufSize)
return e_writeFile;
switch (keyHash) {
case PWM_HASH_SHA1: {
const int hashlen = SHA1_HASH_LEN_BYTE;
Sha1 hash;
hash.sha1_write(reinterpret_cast<const byte *>(pw->latin1()), pw->length());
string ret = hash.sha1_read();
if (f->writeBlock(ret.c_str(), hashlen) != hashlen)
return e_writeFile;
break;
}
case PWM_HASH_SHA256:
/*... fall through */
case PWM_HASH_SHA384:
case PWM_HASH_SHA512:
case PWM_HASH_MD5:
case PWM_HASH_RMD160:
case PWM_HASH_TIGER:
{
if (!LibGCryptIf::available())
return e_hashNotImpl;
LibGCryptIf gc;
PwMerror err;
unsigned char *buf;
size_t hashLen;
err = gc.hash(&buf,
&hashLen,
reinterpret_cast<const unsigned char *>(pw->latin1()),
pw->length(),
keyHash);
if (err != e_success)
return e_hashNotImpl;
if (f->writeBlock(reinterpret_cast<const char *>(buf), hashLen)
!= static_cast<Q_LONG>(hashLen)) {
delete [] buf;
return e_hashNotImpl;
}
delete [] buf;
break;
}
default: {
return e_hashNotImpl;
} }
return e_success;
}
PwMerror PwMDoc::checkHeader(char *cryptAlgo, QString *pw, char *compress,
unsigned int *headerLength, char *dataHashType,
string *dataHash, QFile *f)
{
PWM_ASSERT(cryptAlgo);
PWM_ASSERT(pw);
PWM_ASSERT(headerLength);
PWM_ASSERT(dataHashType);
PWM_ASSERT(dataHash);
PWM_ASSERT(f);
int tmpRet;
// check "magic" header
const char magicHdr[] = FILE_ID_HEADER;
const int hdrLen = array_size(magicHdr) - 1;
char tmp[hdrLen];
if (f->readBlock(tmp, hdrLen) != hdrLen)
return e_readFile;
if (memcmp(tmp, magicHdr, hdrLen) != 0)
return e_fileFormat;
// read and check file ver
int fileV = f->getch();
if (fileV == -1)
return e_fileFormat;
if (fileV != PWM_FILE_VER)
return e_fileVer;
// read hash hash type
int keyHash = f->getch();
if (keyHash == -1)
return e_fileFormat;
// read data hash type
tmpRet = f->getch();
if (tmpRet == -1)
return e_fileFormat;
*dataHashType = tmpRet;
// read crypt algo
tmpRet = f->getch();
if (tmpRet == -1)
return e_fileFormat;
*cryptAlgo = tmpRet;
// get compression-algo
tmpRet = f->getch();
if (tmpRet == -1)
return e_fileFormat;
*compress = tmpRet;
// get the MPW-flag
int mpw_flag = f->getch();
if (mpw_flag == -1)
return e_fileFormat;
if (mpw_flag == 0x01)
setDocStatFlag(DOC_STAT_USE_CHIPCARD);
else
unsetDocStatFlag(DOC_STAT_USE_CHIPCARD);
// skip the "RESERVED"-bytes
if (!(f->at(f->at() + 64)))
return e_fileFormat;
*pw = requestMpw(getDocStatFlag(DOC_STAT_USE_CHIPCARD));
if (*pw == "") {
/* the user didn't give a master-password
* or didn't insert a chipcard
*/
return e_noPw;
}
// verify key-hash
switch (keyHash) {
case PWM_HASH_SHA1: {
// read hash from header
const int hashLen = SHA1_HASH_LEN_BYTE;
string readHash;
int i;
for (i = 0; i < hashLen; ++i)
readHash.push_back(f->getch());
Sha1 hash;
hash.sha1_write(reinterpret_cast<const byte *>(pw->latin1()), pw->length());
string ret = hash.sha1_read();
if (ret != readHash)
return e_wrongPw; // hash doesn't match (wrong key)
break;
}
case PWM_HASH_SHA256:
/*... fall through */
case PWM_HASH_SHA384:
case PWM_HASH_SHA512:
case PWM_HASH_MD5:
case PWM_HASH_RMD160:
case PWM_HASH_TIGER: {
if (!LibGCryptIf::available())
return e_hashNotImpl;
LibGCryptIf gc;
PwMerror err;
unsigned char *buf;
size_t hashLen;
err = gc.hash(&buf,
&hashLen,
reinterpret_cast<const unsigned char *>(pw->latin1()),
pw->length(),
keyHash);
if (err != e_success)
return e_hashNotImpl;
string calcHash(reinterpret_cast<const char *>(buf),
static_cast<string::size_type>(hashLen));
delete [] buf;
// read hash from header
string readHash;
size_t i;
for (i = 0; i < hashLen; ++i)
readHash.push_back(f->getch());
if (calcHash != readHash)
return e_wrongPw; // hash doesn't match (wrong key)
break;
}
default: {
return e_hashNotImpl;
} }
// read the data-hash from the file
unsigned int hashLen, i;
switch (*dataHashType) {
case PWM_HASH_SHA1:
hashLen = SHA1_HASH_LEN_BYTE;
break;
case PWM_HASH_SHA256:
/*... fall through */
case PWM_HASH_SHA384:
case PWM_HASH_SHA512:
case PWM_HASH_MD5:
case PWM_HASH_RMD160:
case PWM_HASH_TIGER: {
if (!LibGCryptIf::available())
return e_hashNotImpl;
LibGCryptIf gc;
hashLen = gc.hashLength(*dataHashType);
if (hashLen == 0)
return e_hashNotImpl;
break;
}
default:
return e_hashNotImpl;
}
*dataHash = "";
for (i = 0; i < hashLen; ++i) {
tmpRet = f->getch();
if (tmpRet == -1)
return e_fileFormat;
dataHash->push_back(static_cast<char>(tmpRet));
}
*headerLength = f->at();
#ifndef PWM_EMBEDDED
printDebug(string("opening file { compress: ")
+ tostr(static_cast<int>(*compress)) + " cryptAlgo: "
+ tostr(static_cast<int>(*cryptAlgo)) + " keyHashAlgo: "
+ tostr(static_cast<int>(keyHash))
+ " }");
#else
printDebug(string("opening file { compress: ")
+ tostr((int)(*compress)) + " cryptAlgo: "
+ tostr((int)(*cryptAlgo)) + " keyHashAlgo: "
+ tostr((int)(keyHash))
+ " }");
#endif
return e_success;
}
PwMerror PwMDoc::writeDataHash(char dataHash, string *d, QFile *f)
{
PWM_ASSERT(d);
PWM_ASSERT(f);
switch (dataHash) {
case PWM_HASH_SHA1: {
const int hashLen = SHA1_HASH_LEN_BYTE;
Sha1 h;
h.sha1_write(reinterpret_cast<const byte *>(d->c_str()), d->size());
string hRet = h.sha1_read();
if (f->writeBlock(hRet.c_str(), hashLen) != hashLen)
return e_writeFile;
break;
}
case PWM_HASH_SHA256:
/*... fall through */
case PWM_HASH_SHA384:
case PWM_HASH_SHA512:
case PWM_HASH_MD5:
case PWM_HASH_RMD160:
case PWM_HASH_TIGER: {
if (!LibGCryptIf::available())
return e_hashNotImpl;
LibGCryptIf gc;
PwMerror err;
unsigned char *buf;
size_t hashLen;
err = gc.hash(&buf,
&hashLen,
reinterpret_cast<const unsigned char *>(d->c_str()),
d->size(),
dataHash);
if (err != e_success)
return e_hashNotImpl;
if (f->writeBlock(reinterpret_cast<const char *>(buf), hashLen)
!= static_cast<Q_LONG>(hashLen)) {
delete [] buf;
return e_hashNotImpl;
}
delete [] buf;
break;
}
default: {
return e_hashNotImpl;
} }
return e_success;
}
bool PwMDoc::backupFile(const QString &filePath)
{
QFileInfo fi(filePath);
if (!fi.exists())
return true; // Yes, true is correct.
QString pathOnly(fi.dirPath(true));
QString nameOnly(fi.fileName());
QString backupPath = pathOnly
+ "/~"
+ nameOnly
+ ".backup";
return copyFile(filePath, backupPath);
}
bool PwMDoc::copyFile(const QString &src, const QString &dst)
{
QFileInfo fi(src);
if (!fi.exists())
return false;
if (QFile::exists(dst)) {
if (!QFile::remove(dst))
return false;
}
QFile srcFd(src);
if (!srcFd.open(IO_ReadOnly))
return false;
QFile dstFd(dst);
if (!dstFd.open(IO_ReadWrite)) {
srcFd.close();
return false;
}
const int tmpBuf_size = 512;
char tmpBuf[tmpBuf_size];
Q_LONG bytesRead, bytesWritten;
while (!srcFd.atEnd()) {
bytesRead = srcFd.readBlock(tmpBuf,
static_cast<Q_ULONG>(tmpBuf_size));
if (bytesRead == -1) {
srcFd.close();
dstFd.close();
return false;
}
bytesWritten = dstFd.writeBlock(tmpBuf,
static_cast<Q_ULONG>(bytesRead));
if (bytesWritten != bytesRead) {
srcFd.close();
dstFd.close();
return false;
}
}
srcFd.close();
dstFd.close();
return true;
}
PwMerror PwMDoc::addEntry(const QString &category, PwMDataItem *d,
bool dontFlagDirty, bool updateMeta)
{
PWM_ASSERT(d);
unsigned int cat = 0;
if (isDeepLocked()) {
PwMerror ret;
ret = deepLock(false);
if (ret != e_success)
return e_lock;
}
addCategory(category, &cat);
if (numEntries(category) >= maxEntries)
return e_maxAllowedEntr;
vector<unsigned int> foundPositions;
/* historically this was:
* const int searchIn = SEARCH_IN_DESC | SEARCH_IN_NAME |
* SEARCH_IN_URL | SEARCH_IN_LAUNCHER;
* But for now we only search in desc.
* That's a tweak to be KWallet compatible. But it should not add
* usability-drop onto PwManager, does it?
* (And yes, "int" was a bug. Correct is "unsigned int")
*/
const unsigned int searchIn = SEARCH_IN_DESC;
findEntry(cat, *d, searchIn, &foundPositions, true);
if (foundPositions.size()) {
// DOH! We found this entry.
return e_entryExists;
}
d->listViewPos = -1;
d->lockStat = conf()->confGlobNewEntrLockStat();
if (updateMeta) {
d->meta.create = QDateTime::currentDateTime();
d->meta.update = d->meta.create;
}
dti.dta[cat].d.push_back(*d);
delAllEmptyCat(true);
if (!dontFlagDirty)
flagDirty();
return e_success;
}
PwMerror PwMDoc::addCategory(const QString &category, unsigned int *categoryIndex,
bool checkIfExist)
{
if (isDeepLocked()) {
PwMerror ret;
ret = deepLock(false);
if (ret != e_success)
return e_lock;
}
if (checkIfExist) {
if (findCategory(category, categoryIndex))
return e_categoryExists;
}
PwMCategoryItem item;
//US ENH: clear item to initialize with default values, or create a constructor
item.clear();
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;
}
PwMerror PwMDoc::getCommentByLvp_long(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) {
if (dti.dta[cat].d[i].binary)
return e_binEntry;
PwMCategoryItem* catItem = getCategoryEntry(cat);
QString retval;
QString tempval = QString (dti.dta[cat].d[i].desc.c_str());
if ( !tempval.isEmpty() ) {
retval += "<b>" +QString ( catItem->desc_text.c_str() )+ ":</b> "+ tempval+"<br>" ;
}
tempval = QString (dti.dta[cat].d[i].name.c_str());
if ( !tempval.isEmpty() ) {
retval += "<b>" +QString ( catItem->name_text.c_str() ) + ":</b> "+ tempval+"<br>" ;
}
tempval = QString (dti.dta[cat].d[i].pw.c_str());
if ( !tempval.isEmpty() ) {
if ( dti.dta[cat].d[i].lockStat )
retval += "<b>" +QString ( catItem->pw_text.c_str() )+ ": " + i18n("LOCKED") +"</b><br>" ;
else
retval += "<b>" +QString ( catItem->pw_text.c_str() )+ ":</b> " + tempval+"<br>" ;
}
tempval = QString (dti.dta[cat].d[i].url.c_str());
if ( !tempval.isEmpty() ) {
retval += "<b>" +i18n("URL:")+ "</b> " + tempval+"<br>" ;
}
tempval = QString (dti.dta[cat].d[i].launcher.c_str());
if ( !tempval.isEmpty() ) {
retval += "<b>" +i18n("Launcher:")+ "</b> " + tempval+"<br>" ;
}
tempval = QString (dti.dta[cat].d[i].comment.c_str());
if ( !tempval.isEmpty() ) {
tempval.replace(QRegExp ( "\n" ), "<br>" );
retval += "<b>" +i18n("Comment:")+ "</b><br>" + tempval+"<br>" ;
}
string ret ( retval.latin1() );
// *foundComment = dti.dta[cat].d[i].comment;
*foundComment = ret;
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);
}
#ifndef PWM_EMBEDDED
case PWM_COMPRESS_BZIP2: {
CompressBzip2 comp;
return comp.compress(d);
}
#endif
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);
}
#ifndef PWM_EMBEDDED
case PWM_COMPRESS_BZIP2: {
CompressBzip2 comp;
return comp.decompress(d);
}
#endif
case PWM_COMPRESS_NONE: {
return true;
}
}
return false;
}
PwMerror PwMDoc::encrypt(string *d, const QString *pw, QFile *f, char algo,
char hashalgo //US BUG: pass _hashalgo because we need it in hashPassphrase
)
{
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;
}
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,
hashalgo //US BUG: pass _hashalgo because we need it in hashPassphrase
);
delete [] plain;
if (err != e_success)
return e_cryptNotImpl;
break;
}
default: {
delete_ifnot_null_array(encrypted);
return e_cryptNotImpl;
} }
// write encrypted data to file
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;
}
delete_ifnot_null_array(encrypted);
return e_success;
}
PwMerror PwMDoc::decrypt(string *d, unsigned int pos, const QString *pw,
char algo,
char hashalgo, //US BUG: pass _hashalgo because we need it in hashPassphrase
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;
}
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,
hashalgo //US BUG: pass _hashalgo because we need it in hashPassphrase
);
if (err != e_success) {
delete [] encrypted;
delete [] decrypted;
return e_cryptNotImpl;
}
break;
}
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;
}
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;
}
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;
/* NOTE: saveDoc() depends on this function to return
* e_success if saveToFile == false
*/
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;
//US ENH: to initialize all members with meaningfull data.
d.clear();
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(&currentPw, &useChipcard);
if (pw == "")