resourcefile.cpp
00001 /* 00002 This file is part of libtdeabc. 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 <tqfile.h> 00029 #include <tqfileinfo.h> 00030 #include <tqtimer.h> 00031 00032 #include <tdeapplication.h> 00033 #include <tdeconfig.h> 00034 #include <kdebug.h> 00035 #include <tdeio/scheduler.h> 00036 #include <tdelocale.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 TDEABC; 00048 00049 ResourceFile::ResourceFile( const TDEConfig *config ) 00050 : Resource( config ), mFormat( 0 ), 00051 mAsynchronous( false ) 00052 { 00053 TQString 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 TQString &fileName, 00067 const TQString &formatName ) 00068 : Resource( 0 ), mFormat( 0 ), 00069 mAsynchronous( false ) 00070 { 00071 init( fileName, formatName ); 00072 } 00073 00074 void ResourceFile::init( const TQString &fileName, const TQString &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, TQT_SIGNAL( dirty(const TQString&) ), TQT_SLOT( fileChanged() ) ); 00087 connect( &mDirWatch, TQT_SIGNAL( created(const TQString&) ), TQT_SLOT( fileChanged() ) ); 00088 connect( &mDirWatch, TQT_SIGNAL( deleted(const TQString&) ), TQT_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( TDEConfig *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 TQFile 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 TQFileInfo 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 kdDebug(5700) << "File size is zero. Evaluating backups" << endl; 00168 for (int i=0; i!=20; i++) 00169 { 00170 TQFile backup( mFileName + "__" + TQString::number(i) ); 00171 kdDebug(5700) << "Evaluating" << backup.name() << " size: " << backup.size() << endl; 00172 if ( backup.size() != 0 ) 00173 { 00174 kdDebug(5700) << "Restoring backup " << i << endl; 00175 const TQString src = mFileName + "__" + TQString::number(i); 00176 const TQString dest = mFileName; 00177 00178 // copy src to dest 00179 if ( ! backup.open( IO_ReadOnly ) ) { 00180 // const TQByteArray data = backup.readAll(); 00181 kdDebug(5700) << "can not open source for reading " << src << endl; 00182 continue; 00183 } 00184 00185 // remove dest 00186 TQFile::remove( dest ); 00187 00188 TQString text; 00189 TQTextStream instream( &backup ); 00190 instream.setEncoding( TQTextStream::UnicodeUTF8 ); 00191 text = instream.read(); 00192 backup.close(); 00193 00194 TQFile out( dest ); 00195 if ( ! out.open( IO_WriteOnly ) ) { 00196 // out.writeBlock( data ); 00197 kdDebug(5700) << "can not open target for writing " << dest << endl; 00198 continue; 00199 } 00200 TQTextStream outstream( &out ); 00201 outstream.setEncoding( TQTextStream::UnicodeUTF8 ); 00202 outstream << text; 00203 out.close(); 00204 00205 return true; 00206 } 00207 } 00208 return true; 00209 } 00210 00211 bool ok = mFormat->checkFormat( &file ); 00212 file.close(); 00213 00214 return ok; 00215 } 00216 } 00217 00218 void ResourceFile::doClose() 00219 { 00220 } 00221 00222 bool ResourceFile::load() 00223 { 00224 kdDebug(5700) << "ResourceFile::load(): '" << mFileName << "'" << endl; 00225 00226 mAsynchronous = false; 00227 00228 TQFile file( mFileName ); 00229 if ( !file.open( IO_ReadOnly ) ) { 00230 addressBook()->error( i18n( "Unable to open file '%1'." ).arg( mFileName ) ); 00231 return false; 00232 } 00233 00234 clear(); 00235 00236 return mFormat->loadAll( addressBook(), this, &file ); 00237 } 00238 00239 bool ResourceFile::asyncLoad() 00240 { 00241 kdDebug(5700) << "ResourceFile::asyncLoad()" << endl; 00242 00243 mAsynchronous = true; 00244 00245 bool ok = load(); 00246 00247 if ( !ok ) 00248 emitLoadingError(); 00249 else 00250 emitLoadingFinished(); 00251 00252 return true; 00253 } 00254 00255 bool ResourceFile::save( Ticket * ) 00256 { 00257 kdDebug(5700) << "ResourceFile::save()" << endl; 00258 00259 // Only do the logrotate dance when the __0 file is not 0 bytes. 00260 TQFile file( mFileName + "__0" ); 00261 if ( file.size() != 0 ) { 00262 const TQString last = mFileName + "__20"; 00263 kdDebug(5700) << "deleting " << last << endl; 00264 00265 TQFile::remove( last ); 00266 00267 for (int i=19; i>=0; i--) 00268 { 00269 const TQString src = mFileName + "__" + TQString::number(i); 00270 const TQString dest = mFileName + "__" + TQString::number(i+1); 00271 kdDebug() << "moving " << src << " -> " << dest << endl; 00272 00273 // copy src to dest 00274 TQFile in( src ); 00275 if ( ! in.exists() ) 00276 continue; 00277 if ( ! in.open( IO_ReadOnly ) ) { 00278 // const TQByteArray data = in.readAll(); 00279 kdDebug(5700) << "can not open source for reading " << src << endl; 00280 return false; 00281 } 00282 TQString text; 00283 TQTextStream instream( &in ); 00284 00285 instream.setEncoding( TQTextStream::UnicodeUTF8 ); 00286 text = instream.read(); 00287 in.close(); 00288 00289 TQFile out( dest ); 00290 if ( ! out.open( IO_WriteOnly ) ) { 00291 // out.writeBlock( data ); 00292 kdDebug(5700) << "can not open target for writing " << dest << endl; 00293 return false; 00294 } 00295 TQTextStream outstream( &out ); 00296 outstream.setEncoding( TQTextStream::UnicodeUTF8 ); 00297 outstream << text; 00298 out.close(); 00299 00300 // remove src 00301 TQFile::remove( src ); 00302 } 00303 } else 00304 kdDebug(5700) << "Not starting logrotate __0 is 0 bytes." << endl; 00305 00306 TQString extension = "__0"; 00307 (void) KSaveFile::backupFile( mFileName, TQString::null /*directory*/, 00308 extension ); 00309 mDirWatch.stopScan(); 00310 00311 KSaveFile saveFile( mFileName ); 00312 bool ok = false; 00313 00314 if ( saveFile.status() == 0 && saveFile.file() ) { 00315 mFormat->saveAll( addressBook(), this, saveFile.file() ); 00316 ok = saveFile.close(); 00317 } 00318 00319 if ( !ok ) { 00320 saveFile.abort(); 00321 addressBook()->error( i18n( "Unable to save file '%1'." ).arg( mFileName ) ); 00322 } 00323 00324 mDirWatch.startScan(); 00325 00326 return ok; 00327 } 00328 00329 bool ResourceFile::asyncSave( Ticket *ticket ) 00330 { 00331 kdDebug(5700) << "ResourceFile::asyncSave()" << endl; 00332 00333 bool ok = save( ticket ); 00334 00335 if ( !ok ) 00336 TQTimer::singleShot( 0, this, TQT_SLOT( emitSavingError() ) ); 00337 else 00338 TQTimer::singleShot( 0, this, TQT_SLOT( emitSavingFinished() ) ); 00339 00340 return ok; 00341 } 00342 00343 void ResourceFile::setFileName( const TQString &fileName ) 00344 { 00345 mDirWatch.stopScan(); 00346 if ( mDirWatch.contains( mFileName ) ) 00347 mDirWatch.removeFile( mFileName ); 00348 00349 mFileName = fileName; 00350 00351 mDirWatch.addFile( mFileName ); 00352 mDirWatch.startScan(); 00353 } 00354 00355 TQString ResourceFile::fileName() const 00356 { 00357 return mFileName; 00358 } 00359 00360 void ResourceFile::setFormat( const TQString &format ) 00361 { 00362 mFormatName = format; 00363 delete mFormat; 00364 00365 FormatFactory *factory = FormatFactory::self(); 00366 mFormat = factory->format( mFormatName ); 00367 } 00368 00369 TQString ResourceFile::format() const 00370 { 00371 return mFormatName; 00372 } 00373 00374 void ResourceFile::fileChanged() 00375 { 00376 kdDebug(5700) << "ResourceFile::fileChanged(): " << mFileName << endl; 00377 00378 if ( !addressBook() ) 00379 return; 00380 00381 if ( mAsynchronous ) 00382 asyncLoad(); 00383 else { 00384 load(); 00385 kdDebug() << "addressBookChanged() " << endl; 00386 addressBook()->emitAddressBookChanged(); 00387 } 00388 } 00389 00390 void ResourceFile::removeAddressee( const Addressee &addr ) 00391 { 00392 TQFile::remove( TQFile::encodeName( locateLocal( "data", "tdeabc/photos/" ) + addr.uid() ) ); 00393 TQFile::remove( TQFile::encodeName( locateLocal( "data", "tdeabc/logos/" ) + addr.uid() ) ); 00394 TQFile::remove( TQFile::encodeName( locateLocal( "data", "tdeabc/sounds/" ) + addr.uid() ) ); 00395 00396 mAddrMap.erase( addr.uid() ); 00397 } 00398 00399 void ResourceFile::emitSavingFinished() 00400 { 00401 emit savingFinished( this ); 00402 } 00403 00404 void ResourceFile::emitSavingError() 00405 { 00406 emit savingError( this, i18n( "Unable to save file '%1'." ).arg( mFileName ) ); 00407 } 00408 00409 void ResourceFile::emitLoadingFinished() 00410 { 00411 emit loadingFinished( this ); 00412 } 00413 00414 void ResourceFile::emitLoadingError() 00415 { 00416 emit loadingError( this, i18n( "Problems during parsing file '%1'." ).arg( mFileName ) ); 00417 } 00418 00419 #include "resourcefile.moc"