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"