resourcenet.cpp

00001 /*
00002     This file is part of libkabc.
00003     Copyright (c) 2003 Tobias Koenig <tokoe@kde.org>
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Library General Public
00007     License as published by the Free Software Foundation; either
00008     version 2 of the License, or (at your option) any later version.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014 
00015     You should have received a copy of the GNU Library General Public License
00016     along with this library; see the file COPYING.LIB.  If not, write to
00017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018     Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include <qfile.h>
00022 
00023 #include <kdebug.h>
00024 #include <kio/netaccess.h>
00025 #include <kio/scheduler.h>
00026 #include <klocale.h>
00027 #include <ksavefile.h>
00028 #include <ktempfile.h>
00029 #include <kurlrequester.h>
00030 
00031 #include "addressbook.h"
00032 #include "formatfactory.h"
00033 #include "resourcenetconfig.h"
00034 #include "stdaddressbook.h"
00035 
00036 #include "resourcenet.h"
00037 
00038 using namespace KABC;
00039 
00040 class ResourceNet::ResourceNetPrivate
00041 {
00042   public:
00043     KIO::Job *mLoadJob;
00044     bool mIsLoading;
00045 
00046     KIO::Job *mSaveJob;
00047     bool mIsSaving;
00048 
00049     QString mLastErrorString;
00050 };
00051 
00052 ResourceNet::ResourceNet( const KConfig *config )
00053   : Resource( config ), mFormat( 0 ),
00054     mTempFile( 0 ),
00055     d( new ResourceNetPrivate )
00056 {
00057   if ( config ) {
00058     init( KURL( config->readPathEntry( "NetUrl" ) ), config->readEntry( "NetFormat" ) );
00059   } else {
00060     init( KURL(), "vcard" );
00061   }
00062 }
00063 
00064 ResourceNet::ResourceNet( const KURL &url, const QString &format )
00065   : Resource( 0 ), mFormat( 0 ),
00066     mTempFile( 0 ),
00067     d( new ResourceNetPrivate )
00068 {
00069   init( url, format );
00070 }
00071 
00072 void ResourceNet::init( const KURL &url, const QString &format )
00073 {
00074   d->mLoadJob = 0;
00075   d->mIsLoading = false;
00076   d->mSaveJob = 0;
00077   d->mIsSaving = false;
00078 
00079   mFormatName = format;
00080 
00081   FormatFactory *factory = FormatFactory::self();
00082   mFormat = factory->format( mFormatName );
00083   if ( !mFormat ) {
00084     mFormatName = "vcard";
00085     mFormat = factory->format( mFormatName );
00086   }
00087 
00088   setUrl( url );
00089 }
00090 
00091 ResourceNet::~ResourceNet()
00092 {
00093   if ( d->mIsLoading )
00094     d->mLoadJob->kill();
00095   if ( d->mIsSaving )
00096     d->mSaveJob->kill();
00097 
00098   delete d;
00099   d = 0;
00100 
00101   delete mFormat;
00102   mFormat = 0;
00103 
00104   deleteLocalTempFile();
00105 }
00106 
00107 void ResourceNet::writeConfig( KConfig *config )
00108 {
00109   Resource::writeConfig( config );
00110 
00111   config->writePathEntry( "NetUrl", mUrl.url() );
00112   config->writeEntry( "NetFormat", mFormatName );
00113 }
00114 
00115 Ticket *ResourceNet::requestSaveTicket()
00116 {
00117   kdDebug(5700) << "ResourceNet::requestSaveTicket()" << endl;
00118 
00119   return createTicket( this );
00120 }
00121 
00122 void ResourceNet::releaseSaveTicket( Ticket *ticket )
00123 {
00124   delete ticket;
00125 }
00126 
00127 bool ResourceNet::doOpen()
00128 {
00129   return true;
00130 }
00131 
00132 void ResourceNet::doClose()
00133 {
00134 }
00135 
00136 bool ResourceNet::load()
00137 {
00138   QString tempFile;
00139     
00140   if ( !KIO::NetAccess::download( mUrl, tempFile, 0 ) ) {
00141     addressBook()->error( i18n( "Unable to download file '%1'." ).arg( mUrl.prettyURL() ) );
00142     return false;
00143   }
00144 
00145   QFile file( tempFile );
00146   if ( !file.open( IO_ReadOnly ) ) {
00147     addressBook()->error( i18n( "Unable to open file '%1'." ).arg( tempFile ) );
00148     KIO::NetAccess::removeTempFile( tempFile );
00149     return false;
00150   }
00151 
00152   bool result = clearAndLoad( &file );
00153   if ( !result )
00154       addressBook()->error( i18n( "Problems during parsing file '%1'." ).arg( tempFile ) );
00155 
00156   KIO::NetAccess::removeTempFile( tempFile );
00157   
00158   return result;
00159 }
00160 
00161 bool ResourceNet::clearAndLoad( QFile *file )
00162 {
00163   clear();
00164   return mFormat->loadAll( addressBook(), this, file );
00165 }
00166 
00167 bool ResourceNet::asyncLoad()
00168 {
00169   if ( d->mIsLoading ) {
00170     abortAsyncLoading();
00171   }
00172 
00173   if (d->mIsSaving) {
00174     kdWarning(5700) << "Aborted asyncLoad() because we're still asyncSave()ing!" << endl;
00175     return false;
00176   }
00177   
00178   bool ok = createLocalTempFile();
00179   if ( ok )
00180     ok = mTempFile->close();
00181 
00182   if ( !ok ) {
00183     emit loadingError( this, i18n( "Unable to open file '%1'." ).arg( mTempFile->name() ) );
00184     deleteLocalTempFile();
00185     return false;
00186   }
00187   
00188   KURL dest;
00189   dest.setPath( mTempFile->name() );
00190 
00191   KIO::Scheduler::checkSlaveOnHold( true );
00192   d->mLoadJob = KIO::file_copy( mUrl, dest, -1, true, false, false );
00193   d->mIsLoading = true;
00194   connect( d->mLoadJob, SIGNAL( result( KIO::Job* ) ),
00195            this, SLOT( downloadFinished( KIO::Job* ) ) );
00196 
00197   return true;
00198 }
00199 
00200 void ResourceNet::abortAsyncLoading()
00201 {
00202   kdDebug(5700) << "ResourceNet::abortAsyncLoading()" << endl;
00203 
00204   if ( d->mLoadJob ) {
00205     d->mLoadJob->kill(); // result not emitted
00206     d->mLoadJob = 0;
00207   }
00208 
00209   deleteLocalTempFile();
00210   d->mIsLoading = false;
00211 }
00212 
00213 void ResourceNet::abortAsyncSaving()
00214 {
00215   kdDebug(5700) << "ResourceNet::abortAsyncSaving()" << endl;
00216 
00217   if ( d->mSaveJob ) {
00218     d->mSaveJob->kill(); // result not emitted
00219     d->mSaveJob = 0;
00220   }
00221   
00222   deleteLocalTempFile();
00223   d->mIsSaving = false;
00224 }
00225 
00226 bool ResourceNet::save( Ticket* )
00227 {
00228   kdDebug(5700) << "ResourceNet::save()" << endl;
00229 
00230   if (d->mIsSaving) {
00231     abortAsyncSaving();
00232   }
00233 
00234   KTempFile tempFile;
00235   tempFile.setAutoDelete( true );
00236   bool ok = false;
00237   
00238   if ( tempFile.status() == 0 && tempFile.file() ) {
00239     saveToFile( tempFile.file() );
00240     ok = tempFile.close();
00241   }
00242   
00243   if ( !ok ) {
00244     addressBook()->error( i18n( "Unable to save file '%1'." ).arg( tempFile.name() ) );
00245     return false;
00246   }
00247 
00248   ok = KIO::NetAccess::upload( tempFile.name(), mUrl, 0 );
00249   if ( !ok )
00250     addressBook()->error( i18n( "Unable to upload to '%1'." ).arg( mUrl.prettyURL() ) );
00251   
00252   return ok;
00253 }
00254 
00255 bool ResourceNet::asyncSave( Ticket* )
00256 {
00257   kdDebug(5700) << "ResourceNet::asyncSave()" << endl;
00258 
00259   if (d->mIsSaving) {
00260     abortAsyncSaving();
00261   }
00262 
00263   if (d->mIsLoading) {
00264     kdWarning(5700) << "Aborted asyncSave() because we're still asyncLoad()ing!" << endl;
00265     return false;
00266   }
00267   
00268   bool ok = createLocalTempFile();
00269   if ( ok ) {
00270     saveToFile( mTempFile->file() );
00271     ok = mTempFile->close();
00272   }
00273   
00274   if ( !ok ) {
00275     emit savingError( this, i18n( "Unable to save file '%1'." ).arg( mTempFile->name() ) );
00276     deleteLocalTempFile();
00277     return false;
00278   }
00279 
00280   KURL src;
00281   src.setPath( mTempFile->name() );
00282 
00283   KIO::Scheduler::checkSlaveOnHold( true );
00284   d->mIsSaving = true;
00285   d->mSaveJob = KIO::file_copy( src, mUrl, -1, true, false, false );
00286   connect( d->mSaveJob, SIGNAL( result( KIO::Job* ) ),
00287            this, SLOT( uploadFinished( KIO::Job* ) ) );
00288 
00289   return true;
00290 }
00291 
00292 bool ResourceNet::createLocalTempFile()
00293 {
00294   deleteStaleTempFile();
00295   mTempFile = new KTempFile();
00296   mTempFile->setAutoDelete( true );
00297   return mTempFile->status() == 0;
00298 }
00299 
00300 void ResourceNet::deleteStaleTempFile()
00301 {
00302   if ( hasTempFile() ) {
00303     kdDebug(5700) << "stale temp file detected " << mTempFile->name() << endl;
00304     deleteLocalTempFile();
00305   }
00306 }
00307 
00308 void ResourceNet::deleteLocalTempFile()
00309 {
00310   delete mTempFile;
00311   mTempFile = 0;
00312 }
00313 
00314 void ResourceNet::saveToFile( QFile *file )
00315 {
00316   mFormat->saveAll( addressBook(), this, file );
00317 }
00318 
00319 void ResourceNet::setUrl( const KURL &url )
00320 {
00321   mUrl = url;
00322 }
00323 
00324 KURL ResourceNet::url() const
00325 {
00326   return mUrl;
00327 }
00328 
00329 void ResourceNet::setFormat( const QString &name )
00330 {
00331   mFormatName = name;
00332   if ( mFormat )
00333     delete mFormat;
00334 
00335   FormatFactory *factory = FormatFactory::self();
00336   mFormat = factory->format( mFormatName );
00337 }
00338 
00339 QString ResourceNet::format() const
00340 {
00341   return mFormatName;
00342 }
00343 
00344 void ResourceNet::downloadFinished( KIO::Job* )
00345 {
00346   kdDebug(5700) << "ResourceNet::downloadFinished()" << endl;
00347 
00348   d->mIsLoading = false;
00349 
00350   if ( !hasTempFile() || mTempFile->status() != 0 ) {
00351     d->mLastErrorString = i18n( "Download failed in some way!" );
00352     QTimer::singleShot( 0, this, SLOT( signalError() ) );
00353     return;
00354   }
00355 
00356   QFile file( mTempFile->name() );
00357   if ( file.open( IO_ReadOnly ) ) {
00358     if ( clearAndLoad( &file ) )
00359       emit loadingFinished( this );
00360     else
00361       emit loadingError( this, i18n( "Problems during parsing file '%1'." ).arg( mTempFile->name() ) );
00362   }
00363   else {
00364     emit loadingError( this, i18n( "Unable to open file '%1'." ).arg( mTempFile->name() ) );
00365   }
00366 
00367   deleteLocalTempFile();
00368 }
00369 
00370 void ResourceNet::uploadFinished( KIO::Job *job )
00371 {
00372   kdDebug(5700) << "ResourceFile::uploadFinished()" << endl;
00373 
00374   d->mIsSaving = false;
00375 
00376   if ( job->error() )
00377     emit savingError( this, job->errorString() );
00378   else
00379     emit savingFinished( this );
00380 
00381   deleteLocalTempFile();
00382 }
00383 
00384 void ResourceNet::signalError()
00385 {
00386   emit loadingError( this, d->mLastErrorString );
00387   d->mLastErrorString.truncate( 0 );
00388 }
00389 
00390 #include "resourcenet.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys