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