00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "resourcedir.h"
00022 #include "resourcedirconfig.h"
00023
00024 #include "kabc/addressbook.h"
00025 #include "kabc/formatfactory.h"
00026 #include "kabc/stdaddressbook.h"
00027 #include "kabc/lock.h"
00028
00029 #include <kconfiggroup.h>
00030 #include <kdebug.h>
00031 #include <kgenericfactory.h>
00032 #include <kglobal.h>
00033 #include <klocale.h>
00034 #include <kstandarddirs.h>
00035 #include <kurlrequester.h>
00036
00037 #include <sys/types.h>
00038 #include <sys/stat.h>
00039 #include <errno.h>
00040 #include <signal.h>
00041 #include <unistd.h>
00042
00043 using namespace KABC;
00044
00045 class ResourceDir::Private
00046 {
00047 public:
00048 Private( ResourceDir *parent )
00049 : mParent( parent ), mFormat( 0 ), mAsynchronous( false )
00050 {
00051 }
00052
00053 ~Private()
00054 {
00055 delete mFormat;
00056 mFormat = 0;
00057 }
00058
00059 void pathChanged();
00060 void init( const QString &path, const QString &format );
00061
00062 ResourceDir *mParent;
00063 Format *mFormat;
00064 KDirWatch mDirWatch;
00065
00066 QString mPath;
00067 QString mFormatName;
00068
00069 Lock *mLock;
00070
00071 bool mAsynchronous;
00072 };
00073
00074 void ResourceDir::Private::init( const QString &path, const QString &format )
00075 {
00076 mFormatName = format;
00077
00078 FormatFactory *factory = FormatFactory::self();
00079 mFormat = factory->format( mFormatName );
00080
00081 if ( !mFormat ) {
00082 mFormatName = QLatin1String( "vcard" );
00083 mFormat = factory->format( mFormatName );
00084 }
00085
00086 mLock = 0;
00087
00088 mParent->connect( &mDirWatch, SIGNAL( dirty(const QString&) ), SLOT( pathChanged() ) );
00089 mParent->connect( &mDirWatch, SIGNAL( created(const QString&) ), SLOT( pathChanged() ) );
00090 mParent->connect( &mDirWatch, SIGNAL( deleted(const QString&) ), SLOT( pathChanged() ) );
00091
00092 mParent->setPath( path );
00093 }
00094
00095 void ResourceDir::Private::pathChanged()
00096 {
00097 if ( !mParent->addressBook() ) {
00098 return;
00099 }
00100
00101 mParent->clear();
00102 if ( mAsynchronous ) {
00103 mParent->asyncLoad();
00104 } else {
00105 mParent->load();
00106 mParent->addressBook()->emitAddressBookChanged();
00107 }
00108 }
00109
00110 ResourceDir::ResourceDir()
00111 : Resource(), d( new Private( this ) )
00112 {
00113 d->init( StdAddressBook::directoryName(), QLatin1String( "vcard" ) );
00114 }
00115
00116 ResourceDir::ResourceDir( const KConfigGroup &group )
00117 : Resource( group ), d( new Private( this ) )
00118 {
00119 d->init( group.readPathEntry( "FilePath", StdAddressBook::directoryName() ),
00120 group.readEntry( "FileFormat", "vcard" ) );
00121 }
00122
00123 ResourceDir::ResourceDir( const QString &path, const QString &format )
00124 : Resource(), d( new Private( this ) )
00125 {
00126 d->init( path, format );
00127 }
00128
00129 ResourceDir::~ResourceDir()
00130 {
00131 delete d;
00132 }
00133
00134 void ResourceDir::writeConfig( KConfigGroup &group )
00135 {
00136 Resource::writeConfig( group );
00137
00138 if ( d->mPath == StdAddressBook::directoryName() ) {
00139 group.deleteEntry( "FilePath" );
00140 } else {
00141 group.writePathEntry( "FilePath", d->mPath );
00142 }
00143
00144 group.writeEntry( "FileFormat", d->mFormatName );
00145 }
00146
00147 Ticket *ResourceDir::requestSaveTicket()
00148 {
00149 kDebug();
00150
00151 if ( !addressBook() ) {
00152 return 0;
00153 }
00154
00155 delete d->mLock;
00156 d->mLock = new Lock( d->mPath );
00157
00158 if ( d->mLock->lock() ) {
00159 addressBook()->emitAddressBookLocked();
00160 } else {
00161 addressBook()->error( d->mLock->error() );
00162 kDebug() << "Unable to lock path '" << d->mPath
00163 << "':" << d->mLock->error();
00164 return 0;
00165 }
00166
00167 return createTicket( this );
00168 }
00169
00170 void ResourceDir::releaseSaveTicket( Ticket *ticket )
00171 {
00172 delete ticket;
00173
00174 delete d->mLock;
00175 d->mLock = 0;
00176 }
00177
00178 bool ResourceDir::doOpen()
00179 {
00180 QDir dir( d->mPath );
00181 if ( !dir.exists() ) {
00182 return dir.mkdir( dir.path() );
00183 } else {
00184 const QStringList lst = dir.entryList( QDir::Files );
00185 if ( lst.isEmpty() ) {
00186 return true;
00187 }
00188 QString testName = lst.first();
00189 QFile file( d->mPath + QDir::separator() + testName );
00190 if ( file.open( QIODevice::ReadOnly ) ) {
00191 return true;
00192 }
00193 if ( file.size() == 0 ) {
00194 return true;
00195 }
00196
00197 bool ok = d->mFormat->checkFormat( &file );
00198 file.close();
00199 return ok;
00200 }
00201 }
00202
00203 void ResourceDir::doClose()
00204 {
00205 }
00206
00207 bool ResourceDir::load()
00208 {
00209 kDebug() << d->mPath << "'";
00210
00211 d->mAsynchronous = false;
00212
00213 QDir dir( d->mPath );
00214 QStringList files = dir.entryList( QDir::Files );
00215
00216 QStringList::Iterator it;
00217 bool ok = true;
00218 for ( it = files.begin(); it != files.end(); ++it ) {
00219 QFile file( d->mPath + QDir::separator() + (*it) );
00220
00221 if ( !file.open( QIODevice::ReadOnly ) ) {
00222 addressBook()->error( i18n( "Unable to open file '%1' for reading", file.fileName() ) );
00223 ok = false;
00224 continue;
00225 }
00226
00227 if ( !d->mFormat->loadAll( addressBook(), this, &file ) ) {
00228 ok = false;
00229 }
00230
00231 file.close();
00232 }
00233
00234 return ok;
00235 }
00236
00237 bool ResourceDir::asyncLoad()
00238 {
00239 d->mAsynchronous = true;
00240
00241 bool ok = load();
00242 if ( !ok ) {
00243 emit loadingError( this, i18n( "Loading resource '%1' failed!", resourceName() ) );
00244 } else {
00245 emit loadingFinished( this );
00246 }
00247
00248 return ok;
00249 }
00250
00251 bool ResourceDir::save( Ticket * )
00252 {
00253 kDebug() << d->mPath << "'";
00254
00255 Addressee::Map::Iterator it;
00256 bool ok = true;
00257
00258 d->mDirWatch.stopScan();
00259
00260 for ( it = mAddrMap.begin(); it != mAddrMap.end(); ++it ) {
00261 if ( !it.value().changed() ) {
00262 continue;
00263 }
00264
00265 QFile file( d->mPath + QDir::separator() + (*it).uid() );
00266 if ( !file.open( QIODevice::WriteOnly ) ) {
00267 addressBook()->error( i18n( "Unable to open file '%1' for writing", file.fileName() ) );
00268 continue;
00269 }
00270
00271 d->mFormat->save( *it, &file );
00272
00273
00274 (*it).setChanged( false );
00275
00276 file.close();
00277 }
00278
00279 d->mDirWatch.startScan();
00280
00281 return ok;
00282 }
00283
00284 bool ResourceDir::asyncSave( Ticket *ticket )
00285 {
00286 bool ok = save( ticket );
00287 if ( !ok ) {
00288 emit savingError( this, i18n( "Saving resource '%1' failed!", resourceName() ) );
00289 } else {
00290 emit savingFinished( this );
00291 }
00292 return ok;
00293 }
00294
00295 void ResourceDir::setPath( const QString &path )
00296 {
00297 d->mDirWatch.stopScan();
00298 if ( d->mDirWatch.contains( d->mPath ) ) {
00299 d->mDirWatch.removeDir( d->mPath );
00300 }
00301
00302 d->mPath = path;
00303 d->mDirWatch.addDir( d->mPath, KDirWatch::WatchFiles );
00304 d->mDirWatch.startScan();
00305 }
00306
00307 QString ResourceDir::path() const
00308 {
00309 return d->mPath;
00310 }
00311
00312 void ResourceDir::setFormat( const QString &format )
00313 {
00314 d->mFormatName = format;
00315
00316 delete d->mFormat;
00317
00318 FormatFactory *factory = FormatFactory::self();
00319 d->mFormat = factory->format( d->mFormatName );
00320 }
00321
00322 QString ResourceDir::format() const
00323 {
00324 return d->mFormatName;
00325 }
00326
00327 void ResourceDir::removeAddressee( const Addressee &addr )
00328 {
00329 QFile::remove( d->mPath + QDir::separator() + addr.uid() );
00330 mAddrMap.remove( addr.uid() );
00331 }
00332
00333 #include "resourcedir.moc"