00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "kimproxy.h"
00025
00026 #include <QtCore/QBool>
00027 #include <QtGui/QPixmapCache>
00028
00029 #include <kapplication.h>
00030 #include <kdbusservicestarter.h>
00031 #include <kdebug.h>
00032 #include <kmessagebox.h>
00033 #include <kconfig.h>
00034 #include <kconfiggroup.h>
00035 #include <kiconloader.h>
00036 #include <kservice.h>
00037 #include <kservicetypetrader.h>
00038
00039 #include "kimiface.h"
00040
00041 #include <kservicetype.h>
00042
00043 struct AppPresenceCurrent
00044 {
00045 QString appId;
00046 int presence;
00047 };
00048
00049 static int debugArea() {
00050 static int s_area = KDebug::registerArea("kimproxy (kdelibs)");
00051 return s_area;
00052 }
00053
00054 class ContactPresenceListCurrent : public QList<AppPresenceCurrent>
00055 {
00056 public:
00057
00058 bool update( const AppPresenceCurrent );
00059 AppPresenceCurrent best();
00060 };
00061
00062
00063 class KIMProxy::Private
00064 {
00065 public:
00066
00067 QStringList presence_strings;
00068
00069 QStringList presence_icons;
00070
00071 PresenceStringMap presence_map;
00072 };
00073
00074 bool ContactPresenceListCurrent::update( AppPresenceCurrent ap )
00075 {
00076 if ( isEmpty() )
00077 {
00078 append( ap );
00079 return true;
00080 }
00081
00082 bool bestChanged = false;
00083 AppPresenceCurrent best;
00084 best.presence = -1;
00085 ContactPresenceListCurrent::iterator it = begin();
00086 const ContactPresenceListCurrent::iterator itEnd = end();
00087 ContactPresenceListCurrent::iterator existing = itEnd;
00088
00089 while ( it != itEnd )
00090 {
00091 if ( (*it).presence > best.presence )
00092 best = (*it);
00093 if ( (*it).appId == ap.appId )
00094 existing = it;
00095 ++it;
00096 }
00097
00098 if ( ap.presence > best.presence ||
00099 best.appId == ap.appId )
00100 bestChanged = true;
00101
00102 if ( existing != itEnd )
00103 {
00104 erase( existing );
00105 append( ap );
00106 }
00107 return bestChanged;
00108 }
00109
00110 AppPresenceCurrent ContactPresenceListCurrent::best()
00111 {
00112 AppPresenceCurrent best;
00113 best.presence = -1;
00114 ContactPresenceListCurrent::iterator it = begin();
00115 const ContactPresenceListCurrent::iterator itEnd = end();
00116 while ( it != itEnd )
00117 {
00118 if ( (*it).presence > best.presence )
00119 best = (*it);
00120 ++it;
00121 }
00122
00123 if ( best.presence == -1 )
00124 best.presence = 0;
00125 return best;
00126 }
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170 OrgKdeKIMInterface * findInterface( const QString & app )
00171 {
00172 return new OrgKdeKIMInterface( app, "/KIMIface", QDBusConnection::sessionBus() );
00173 }
00174
00175 KIMProxy * KIMProxy::instance()
00176 {
00177 K_GLOBAL_STATIC(KIMProxy, s_instance)
00178 return s_instance;
00179 }
00180
00181 KIMProxy::KIMProxy() : QObject(), d( new Private )
00182 {
00183
00184 m_initialized = false;
00185 connect( QDBusConnection::sessionBus().interface(),
00186 SIGNAL(serviceOwnerChanged(QString,QString,QString)),
00187 SLOT(nameOwnerChanged(QString,QString,QString)) );
00188
00189 d->presence_strings.append( "Unknown" );
00190 d->presence_strings.append( "Offline" );
00191 d->presence_strings.append( "Connecting" );
00192 d->presence_strings.append( "Away" );
00193 d->presence_strings.append( "Online" );
00194
00195 d->presence_icons.append( "presence_unknown" );
00196 d->presence_icons.append( "presence_offline" );
00197 d->presence_icons.append( "presence_connecting" );
00198 d->presence_icons.append( "presence_away" );
00199 d->presence_icons.append( "presence_online" );
00200
00201
00202
00203
00204
00205
00206 QDBusConnection::sessionBus().connect( QString(), "/KIMIface", "org.kde.KIM", "contactPresenceChanged",
00207 this, SLOT(contactPresenceChanged(QString,QString,int)) );
00208 }
00209
00210 KIMProxy::~KIMProxy( )
00211 {
00212 qDeleteAll(m_im_client_stubs);
00213 }
00214
00215 bool KIMProxy::initialize()
00216 {
00217 if ( !m_initialized )
00218 {
00219 m_initialized = true;
00220
00221 if ( KServiceType::serviceType( IM_SERVICE_TYPE ) )
00222 {
00223
00224 const KService::List offers = KServiceTypeTrader::self()->query( IM_SERVICE_TYPE );
00225 KService::List::const_iterator offer;
00226 QStringList registeredApps = QDBusConnection::sessionBus().interface()->registeredServiceNames();
00227 foreach (const QString &app, registeredApps)
00228 {
00229
00230
00231 for ( offer = offers.begin(); offer != offers.end(); ++offer )
00232 {
00233 QString dbusService = (*offer)->property("X-DBUS-ServiceName").toString();
00234 if ( !dbusService.isEmpty() )
00235 {
00236
00237
00238 if ( app.startsWith( dbusService ) )
00239 {
00240 m_apps_available = true;
00241
00242 if ( !m_im_client_stubs.contains( dbusService ) )
00243 {
00244 kDebug( debugArea() ) << "App " << app << ", found, using it for presence info.";
00245 m_im_client_stubs.insert( app, findInterface( app ) );
00246 pollApp( app );
00247 }
00248 }
00249 }
00250 }
00251 }
00252 }
00253 }
00254 return !m_im_client_stubs.isEmpty();
00255 }
00256
00257 void KIMProxy::nameOwnerChanged( const QString & appId, const QString &, const QString & newOwner )
00258 {
00259
00260 if ( m_im_client_stubs.contains( appId ) )
00261 {
00262 kDebug( debugArea() ) << appId << " quit, removing its presence info.";
00263
00264 PresenceStringMap::Iterator it = d->presence_map.begin();
00265 const PresenceStringMap::Iterator end = d->presence_map.end();
00266 for ( ; it != end; ++it )
00267 {
00268 ContactPresenceListCurrent list = it.value();
00269 ContactPresenceListCurrent::iterator cpIt = list.begin();
00270 while( cpIt != list.end() )
00271 {
00272 ContactPresenceListCurrent::iterator gone = cpIt++;
00273 if ( (*gone).appId == appId )
00274 {
00275 list.erase( gone );
00276 }
00277 }
00278 }
00279 delete m_im_client_stubs.take( appId );
00280 emit sigPresenceInfoExpired();
00281 }
00282
00283
00284 if ( !newOwner.isEmpty() ) {
00285 bool newApp = false;
00286
00287
00288
00289 const KService::List offers = KServiceTypeTrader::self()->query( IM_SERVICE_TYPE );
00290 KService::List::const_iterator it;
00291 for ( it = offers.begin(); it != offers.end(); ++it )
00292 {
00293 QString dbusService = (*it)->property("X-DBUS-ServiceName").toString();
00294 if ( appId.startsWith( dbusService ) )
00295 {
00296
00297 if ( !m_im_client_stubs.contains( appId ) )
00298 {
00299 newApp = true;
00300 kDebug( debugArea() ) << "App: " << appId << ", dbusService: " << dbusService << " started, using it for presence info.";
00301 m_im_client_stubs.insert( appId, findInterface( appId ) );
00302 }
00303 }
00304
00305
00306 }
00307
00308
00309 }
00310 }
00311
00312 void KIMProxy::contactPresenceChanged( const QString& uid, const QString& appId, int presence )
00313 {
00314
00315
00316 ContactPresenceListCurrent current;
00317 current = d->presence_map[ uid ];
00318
00319 AppPresenceCurrent newPresence;
00320 newPresence.appId = appId;
00321 newPresence.presence = presence;
00322
00323 if ( current.update( newPresence ) )
00324 {
00325 d->presence_map.insert( uid, current );
00326 emit sigContactPresenceChanged( uid );
00327 }
00328 }
00329
00330 int KIMProxy::presenceNumeric( const QString& uid )
00331 {
00332 AppPresenceCurrent ap;
00333 ap.presence = 0;
00334 if ( initialize() )
00335 {
00336 ContactPresenceListCurrent presence = d->presence_map[ uid ];
00337 ap = presence.best();
00338 }
00339 return ap.presence;
00340 }
00341
00342 QString KIMProxy::presenceString( const QString& uid )
00343 {
00344 AppPresenceCurrent ap;
00345 ap.presence = 0;
00346 if ( initialize() )
00347 {
00348 ContactPresenceListCurrent presence = d->presence_map[ uid ];
00349 ap = presence.best();
00350 }
00351 if ( ap.appId.isEmpty() )
00352 return QString();
00353 else
00354 return d->presence_strings[ ap.presence ];
00355 }
00356
00357 QPixmap KIMProxy::presenceIcon( const QString& uid )
00358 {
00359 AppPresenceCurrent ap;
00360 ap.presence = 0;
00361 if ( initialize() )
00362 {
00363 ContactPresenceListCurrent presence = d->presence_map[ uid ];
00364 ap = presence.best();
00365 }
00366 if ( ap.appId.isEmpty() )
00367 {
00368
00369 return QPixmap();
00370 }
00371 else
00372 {
00373
00374 return SmallIcon( d->presence_icons[ ap.presence ]);
00375 }
00376 }
00377
00378 QStringList KIMProxy::allContacts()
00379 {
00380 QStringList value = d->presence_map.keys();
00381 return value;
00382 }
00383
00384 QStringList KIMProxy::reachableContacts()
00385 {
00386 QStringList value;
00387
00388 if ( initialize() )
00389 {
00390 QHashIterator<QString, OrgKdeKIMInterface*> it( m_im_client_stubs );
00391 while (it.hasNext())
00392 {
00393 it.next();
00394 value += it.value()->reachableContacts( );
00395 }
00396 }
00397 return value;
00398 }
00399
00400 QStringList KIMProxy::onlineContacts()
00401 {
00402 QStringList value;
00403 PresenceStringMap::iterator it = d->presence_map.begin();
00404 const PresenceStringMap::iterator end= d->presence_map.end();
00405 for ( ; it != end; ++it )
00406 if ( it.value().best().presence > 2 )
00407 value.append( it.key() );
00408
00409 return value;
00410 }
00411
00412 QStringList KIMProxy::fileTransferContacts()
00413 {
00414 QStringList value;
00415
00416 if ( initialize() )
00417 {
00418 QHashIterator<QString, OrgKdeKIMInterface*> it( m_im_client_stubs );
00419 while (it.hasNext())
00420 {
00421 it.next();
00422 value += it.value()->fileTransferContacts( );
00423 }
00424 }
00425 return value;
00426 }
00427
00428 bool KIMProxy::isPresent( const QString& uid )
00429 {
00430 return ( !d->presence_map[ uid ].isEmpty() );
00431 }
00432
00433 QString KIMProxy::displayName( const QString& uid )
00434 {
00435 QString name;
00436 if ( initialize() )
00437 {
00438 if ( OrgKdeKIMInterface* s = stubForUid( uid ) )
00439 name = s->displayName( uid );
00440 }
00441
00442 return name;
00443 }
00444
00445 bool KIMProxy::canReceiveFiles( const QString & uid )
00446 {
00447 if ( initialize() )
00448 {
00449 if ( OrgKdeKIMInterface* s = stubForUid( uid ) )
00450 return s->canReceiveFiles( uid );
00451 }
00452 return false;
00453 }
00454
00455 bool KIMProxy::canRespond( const QString & uid )
00456 {
00457 if ( initialize() )
00458 {
00459 if ( OrgKdeKIMInterface* s = stubForUid( uid ) )
00460 return s->canRespond( uid );
00461 }
00462 return false;
00463 }
00464
00465 QString KIMProxy::context( const QString & uid )
00466 {
00467 if ( initialize() )
00468 {
00469 if ( OrgKdeKIMInterface* s = stubForUid( uid ) )
00470 return s->context( uid );
00471 }
00472 return QString();
00473 }
00474
00475 void KIMProxy::chatWithContact( const QString& uid )
00476 {
00477 if ( initialize() )
00478 {
00479 if ( OrgKdeKIMInterface* s = stubForUid( uid ) )
00480 {
00481 kapp->updateRemoteUserTimestamp( s->service() );
00482 s->chatWithContact( uid );
00483 }
00484 }
00485 return;
00486 }
00487
00488 void KIMProxy::messageContact( const QString& uid, const QString& message )
00489 {
00490 if ( initialize() )
00491 {
00492 if ( OrgKdeKIMInterface* s = stubForUid( uid ) )
00493 {
00494 kapp->updateRemoteUserTimestamp( s->service() );
00495 s->messageContact( uid, message );
00496 }
00497 }
00498 return;
00499 }
00500
00501 void KIMProxy::sendFile(const QString &uid, const QString &sourceURL, const QString &altFileName, uint fileSize )
00502 {
00503 if ( initialize() )
00504 {
00505 QHashIterator<QString,OrgKdeKIMInterface*> it( m_im_client_stubs );
00506 while ( it.hasNext() )
00507 {
00508 it.next();
00509 if ( it.value()->canReceiveFiles( uid ) )
00510 {
00511 kapp->updateRemoteUserTimestamp( it.value()->service() );
00512 it.value()->sendFile( uid, sourceURL, altFileName, fileSize );
00513 break;
00514 }
00515 }
00516 }
00517 return;
00518 }
00519
00520 bool KIMProxy::addContact( const QString &contactId, const QString &protocol )
00521 {
00522 if ( initialize() )
00523 {
00524 if ( OrgKdeKIMInterface* s = stubForProtocol( protocol ) )
00525 return s->addContact( contactId, protocol );
00526 }
00527 return false;
00528 }
00529
00530 QString KIMProxy::locate( const QString & contactId, const QString & protocol )
00531 {
00532 if ( initialize() )
00533 {
00534 if ( OrgKdeKIMInterface* s = stubForProtocol( protocol ) )
00535 return s->locate( contactId, protocol );
00536 }
00537 return QString();
00538 }
00539
00540 bool KIMProxy::imAppsAvailable()
00541 {
00542 return ( !m_im_client_stubs.isEmpty() );
00543 }
00544
00545 bool KIMProxy::startPreferredApp()
00546 {
00547 #ifdef __GNUC__
00548 # warning "unused variable: preferences"
00549 #endif
00550 QString preferences = QString("[X-DBUS-ServiceName] = '%1'").arg( preferredApp() );
00551
00552 QString error;
00553 QString dbusService;
00554
00555
00556
00557 preferences.clear();
00558 int result = KDBusServiceStarter::self()->findServiceFor( IM_SERVICE_TYPE, QString("Application"), &error, &dbusService );
00559
00560 kDebug( debugArea() ) << "error was: " << error << ", dbusService: " << dbusService;
00561
00562 return ( result == 0 );
00563 }
00564
00565
00566 void KIMProxy::pollAll( const QString &uid )
00567 {
00568 Q_UNUSED(uid);
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583 }
00584
00585 void KIMProxy::pollApp( const QString & appId )
00586 {
00587
00588 OrgKdeKIMInterface * appStub = m_im_client_stubs.value( appId );
00589 QStringList contacts = m_im_client_stubs.value( appId )->allContacts();
00590 QStringList::iterator it = contacts.begin();
00591 QStringList::iterator end = contacts.end();
00592 for ( ; it != end; ++it )
00593 {
00594 ContactPresenceListCurrent current = d->presence_map[ *it ];
00595 AppPresenceCurrent ap;
00596 ap.appId = appId;
00597 #ifdef __GNUC__
00598 # warning "KIMProxy::pollApp( const QString & appId ).presenceStatus() function doesn't exist Need to fix it"
00599 #endif
00600
00601 current.append( ap );
00602
00603 d->presence_map.insert( *it, current );
00604 if ( current.update( ap ) )
00605 emit sigContactPresenceChanged( *it );
00606
00607 }
00608 }
00609
00610 OrgKdeKIMInterface * KIMProxy::stubForUid( const QString &uid )
00611 {
00612
00613 AppPresenceCurrent ap = d->presence_map[ uid ].best();
00614
00615 return m_im_client_stubs.value( ap.appId );
00616 }
00617
00618 OrgKdeKIMInterface * KIMProxy::stubForProtocol( const QString &protocol)
00619 {
00620 Q_UNUSED(protocol)
00621 #ifdef __GNUC__
00622 # warning "KIMProxy::stubForProtocol( const QString &protocol) code disabled: protocols() function doesn't exist. Need to fix it"
00623 #endif
00624 #if 0
00625 OrgKdeKIMInterface * app;
00626
00627 QString preferred = preferredApp();
00628 if ( ( app = m_im_client_stubs.value( preferred ) ) )
00629 {
00630 if ( app->protocols().value().filter( protocol ).count() > 0 )
00631 return app;
00632 }
00633
00634 QHashIterator<QString, OrgKdeKIMInterface*> it( m_im_client_stubs );
00635 while ( it.hasNext() )
00636 {
00637 it.next();
00638 if ( it.value()->protocols().value().filter( protocol ).count() > 0 )
00639 return it.value();
00640 }
00641 #endif
00642 return 0L;
00643 }
00644
00645 QString KIMProxy::preferredApp()
00646 {
00647 KConfig cfg( IM_CLIENT_PREFERENCES_FILE, KConfig::SimpleConfig );
00648 KConfigGroup cg(&cfg, IM_CLIENT_PREFERENCES_SECTION );
00649 QString preferredApp = cg.readEntry( IM_CLIENT_PREFERENCES_ENTRY );
00650
00651 return preferredApp;
00652 }
00653
00654 #include "kimproxy.moc"