akonadi
agentbase.cpp
00001 /* 00002 Copyright (c) 2006 Till Adam <adam@kde.org> 00003 Copyright (c) 2007 Volker Krause <vkrause@kde.org> 00004 Copyright (c) 2007 Bruno Virlet <bruno.virlet@gmail.com> 00005 Copyright (c) 2008 Kevin Krammer <kevin.krammer@gmx.at> 00006 00007 This library is free software; you can redistribute it and/or modify it 00008 under the terms of the GNU Library General Public License as published by 00009 the Free Software Foundation; either version 2 of the License, or (at your 00010 option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, but WITHOUT 00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00015 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 the 00019 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00020 02110-1301, USA. 00021 */ 00022 00023 #include "agentbase.h" 00024 #include "agentbase_p.h" 00025 00026 #include "agentmanager.h" 00027 #include "changerecorder.h" 00028 #include "controladaptor.h" 00029 #include "dbusconnectionpool.h" 00030 #include "itemfetchjob.h" 00031 #include "kdepimlibs-version.h" 00032 #include "monitor_p.h" 00033 #include "servermanager_p.h" 00034 #include "session.h" 00035 #include "session_p.h" 00036 #include "statusadaptor.h" 00037 #include "xdgbasedirs_p.h" 00038 00039 #include <kaboutdata.h> 00040 #include <kcmdlineargs.h> 00041 #include <kdebug.h> 00042 #include <klocale.h> 00043 #include <kstandarddirs.h> 00044 00045 #include <QtCore/QDir> 00046 #include <QtCore/QSettings> 00047 #include <QtCore/QTimer> 00048 #include <QtDBus/QtDBus> 00049 #include <QtGui/QApplication> 00050 00051 #include <signal.h> 00052 #include <stdlib.h> 00053 00054 00055 //#define EXPERIMENTAL_INPROCESS_AGENTS 1 00056 00057 using namespace Akonadi; 00058 00059 static AgentBase *sAgentBase = 0; 00060 00061 AgentBase::Observer::Observer() 00062 { 00063 } 00064 00065 AgentBase::Observer::~Observer() 00066 { 00067 } 00068 00069 void AgentBase::Observer::itemAdded( const Item &item, const Collection &collection ) 00070 { 00071 Q_UNUSED( item ); 00072 Q_UNUSED( collection ); 00073 if ( sAgentBase != 0 ) 00074 sAgentBase->d_ptr->changeProcessed(); 00075 } 00076 00077 void AgentBase::Observer::itemChanged( const Item &item, const QSet<QByteArray> &partIdentifiers ) 00078 { 00079 Q_UNUSED( item ); 00080 Q_UNUSED( partIdentifiers ); 00081 if ( sAgentBase != 0 ) 00082 sAgentBase->d_ptr->changeProcessed(); 00083 } 00084 00085 void AgentBase::Observer::itemRemoved( const Item &item ) 00086 { 00087 Q_UNUSED( item ); 00088 if ( sAgentBase != 0 ) 00089 sAgentBase->d_ptr->changeProcessed(); 00090 } 00091 00092 void AgentBase::Observer::collectionAdded( const Akonadi::Collection &collection, const Akonadi::Collection &parent ) 00093 { 00094 Q_UNUSED( collection ); 00095 Q_UNUSED( parent ); 00096 if ( sAgentBase != 0 ) 00097 sAgentBase->d_ptr->changeProcessed(); 00098 } 00099 00100 void AgentBase::Observer::collectionChanged( const Collection &collection ) 00101 { 00102 Q_UNUSED( collection ); 00103 if ( sAgentBase != 0 ) 00104 sAgentBase->d_ptr->changeProcessed(); 00105 } 00106 00107 void AgentBase::Observer::collectionRemoved( const Collection &collection ) 00108 { 00109 Q_UNUSED( collection ); 00110 if ( sAgentBase != 0 ) 00111 sAgentBase->d_ptr->changeProcessed(); 00112 } 00113 00114 void AgentBase::ObserverV2::itemMoved( const Akonadi::Item &item, const Akonadi::Collection &source, const Akonadi::Collection &dest ) 00115 { 00116 Q_UNUSED( item ); 00117 Q_UNUSED( source ); 00118 Q_UNUSED( dest ); 00119 if ( sAgentBase != 0 ) 00120 sAgentBase->d_ptr->changeProcessed(); 00121 } 00122 00123 void AgentBase::ObserverV2::itemLinked( const Akonadi::Item& item, const Akonadi::Collection& collection ) 00124 { 00125 Q_UNUSED( item ); 00126 Q_UNUSED( collection ); 00127 if ( sAgentBase != 0 ) { 00128 // not implementation, let's disconnect the signal to enable optimizations in Monitor 00129 QObject::disconnect( sAgentBase->changeRecorder(), SIGNAL( itemLinked( const Akonadi::Item&, const Akonadi::Collection& ) ), 00130 sAgentBase->d_ptr, SLOT( itemLinked( const Akonadi::Item&, const Akonadi::Collection& ) ) ); 00131 sAgentBase->d_ptr->changeProcessed(); 00132 } 00133 } 00134 00135 void AgentBase::ObserverV2::itemUnlinked( const Akonadi::Item& item, const Akonadi::Collection& collection ) 00136 { 00137 Q_UNUSED( item ); 00138 Q_UNUSED( collection ); 00139 if ( sAgentBase != 0 ) { 00140 // not implementation, let's disconnect the signal to enable optimizations in Monitor 00141 QObject::disconnect( sAgentBase->changeRecorder(), SIGNAL( itemUnlinked( const Akonadi::Item&, const Akonadi::Collection& ) ), 00142 sAgentBase->d_ptr, SLOT( itemUnlinked( const Akonadi::Item&, const Akonadi::Collection& ) ) ); 00143 sAgentBase->d_ptr->changeProcessed(); 00144 } 00145 } 00146 00147 void AgentBase::ObserverV2::collectionMoved( const Akonadi::Collection &collection, const Akonadi::Collection &source, const Akonadi::Collection &dest ) 00148 { 00149 Q_UNUSED( collection ); 00150 Q_UNUSED( source ); 00151 Q_UNUSED( dest ); 00152 if ( sAgentBase != 0 ) 00153 sAgentBase->d_ptr->changeProcessed(); 00154 } 00155 00156 void AgentBase::ObserverV2::collectionChanged( const Akonadi::Collection &collection, const QSet<QByteArray> &partIdentifiers ) 00157 { 00158 Q_UNUSED( partIdentifiers ); 00159 collectionChanged( collection ); 00160 } 00161 00162 //@cond PRIVATE 00163 00164 AgentBasePrivate::AgentBasePrivate( AgentBase *parent ) 00165 : q_ptr( parent ), 00166 mDBusConnection( QString() ), 00167 mStatusCode( AgentBase::Idle ), 00168 mProgress( 0 ), 00169 mNeedsNetwork( false ), 00170 mOnline( false ), 00171 mSettings( 0 ), 00172 mObserver( 0 ) 00173 { 00174 #ifdef _WIN32_WCE 00175 QThread::currentThread()->setPriority(QThread::LowPriority); 00176 #endif 00177 Internal::setClientType( Internal::Agent ); 00178 } 00179 00180 AgentBasePrivate::~AgentBasePrivate() 00181 { 00182 mChangeRecorder->setConfig( 0 ); 00183 delete mSettings; 00184 } 00185 00186 void AgentBasePrivate::init() 00187 { 00188 Q_Q( AgentBase ); 00189 00193 SessionPrivate::createDefaultSession( mId.toLatin1() ); 00194 00195 if ( QThread::currentThread() != QCoreApplication::instance()->thread() ) { 00196 mDBusConnection = QDBusConnection::connectToBus( QDBusConnection::SessionBus, q->identifier() ); 00197 Q_ASSERT( mDBusConnection.isConnected() ); 00198 } 00199 00200 mTracer = new org::freedesktop::Akonadi::Tracer( QLatin1String( "org.freedesktop.Akonadi" ), 00201 QLatin1String( "/tracing" ), 00202 DBusConnectionPool::threadConnection(), q ); 00203 00204 new Akonadi__ControlAdaptor( q ); 00205 new Akonadi__StatusAdaptor( q ); 00206 if ( !DBusConnectionPool::threadConnection().registerObject( QLatin1String( "/" ), q, QDBusConnection::ExportAdaptors ) ) 00207 q->error( QString::fromLatin1( "Unable to register object at dbus: %1" ).arg( DBusConnectionPool::threadConnection().lastError().message() ) ); 00208 00209 mSettings = new QSettings( QString::fromLatin1( "%1/agent_config_%2" ).arg( XdgBaseDirs::saveDir( "config", QLatin1String( "akonadi" ) ), mId ), QSettings::IniFormat ); 00210 00211 mChangeRecorder = new ChangeRecorder( q ); 00212 mChangeRecorder->ignoreSession( Session::defaultSession() ); 00213 mChangeRecorder->itemFetchScope().setCacheOnly( true ); 00214 mChangeRecorder->setConfig( mSettings ); 00215 00216 mOnline = mSettings->value( QLatin1String( "Agent/Online" ), true ).toBool(); 00217 00218 // reinitialize the status message now that online state is available 00219 mStatusMessage = defaultReadyMessage(); 00220 00221 mName = mSettings->value( QLatin1String( "Agent/Name" ) ).toString(); 00222 if ( mName.isEmpty() ) { 00223 mName = mSettings->value( QLatin1String( "Resource/Name" ) ).toString(); 00224 if ( !mName.isEmpty() ) { 00225 mSettings->remove( QLatin1String( "Resource/Name" ) ); 00226 mSettings->setValue( QLatin1String( "Agent/Name" ), mName ); 00227 } 00228 } 00229 00230 connect( mChangeRecorder, SIGNAL( itemAdded( const Akonadi::Item&, const Akonadi::Collection& ) ), 00231 SLOT( itemAdded( const Akonadi::Item&, const Akonadi::Collection& ) ) ); 00232 connect( mChangeRecorder, SIGNAL( itemChanged( const Akonadi::Item&, const QSet<QByteArray>& ) ), 00233 SLOT( itemChanged( const Akonadi::Item&, const QSet<QByteArray>& ) ) ); 00234 connect( mChangeRecorder, SIGNAL( itemMoved( const Akonadi::Item&, const Akonadi::Collection&, const Akonadi::Collection& ) ), 00235 SLOT( itemMoved( const Akonadi::Item&, const Akonadi::Collection&, const Akonadi::Collection& ) ) ); 00236 connect( mChangeRecorder, SIGNAL( itemRemoved( const Akonadi::Item& ) ), 00237 SLOT( itemRemoved( const Akonadi::Item& ) ) ); 00238 connect( mChangeRecorder, SIGNAL( collectionAdded( const Akonadi::Collection&, const Akonadi::Collection& ) ), 00239 SLOT( collectionAdded( const Akonadi::Collection&, const Akonadi::Collection& ) ) ); 00240 connect( mChangeRecorder, SIGNAL( itemLinked( const Akonadi::Item&, const Akonadi::Collection& ) ), 00241 SLOT( itemLinked( const Akonadi::Item&, const Akonadi::Collection& ) ) ); 00242 connect( mChangeRecorder, SIGNAL( itemUnlinked( const Akonadi::Item&, const Akonadi::Collection& ) ), 00243 SLOT( itemUnlinked( const Akonadi::Item&, const Akonadi::Collection& ) ) ); 00244 connect( mChangeRecorder, SIGNAL( collectionChanged( const Akonadi::Collection& ) ), 00245 SLOT( collectionChanged( const Akonadi::Collection& ) ) ); 00246 connect( mChangeRecorder, SIGNAL( collectionChanged( const Akonadi::Collection&, const QSet<QByteArray>& ) ), 00247 SLOT( collectionChanged( const Akonadi::Collection&, const QSet<QByteArray>& ) ) ); 00248 connect( mChangeRecorder, SIGNAL( collectionMoved( const Akonadi::Collection&, const Akonadi::Collection&, const Akonadi::Collection& ) ), 00249 SLOT( collectionMoved( const Akonadi::Collection&, const Akonadi::Collection&, const Akonadi::Collection& ) ) ); 00250 connect( mChangeRecorder, SIGNAL( collectionRemoved( const Akonadi::Collection& ) ), 00251 SLOT( collectionRemoved( const Akonadi::Collection& ) ) ); 00252 connect( mChangeRecorder, SIGNAL( collectionSubscribed( const Akonadi::Collection&, const Akonadi::Collection& ) ), 00253 SLOT( collectionSubscribed( const Akonadi::Collection&, const Akonadi::Collection& ) ) ); 00254 connect( mChangeRecorder, SIGNAL( collectionUnsubscribed( const Akonadi::Collection& ) ), 00255 SLOT( collectionUnsubscribed( const Akonadi::Collection& ) ) ); 00256 00257 connect( q, SIGNAL( status( int, const QString& ) ), q, SLOT( slotStatus( int, const QString& ) ) ); 00258 connect( q, SIGNAL( percent( int ) ), q, SLOT( slotPercent( int ) ) ); 00259 connect( q, SIGNAL( warning( const QString& ) ), q, SLOT( slotWarning( const QString& ) ) ); 00260 connect( q, SIGNAL( error( const QString& ) ), q, SLOT( slotError( const QString& ) ) ); 00261 00262 // Use reference counting to allow agents to finish internal jobs when the 00263 // agent is stopped. 00264 KGlobal::ref(); 00265 if ( QThread::currentThread() == QCoreApplication::instance()->thread() ) 00266 KGlobal::setAllowQuit( true ); 00267 00268 #ifndef Q_OS_WINCE 00269 // disable session management 00270 if ( KApplication::kApplication() ) 00271 KApplication::kApplication()->disableSessionManagement(); 00272 #endif 00273 00274 mResourceTypeName = AgentManager::self()->instance(mId).type().name(); 00275 setProgramName(); 00276 00277 QTimer::singleShot( 0, q, SLOT(delayedInit()) ); 00278 } 00279 00280 void AgentBasePrivate::delayedInit() 00281 { 00282 Q_Q( AgentBase ); 00283 if ( !DBusConnectionPool::threadConnection().registerService( QLatin1String( "org.freedesktop.Akonadi.Agent." ) + mId ) ) 00284 kFatal() << "Unable to register service at dbus:" << DBusConnectionPool::threadConnection().lastError().message(); 00285 q->setOnline( mOnline ); 00286 } 00287 00288 void AgentBasePrivate::setProgramName() 00289 { 00290 // ugly, really ugly, if you find another solution, change it and blame me for this code (Andras) 00291 QString programName = mResourceTypeName; 00292 if ( !mName.isEmpty() ) { 00293 programName = i18nc( "Name and type of Akonadi resource", "%1 of type %2", mName, mResourceTypeName ) ; 00294 } 00295 const_cast<KAboutData*>( KGlobal::mainComponent().aboutData() )->setProgramName( ki18n( programName.toUtf8() ) ); 00296 } 00297 00298 void AgentBasePrivate::itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection ) 00299 { 00300 if ( mObserver != 0 ) 00301 mObserver->itemAdded( item, collection ); 00302 } 00303 00304 void AgentBasePrivate::itemChanged( const Akonadi::Item &item, const QSet<QByteArray> &partIdentifiers ) 00305 { 00306 if ( mObserver != 0 ) 00307 mObserver->itemChanged( item, partIdentifiers ); 00308 } 00309 00310 void AgentBasePrivate::itemMoved( const Akonadi::Item &item, const Akonadi::Collection &source, const Akonadi::Collection &dest ) 00311 { 00312 AgentBase::ObserverV2 *observer2 = dynamic_cast<AgentBase::ObserverV2*>( mObserver ); 00313 if ( mObserver ) { 00314 // inter-resource moves, requires we know which resources the source and destination are in though 00315 if ( !source.resource().isEmpty() && !dest.resource().isEmpty() ) { 00316 if ( source.resource() != dest.resource() ) { 00317 if ( source.resource() == q_ptr->identifier() ) { // moved away from us 00318 Akonadi::Item i( item ); 00319 i.setParentCollection( source ); 00320 mObserver->itemRemoved( i ); 00321 } 00322 else if ( dest.resource() == q_ptr->identifier() ) // moved to us 00323 mObserver->itemAdded( item, dest ); 00324 else if ( observer2 ) 00325 observer2->itemMoved( item, source, dest ); 00326 else 00327 // not for us, not sure if we should get here at all 00328 changeProcessed(); 00329 return; 00330 } 00331 } 00332 // intra-resource move 00333 if ( observer2 ) { 00334 observer2->itemMoved( item, source, dest ); 00335 } else { 00336 // ### we cannot just call itemRemoved here as this will already trigger changeProcessed() 00337 // so, just itemAdded() is good enough as no resource can have implemented intra-resource moves anyway 00338 // without using ObserverV2 00339 mObserver->itemAdded( item, dest ); 00340 // mObserver->itemRemoved( item ); 00341 } 00342 } 00343 } 00344 00345 void AgentBasePrivate::itemRemoved( const Akonadi::Item &item ) 00346 { 00347 if ( mObserver != 0 ) 00348 mObserver->itemRemoved( item ); 00349 } 00350 00351 void AgentBasePrivate::itemLinked( const Akonadi::Item &item, const Akonadi::Collection &collection ) 00352 { 00353 AgentBase::ObserverV2 *observer2 = dynamic_cast<AgentBase::ObserverV2*>( mObserver ); 00354 if ( observer2 ) 00355 observer2->itemLinked( item, collection ); 00356 else 00357 changeProcessed(); 00358 } 00359 00360 void AgentBasePrivate::itemUnlinked( const Akonadi::Item &item, const Akonadi::Collection &collection ) 00361 { 00362 AgentBase::ObserverV2 *observer2 = dynamic_cast<AgentBase::ObserverV2*>( mObserver ); 00363 if ( observer2 ) 00364 observer2->itemUnlinked( item, collection ); 00365 else 00366 changeProcessed(); 00367 } 00368 00369 void AgentBasePrivate::collectionAdded( const Akonadi::Collection &collection, const Akonadi::Collection &parent ) 00370 { 00371 if ( mObserver != 0 ) 00372 mObserver->collectionAdded( collection, parent ); 00373 } 00374 00375 void AgentBasePrivate::collectionChanged( const Akonadi::Collection &collection ) 00376 { 00377 AgentBase::ObserverV2 *observer2 = dynamic_cast<AgentBase::ObserverV2*>( mObserver ); 00378 if ( mObserver != 0 && observer2 == 0 ) // For ObserverV2 we use the variant with the part identifiers 00379 mObserver->collectionChanged( collection ); 00380 } 00381 00382 void AgentBasePrivate::collectionChanged( const Akonadi::Collection &collection, const QSet<QByteArray> &partIdentifiers ) 00383 { 00384 AgentBase::ObserverV2 *observer2 = dynamic_cast<AgentBase::ObserverV2*>( mObserver ); 00385 if ( observer2 != 0 ) 00386 observer2->collectionChanged( collection, partIdentifiers ); 00387 } 00388 00389 void AgentBasePrivate::collectionMoved( const Akonadi::Collection &collection, const Akonadi::Collection &source, const Akonadi::Collection &dest ) 00390 { 00391 AgentBase::ObserverV2 *observer2 = dynamic_cast<AgentBase::ObserverV2*>( mObserver ); 00392 if ( mObserver ) { 00393 // inter-resource moves, requires we know which resources the source and destination are in though 00394 if ( !source.resource().isEmpty() && !dest.resource().isEmpty() ) { 00395 if ( source.resource() != dest.resource() ) { 00396 if ( source.resource() == q_ptr->identifier() ) // moved away from us 00397 mObserver->collectionRemoved( collection ); 00398 else if ( dest.resource() == q_ptr->identifier() ) // moved to us 00399 mObserver->collectionAdded( collection, dest ); 00400 else if ( observer2 ) 00401 observer2->collectionMoved( collection, source, dest ); 00402 else // not for us, not sure if we should get here at all 00403 changeProcessed(); 00404 return; 00405 } 00406 } 00407 // intra-resource move 00408 if ( observer2 ) { 00409 observer2->collectionMoved( collection, source, dest ); 00410 } else { 00411 // ### we cannot just call collectionRemoved here as this will already trigger changeProcessed() 00412 // so, just collectionAdded() is good enough as no resource can have implemented intra-resource moves anyway 00413 // without using ObserverV2 00414 mObserver->collectionAdded( collection, dest ); 00415 } 00416 } 00417 } 00418 00419 void AgentBasePrivate::collectionRemoved( const Akonadi::Collection &collection ) 00420 { 00421 if ( mObserver != 0 ) 00422 mObserver->collectionRemoved( collection ); 00423 } 00424 00425 void AgentBasePrivate::collectionSubscribed( const Akonadi::Collection &collection, const Akonadi::Collection &parent ) 00426 { 00427 Q_UNUSED( collection ); 00428 Q_UNUSED( parent ); 00429 changeProcessed(); 00430 } 00431 00432 void AgentBasePrivate::collectionUnsubscribed( const Akonadi::Collection &collection ) 00433 { 00434 Q_UNUSED( collection ); 00435 changeProcessed(); 00436 } 00437 00438 void AgentBasePrivate::changeProcessed() 00439 { 00440 mChangeRecorder->changeProcessed(); 00441 QTimer::singleShot( 0, mChangeRecorder, SLOT( replayNext() ) ); 00442 } 00443 00444 void AgentBasePrivate::slotStatus( int status, const QString &message ) 00445 { 00446 mStatusMessage = message; 00447 mStatusCode = 0; 00448 00449 switch ( status ) { 00450 case AgentBase::Idle: 00451 if ( mStatusMessage.isEmpty() ) 00452 mStatusMessage = defaultReadyMessage(); 00453 00454 mStatusCode = 0; 00455 break; 00456 case AgentBase::Running: 00457 if ( mStatusMessage.isEmpty() ) 00458 mStatusMessage = defaultSyncingMessage(); 00459 00460 mStatusCode = 1; 00461 break; 00462 case AgentBase::Broken: 00463 if ( mStatusMessage.isEmpty() ) 00464 mStatusMessage = defaultErrorMessage(); 00465 00466 mStatusCode = 2; 00467 break; 00468 default: 00469 Q_ASSERT( !"Unknown status passed" ); 00470 break; 00471 } 00472 } 00473 00474 void AgentBasePrivate::slotPercent( int progress ) 00475 { 00476 mProgress = progress; 00477 } 00478 00479 void AgentBasePrivate::slotWarning( const QString& message ) 00480 { 00481 mTracer->warning( QString::fromLatin1( "AgentBase(%1)" ).arg( mId ), message ); 00482 } 00483 00484 void AgentBasePrivate::slotError( const QString& message ) 00485 { 00486 mTracer->error( QString::fromLatin1( "AgentBase(%1)" ).arg( mId ), message ); 00487 } 00488 00489 void AgentBasePrivate::slotNetworkStatusChange( Solid::Networking::Status stat ) 00490 { 00491 Q_Q( AgentBase ); 00492 q->setOnline( stat == Solid::Networking::Unknown || stat == Solid::Networking::Connected ); 00493 } 00494 00495 AgentBase::AgentBase( const QString & id ) 00496 : d_ptr( new AgentBasePrivate( this ) ) 00497 { 00498 sAgentBase = this; 00499 d_ptr->mId = id; 00500 d_ptr->init(); 00501 } 00502 00503 AgentBase::AgentBase( AgentBasePrivate* d, const QString &id ) : 00504 d_ptr( d ) 00505 { 00506 sAgentBase = this; 00507 d_ptr->mId = id; 00508 d_ptr->init(); 00509 } 00510 00511 AgentBase::~AgentBase() 00512 { 00513 delete d_ptr; 00514 } 00515 00516 QString AgentBase::parseArguments( int argc, char **argv ) 00517 { 00518 QString identifier; 00519 if ( argc < 3 ) { 00520 kDebug() << "Not enough arguments passed..."; 00521 exit( 1 ); 00522 } 00523 00524 for ( int i = 1; i < argc - 1; ++i ) { 00525 if ( QLatin1String( argv[ i ] ) == QLatin1String( "--identifier" ) ) 00526 identifier = QLatin1String( argv[ i + 1 ] ); 00527 } 00528 00529 if ( identifier.isEmpty() ) { 00530 kDebug() << "Identifier argument missing"; 00531 exit( 1 ); 00532 } 00533 00534 const QFileInfo fi( QString::fromLocal8Bit( argv[0] ) ); 00535 // strip off full path and possible .exe suffix 00536 const QByteArray catalog = fi.baseName().toLatin1(); 00537 00538 KCmdLineArgs::init( argc, argv, identifier.toLatin1(), catalog, ki18n( "Akonadi Agent" ), KDEPIMLIBS_VERSION, 00539 ki18n( "Akonadi Agent" ) ); 00540 00541 KCmdLineOptions options; 00542 options.add( "identifier <argument>", ki18n( "Agent identifier" ) ); 00543 KCmdLineArgs::addCmdLineOptions( options ); 00544 00545 return identifier; 00546 } 00547 00548 // @endcond 00549 00550 int AgentBase::init( AgentBase *r ) 00551 { 00552 QApplication::setQuitOnLastWindowClosed( false ); 00553 KGlobal::locale()->insertCatalog( QLatin1String( "libakonadi" ) ); 00554 int rv = kapp->exec(); 00555 delete r; 00556 return rv; 00557 } 00558 00559 int AgentBase::status() const 00560 { 00561 Q_D( const AgentBase ); 00562 00563 return d->mStatusCode; 00564 } 00565 00566 QString AgentBase::statusMessage() const 00567 { 00568 Q_D( const AgentBase ); 00569 00570 return d->mStatusMessage; 00571 } 00572 00573 int AgentBase::progress() const 00574 { 00575 Q_D( const AgentBase ); 00576 00577 return d->mProgress; 00578 } 00579 00580 QString AgentBase::progressMessage() const 00581 { 00582 Q_D( const AgentBase ); 00583 00584 return d->mProgressMessage; 00585 } 00586 00587 bool AgentBase::isOnline() const 00588 { 00589 Q_D( const AgentBase ); 00590 00591 return d->mOnline; 00592 } 00593 00594 void AgentBase::setNeedsNetwork( bool needsNetwork ) 00595 { 00596 Q_D( AgentBase ); 00597 d->mNeedsNetwork = needsNetwork; 00598 00599 if ( d->mNeedsNetwork ) { 00600 connect( Solid::Networking::notifier() 00601 , SIGNAL( statusChanged( Solid::Networking::Status ) ) 00602 , this, SLOT( slotNetworkStatusChange( Solid::Networking::Status ) ) ); 00603 } else { 00604 disconnect( Solid::Networking::notifier(), 0, 0, 0 ); 00605 setOnline( true ); 00606 } 00607 } 00608 00609 void AgentBase::setOnline( bool state ) 00610 { 00611 Q_D( AgentBase ); 00612 d->mOnline = state; 00613 d->mSettings->setValue( QLatin1String( "Agent/Online" ), state ); 00614 doSetOnline( state ); 00615 emit onlineChanged( state ); 00616 } 00617 00618 void AgentBase::doSetOnline( bool online ) 00619 { 00620 Q_UNUSED( online ); 00621 } 00622 00623 void AgentBase::configure( WId windowId ) 00624 { 00625 Q_UNUSED( windowId ); 00626 emit configurationDialogAccepted(); 00627 } 00628 00629 #ifdef Q_OS_WIN //krazy:exclude=cpp 00630 void AgentBase::configure( qlonglong windowId ) 00631 { 00632 configure( reinterpret_cast<WId>( windowId ) ); 00633 } 00634 #endif 00635 00636 WId AgentBase::winIdForDialogs() const 00637 { 00638 const bool registered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( QLatin1String( "org.freedesktop.akonaditray" ) ); 00639 if ( !registered ) 00640 return 0; 00641 00642 QDBusInterface dbus( QLatin1String( "org.freedesktop.akonaditray" ), QLatin1String( "/Actions" ), 00643 QLatin1String( "org.freedesktop.Akonadi.Tray" ) ); 00644 const QDBusMessage reply = dbus.call( QLatin1String( "getWinId" ) ); 00645 00646 if ( reply.type() == QDBusMessage::ErrorMessage ) 00647 return 0; 00648 00649 const WId winid = (WId)reply.arguments().at( 0 ).toLongLong(); 00650 00651 return winid; 00652 } 00653 00654 void AgentBase::quit() 00655 { 00656 Q_D( AgentBase ); 00657 aboutToQuit(); 00658 00659 if ( d->mSettings ) { 00660 d->mChangeRecorder->setConfig( 0 ); 00661 d->mSettings->sync(); 00662 } 00663 00664 KGlobal::deref(); 00665 } 00666 00667 void AgentBase::aboutToQuit() 00668 { 00669 } 00670 00671 void AgentBase::cleanup() 00672 { 00673 Q_D( AgentBase ); 00674 // prevent the monitor from picking up deletion signals for our own data if we are a resource 00675 // and thus avoid that we kill our own data as last act before our own death 00676 d->mChangeRecorder->blockSignals( true ); 00677 00678 aboutToQuit(); 00679 00680 const QString fileName = d->mSettings->fileName(); 00681 00682 /* 00683 * First destroy the settings object... 00684 */ 00685 d->mChangeRecorder->setConfig( 0 ); 00686 delete d->mSettings; 00687 d->mSettings = 0; 00688 00689 /* 00690 * ... then remove the file from hd. 00691 */ 00692 QFile::remove( fileName ); 00693 00694 /* 00695 * ... and remove the changes file from hd. 00696 */ 00697 QFile::remove( fileName + QLatin1String( "_changes.dat" ) ); 00698 00699 /* 00700 * ... and also remove the agent configuration file if there is one. 00701 */ 00702 QString configFile = KStandardDirs::locateLocal( "config", config()->name() ); 00703 QFile::remove( configFile ); 00704 00705 KGlobal::deref(); 00706 } 00707 00708 void AgentBase::registerObserver( Observer *observer ) 00709 { 00710 // TODO in theory we should re-connect change recorder signals here that we disconnected previously 00711 d_ptr->mObserver = observer; 00712 } 00713 00714 QString AgentBase::identifier() const 00715 { 00716 return d_ptr->mId; 00717 } 00718 00719 void AgentBase::setAgentName( const QString &name ) 00720 { 00721 Q_D( AgentBase ); 00722 if ( name == d->mName ) 00723 return; 00724 00725 // TODO: rename collection 00726 d->mName = name; 00727 00728 if ( d->mName.isEmpty() || d->mName == d->mId ) { 00729 d->mSettings->remove( QLatin1String( "Resource/Name" ) ); 00730 d->mSettings->remove( QLatin1String( "Agent/Name" ) ); 00731 } else 00732 d->mSettings->setValue( QLatin1String( "Agent/Name" ), d->mName ); 00733 00734 d->mSettings->sync(); 00735 00736 d->setProgramName(); 00737 00738 emit agentNameChanged( d->mName ); 00739 } 00740 00741 QString AgentBase::agentName() const 00742 { 00743 Q_D( const AgentBase ); 00744 if ( d->mName.isEmpty() ) 00745 return d->mId; 00746 else 00747 return d->mName; 00748 } 00749 00750 void AgentBase::changeProcessed() 00751 { 00752 Q_D( AgentBase ); 00753 d->changeProcessed(); 00754 } 00755 00756 ChangeRecorder * AgentBase::changeRecorder() const 00757 { 00758 return d_ptr->mChangeRecorder; 00759 } 00760 00761 KSharedConfigPtr AgentBase::config() 00762 { 00763 if ( QCoreApplication::instance()->thread() == QThread::currentThread() ) 00764 return KGlobal::config(); 00765 else 00766 return componentData().config(); 00767 } 00768 00769 void AgentBase::abort() 00770 { 00771 emit abortRequested(); 00772 } 00773 00774 void AgentBase::reconfigure() 00775 { 00776 emit reloadConfiguration(); 00777 } 00778 00779 extern QThreadStorage<KComponentData*> s_agentComponentDatas; 00780 00781 KComponentData AgentBase::componentData() 00782 { 00783 if ( QThread::currentThread() == QCoreApplication::instance()->thread() ) { 00784 if ( s_agentComponentDatas.hasLocalData() ) 00785 return *(s_agentComponentDatas.localData()); 00786 else 00787 return KGlobal::mainComponent(); 00788 } 00789 00790 Q_ASSERT( s_agentComponentDatas.hasLocalData() ); 00791 return *(s_agentComponentDatas.localData()); 00792 } 00793 00794 #include "agentbase.moc" 00795 #include "agentbase_p.moc"