patch for KABC file plugin

Carsten Pfeiffer Carsten.Pfeiffer at alumni.TU-Berlin.DE
Sun Feb 19 12:48:07 GMT 2006


On Thu, Feb 16, 2006 at 05:49:01PM +0100, Carsten Pfeiffer wrote:

On Thursday 16 February 2006 17:49, Carsten Pfeiffer wrote:

Hi,

> Attached is a patch for the 3.5 branch. I'll also fix the net plugin later,
> which has similar issues.

here's a revisited patch, which adds further error handling, fixes usage of
KTempFile/KSaveFile and also covers the net plugin.

Note: I didn't care about binary compatibility, because I think that noone
uses these classes directly. Please correct me if I'm wrong.

Cheers,
Carsten
-------------- next part --------------
Index: plugins/file/resourcefile.cpp
===================================================================
--- plugins/file/resourcefile.cpp	(Revision 510236)
+++ plugins/file/resourcefile.cpp	(Arbeitskopie)
@@ -58,7 +58,7 @@ class ResourceFile::ResourceFilePrivate
 };
 
 ResourceFile::ResourceFile( const KConfig *config )
-  : Resource( config ), mFormat( 0 ), mLocalTempFile( 0 ),
+  : Resource( config ), mFormat( 0 ), mTempFile( 0 ),
     mAsynchronous( false ), d( new ResourceFilePrivate )
 {
   QString fileName, formatName;
@@ -76,7 +76,7 @@ ResourceFile::ResourceFile( const KConfi
 
 ResourceFile::ResourceFile( const QString &fileName,
                             const QString &formatName )
-  : Resource( 0 ), mFormat( 0 ), mLocalTempFile( 0 ),
+  : Resource( 0 ), mFormat( 0 ), mTempFile( 0 ),
     mAsynchronous( false ), d( new ResourceFilePrivate )
 {
   init( fileName, formatName );
@@ -119,8 +119,8 @@ ResourceFile::~ResourceFile()
   d = 0;
   delete mFormat;
   mFormat = 0;
-  delete mLocalTempFile;
-  mLocalTempFile = 0;
+
+  deleteLocalTempFile();
 }
 
 void ResourceFile::writeConfig( KConfig *config )
@@ -207,6 +207,10 @@ bool ResourceFile::load()
 {
   kdDebug(5700) << "ResourceFile::load(): '" << mFileName << "'" << endl;
 
+  if ( d->mIsLoading ) {
+    abortAsyncLoading();
+  }
+
   mAsynchronous = false;
 
   QFile file( mFileName );
@@ -215,24 +219,45 @@ bool ResourceFile::load()
     return false;
   }
 
-  return mFormat->loadAll( addressBook(), this, &file );
+  if ( !clearAndLoad( &file ) ) {
+      addressBook()->error( i18n( "Problems during parsing file '%1'." ).arg( mFileName ) );
+    return false;
+  }
+
+  return true;
+}
+
+bool ResourceFile::clearAndLoad( QFile *file )
+{
+  clear();
+  return mFormat->loadAll( addressBook(), this, file );
 }
 
 bool ResourceFile::asyncLoad()
 {
-  mAsynchronous = true;
+  if ( d->mIsLoading ) {
+    abortAsyncLoading();
+  }
 
-  if ( mLocalTempFile ) {
-    kdDebug(5700) << "stale temp file detected " << mLocalTempFile->name() << endl;
-    delete mLocalTempFile;
+  if (d->mIsSaving) {
+    kdWarning(5700) << "Aborted asyncSave() because we're still asyncSave()ing!" << endl;
+    return false;
   }
 
-  mLocalTempFile = new KTempFile();
-  mLocalTempFile->setAutoDelete( true );
-  mTempFile = mLocalTempFile->name();
+  mAsynchronous = true;
+
+  bool ok = createLocalTempFile();
+  if ( ok )
+    ok = mTempFile->close(); // we only need the filename
+
+  if ( !ok ) {
+    emit loadingError( this, i18n( "Unable to open file '%1'." ).arg( mTempFile->name() ) );
+    deleteLocalTempFile();
+    return false;
+  }
 
   KURL dest, src;
-  dest.setPath( mTempFile );
+  dest.setPath( mTempFile->name() );
   src.setPath( mFileName );
 
   KIO::Scheduler::checkSlaveOnHold( true );
@@ -244,26 +269,60 @@ bool ResourceFile::asyncLoad()
   return true;
 }
 
+void ResourceFile::abortAsyncLoading()
+{
+  kdDebug(5700) << "ResourceFile::abortAsyncLoading()" << endl;
+
+  if ( d->mLoadJob ) {
+    d->mLoadJob->kill(); // result not emitted
+    d->mLoadJob = 0;
+  }
+
+  deleteLocalTempFile();
+  d->mIsLoading = false;
+}
+
+void ResourceFile::abortAsyncSaving()
+{
+  kdDebug(5700) << "ResourceFile::abortAsyncSaving()" << endl;
+
+  if ( d->mSaveJob ) {
+    d->mSaveJob->kill(); // result not emitted
+    d->mSaveJob = 0;
+  }
+
+  deleteLocalTempFile();
+  d->mIsSaving = false;
+}
+
 bool ResourceFile::save( Ticket * )
 {
   kdDebug(5700) << "ResourceFile::save()" << endl;
 
+  if (d->mIsSaving) {
+    abortAsyncSaving();
+  }
+
   // create backup file
   QString extension = "_" + QString::number( QDate::currentDate().dayOfWeek() );
   (void) KSaveFile::backupFile( mFileName, QString::null /*directory*/,
                                 extension );
 
   mDirWatch.stopScan();
+
   KSaveFile saveFile( mFileName );
   bool ok = false;
-  if ( saveFile.status() == 0 && saveFile.file() )
-  {
-    mFormat->saveAll( addressBook(), this, saveFile.file() );
+
+  if ( saveFile.status() == 0 && saveFile.file() ) {
+    saveToFile( saveFile.file() );
     ok = saveFile.close();
   }
 
-  if ( !ok )
+  if ( !ok ) {
+    saveFile.abort();
     addressBook()->error( i18n( "Unable to save file '%1'." ).arg( mFileName ) );
+  }
+
   mDirWatch.startScan();
 
   return ok;
@@ -271,30 +330,70 @@ bool ResourceFile::save( Ticket * )
 
 bool ResourceFile::asyncSave( Ticket * )
 {
-  QFile file( mTempFile );
+  kdDebug(5700) << "ResourceFile::asyncSave()" << endl;
+
+  if (d->mIsSaving) {
+    abortAsyncSaving();
+  }
 
-  if ( !file.open( IO_WriteOnly ) ) {
-    emit savingError( this, i18n( "Unable to open file '%1'." ).arg( mTempFile ) );
+  if (d->mIsLoading) {
+    kdWarning(5700) << "Aborted asyncSave() because we're still asyncLoad()ing!" << endl;
     return false;
   }
 
-  mDirWatch.stopScan();
-  mFormat->saveAll( addressBook(), this, &file );
-  file.close();
+  bool ok = createLocalTempFile();
+  if ( ok ) {
+    saveToFile( mTempFile->file() );
+    ok = mTempFile->close();
+  }
+
+  if ( !ok ) {
+    emit savingError( this, i18n( "Unable to save file '%1'." ).arg( mTempFile->name() ) );
+    deleteLocalTempFile();
+    return false;
+  }
 
   KURL src, dest;
-  src.setPath( mTempFile );
+  src.setPath( mTempFile->name() );
   dest.setPath( mFileName );
 
   KIO::Scheduler::checkSlaveOnHold( true );
-  d->mSaveJob = KIO::file_copy( src, dest, -1, true, false, false );
   d->mIsSaving = true;
+  mDirWatch.stopScan(); // restarted in uploadFinished()
+  d->mSaveJob = KIO::file_copy( src, dest, -1, true, false, false );
   connect( d->mSaveJob, SIGNAL( result( KIO::Job* ) ),
            this, SLOT( uploadFinished( KIO::Job* ) ) );
 
   return true;
 }
 
+bool ResourceFile::createLocalTempFile()
+{
+  deleteStaleTempFile();
+  mTempFile = new KTempFile();
+  mTempFile->setAutoDelete( true );
+  return mTempFile->status() == 0;
+}
+
+void ResourceFile::deleteStaleTempFile()
+{
+  if ( hasTempFile() ) {
+    kdDebug(5700) << "stale temp file detected " << mTempFile->name() << endl;
+    deleteLocalTempFile();
+  }
+}
+
+void ResourceFile::deleteLocalTempFile()
+{
+  delete mTempFile;
+  mTempFile = 0;
+}
+
+void ResourceFile::saveToFile( QFile *file )
+{
+  mFormat->saveAll( addressBook(), this, file );
+}
+
 void ResourceFile::setFileName( const QString &fileName )
 {
   mDirWatch.stopScan();
@@ -328,10 +427,12 @@ QString ResourceFile::format() const
 
 void ResourceFile::fileChanged()
 {
+    kdDebug(5700) << "ResourceFile::fileChanged(): " << mFileName << endl;
+
   if ( !addressBook() )
     return;
 
-  clear();
+//  clear(); // moved to clearAndLoad()
   if ( mAsynchronous )
     asyncLoad();
   else {
@@ -352,31 +453,41 @@ void ResourceFile::removeAddressee( cons
 
 void ResourceFile::downloadFinished( KIO::Job* )
 {
+  kdDebug(5700) << "ResourceFile::downloadFinished()" << endl;
+
   d->mIsLoading = false;
 
-  if ( !mLocalTempFile )
+  if ( !hasTempFile() || mTempFile->status() != 0 ) {
     emit loadingError( this, i18n( "Download failed in some way!" ) );
-
-  QFile file( mTempFile );
-  if ( !file.open( IO_ReadOnly ) ) {
-    emit loadingError( this, i18n( "Unable to open file '%1'." ).arg( mTempFile ) );
     return;
   }
 
-  if ( !mFormat->loadAll( addressBook(), this, &file ) )
-    emit loadingError( this, i18n( "Problems during parsing file '%1'." ).arg( mTempFile ) );
-  else
+  QFile file( mTempFile->name() );
+  if ( file.open( IO_ReadOnly ) ) {
+    if ( clearAndLoad( &file ) )
     emit loadingFinished( this );
+    else
+      emit loadingError( this, i18n( "Problems during parsing file '%1'." ).arg( mTempFile->name() ) );
+  }
+  else {
+    emit loadingError( this, i18n( "Unable to open file '%1'." ).arg( mTempFile->name() ) );
+  }
+
+  deleteLocalTempFile();
 }
 
 void ResourceFile::uploadFinished( KIO::Job *job )
 {
+  kdDebug(5700) << "ResourceFile::uploadFinished()" << endl;
+
   d->mIsSaving = false;
 
   if ( job->error() )
     emit savingError( this, job->errorString() );
   else
     emit savingFinished( this );
+
+  deleteLocalTempFile();
   mDirWatch.startScan();
 }
 
Index: plugins/file/resourcefile.h
===================================================================
--- plugins/file/resourcefile.h	(Revision 510236)
+++ plugins/file/resourcefile.h	(Arbeitskopie)
@@ -28,8 +28,8 @@
 
 #include <kabc/resource.h>
 
+class QFile;
 class QTimer;
-
 class KTempFile;
 
 namespace KIO {
@@ -148,6 +148,15 @@ class KABC_EXPORT ResourceFile : public 
     void unlock( const QString &fileName );
 
   private:
+    bool clearAndLoad( QFile *file );
+    void saveToFile( QFile *file );
+    void abortAsyncLoading();
+    void abortAsyncSaving();
+    bool createLocalTempFile();
+    void deleteLocalTempFile();
+    void deleteStaleTempFile();
+    bool hasTempFile() const { return mTempFile != 0; }
+
     QString mFileName;
     QString mFormatName;
 
@@ -157,8 +166,7 @@ class KABC_EXPORT ResourceFile : public 
     
     KDirWatch mDirWatch;
 
-    QString mTempFile;
-    KTempFile *mLocalTempFile;
+    KTempFile *mTempFile;
 
     bool mAsynchronous;
 
Index: plugins/net/resourcenet.cpp
===================================================================
--- plugins/net/resourcenet.cpp	(Revision 510236)
+++ plugins/net/resourcenet.cpp	(Arbeitskopie)
@@ -24,6 +24,7 @@
 #include <kio/netaccess.h>
 #include <kio/scheduler.h>
 #include <klocale.h>
+#include <ksavefile.h>
 #include <ktempfile.h>
 #include <kurlrequester.h>
 
@@ -48,7 +49,7 @@ class ResourceNet::ResourceNetPrivate
 
 ResourceNet::ResourceNet( const KConfig *config )
   : Resource( config ), mFormat( 0 ),
-    mLocalTempFile( 0 ), mUseLocalTempFile( false ),
+    mTempFile( 0 ),
     d( new ResourceNetPrivate )
 {
   if ( config ) {
@@ -60,7 +61,7 @@ ResourceNet::ResourceNet( const KConfig 
 
 ResourceNet::ResourceNet( const KURL &url, const QString &format )
   : Resource( 0 ), mFormat( 0 ),
-    mLocalTempFile( 0 ), mUseLocalTempFile( false ),
+    mTempFile( 0 ),
     d( new ResourceNetPrivate )
 {
   init( url, format );
@@ -98,8 +99,7 @@ ResourceNet::~ResourceNet()
   delete mFormat;
   mFormat = 0;
 
-  delete mLocalTempFile;
-  mLocalTempFile = 0;
+  deleteLocalTempFile();
 }
 
 void ResourceNet::writeConfig( KConfig *config )
@@ -114,15 +114,11 @@ Ticket *ResourceNet::requestSaveTicket()
 {
   kdDebug(5700) << "ResourceNet::requestSaveTicket()" << endl;
 
-  if ( mTempFile.isEmpty() )
-    return 0;
-
   return createTicket( this );
 }
 
 void ResourceNet::releaseSaveTicket( Ticket *ticket )
 {
-  KIO::NetAccess::removeTempFile( mTempFile );
   delete ticket;
 }
 
@@ -137,41 +133,58 @@ void ResourceNet::doClose()
 
 bool ResourceNet::load()
 {
-  if ( !KIO::NetAccess::exists( mUrl, true, 0 ) ) {
-    mLocalTempFile = new KTempFile();
-    mLocalTempFile->setAutoDelete( true );
-    mUseLocalTempFile = true;
-    mTempFile = mLocalTempFile->name();
-  }
+  QString tempFile;
 
-  if ( !KIO::NetAccess::download( mUrl, mTempFile, 0 ) ) {
-    addressBook()->error( i18n( "Unable to download file '%1'." ).arg( mUrl.url() ) );
+  if ( !KIO::NetAccess::download( mUrl, tempFile, 0 ) ) {
+    addressBook()->error( i18n( "Unable to download file '%1'." ).arg( mUrl.prettyURL() ) );
     return false;
   }
 
-  QFile file( mTempFile );
+  QFile file( tempFile );
   if ( !file.open( IO_ReadOnly ) ) {
-    addressBook()->error( i18n( "Unable to open file '%1'." ).arg( mUrl.url() ) );
+    addressBook()->error( i18n( "Unable to open file '%1'." ).arg( tempFile ) );
+    KIO::NetAccess::removeTempFile( tempFile );
     return false;
   }
 
-  return mFormat->loadAll( addressBook(), this, &file );
+  bool result = clearAndLoad( &file );
+  if ( !result )
+      addressBook()->error( i18n( "Problems during parsing file '%1'." ).arg( tempFile ) );
+
+  KIO::NetAccess::removeTempFile( tempFile );
+  
+  return result;
+}
+
+bool ResourceNet::clearAndLoad( QFile *file )
+{
+  clear();
+  return mFormat->loadAll( addressBook(), this, file );
 }
 
 bool ResourceNet::asyncLoad()
 {
-  if ( mLocalTempFile ) {
-    kdDebug(5700) << "stale temp file detected " << mLocalTempFile->name() << endl;
-    mLocalTempFile->setAutoDelete( true );
-    delete mLocalTempFile;
+  if ( d->mIsLoading ) {
+    abortAsyncLoading();
+  }
+
+  if (d->mIsSaving) {
+    kdWarning(5700) << "Aborted asyncLoad() because we're still asyncSave()ing!" << endl;
+    return false;
   }
 
-  mLocalTempFile = new KTempFile();
-  mUseLocalTempFile = true;
-  mTempFile = mLocalTempFile->name();
+  bool ok = createLocalTempFile();
+  if ( ok )
+    ok = mTempFile->close();
+
+  if ( !ok ) {
+    emit loadingError( this, i18n( "Unable to open file '%1'." ).arg( mTempFile->name() ) );
+    deleteLocalTempFile();
+    return false;
+  }
 
   KURL dest;
-  dest.setPath( mTempFile );
+  dest.setPath( mTempFile->name() );
 
   KIO::Scheduler::checkSlaveOnHold( true );
   d->mLoadJob = KIO::file_copy( mUrl, dest, -1, true, false, false );
@@ -182,45 +195,125 @@ bool ResourceNet::asyncLoad()
   return true;
 }
 
+void ResourceNet::abortAsyncLoading()
+{
+  kdDebug(5700) << "ResourceNet::abortAsyncLoading()" << endl;
+
+  if ( d->mLoadJob ) {
+    d->mLoadJob->kill(); // result not emitted
+    d->mLoadJob = 0;
+  }
+
+  deleteLocalTempFile();
+  d->mIsLoading = false;
+}
+
+void ResourceNet::abortAsyncSaving()
+{
+  kdDebug(5700) << "ResourceNet::abortAsyncSaving()" << endl;
+
+  if ( d->mSaveJob ) {
+    d->mSaveJob->kill(); // result not emitted
+    d->mSaveJob = 0;
+  }
+  
+  deleteLocalTempFile();
+  d->mIsSaving = false;
+}
+
 bool ResourceNet::save( Ticket* )
 {
-  QFile file( mTempFile );
+  kdDebug(5700) << "ResourceNet::save()" << endl;
+
+  if (d->mIsSaving) {
+    abortAsyncSaving();
+  }
+
+  KTempFile tempFile;
+  tempFile.setAutoDelete( true );
+  bool ok = false;
+  
+  if ( tempFile.status() == 0 && tempFile.file() ) {
+    saveToFile( tempFile.file() );
+    ok = tempFile.close();
+  }
 
-  if ( !file.open( IO_WriteOnly ) ) {
-    addressBook()->error( i18n( "Unable to open file '%1'." ).arg( mUrl.url() ) );
+  if ( !ok ) {
+    addressBook()->error( i18n( "Unable to save file '%1'." ).arg( tempFile.name() ) );
     return false;
   }
 
-  mFormat->saveAll( addressBook(), this, &file );
-  file.close();
+  ok = KIO::NetAccess::upload( tempFile.name(), mUrl, 0 );
+  if ( !ok )
+    addressBook()->error( i18n( "Unable to upload to '%1'." ).arg( mUrl.prettyURL() ) );
 
-  return KIO::NetAccess::upload( mTempFile, mUrl, 0 );
+  return ok;
 }
 
 bool ResourceNet::asyncSave( Ticket* )
 {
-  QFile file( mTempFile );
+  kdDebug(5700) << "ResourceNet::asyncSave()" << endl;
 
-  if ( !file.open( IO_WriteOnly ) ) {
-    emit savingError( this, i18n( "Unable to open file '%1'." ).arg( mTempFile ) );
+  if (d->mIsSaving) {
+    abortAsyncSaving();
+  }
+
+  if (d->mIsLoading) {
+    kdWarning(5700) << "Aborted asyncSave() because we're still asyncLoad()ing!" << endl;
     return false;
   }
 
-  mFormat->saveAll( addressBook(), this, &file );
-  file.close();
+  bool ok = createLocalTempFile();
+  if ( ok ) {
+    saveToFile( mTempFile->file() );
+    ok = mTempFile->close();
+  }
+  
+  if ( !ok ) {
+    emit savingError( this, i18n( "Unable to save file '%1'." ).arg( mTempFile->name() ) );
+    deleteLocalTempFile();
+    return false;
+  }
 
   KURL src;
-  src.setPath( mTempFile );
+  src.setPath( mTempFile->name() );
 
   KIO::Scheduler::checkSlaveOnHold( true );
-  d->mSaveJob = KIO::file_copy( src, mUrl, -1, true, false, false );
   d->mIsSaving = true;
+  d->mSaveJob = KIO::file_copy( src, mUrl, -1, true, false, false );
   connect( d->mSaveJob, SIGNAL( result( KIO::Job* ) ),
            this, SLOT( uploadFinished( KIO::Job* ) ) );
 
   return true;
 }
 
+bool ResourceNet::createLocalTempFile()
+{
+  deleteStaleTempFile();
+  mTempFile = new KTempFile();
+  mTempFile->setAutoDelete( true );
+  return mTempFile->status() == 0;
+}
+
+void ResourceNet::deleteStaleTempFile()
+{
+  if ( hasTempFile() ) {
+    kdDebug(5700) << "stale temp file detected " << mTempFile->name() << endl;
+    deleteLocalTempFile();
+  }
+}
+
+void ResourceNet::deleteLocalTempFile()
+{
+  delete mTempFile;
+  mTempFile = 0;
+}
+
+void ResourceNet::saveToFile( QFile *file )
+{
+  mFormat->saveAll( addressBook(), this, file );
+}
+
 void ResourceNet::setUrl( const KURL &url )
 {
   mUrl = url;
@@ -248,31 +341,41 @@ QString ResourceNet::format() const
 
 void ResourceNet::downloadFinished( KIO::Job* )
 {
+  kdDebug(5700) << "ResourceNet::downloadFinished()" << endl;
+
   d->mIsLoading = false;
 
-  if ( !mLocalTempFile )
+  if ( !hasTempFile() || mTempFile->status() != 0 ) {
     emit loadingError( this, i18n( "Download failed in some way!" ) );
-
-  QFile file( mTempFile );
-  if ( !file.open( IO_ReadOnly ) ) {
-    emit loadingError( this, i18n( "Unable to open file '%1'." ).arg( mTempFile ) );
     return;
   }
 
-  if ( !mFormat->loadAll( addressBook(), this, &file ) )
-    emit loadingError( this, i18n( "Problems during parsing file '%1'." ).arg( mTempFile ) );
-  else
+  QFile file( mTempFile->name() );
+  if ( file.open( IO_ReadOnly ) ) {
+    if ( clearAndLoad( &file ) )
     emit loadingFinished( this );
+    else
+      emit loadingError( this, i18n( "Problems during parsing file '%1'." ).arg( mTempFile->name() ) );
+  }
+  else {
+    emit loadingError( this, i18n( "Unable to open file '%1'." ).arg( mTempFile->name() ) );
+  }
+
+  deleteLocalTempFile();
 }
 
 void ResourceNet::uploadFinished( KIO::Job *job )
 {
+  kdDebug(5700) << "ResourceFile::uploadFinished()" << endl;
+
   d->mIsSaving = false;
 
   if ( job->error() )
     emit savingError( this, job->errorString() );
   else
     emit savingFinished( this );
+
+  deleteLocalTempFile();
 }
 
 #include "resourcenet.moc"
Index: plugins/net/resourcenet.h
===================================================================
--- plugins/net/resourcenet.h	(Revision 510236)
+++ plugins/net/resourcenet.h	(Arbeitskopie)
@@ -27,6 +27,7 @@
 
 #include <kabc/resource.h>
 
+class QFile;
 class QTimer;
 class KTempFile;
 
@@ -91,13 +92,20 @@ class KABC_EXPORT ResourceNet : public R
     void uploadFinished( KIO::Job* );
 
   private:
+    bool clearAndLoad( QFile *file );
+    void saveToFile( QFile *file );
+    bool hasTempFile() const { return mTempFile != 0; }
+    void abortAsyncLoading();
+    void abortAsyncSaving();
+    bool createLocalTempFile();
+    void deleteLocalTempFile();
+    void deleteStaleTempFile();
+
     FormatPlugin *mFormat;
     QString mFormatName;
 
     KURL mUrl;
-    QString mTempFile;
-    KTempFile *mLocalTempFile;
-    bool mUseLocalTempFile;
+    KTempFile *mTempFile;
 
     class ResourceNetPrivate;
     ResourceNetPrivate *d;


More information about the kde-core-devel mailing list