/* This file is part of libkabc. Copyright (c) 2001,2003 Cornelius Schumacher Copyright (c) 2006 Tom Abers This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "formatfactory.h" #include "resourcefileconfig.h" #include "stdaddressbook.h" #include "lock.h" #include "resourcefile.h" using namespace KABC; ResourceFile::ResourceFile( const KConfig *config ) : Resource( config ), mFormat( 0 ), mAsynchronous( false ) { TQString fileName, formatName; if ( config ) { fileName = config->readPathEntry( "FileName", StdAddressBook::fileName() ); formatName = config->readEntry( "FileFormat", "vcard" ); } else { fileName = StdAddressBook::fileName(); formatName = "vcard"; } init( fileName, formatName ); } ResourceFile::ResourceFile( const TQString &fileName, const TQString &formatName ) : Resource( 0 ), mFormat( 0 ), mAsynchronous( false ) { init( fileName, formatName ); } void ResourceFile::init( const TQString &fileName, const TQString &formatName ) { mFormatName = formatName; FormatFactory *factory = FormatFactory::self(); mFormat = factory->format( mFormatName ); if ( !mFormat ) { mFormatName = "vcard"; mFormat = factory->format( mFormatName ); } connect( &mDirWatch, TQT_SIGNAL( dirty(const TQString&) ), TQT_SLOT( fileChanged() ) ); connect( &mDirWatch, TQT_SIGNAL( created(const TQString&) ), TQT_SLOT( fileChanged() ) ); connect( &mDirWatch, TQT_SIGNAL( deleted(const TQString&) ), TQT_SLOT( fileChanged() ) ); setFileName( fileName ); mLock = 0; } ResourceFile::~ResourceFile() { delete mFormat; mFormat = 0; } void ResourceFile::writeConfig( KConfig *config ) { Resource::writeConfig( config ); if ( mFileName == StdAddressBook::fileName() ) config->deleteEntry( "FileName" ); else config->writePathEntry( "FileName", mFileName ); config->writeEntry( "FileFormat", mFormatName ); } Ticket *ResourceFile::requestSaveTicket() { kdDebug(5700) << "ResourceFile::requestSaveTicket()" << endl; if ( !addressBook() ) return 0; delete mLock; mLock = new Lock( mFileName ); if ( mLock->lock() ) { addressBook()->emitAddressBookLocked(); } else { addressBook()->error( mLock->error() ); kdDebug(5700) << "ResourceFile::requestSaveTicket(): Unable to lock file '" << mFileName << "': " << mLock->error() << endl; return 0; } return createTicket( this ); } void ResourceFile::releaseSaveTicket( Ticket *ticket ) { delete ticket; delete mLock; mLock = 0; addressBook()->emitAddressBookUnlocked(); } bool ResourceFile::doOpen() { TQFile file( mFileName ); if ( !file.exists() ) { // try to create the file bool ok = file.open( IO_WriteOnly ); if ( ok ) file.close(); return ok; } else { TQFileInfo fileInfo( mFileName ); if ( readOnly() || !fileInfo.isWritable() ) { if ( !file.open( IO_ReadOnly ) ) return false; } else { if ( !file.open( IO_ReadWrite ) ) return false; } if ( file.size() == 0 ) { file.close(); kdDebug(5700) << "File size is zero. Evaluating backups" << endl; for (int i=0; i!=20; i++) { TQFile backup( mFileName + "__" + TQString::number(i) ); kdDebug(5700) << "Evaluating" << backup.name() << " size: " << backup.size() << endl; if ( backup.size() != 0 ) { kdDebug(5700) << "Restoring backup " << i << endl; const TQString src = mFileName + "__" + TQString::number(i); const TQString dest = mFileName; // copy src to dest if ( ! backup.open( IO_ReadOnly ) ) { // const TQByteArray data = backup.readAll(); kdDebug(5700) << "can not open source for reading " << src << endl; continue; } // remove dest TQFile::remove( dest ); TQString text; TQTextStream instream( &backup ); instream.setEncoding( TQTextStream::UnicodeUTF8 ); text = instream.read(); backup.close(); TQFile out( dest ); if ( ! out.open( IO_WriteOnly ) ) { // out.writeBlock( data ); kdDebug(5700) << "can not open target for writing " << dest << endl; continue; } TQTextStream outstream( &out ); outstream.setEncoding( TQTextStream::UnicodeUTF8 ); outstream << text; out.close(); return true; } } return true; } bool ok = mFormat->checkFormat( &file ); file.close(); return ok; } } void ResourceFile::doClose() { } bool ResourceFile::load() { kdDebug(5700) << "ResourceFile::load(): '" << mFileName << "'" << endl; mAsynchronous = false; TQFile file( mFileName ); if ( !file.open( IO_ReadOnly ) ) { addressBook()->error( i18n( "Unable to open file '%1'." ).arg( mFileName ) ); return false; } clear(); return mFormat->loadAll( addressBook(), this, &file ); } bool ResourceFile::asyncLoad() { kdDebug(5700) << "ResourceFile::asyncLoad()" << endl; mAsynchronous = true; bool ok = load(); if ( !ok ) emitLoadingError(); else emitLoadingFinished(); return true; } bool ResourceFile::save( Ticket * ) { kdDebug(5700) << "ResourceFile::save()" << endl; // Only do the logrotate dance when the __0 file is not 0 bytes. TQFile file( mFileName + "__0" ); if ( file.size() != 0 ) { const TQString last = mFileName + "__20"; kdDebug(5700) << "deleting " << last << endl; TQFile::remove( last ); for (int i=19; i>=0; i--) { const TQString src = mFileName + "__" + TQString::number(i); const TQString dest = mFileName + "__" + TQString::number(i+1); kdDebug() << "moving " << src << " -> " << dest << endl; // copy src to dest TQFile in( src ); if ( ! in.exists() ) continue; if ( ! in.open( IO_ReadOnly ) ) { // const TQByteArray data = in.readAll(); kdDebug(5700) << "can not open source for reading " << src << endl; return false; } TQString text; TQTextStream instream( &in ); instream.setEncoding( TQTextStream::UnicodeUTF8 ); text = instream.read(); in.close(); TQFile out( dest ); if ( ! out.open( IO_WriteOnly ) ) { // out.writeBlock( data ); kdDebug(5700) << "can not open target for writing " << dest << endl; return false; } TQTextStream outstream( &out ); outstream.setEncoding( TQTextStream::UnicodeUTF8 ); outstream << text; out.close(); // remove src TQFile::remove( src ); } } else kdDebug(5700) << "Not starting logrotate __0 is 0 bytes." << endl; TQString extension = "__0"; (void) KSaveFile::backupFile( mFileName, TQString::null /*directory*/, extension ); mDirWatch.stopScan(); KSaveFile saveFile( mFileName ); bool ok = false; if ( saveFile.status() == 0 && saveFile.file() ) { mFormat->saveAll( addressBook(), this, saveFile.file() ); ok = saveFile.close(); } if ( !ok ) { saveFile.abort(); addressBook()->error( i18n( "Unable to save file '%1'." ).arg( mFileName ) ); } mDirWatch.startScan(); return ok; } bool ResourceFile::asyncSave( Ticket *ticket ) { kdDebug(5700) << "ResourceFile::asyncSave()" << endl; bool ok = save( ticket ); if ( !ok ) TQTimer::singleShot( 0, this, TQT_SLOT( emitSavingError() ) ); else TQTimer::singleShot( 0, this, TQT_SLOT( emitSavingFinished() ) ); return ok; } void ResourceFile::setFileName( const TQString &fileName ) { mDirWatch.stopScan(); if ( mDirWatch.contains( mFileName ) ) mDirWatch.removeFile( mFileName ); mFileName = fileName; mDirWatch.addFile( mFileName ); mDirWatch.startScan(); } TQString ResourceFile::fileName() const { return mFileName; } void ResourceFile::setFormat( const TQString &format ) { mFormatName = format; delete mFormat; FormatFactory *factory = FormatFactory::self(); mFormat = factory->format( mFormatName ); } TQString ResourceFile::format() const { return mFormatName; } void ResourceFile::fileChanged() { kdDebug(5700) << "ResourceFile::fileChanged(): " << mFileName << endl; if ( !addressBook() ) return; if ( mAsynchronous ) asyncLoad(); else { load(); kdDebug() << "addressBookChanged() " << endl; addressBook()->emitAddressBookChanged(); } } void ResourceFile::removeAddressee( const Addressee &addr ) { TQFile::remove( TQFile::encodeName( locateLocal( "data", "kabc/photos/" ) + addr.uid() ) ); TQFile::remove( TQFile::encodeName( locateLocal( "data", "kabc/logos/" ) + addr.uid() ) ); TQFile::remove( TQFile::encodeName( locateLocal( "data", "kabc/sounds/" ) + addr.uid() ) ); mAddrMap.erase( addr.uid() ); } void ResourceFile::emitSavingFinished() { emit savingFinished( this ); } void ResourceFile::emitSavingError() { emit savingError( this, i18n( "Unable to save file '%1'." ).arg( mFileName ) ); } void ResourceFile::emitLoadingFinished() { emit loadingFinished( this ); } void ResourceFile::emitLoadingError() { emit loadingError( this, i18n( "Problems during parsing file '%1'." ).arg( mFileName ) ); } #include "resourcefile.moc"