00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "agentbase.h"
00024 #include "agentbase_p.h"
00025
00026 #include "controladaptor.h"
00027 #include "statusadaptor.h"
00028 #include "monitor_p.h"
00029 #include "xdgbasedirs_p.h"
00030
00031 #include "session.h"
00032 #include "session_p.h"
00033 #include "changerecorder.h"
00034 #include "itemfetchjob.h"
00035
00036 #include <kaboutdata.h>
00037 #include <kcmdlineargs.h>
00038 #include <kdebug.h>
00039 #include <klocale.h>
00040 #include <kstandarddirs.h>
00041
00042 #include <QtCore/QDir>
00043 #include <QtCore/QSettings>
00044 #include <QtCore/QTimer>
00045 #include <QtGui/QApplication>
00046 #include <QtDBus/QtDBus>
00047
00048 #include <signal.h>
00049 #include <stdlib.h>
00050
00051 using namespace Akonadi;
00052
00053 static AgentBase *sAgentBase = 0;
00054
00055 AgentBase::Observer::Observer()
00056 {
00057 }
00058
00059 AgentBase::Observer::~Observer()
00060 {
00061 }
00062
00063 void AgentBase::Observer::itemAdded( const Item &item, const Collection &collection )
00064 {
00065 kDebug() << "sAgentBase=" << (void*) sAgentBase << "this=" << (void*) this;
00066 Q_UNUSED( item );
00067 Q_UNUSED( collection );
00068 if ( sAgentBase != 0 )
00069 sAgentBase->d_ptr->changeProcessed();
00070 }
00071
00072 void AgentBase::Observer::itemChanged( const Item &item, const QSet<QByteArray> &partIdentifiers )
00073 {
00074 kDebug() << "sAgentBase=" << (void*) sAgentBase << "this=" << (void*) this;
00075 Q_UNUSED( item );
00076 Q_UNUSED( partIdentifiers );
00077 if ( sAgentBase != 0 )
00078 sAgentBase->d_ptr->changeProcessed();
00079 }
00080
00081 void AgentBase::Observer::itemRemoved( const Item &item )
00082 {
00083 kDebug() << "sAgentBase=" << (void*) sAgentBase << "this=" << (void*) this;
00084 Q_UNUSED( item );
00085 if ( sAgentBase != 0 )
00086 sAgentBase->d_ptr->changeProcessed();
00087 }
00088
00089 void AgentBase::Observer::collectionAdded( const Akonadi::Collection &collection, const Akonadi::Collection &parent )
00090 {
00091 kDebug() << "sAgentBase=" << (void*) sAgentBase << "this=" << (void*) this;
00092 Q_UNUSED( collection );
00093 Q_UNUSED( parent );
00094 if ( sAgentBase != 0 )
00095 sAgentBase->d_ptr->changeProcessed();
00096 }
00097
00098 void AgentBase::Observer::collectionChanged( const Collection &collection )
00099 {
00100 kDebug() << "sAgentBase=" << (void*) sAgentBase << "this=" << (void*) this;
00101 Q_UNUSED( collection );
00102 if ( sAgentBase != 0 )
00103 sAgentBase->d_ptr->changeProcessed();
00104 }
00105
00106 void AgentBase::Observer::collectionRemoved( const Collection &collection )
00107 {
00108 kDebug() << "sAgentBase=" << (void*) sAgentBase << "this=" << (void*) this;
00109 Q_UNUSED( collection );
00110 if ( sAgentBase != 0 )
00111 sAgentBase->d_ptr->changeProcessed();
00112 }
00113
00114
00115
00116 AgentBasePrivate::AgentBasePrivate( AgentBase *parent )
00117 : q_ptr( parent ),
00118 mStatusCode( AgentBase::Idle ),
00119 mProgress( 0 ),
00120 mNeedsNetwork( false ),
00121 mOnline( false ),
00122 mSettings( 0 ),
00123 mObserver( 0 )
00124 {
00125 }
00126
00127 AgentBasePrivate::~AgentBasePrivate()
00128 {
00129 mMonitor->setConfig( 0 );
00130 delete mSettings;
00131 }
00132
00133 void AgentBasePrivate::init()
00134 {
00135 Q_Q( AgentBase );
00136
00140 SessionPrivate::createDefaultSession( mId.toLatin1() );
00141
00142 mTracer = new org::freedesktop::Akonadi::Tracer( QLatin1String( "org.freedesktop.Akonadi" ), QLatin1String( "/tracing" ),
00143 QDBusConnection::sessionBus(), q );
00144
00145 new ControlAdaptor( q );
00146 new StatusAdaptor( q );
00147 if ( !QDBusConnection::sessionBus().registerObject( QLatin1String( "/" ), q, QDBusConnection::ExportAdaptors ) )
00148 q->error( QString::fromLatin1( "Unable to register object at dbus: %1" ).arg( QDBusConnection::sessionBus().lastError().message() ) );
00149
00150 mSettings = new QSettings( QString::fromLatin1( "%1/agent_config_%2" ).arg( XdgBaseDirs::saveDir( "config", QLatin1String( "akonadi" ) ), mId ), QSettings::IniFormat );
00151
00152 mMonitor = new ChangeRecorder( q );
00153 mMonitor->ignoreSession( Session::defaultSession() );
00154 mMonitor->itemFetchScope().setCacheOnly( true );
00155 mMonitor->setConfig( mSettings );
00156
00157 mOnline = mSettings->value( QLatin1String( "Agent/Online" ), true ).toBool();
00158
00159 mName = mSettings->value( QLatin1String( "Agent/Name" ) ).toString();
00160 if ( mName.isEmpty() ) {
00161 mName = mSettings->value( QLatin1String( "Resource/Name" ) ).toString();
00162 if ( !mName.isEmpty() ) {
00163 mSettings->remove( QLatin1String( "Resource/Name" ) );
00164 mSettings->setValue( QLatin1String( "Agent/Name" ), mName );
00165 }
00166 }
00167
00168 connect( mMonitor, SIGNAL( itemAdded( const Akonadi::Item&, const Akonadi::Collection& ) ),
00169 SLOT( itemAdded( const Akonadi::Item&, const Akonadi::Collection& ) ) );
00170 connect( mMonitor, SIGNAL( itemChanged( const Akonadi::Item&, const QSet<QByteArray>& ) ),
00171 SLOT( itemChanged( const Akonadi::Item&, const QSet<QByteArray>& ) ) );
00172 connect( mMonitor, SIGNAL( itemMoved( const Akonadi::Item&, const Akonadi::Collection&, const Akonadi::Collection& ) ),
00173 SLOT( itemMoved( const Akonadi::Item&, const Akonadi::Collection&, const Akonadi::Collection& ) ) );
00174 connect( mMonitor, SIGNAL( itemRemoved( const Akonadi::Item& ) ),
00175 SLOT( itemRemoved( const Akonadi::Item& ) ) );
00176 connect( mMonitor, SIGNAL( collectionAdded( const Akonadi::Collection&, const Akonadi::Collection& ) ),
00177 SLOT( collectionAdded( const Akonadi::Collection&, const Akonadi::Collection& ) ) );
00178 connect( mMonitor, SIGNAL( collectionChanged( const Akonadi::Collection& ) ),
00179 SLOT( collectionChanged( const Akonadi::Collection& ) ) );
00180 connect( mMonitor, SIGNAL( collectionRemoved( const Akonadi::Collection& ) ),
00181 SLOT( collectionRemoved( const Akonadi::Collection& ) ) );
00182
00183 connect( q, SIGNAL( status( int, const QString& ) ), q, SLOT( slotStatus( int, const QString& ) ) );
00184 connect( q, SIGNAL( percent( int ) ), q, SLOT( slotPercent( int ) ) );
00185 connect( q, SIGNAL( warning( const QString& ) ), q, SLOT( slotWarning( const QString& ) ) );
00186 connect( q, SIGNAL( error( const QString& ) ), q, SLOT( slotError( const QString& ) ) );
00187
00188
00189
00190 KGlobal::ref();
00191 KGlobal::setAllowQuit(true);
00192
00193 QTimer::singleShot( 0, q, SLOT( delayedInit() ) );
00194 }
00195
00196 void AgentBasePrivate::delayedInit()
00197 {
00198 Q_Q( AgentBase );
00199 if ( !QDBusConnection::sessionBus().registerService( QLatin1String( "org.freedesktop.Akonadi.Agent." ) + mId ) )
00200 kFatal() << "Unable to register service at dbus:" << QDBusConnection::sessionBus().lastError().message();
00201 q->setOnline( mOnline );
00202 }
00203
00204 void AgentBasePrivate::itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection )
00205 {
00206 kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this;
00207 if ( mObserver != 0 )
00208 mObserver->itemAdded( item, collection );
00209 }
00210
00211 void AgentBasePrivate::itemChanged( const Akonadi::Item &item, const QSet<QByteArray> &partIdentifiers )
00212 {
00213 kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this;
00214 if ( mObserver != 0 )
00215 mObserver->itemChanged( item, partIdentifiers );
00216 }
00217
00218 void AgentBasePrivate::itemMoved( const Akonadi::Item &item, const Akonadi::Collection &source, const Akonadi::Collection &dest )
00219 {
00220 kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this;
00221 if ( mObserver ) {
00222
00223 if ( !source.resource().isEmpty() && !dest.resource().isEmpty() ) {
00224 if ( source.resource() != dest.resource() ) {
00225 if ( source.resource() == q_ptr->identifier() )
00226 mObserver->itemRemoved( item );
00227 else if ( dest.resource() == q_ptr->identifier() )
00228 mObserver->itemAdded( item, dest );
00229 else
00230 changeProcessed();
00231 return;
00232 }
00233 }
00234
00235
00236
00237
00238 mObserver->itemAdded( item, dest );
00239
00240 }
00241 }
00242
00243 void AgentBasePrivate::itemRemoved( const Akonadi::Item &item )
00244 {
00245 kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this;
00246 if ( mObserver != 0 )
00247 mObserver->itemRemoved( item );
00248 }
00249
00250 void AgentBasePrivate::collectionAdded( const Akonadi::Collection &collection, const Akonadi::Collection &parent )
00251 {
00252 kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this;
00253 if ( mObserver != 0 )
00254 mObserver->collectionAdded( collection, parent );
00255 }
00256
00257 void AgentBasePrivate::collectionChanged( const Akonadi::Collection &collection )
00258 {
00259 kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this;
00260 if ( mObserver != 0 )
00261 mObserver->collectionChanged( collection );
00262 }
00263
00264 void AgentBasePrivate::collectionRemoved( const Akonadi::Collection &collection )
00265 {
00266 kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this;
00267 if ( mObserver != 0 )
00268 mObserver->collectionRemoved( collection );
00269 }
00270
00271 void AgentBasePrivate::changeProcessed()
00272 {
00273 mMonitor->changeProcessed();
00274 QTimer::singleShot( 0, mMonitor, SLOT( replayNext() ) );
00275 }
00276
00277 void AgentBasePrivate::slotStatus( int status, const QString &message )
00278 {
00279 mStatusMessage = message;
00280 mStatusCode = 0;
00281
00282 switch ( status ) {
00283 case AgentBase::Idle:
00284 if ( mStatusMessage.isEmpty() )
00285 mStatusMessage = defaultReadyMessage();
00286
00287 mStatusCode = 0;
00288 break;
00289 case AgentBase::Running:
00290 if ( mStatusMessage.isEmpty() )
00291 mStatusMessage = defaultSyncingMessage();
00292
00293 mStatusCode = 1;
00294 break;
00295 case AgentBase::Broken:
00296 if ( mStatusMessage.isEmpty() )
00297 mStatusMessage = defaultErrorMessage();
00298
00299 mStatusCode = 2;
00300 break;
00301 default:
00302 Q_ASSERT( !"Unknown status passed" );
00303 break;
00304 }
00305 }
00306
00307 void AgentBasePrivate::slotPercent( int progress )
00308 {
00309 mProgress = progress;
00310 }
00311
00312 void AgentBasePrivate::slotWarning( const QString& message )
00313 {
00314 mTracer->warning( QString::fromLatin1( "AgentBase(%1)" ).arg( mId ), message );
00315 }
00316
00317 void AgentBasePrivate::slotError( const QString& message )
00318 {
00319 mTracer->error( QString::fromLatin1( "AgentBase(%1)" ).arg( mId ), message );
00320 }
00321
00322 void AgentBasePrivate::slotNetworkStatusChange( Solid::Networking::Status stat )
00323 {
00324 Q_Q( AgentBase );
00325 q->setOnline( stat == Solid::Networking::Connected );
00326 }
00327
00328
00329 AgentBase::AgentBase( const QString & id )
00330 : d_ptr( new AgentBasePrivate( this ) )
00331 {
00332 sAgentBase = this;
00333 d_ptr->mId = id;
00334 d_ptr->init();
00335 if ( KApplication::kApplication() )
00336 KApplication::kApplication()->disableSessionManagement();
00337 }
00338
00339 AgentBase::AgentBase( AgentBasePrivate* d, const QString &id ) :
00340 d_ptr( d )
00341 {
00342 sAgentBase = this;
00343 d_ptr->mId = id;
00344 d_ptr->init();
00345 }
00346
00347 AgentBase::~AgentBase()
00348 {
00349 delete d_ptr;
00350 }
00351
00352 QString AgentBase::parseArguments( int argc, char **argv )
00353 {
00354 QString identifier;
00355 if ( argc < 3 ) {
00356 kDebug( 5250 ) << "Not enough arguments passed...";
00357 exit( 1 );
00358 }
00359
00360 for ( int i = 1; i < argc - 1; ++i ) {
00361 if ( QLatin1String( argv[ i ] ) == QLatin1String( "--identifier" ) )
00362 identifier = QLatin1String( argv[ i + 1 ] );
00363 }
00364
00365 if ( identifier.isEmpty() ) {
00366 kDebug( 5250 ) << "Identifier argument missing";
00367 exit( 1 );
00368 }
00369
00370 QByteArray catalog;
00371 char *p = strrchr( argv[0], '/' );
00372 if ( p )
00373 catalog = QByteArray( p + 1 );
00374 else
00375 catalog = QByteArray( argv[0] );
00376
00377 KCmdLineArgs::init( argc, argv, identifier.toLatin1(), catalog, ki18n("Akonadi Agent"),"0.1" ,
00378 ki18n("Akonadi Agent") );
00379
00380 KCmdLineOptions options;
00381 options.add("identifier <argument>", ki18n("Agent identifier"));
00382 KCmdLineArgs::addCmdLineOptions( options );
00383
00384 return identifier;
00385 }
00386
00387
00388
00389 int AgentBase::init( AgentBase *r )
00390 {
00391 QApplication::setQuitOnLastWindowClosed( false );
00392 KGlobal::locale()->insertCatalog( QLatin1String("libakonadi") );
00393 int rv = kapp->exec();
00394 delete r;
00395 return rv;
00396 }
00397
00398 int AgentBase::status() const
00399 {
00400 Q_D( const AgentBase );
00401
00402 return d->mStatusCode;
00403 }
00404
00405 QString AgentBase::statusMessage() const
00406 {
00407 Q_D( const AgentBase );
00408
00409 return d->mStatusMessage;
00410 }
00411
00412 int AgentBase::progress() const
00413 {
00414 Q_D( const AgentBase );
00415
00416 return d->mProgress;
00417 }
00418
00419 QString AgentBase::progressMessage() const
00420 {
00421 Q_D( const AgentBase );
00422
00423 return d->mProgressMessage;
00424 }
00425
00426 bool AgentBase::isOnline() const
00427 {
00428 Q_D( const AgentBase );
00429
00430 return d->mOnline;
00431 }
00432
00433 void AgentBase::setNeedsNetwork( bool needsNetwork )
00434 {
00435 Q_D( AgentBase );
00436 d->mNeedsNetwork = needsNetwork;
00437
00438 if ( d->mNeedsNetwork ) {
00439 connect( Solid::Networking::notifier()
00440 , SIGNAL( statusChanged( Solid::Networking::Status ) )
00441 , this, SLOT( slotNetworkStatusChange( Solid::Networking::Status ) ) );
00442 } else {
00443 disconnect( Solid::Networking::notifier(), 0, 0, 0 );
00444 setOnline( true );
00445 }
00446 }
00447
00448 void AgentBase::setOnline( bool state )
00449 {
00450 Q_D( AgentBase );
00451 d->mOnline = state;
00452 d->mSettings->setValue( QLatin1String( "Agent/Online" ), state );
00453 doSetOnline( state );
00454 emit onlineChanged( state );
00455 }
00456
00457 void AgentBase::doSetOnline( bool online )
00458 {
00459 Q_UNUSED( online );
00460 }
00461
00462 void AgentBase::configure( WId windowId )
00463 {
00464 Q_UNUSED( windowId );
00465 }
00466
00467 #ifdef Q_OS_WIN //krazy:exclude=cpp
00468 void AgentBase::configure( qlonglong windowId )
00469 {
00470 configure( reinterpret_cast<WId>( windowId ) );
00471 }
00472 #endif
00473
00474 WId AgentBase::winIdForDialogs() const
00475 {
00476 bool registered = QDBusConnection::sessionBus().interface()->isServiceRegistered( QLatin1String("org.freedesktop.akonaditray") );
00477 if ( !registered )
00478 return 0;
00479
00480 QDBusInterface dbus( QLatin1String("org.freedesktop.akonaditray"), QLatin1String("/Actions"),
00481 QLatin1String("org.freedesktop.Akonadi.Tray") );
00482 QDBusMessage reply = dbus.call( QLatin1String("getWinId") );
00483
00484 if ( reply.type() == QDBusMessage::ErrorMessage )
00485 return 0;
00486
00487 WId winid = (WId)reply.arguments().at( 0 ).toLongLong();
00488 return winid;
00489 }
00490
00491 void AgentBase::quit()
00492 {
00493 Q_D( AgentBase );
00494 aboutToQuit();
00495
00496 if ( d->mSettings ) {
00497 d->mMonitor->setConfig( 0 );
00498 d->mSettings->sync();
00499 }
00500
00501 KGlobal::deref();
00502 }
00503
00504 void AgentBase::aboutToQuit()
00505 {
00506 }
00507
00508 void AgentBase::cleanup()
00509 {
00510 Q_D( AgentBase );
00511
00512
00513 d->mMonitor->blockSignals( true );
00514
00515 aboutToQuit();
00516
00517 const QString fileName = d->mSettings->fileName();
00518
00519
00520
00521
00522 d->mMonitor->setConfig( 0 );
00523 delete d->mSettings;
00524 d->mSettings = 0;
00525
00526
00527
00528
00529 QFile::remove( fileName );
00530
00531
00532
00533
00534 QString configFile = KStandardDirs::locateLocal( "config", KGlobal::config()->name() );
00535 QFile::remove( configFile );
00536
00537 KGlobal::deref();
00538 }
00539
00540 void AgentBase::registerObserver( Observer *observer )
00541 {
00542 kDebug() << "observer=" << (void*) observer << "this=" << (void*) this;
00543 d_ptr->mObserver = observer;
00544 }
00545
00546 QString AgentBase::identifier() const
00547 {
00548 return d_ptr->mId;
00549 }
00550
00551 void AgentBase::setAgentName( const QString &name )
00552 {
00553 Q_D( AgentBase );
00554 if ( name == d->mName )
00555 return;
00556
00557
00558 d->mName = name;
00559
00560 if ( d->mName.isEmpty() || d->mName == d->mId ) {
00561 d->mSettings->remove( QLatin1String( "Resource/Name" ) );
00562 d->mSettings->remove( QLatin1String( "Agent/Name" ) );
00563 } else
00564 d->mSettings->setValue( QLatin1String( "Agent/Name" ), d->mName );
00565
00566 d->mSettings->sync();
00567
00568 emit agentNameChanged( d->mName );
00569 }
00570
00571 QString AgentBase::agentName() const
00572 {
00573 Q_D( const AgentBase );
00574 if ( d->mName.isEmpty() )
00575 return d->mId;
00576 else
00577 return d->mName;
00578 }
00579
00580 void AgentBase::changeProcessed()
00581 {
00582 Q_D( AgentBase );
00583 d->changeProcessed();
00584 }
00585
00586 ChangeRecorder * AgentBase::changeRecorder() const
00587 {
00588 return d_ptr->mMonitor;
00589 }
00590
00591 void AgentBase::reconfigure()
00592 {
00593 emit reloadConfiguration();
00594 }
00595
00596 #include "agentbase.moc"
00597 #include "agentbase_p.moc"