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