00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "resourcefile.h"
00023 #include "resourcefileconfig.h"
00024
00025 #include "kabc/formatfactory.h"
00026 #include "kabc/stdaddressbook.h"
00027 #include "kabc/lock.h"
00028
00029 #include <kio/scheduler.h>
00030 #include <kconfiggroup.h>
00031 #include <kdebug.h>
00032 #include <klocale.h>
00033 #include <ksavefile.h>
00034 #include <kstandarddirs.h>
00035 #include <ktemporaryfile.h>
00036
00037 #include <QtCore/QFile>
00038 #include <QtCore/QFileInfo>
00039
00040 #include <sys/types.h>
00041 #include <sys/stat.h>
00042 #include <signal.h>
00043 #include <unistd.h>
00044
00045 using namespace KABC;
00046
00047 typedef QList< QPair<QString, QString> > MissingEntryList;
00048
00049 class ResourceFile::ResourceFilePrivate
00050 {
00051 public:
00052 QMap< QString, MissingEntryList > mMissingEntries;
00053 };
00054
00055 ResourceFile::ResourceFile()
00056 : Resource(), mFormat( 0 ), mTempFile( 0 ),
00057 mAsynchronous( false ), d( new ResourceFilePrivate )
00058 {
00059 QString fileName, formatName;
00060
00061 fileName = StdAddressBook::fileName();
00062 formatName = QLatin1String( "vcard" );
00063
00064 init( fileName, formatName );
00065 }
00066
00067 ResourceFile::ResourceFile( const KConfigGroup &group )
00068 : Resource( group ), mFormat( 0 ), mTempFile( 0 ),
00069 mAsynchronous( false ), d( new ResourceFilePrivate )
00070 {
00071 QString fileName, formatName;
00072
00073 fileName = group.readPathEntry( "FileName", StdAddressBook::fileName() );
00074 formatName = group.readEntry( "FileFormat", "vcard" );
00075
00076 init( fileName, formatName );
00077 }
00078
00079 ResourceFile::ResourceFile( const QString &fileName,
00080 const QString &formatName )
00081 : Resource(), mFormat( 0 ), mTempFile( 0 ),
00082 mAsynchronous( false ), d( new ResourceFilePrivate )
00083 {
00084 init( fileName, formatName );
00085 }
00086
00087 void ResourceFile::init( const QString &fileName, const QString &formatName )
00088 {
00089 mFormatName = formatName;
00090
00091 FormatFactory *factory = FormatFactory::self();
00092 mFormat = factory->format( mFormatName );
00093
00094 if ( !mFormat ) {
00095 mFormatName = QLatin1String( "vcard" );
00096 mFormat = factory->format( mFormatName );
00097 }
00098
00099 connect( &mDirWatch, SIGNAL( dirty(const QString&) ), SLOT( fileChanged(const QString&) ) );
00100 connect( &mDirWatch, SIGNAL( created(const QString&) ), SLOT( fileChanged(const QString&) ) );
00101 connect( &mDirWatch, SIGNAL( deleted(const QString&) ), SLOT( fileChanged(const QString&) ) );
00102
00103 setFileName( fileName );
00104
00105 mDirWatch.addFile( KStandardDirs::locateLocal( "data", QLatin1String( "kabc/distlists" ) ) );
00106
00107 mLock = 0;
00108 }
00109
00110 ResourceFile::~ResourceFile()
00111 {
00112 delete d;
00113 d = 0;
00114 delete mFormat;
00115 mFormat = 0;
00116 }
00117
00118 void ResourceFile::writeConfig( KConfigGroup &group )
00119 {
00120 Resource::writeConfig( group );
00121
00122 if ( mFileName == StdAddressBook::fileName() ) {
00123 group.deleteEntry( "FileName" );
00124 } else {
00125 group.writePathEntry( "FileName", mFileName );
00126 }
00127
00128 group.writeEntry( "FileFormat", mFormatName );
00129 }
00130
00131 Ticket *ResourceFile::requestSaveTicket()
00132 {
00133 kDebug();
00134
00135 if ( !addressBook() ) {
00136 return 0;
00137 }
00138
00139 delete mLock;
00140 mLock = new Lock( mFileName );
00141
00142 if ( mLock->lock() ) {
00143 addressBook()->emitAddressBookLocked();
00144 } else {
00145 addressBook()->error( mLock->error() );
00146 kDebug() << "Unable to lock file '" << mFileName
00147 << "':" << mLock->error();
00148 return 0;
00149 }
00150
00151 return createTicket( this );
00152 }
00153
00154 void ResourceFile::releaseSaveTicket( Ticket *ticket )
00155 {
00156 delete ticket;
00157
00158 delete mLock;
00159 mLock = 0;
00160
00161 addressBook()->emitAddressBookUnlocked();
00162 }
00163
00164 bool ResourceFile::doOpen()
00165 {
00166 QFile file( mFileName );
00167
00168 if ( !file.exists() ) {
00169
00170 bool ok = file.open( QIODevice::WriteOnly );
00171 if ( ok ) {
00172 file.close();
00173 }
00174 return ok;
00175 } else {
00176 QFileInfo fileInfo( mFileName );
00177 if ( readOnly() || !fileInfo.isWritable() ) {
00178 if ( !file.open( QIODevice::ReadOnly ) ) {
00179 return false;
00180 }
00181 } else {
00182 if ( !file.open( QIODevice::ReadWrite ) ) {
00183 return false;
00184 }
00185 }
00186
00187 if ( file.size() == 0 ) {
00188 file.close();
00189 return true;
00190 }
00191
00192 bool ok = mFormat->checkFormat( &file );
00193 file.close();
00194
00195 return ok;
00196 }
00197 }
00198
00199 void ResourceFile::doClose()
00200 {
00201 }
00202
00203 bool ResourceFile::load()
00204 {
00205 kDebug() << mFileName << "'";
00206
00207 mAsynchronous = false;
00208
00209 QFile file( mFileName );
00210 if ( !file.open( QIODevice::ReadOnly ) ) {
00211 addressBook()->error( i18n( "Unable to open file '%1'.", mFileName ) );
00212 return false;
00213 }
00214
00215 if ( !clearAndLoad( &file ) ) {
00216 addressBook()->error( i18n( "Problems parsing file '%1'.", mFileName ) );
00217 return false;
00218 }
00219
00220 return true;
00221 }
00222
00223 bool ResourceFile::clearAndLoad( QFile *file )
00224 {
00225 clear();
00226
00227 bool addresseesOk = mFormat->loadAll( addressBook(), this, file );
00228
00229 bool listsOk = loadDistributionLists();
00230
00231 return addresseesOk && listsOk;
00232 }
00233
00234 bool ResourceFile::asyncLoad()
00235 {
00236 mAsynchronous = true;
00237
00238 load();
00239
00240 QTimer::singleShot( 0, this, SLOT( emitLoadingFinished() ) );
00241
00242 return true;
00243 }
00244
00245 bool ResourceFile::save( Ticket *ticket )
00246 {
00247 Q_UNUSED( ticket );
00248 kDebug();
00249
00250
00251 QString extension = QLatin1Char( '_' ) + QString::number( QDate::currentDate().dayOfWeek() );
00252 (void) KSaveFile::simpleBackupFile( mFileName, QString(), extension );
00253
00254 mDirWatch.stopScan();
00255
00256 KSaveFile saveFile( mFileName );
00257 bool ok = false;
00258
00259 if ( saveFile.open() ) {
00260 saveToFile( &saveFile );
00261 ok = saveFile.finalize();
00262 }
00263
00264 if ( !ok ) {
00265 addressBook()->error( i18n( "Unable to save file '%1'.", mFileName ) );
00266 }
00267
00268 mDirWatch.startScan();
00269
00270 return ok;
00271 }
00272
00273 bool ResourceFile::asyncSave( Ticket *ticket )
00274 {
00275 kDebug();
00276
00277 save( ticket );
00278
00279 QTimer::singleShot( 0, this, SLOT( emitSavingFinished() ) );
00280
00281 return true;
00282 }
00283
00284 void ResourceFile::emitLoadingFinished()
00285 {
00286 emit loadingFinished( this );
00287 }
00288
00289 void ResourceFile::emitSavingFinished()
00290 {
00291 emit savingFinished( this );
00292 }
00293
00294 bool ResourceFile::loadDistributionLists()
00295 {
00296 KConfig cfg( KStandardDirs::locateLocal( "data", QLatin1String( "kabc/distlists" ) ) );
00297
00298 KConfigGroup cg( &cfg, "DistributionLists" );
00299 KConfigGroup cgId( &cfg, "DistributionLists-Identifiers" );
00300 const QStringList entryList = cg.keyList();
00301
00302 d->mMissingEntries.clear();
00303
00304 QStringList::ConstIterator it;
00305 for ( it = entryList.constBegin(); it != entryList.constEnd(); ++it ) {
00306 const QString name = *it;
00307 const QStringList value = cg.readEntry( name, QStringList() );
00308
00309 kDebug() << name << QLatin1Char( ':' ) << value.join( QLatin1String( "," ) );
00310
00311 DistributionList *list = 0;
00312 if ( cgId.isValid() ) {
00313 const QString identifier = cgId.readEntry( name, QString() );
00314 if ( !identifier.isEmpty() ) {
00315 list = new DistributionList( this, identifier, name );
00316 }
00317 }
00318
00319 if ( list == 0 ) {
00320 list = new DistributionList( this, name );
00321 }
00322
00323 MissingEntryList missingEntries;
00324 QStringList::ConstIterator entryIt = value.constBegin();
00325 while ( entryIt != value.constEnd() ) {
00326 QString id = *entryIt++;
00327 QString email = entryIt != value.constEnd() ? *entryIt : QString();
00328 if ( email.isEmpty() && !email.isNull() ) {
00329 email = QString();
00330 }
00331
00332 kDebug() << "----- Entry" << id;
00333
00334 Addressee a = addressBook()->findByUid( id );
00335 if ( !a.isEmpty() ) {
00336 list->insertEntry( a, email );
00337 } else {
00338 missingEntries.append( qMakePair( id, email ) );
00339 }
00340
00341 if ( entryIt == value.constEnd() ) {
00342 break;
00343 }
00344 ++entryIt;
00345 }
00346
00347 d->mMissingEntries.insert( name, missingEntries );
00348 }
00349
00350 return true;
00351 }
00352
00353 void ResourceFile::saveDistributionLists()
00354 {
00355 kDebug();
00356
00357 KConfig cfg( KStandardDirs::locateLocal( "data", QLatin1String( "kabc/distlists" ) ) );
00358 KConfigGroup cg( &cfg, "DistributionLists" );
00359 cg.deleteGroup();
00360 KConfigGroup cgId( &cfg, "DistributionLists-Identifiers" );
00361 cgId.deleteGroup();
00362
00363 QMapIterator<QString, DistributionList*> it( mDistListMap );
00364 while ( it.hasNext() ) {
00365 DistributionList *list = it.next().value();
00366 kDebug() << " Saving '" << list->name() << "'";
00367
00368 QStringList value;
00369 const DistributionList::Entry::List entries = list->entries();
00370 DistributionList::Entry::List::ConstIterator it;
00371 for ( it = entries.begin(); it != entries.end(); ++it ) {
00372 value.append( (*it).addressee().uid() );
00373 value.append( (*it).email() );
00374 }
00375
00376 if ( d->mMissingEntries.find( list->name() ) != d->mMissingEntries.end() ) {
00377 const MissingEntryList missList = d->mMissingEntries[ list->name() ];
00378 MissingEntryList::ConstIterator missIt;
00379 for ( missIt = missList.begin(); missIt != missList.end(); ++missIt ) {
00380 value.append( (*missIt).first );
00381 value.append( (*missIt).second );
00382 }
00383 }
00384
00385 cg.writeEntry( list->name(), value );
00386 cgId.writeEntry( list->name(), list->identifier() );
00387 }
00388
00389 cfg.sync();
00390 }
00391
00392 void ResourceFile::saveToFile( QFile *file )
00393 {
00394 mFormat->saveAll( addressBook(), this, file );
00395
00396 saveDistributionLists();
00397 }
00398
00399 void ResourceFile::setFileName( const QString &fileName )
00400 {
00401 mDirWatch.stopScan();
00402 if ( mDirWatch.contains( mFileName ) ) {
00403 mDirWatch.removeFile( mFileName );
00404 }
00405
00406 mFileName = fileName;
00407
00408 mDirWatch.addFile( mFileName );
00409 mDirWatch.startScan();
00410 }
00411
00412 QString ResourceFile::fileName() const
00413 {
00414 return mFileName;
00415 }
00416
00417 void ResourceFile::setFormat( const QString &format )
00418 {
00419 mFormatName = format;
00420 delete mFormat;
00421
00422 FormatFactory *factory = FormatFactory::self();
00423 mFormat = factory->format( mFormatName );
00424 }
00425
00426 QString ResourceFile::format() const
00427 {
00428 return mFormatName;
00429 }
00430
00431 void ResourceFile::fileChanged( const QString &path )
00432 {
00433 kDebug() << path;
00434
00435 if ( !addressBook() ) {
00436 return;
00437 }
00438
00439 if ( path == KStandardDirs::locateLocal( "data", QLatin1String( "kabc/distlists" ) ) ) {
00440
00441
00442
00443
00444 DistributionListMap tempDistListMap( mDistListMap );
00445 mDistListMap.clear();
00446 qDeleteAll( tempDistListMap );
00447
00448 loadDistributionLists();
00449
00450 kDebug() << "addressBookChanged()";
00451 addressBook()->emitAddressBookChanged();
00452
00453 return;
00454 }
00455
00456
00457 if ( mAsynchronous ) {
00458 asyncLoad();
00459 } else {
00460 load();
00461 kDebug() << "addressBookChanged()";
00462 addressBook()->emitAddressBookChanged();
00463 }
00464 }
00465
00466 void ResourceFile::removeAddressee( const Addressee &addr )
00467 {
00468 QFile::remove( KStandardDirs::locateLocal(
00469 "data", QLatin1String( "kabc/photos/" ) ) + addr.uid() );
00470 QFile::remove( KStandardDirs::locateLocal(
00471 "data", QLatin1String( "kabc/logos/" ) ) + addr.uid() );
00472 QFile::remove( KStandardDirs::locateLocal(
00473 "data", QLatin1String( "kabc/sounds/" ) ) + addr.uid() );
00474
00475 mAddrMap.remove( addr.uid() );
00476 }
00477
00478 #include "resourcefile.moc"