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 #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     // try to create the file
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   // Only do the logrotate dance when the __0 file is not 0 bytes.
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 /*directory*/,
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"
KDE Home | KDE Accessibility Home | Description of Access Keys