00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <signal.h>
00023 #include <sys/types.h>
00024 #include <sys/stat.h>
00025 #include <unistd.h>
00026
00027 #include <qfile.h>
00028 #include <qregexp.h>
00029 #include <qtimer.h>
00030
00031 #include <kapplication.h>
00032 #include <kconfig.h>
00033 #include <kdebug.h>
00034 #include <kio/scheduler.h>
00035 #include <klocale.h>
00036 #include <ksavefile.h>
00037 #include <kstandarddirs.h>
00038 #include <ktempfile.h>
00039
00040 #include "formatfactory.h"
00041 #include "resourcefileconfig.h"
00042 #include "stdaddressbook.h"
00043 #include "lock.h"
00044
00045 #include "resourcefile.h"
00046
00047 using namespace KABC;
00048
00049 class ResourceFile::ResourceFilePrivate
00050 {
00051 public:
00052 KIO::Job *mLoadJob;
00053 bool mIsLoading;
00054
00055 KIO::Job *mSaveJob;
00056 bool mIsSaving;
00057 };
00058
00059 ResourceFile::ResourceFile( const KConfig *config )
00060 : Resource( config ), mFormat( 0 ), mLocalTempFile( 0 ),
00061 mAsynchronous( false ), d( new ResourceFilePrivate )
00062 {
00063 QString fileName, formatName;
00064
00065 if ( config ) {
00066 fileName = config->readPathEntry( "FileName", StdAddressBook::fileName() );
00067 formatName = config->readEntry( "FileFormat", "vcard" );
00068 } else {
00069 fileName = StdAddressBook::fileName();
00070 formatName = "vcard";
00071 }
00072
00073 init( fileName, formatName );
00074 }
00075
00076 ResourceFile::ResourceFile( const QString &fileName,
00077 const QString &formatName )
00078 : Resource( 0 ), mFormat( 0 ), mLocalTempFile( 0 ),
00079 mAsynchronous( false ), d( new ResourceFilePrivate )
00080 {
00081 init( fileName, formatName );
00082 }
00083
00084 void ResourceFile::init( const QString &fileName, const QString &formatName )
00085 {
00086 d->mLoadJob = 0;
00087 d->mIsLoading = false;
00088 d->mSaveJob = 0;
00089 d->mIsSaving = false;
00090
00091 mFormatName = formatName;
00092
00093 FormatFactory *factory = FormatFactory::self();
00094 mFormat = factory->format( mFormatName );
00095
00096 if ( !mFormat ) {
00097 mFormatName = "vcard";
00098 mFormat = factory->format( mFormatName );
00099 }
00100
00101 connect( &mDirWatch, SIGNAL( dirty(const QString&) ), SLOT( fileChanged() ) );
00102 connect( &mDirWatch, SIGNAL( created(const QString&) ), SLOT( fileChanged() ) );
00103 connect( &mDirWatch, SIGNAL( deleted(const QString&) ), SLOT( fileChanged() ) );
00104
00105 setFileName( fileName );
00106
00107 mLock = 0;
00108 }
00109
00110 ResourceFile::~ResourceFile()
00111 {
00112 if ( d->mIsLoading )
00113 d->mLoadJob->kill();
00114 if ( d->mIsSaving )
00115 d->mSaveJob->kill();
00116
00117 delete d;
00118 d = 0;
00119 delete mFormat;
00120 mFormat = 0;
00121 delete mLocalTempFile;
00122 mLocalTempFile = 0;
00123 }
00124
00125 void ResourceFile::writeConfig( KConfig *config )
00126 {
00127 Resource::writeConfig( config );
00128
00129 if ( mFileName == StdAddressBook::fileName() )
00130 config->deleteEntry( "FileName" );
00131 else
00132 config->writePathEntry( "FileName", mFileName );
00133
00134 config->writeEntry( "FileFormat", mFormatName );
00135 }
00136
00137 Ticket *ResourceFile::requestSaveTicket()
00138 {
00139 kdDebug(5700) << "ResourceFile::requestSaveTicket()" << endl;
00140
00141 if ( !addressBook() ) return 0;
00142
00143 delete mLock;
00144 mLock = new Lock( mFileName );
00145
00146 if ( mLock->lock() ) {
00147 addressBook()->emitAddressBookLocked();
00148 } else {
00149 addressBook()->error( mLock->error() );
00150 kdDebug(5700) << "ResourceFile::requestSaveTicket(): Unable to lock file '"
00151 << mFileName << "': " << mLock->error() << endl;
00152 return 0;
00153 }
00154
00155 return createTicket( this );
00156 }
00157
00158 void ResourceFile::releaseSaveTicket( Ticket *ticket )
00159 {
00160 delete ticket;
00161
00162 delete mLock;
00163 mLock = 0;
00164
00165 addressBook()->emitAddressBookUnlocked();
00166 }
00167
00168 bool ResourceFile::doOpen()
00169 {
00170 QFile file( mFileName );
00171
00172 if ( !file.exists() ) {
00173
00174 bool ok = file.open( IO_WriteOnly );
00175 if ( ok )
00176 file.close();
00177
00178 return ok;
00179 } else {
00180 if ( readOnly() ) {
00181 if ( !file.open( IO_ReadOnly ) )
00182 return false;
00183 } else {
00184 if ( !file.open( IO_ReadWrite ) )
00185 return false;
00186 }
00187
00188 if ( file.size() == 0 ) {
00189 file.close();
00190 return true;
00191 }
00192
00193 bool ok = mFormat->checkFormat( &file );
00194 file.close();
00195
00196 return ok;
00197 }
00198 }
00199
00200 void ResourceFile::doClose()
00201 {
00202 }
00203
00204 bool ResourceFile::load()
00205 {
00206 kdDebug(5700) << "ResourceFile::load(): '" << mFileName << "'" << endl;
00207
00208 mAsynchronous = false;
00209
00210 QFile file( mFileName );
00211 if ( !file.open( IO_ReadOnly ) ) {
00212 addressBook()->error( i18n( "Unable to open file '%1'." ).arg( mFileName ) );
00213 return false;
00214 }
00215
00216 return mFormat->loadAll( addressBook(), this, &file );
00217 }
00218
00219 bool ResourceFile::asyncLoad()
00220 {
00221 mAsynchronous = true;
00222
00223 if ( mLocalTempFile ) {
00224 kdDebug(5700) << "stale temp file detected " << mLocalTempFile->name() << endl;
00225 delete mLocalTempFile;
00226 }
00227
00228 mLocalTempFile = new KTempFile();
00229 mLocalTempFile->setAutoDelete( true );
00230 mTempFile = mLocalTempFile->name();
00231
00232 KURL dest, src;
00233 dest.setPath( mTempFile );
00234 src.setPath( mFileName );
00235
00236 KIO::Scheduler::checkSlaveOnHold( true );
00237 d->mLoadJob = KIO::file_copy( src, dest, -1, true, false, false );
00238 d->mIsLoading = true;
00239 connect( d->mLoadJob, SIGNAL( result( KIO::Job* ) ),
00240 this, SLOT( downloadFinished( KIO::Job* ) ) );
00241
00242 return true;
00243 }
00244
00245 bool ResourceFile::save( Ticket * )
00246 {
00247 kdDebug(5700) << "ResourceFile::save()" << endl;
00248
00249
00250 QString extension = "_" + QString::number( QDate::currentDate().dayOfWeek() );
00251 (void) KSaveFile::backupFile( mFileName, QString::null ,
00252 extension );
00253
00254 mDirWatch.stopScan();
00255 KSaveFile saveFile( mFileName );
00256 bool ok = false;
00257 if ( saveFile.status() == 0 && saveFile.file() )
00258 {
00259 mFormat->saveAll( addressBook(), this, saveFile.file() );
00260 ok = saveFile.close();
00261 }
00262
00263 if ( !ok )
00264 addressBook()->error( i18n( "Unable to save file '%1'." ).arg( mFileName ) );
00265 mDirWatch.startScan();
00266
00267 return ok;
00268 }
00269
00270 bool ResourceFile::asyncSave( Ticket * )
00271 {
00272 QFile file( mTempFile );
00273
00274 if ( !file.open( IO_WriteOnly ) ) {
00275 emit savingError( this, i18n( "Unable to open file '%1'." ).arg( mTempFile ) );
00276 return false;
00277 }
00278
00279 mDirWatch.stopScan();
00280 mFormat->saveAll( addressBook(), this, &file );
00281 file.close();
00282
00283 KURL src, dest;
00284 src.setPath( mTempFile );
00285 dest.setPath( mFileName );
00286
00287 KIO::Scheduler::checkSlaveOnHold( true );
00288 d->mSaveJob = KIO::file_copy( src, dest, -1, true, false, false );
00289 d->mIsSaving = true;
00290 connect( d->mSaveJob, SIGNAL( result( KIO::Job* ) ),
00291 this, SLOT( uploadFinished( KIO::Job* ) ) );
00292
00293 return true;
00294 }
00295
00296 void ResourceFile::setFileName( const QString &fileName )
00297 {
00298 mDirWatch.stopScan();
00299 if ( mDirWatch.contains( mFileName ) )
00300 mDirWatch.removeFile( mFileName );
00301
00302 mFileName = fileName;
00303
00304 mDirWatch.addFile( mFileName );
00305 mDirWatch.startScan();
00306 }
00307
00308 QString ResourceFile::fileName() const
00309 {
00310 return mFileName;
00311 }
00312
00313 void ResourceFile::setFormat( const QString &format )
00314 {
00315 mFormatName = format;
00316 delete mFormat;
00317
00318 FormatFactory *factory = FormatFactory::self();
00319 mFormat = factory->format( mFormatName );
00320 }
00321
00322 QString ResourceFile::format() const
00323 {
00324 return mFormatName;
00325 }
00326
00327 void ResourceFile::fileChanged()
00328 {
00329 if ( !addressBook() )
00330 return;
00331
00332 clear();
00333 if ( mAsynchronous )
00334 asyncLoad();
00335 else {
00336 load();
00337 kdDebug() << "addressBookChanged() " << endl;
00338 addressBook()->emitAddressBookChanged();
00339 }
00340 }
00341
00342 void ResourceFile::removeAddressee( const Addressee &addr )
00343 {
00344 QFile::remove( QFile::encodeName( locateLocal( "data", "kabc/photos/" ) + addr.uid() ) );
00345 QFile::remove( QFile::encodeName( locateLocal( "data", "kabc/logos/" ) + addr.uid() ) );
00346 QFile::remove( QFile::encodeName( locateLocal( "data", "kabc/sounds/" ) + addr.uid() ) );
00347
00348 mAddrMap.erase( addr.uid() );
00349 }
00350
00351 void ResourceFile::downloadFinished( KIO::Job* )
00352 {
00353 d->mIsLoading = false;
00354
00355 if ( !mLocalTempFile )
00356 emit loadingError( this, i18n( "Download failed in some way!" ) );
00357
00358 QFile file( mTempFile );
00359 if ( !file.open( IO_ReadOnly ) ) {
00360 emit loadingError( this, i18n( "Unable to open file '%1'." ).arg( mTempFile ) );
00361 return;
00362 }
00363
00364 if ( !mFormat->loadAll( addressBook(), this, &file ) )
00365 emit loadingError( this, i18n( "Problems during parsing file '%1'." ).arg( mTempFile ) );
00366 else
00367 emit loadingFinished( this );
00368 }
00369
00370 void ResourceFile::uploadFinished( KIO::Job *job )
00371 {
00372 d->mIsSaving = false;
00373
00374 if ( job->error() )
00375 emit savingError( this, job->errorString() );
00376 else
00377 emit savingFinished( this );
00378 mDirWatch.startScan();
00379 }
00380
00381 #include "resourcefile.moc"