resourcefile.cpp

00001 /*
00002     This file is part of libkabc.
00003 
00004     Copyright (c) 2001,2003 Cornelius Schumacher <schumacher@kde.org>
00005     Copyright (c) 2006 Tom Abers <tomalbers@kde.nl>
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Library General Public
00009     License as published by the Free Software Foundation; either
00010     version 2 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Library General Public License for more details.
00016 
00017     You should have received a copy of the GNU Library General Public License
00018     along with this library; see the file COPYING.LIB.  If not, write to
00019     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020     Boston, MA 02110-1301, USA.
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 
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 ResourceFile::ResourceFile( const KConfig *config )
00050   : Resource( config ), mFormat( 0 ),
00051     mAsynchronous( false )
00052 {
00053   QString fileName, formatName;
00054 
00055   if ( config ) {
00056     fileName = config->readPathEntry( "FileName", StdAddressBook::fileName() );
00057     formatName = config->readEntry( "FileFormat", "vcard" );
00058   } else {
00059     fileName = StdAddressBook::fileName();
00060     formatName = "vcard";
00061   }
00062 
00063   init( fileName, formatName );
00064 }
00065 
00066 ResourceFile::ResourceFile( const QString &fileName,
00067                             const QString &formatName )
00068   : Resource( 0 ), mFormat( 0 ),
00069     mAsynchronous( false )
00070 {
00071   init( fileName, formatName );
00072 }
00073 
00074 void ResourceFile::init( const QString &fileName, const QString &formatName )
00075 {
00076   mFormatName = formatName;
00077 
00078   FormatFactory *factory = FormatFactory::self();
00079   mFormat = factory->format( mFormatName );
00080 
00081   if ( !mFormat ) {
00082     mFormatName = "vcard";
00083     mFormat = factory->format( mFormatName );
00084   }
00085 
00086   connect( &mDirWatch, SIGNAL( dirty(const QString&) ), SLOT( fileChanged() ) );
00087   connect( &mDirWatch, SIGNAL( created(const QString&) ), SLOT( fileChanged() ) );
00088   connect( &mDirWatch, SIGNAL( deleted(const QString&) ), SLOT( fileChanged() ) );
00089 
00090   setFileName( fileName );
00091 
00092   mLock = 0;
00093 }
00094 
00095 ResourceFile::~ResourceFile()
00096 {
00097   delete mFormat;
00098   mFormat = 0;
00099 }
00100 
00101 void ResourceFile::writeConfig( KConfig *config )
00102 {
00103   Resource::writeConfig( config );
00104 
00105   if ( mFileName == StdAddressBook::fileName() )
00106     config->deleteEntry( "FileName" );
00107   else
00108     config->writePathEntry( "FileName", mFileName );
00109 
00110   config->writeEntry( "FileFormat", mFormatName );
00111 }
00112 
00113 Ticket *ResourceFile::requestSaveTicket()
00114 {
00115   kdDebug(5700) << "ResourceFile::requestSaveTicket()" << endl;
00116 
00117   if ( !addressBook() ) return 0;
00118 
00119   delete mLock;
00120   mLock = new Lock( mFileName );
00121 
00122   if ( mLock->lock() ) {
00123     addressBook()->emitAddressBookLocked();
00124   } else {
00125     addressBook()->error( mLock->error() );
00126     kdDebug(5700) << "ResourceFile::requestSaveTicket(): Unable to lock file '"
00127                   << mFileName << "': " << mLock->error() << endl;
00128     return 0;
00129   }
00130 
00131   return createTicket( this );
00132 }
00133 
00134 void ResourceFile::releaseSaveTicket( Ticket *ticket )
00135 {
00136   delete ticket;
00137 
00138   delete mLock;
00139   mLock = 0;
00140 
00141   addressBook()->emitAddressBookUnlocked();
00142 }
00143 
00144 bool ResourceFile::doOpen()
00145 {
00146   QFile file( mFileName );
00147 
00148   if ( !file.exists() ) {
00149     // try to create the file
00150     bool ok = file.open( IO_WriteOnly );
00151     if ( ok )
00152       file.close();
00153 
00154     return ok;
00155   } else {
00156     QFileInfo fileInfo( mFileName );
00157     if ( readOnly() || !fileInfo.isWritable() ) {
00158       if ( !file.open( IO_ReadOnly ) )
00159         return false;
00160     } else {
00161       if ( !file.open( IO_ReadWrite ) )
00162         return false;
00163     }
00164 
00165     if ( file.size() == 0 ) {
00166       file.close();
00167 #if 0
00168       kdDebug() << "File size is zero. Evaluating backups" << endl;
00169       for (int i=0; i!=20; i++)
00170       {
00171         QFile backup( mFileName + "__" + QString::number(i) );
00172         kdDebug() << "Evaluating" << backup.name() << " size: " << backup.size() << endl;
00173         if ( backup.size() != 0 )
00174         {
00175           kdDebug() << "Restoring backup " << i << endl;
00176           const QString src = mFileName + "__" + QString::number(i);
00177           const QString dest = mFileName;
00178 
00179           // remove dest
00180           QFile::remove( dest );
00181 
00182           // copy src to dest
00183           if ( backup.open( IO_ReadOnly ) ) {
00184             const QByteArray data = backup.readAll();
00185 
00186             QFile out( dest );
00187             if ( out.open( IO_WriteOnly ) ) {
00188               out.writeBlock( data );
00189               out.close();
00190             }
00191 
00192             backup.close();
00193           }
00194           return true; 
00195         }
00196       }
00197 #endif
00198       return true;
00199     }
00200 
00201     bool ok = mFormat->checkFormat( &file );
00202     file.close();
00203 
00204     return ok;
00205   }
00206 }
00207 
00208 void ResourceFile::doClose()
00209 {
00210 }
00211 
00212 bool ResourceFile::load()
00213 {
00214   kdDebug(5700) << "ResourceFile::load(): '" << mFileName << "'" << endl;
00215 
00216   mAsynchronous = false;
00217 
00218   QFile file( mFileName );
00219   if ( !file.open( IO_ReadOnly ) ) {
00220     addressBook()->error( i18n( "Unable to open file '%1'." ).arg( mFileName ) );
00221     return false;
00222   }
00223 
00224   clear();
00225 
00226   return mFormat->loadAll( addressBook(), this, &file );
00227 }
00228 
00229 bool ResourceFile::asyncLoad()
00230 {
00231   kdDebug(5700) << "ResourceFile::asyncLoad()" << endl;
00232 
00233   mAsynchronous = true;
00234 
00235   bool ok = load();
00236 
00237   if ( !ok )
00238     emitLoadingError();
00239   else
00240     emitLoadingFinished();
00241 
00242   return true;
00243 }
00244 
00245 bool ResourceFile::save( Ticket * )
00246 {
00247   kdDebug(5700) << "ResourceFile::save()" << endl;
00248 
00249   // create backup file
00250   QString extension = "_" + QString::number( QDate::currentDate().dayOfWeek() );
00251 #if 0
00252   // Only do the logrotate dance when the __0 file is not 0 bytes.
00253   QFile file( mFileName + "__0" );
00254   if ( file.size() != 0 ) {
00255     const QString last = mFileName + "__20";
00256     kdDebug() << "deleting " << last << endl;
00257 
00258     QFile::remove( last );
00259 
00260     for (int i=19; i>=0; i--)
00261     {
00262       const QString src = mFileName + "__" + QString::number(i);
00263       const QString dest = mFileName + "__" + QString::number(i+1);
00264       kdDebug() << "moving " << src << " -> " << dest << endl;
00265 
00266       // copy src to dest
00267       QFile in( src );
00268       if ( in.open( IO_ReadOnly ) ) {
00269         const QByteArray data = in.readAll();
00270 
00271         QFile out( dest );
00272         if ( out.open( IO_WriteOnly ) ) {
00273           out.writeBlock( data );
00274           out.close();
00275         }
00276 
00277         in.close();
00278       }
00279 
00280       // remove src
00281       QFile::remove( src );
00282     }
00283   } else
00284     kdDebug() << "Not starting logrotate __0 is 0 bytes." << endl;
00285 
00286   QString extension = "__0";
00287 #endif
00288   (void) KSaveFile::backupFile( mFileName, QString::null /*directory*/,
00289                                 extension );
00290 
00291   mDirWatch.stopScan();
00292 
00293   KSaveFile saveFile( mFileName );
00294   bool ok = false;
00295 
00296   if ( saveFile.status() == 0 && saveFile.file() ) {
00297     mFormat->saveAll( addressBook(), this, saveFile.file() );
00298     ok = saveFile.close();
00299   }
00300 
00301   if ( !ok ) {
00302     saveFile.abort();
00303     addressBook()->error( i18n( "Unable to save file '%1'." ).arg( mFileName ) );
00304   }
00305 
00306   mDirWatch.startScan();
00307 
00308   return ok;
00309 }
00310 
00311 bool ResourceFile::asyncSave( Ticket *ticket )
00312 {
00313   kdDebug(5700) << "ResourceFile::asyncSave()" << endl;
00314 
00315   bool ok = save( ticket );
00316 
00317   if ( !ok )
00318     QTimer::singleShot( 0, this, SLOT( emitSavingError() ) );
00319   else
00320     QTimer::singleShot( 0, this, SLOT( emitSavingFinished() ) );
00321 
00322   return ok;
00323 }
00324 
00325 void ResourceFile::setFileName( const QString &fileName )
00326 {
00327   mDirWatch.stopScan();
00328   if ( mDirWatch.contains( mFileName ) )
00329     mDirWatch.removeFile( mFileName );
00330 
00331   mFileName = fileName;
00332 
00333   mDirWatch.addFile( mFileName );
00334   mDirWatch.startScan();
00335 }
00336 
00337 QString ResourceFile::fileName() const
00338 {
00339   return mFileName;
00340 }
00341 
00342 void ResourceFile::setFormat( const QString &format )
00343 {
00344   mFormatName = format;
00345   delete mFormat;
00346 
00347   FormatFactory *factory = FormatFactory::self();
00348   mFormat = factory->format( mFormatName );
00349 }
00350 
00351 QString ResourceFile::format() const
00352 {
00353   return mFormatName;
00354 }
00355 
00356 void ResourceFile::fileChanged()
00357 {
00358     kdDebug(5700) << "ResourceFile::fileChanged(): " << mFileName << endl;
00359 
00360   if ( !addressBook() )
00361     return;
00362 
00363   if ( mAsynchronous )
00364     asyncLoad();
00365   else {
00366     load();
00367     kdDebug() << "addressBookChanged() " << endl;
00368     addressBook()->emitAddressBookChanged();
00369   }
00370 }
00371 
00372 void ResourceFile::removeAddressee( const Addressee &addr )
00373 {
00374   QFile::remove( QFile::encodeName( locateLocal( "data", "kabc/photos/" ) + addr.uid() ) );
00375   QFile::remove( QFile::encodeName( locateLocal( "data", "kabc/logos/" ) + addr.uid() ) );
00376   QFile::remove( QFile::encodeName( locateLocal( "data", "kabc/sounds/" ) + addr.uid() ) );
00377 
00378   mAddrMap.erase( addr.uid() );
00379 }
00380 
00381 void ResourceFile::emitSavingFinished()
00382 {
00383   emit savingFinished( this );
00384 }
00385 
00386 void ResourceFile::emitSavingError()
00387 {
00388   emit savingError( this, i18n( "Unable to save file '%1'." ).arg( mFileName ) );
00389 }
00390 
00391 void ResourceFile::emitLoadingFinished()
00392 {
00393   emit loadingFinished( this );
00394 }
00395 
00396 void ResourceFile::emitLoadingError()
00397 {
00398   emit loadingError( this, i18n( "Problems during parsing file '%1'." ).arg( mFileName ) );
00399 }
00400 
00401 #include "resourcefile.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys