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