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 <kdcopservicestarter.h>
00028 #include <kdebug.h>
00029 #include <kmessagebox.h>
00030 #include <ksimpleconfig.h>
00031 #include <kiconloader.h>
00032 #include <kservice.h>
00033 #include <kservicetype.h>
00034
00035 #include "kimiface_stub.h"
00036
00037 #include "kimproxy.h"
00038
00039 static KStaticDeleter<KIMProxy> _staticDeleter;
00040
00041 KIMProxy * KIMProxy::s_instance = 0L;
00042
00043 int bestPresence( AppPresence* ap )
00044 {
00045 Q_ASSERT( ap );
00046 AppPresence::const_iterator it;
00047 it = ap->begin();
00048 int best = 0;
00049 if ( it != ap->end() )
00050 {
00051 best = it.data();
00052 ++it;
00053 for ( ; it != ap->end(); ++it )
00054 {
00055 if ( it.data() > best )
00056 best = it.data();
00057 }
00058 }
00059 return best;
00060 }
00061
00062 QCString bestAppId( AppPresence* ap )
00063 {
00064 Q_ASSERT( ap );
00065 AppPresence::const_iterator it;
00066 QCString bestAppId;
00067 it = ap->begin();
00068 if ( it != ap->end() )
00069 {
00070 int best = it.data();
00071 bestAppId = it.key();
00072 ++it;
00073 for ( ; it != ap->end(); ++it )
00074 {
00075 if ( it.data() > best )
00076 {
00077 best = it.data();
00078 bestAppId = it.key();
00079 }
00080 }
00081 }
00082 return bestAppId;
00083 }
00084
00085 KIMProxy * KIMProxy::instance( DCOPClient * client )
00086 {
00087 if ( client )
00088 {
00089 if ( !s_instance )
00090 _staticDeleter.setObject( s_instance, new KIMProxy( client ) );
00091 return s_instance;
00092 }
00093 else
00094 return 0L;
00095 }
00096
00097 KIMProxy::KIMProxy( DCOPClient* dc ) : DCOPObject( "KIMProxyIface" ), QObject()
00098 {
00099 m_im_client_stubs.setAutoDelete( true );
00100 m_presence_map.setAutoDelete( true );
00101
00102 m_apps_available = false;
00103 m_dc = dc;
00104 m_initialized = false;
00105 connect( m_dc, SIGNAL( applicationRemoved( const QCString& ) ) , this, SLOT( unregisteredFromDCOP( const QCString& ) ) );
00106 connect( m_dc, SIGNAL( applicationRegistered( const QCString& ) ) , this, SLOT( registeredToDCOP( const QCString& ) ) );
00107 m_dc->setNotifications( true );
00108
00109
00110
00111 QCString method = "contactPresenceChanged( QString, QCString, int )";
00112
00113
00114
00115 if ( !connectDCOPSignal( 0, 0, method, method, false ) )
00116 KMessageBox::information( 0, QString( "Couldn't connect DCOP signal.\nWon't receive any status notifications!" ) );
00117 }
00118
00119 KIMProxy::~KIMProxy( )
00120 {
00121
00122 }
00123
00124 bool KIMProxy::initialize()
00125 {
00126 if ( !m_initialized )
00127 {
00128 m_initialized = true;
00129
00130 if ( KServiceType::serviceType( IM_SERVICE_TYPE ) )
00131 {
00132 kdDebug( 5301 ) << k_funcinfo << endl;
00133 QCString dcopObjectId = "KIMIface";
00134
00135
00136 KService::List offers = KServiceType::offers( IM_SERVICE_TYPE );
00137 KService::List::iterator offer;
00138 typedef QValueList<QCString> QCStringList;
00139 QCStringList registeredApps = m_dc->registeredApplications();
00140 QCStringList::iterator app;
00141 const QCStringList::iterator end = registeredApps.end();
00142
00143 for ( app = registeredApps.begin(); app != end; ++app )
00144 {
00145
00146
00147 for ( offer = offers.begin(); offer != offers.end(); ++offer )
00148 {
00149 QCString dcopService = (*offer)->property("X-DCOP-ServiceName").toString().latin1();
00150 if ( !dcopService.isEmpty() )
00151 {
00152
00153
00154 QCString instanceName = (*app).left( dcopService.length() );
00155
00156 if ( instanceName == dcopService )
00157 {
00158 m_apps_available = true;
00159
00160 if ( !m_im_client_stubs.find( dcopService ) )
00161 {
00162 kdDebug( 5301 ) << "inserting new stub for " << *app << " dcopObjectId " << dcopObjectId << endl;
00163 m_im_client_stubs.insert( *app, new KIMIface_stub( m_dc, *app, dcopObjectId ) );
00164 }
00165 }
00166 }
00167 }
00168 }
00169 }
00170 }
00171 return !m_im_client_stubs.isEmpty();
00172 }
00173
00174 QStringList KIMProxy::allContacts()
00175 {
00176 QStringList value;
00177
00178 if ( initialize() )
00179 {
00180 QDictIterator<KIMIface_stub> it( m_im_client_stubs );
00181 for ( ; it.current(); ++it )
00182 {
00183 value += it.current()->allContacts();
00184 }
00185 }
00186 return value;
00187 }
00188
00189 QStringList KIMProxy::reachableContacts()
00190 {
00191 QStringList value;
00192
00193 if ( initialize() )
00194 {
00195 QDictIterator<KIMIface_stub> it( m_im_client_stubs );
00196 for ( ; it.current(); ++it )
00197 {
00198 value += it.current()->reachableContacts( );
00199 }
00200 }
00201 return value;
00202 }
00203
00204 QStringList KIMProxy::onlineContacts()
00205 {
00206 QStringList value;
00207
00208 if ( initialize() )
00209 {
00210 QDictIterator<KIMIface_stub> it( m_im_client_stubs );
00211 for ( ; it.current(); ++it )
00212 {
00213 value += it.current()->onlineContacts( );
00214 }
00215 }
00216 return value;
00217 }
00218
00219 QStringList KIMProxy::fileTransferContacts()
00220 {
00221 QStringList value;
00222
00223 if ( initialize() )
00224 {
00225 QDictIterator<KIMIface_stub> it( m_im_client_stubs );
00226 for ( ; it.current(); ++it )
00227 {
00228 value += it.current()->fileTransferContacts( );
00229 }
00230 }
00231 return value;
00232 }
00233
00234 bool KIMProxy::isPresent( const QString& uid )
00235 {
00236 bool present = false;
00237 if ( initialize() )
00238 {
00239 QDictIterator<KIMIface_stub> it( m_im_client_stubs );
00240 for ( ; it.current(); ++it )
00241 {
00242 if (it.current()->isPresent( uid ) )
00243 {
00244 present = true;
00245 break;
00246 }
00247 }
00248 }
00249 return present;
00250 }
00251
00252 QString KIMProxy::displayName( const QString& uid )
00253 {
00254 QString name;
00255 if ( initialize() )
00256 {
00257 if ( KIMIface_stub* s = stubForUid( uid ) )
00258 name = s->displayName( uid );
00259 }
00260
00261 return name;
00262 }
00263
00264 int KIMProxy::presenceNumeric( const QString& uid )
00265 {
00266 int presence = -1;
00267 if ( initialize() )
00268 {
00269 pollAll( uid );
00270 AppPresence *ap = m_presence_map.find( uid );
00271 if ( ap )
00272 presence = bestPresence( ap );
00273 }
00274 return presence;
00275 }
00276
00277 QString KIMProxy::presenceString( const QString& uid )
00278 {
00279
00280
00281 QString presence;
00282 KIMIface_stub* s = stubForUid( uid );
00283 if ( initialize() && s )
00284 {
00285
00286 PresenceStringMap * appPresenceStrings = m_client_presence_strings[ s ];
00287 if ( !appPresenceStrings )
00288 {
00289
00290 appPresenceStrings = new PresenceStringMap();
00291 m_client_presence_strings.insert( s, appPresenceStrings );
00292 }
00293 int numeric = presenceNumeric( uid );
00294 presence = (*appPresenceStrings)[ numeric ];
00295 if ( presence.isEmpty() )
00296 {
00297
00298 presence = s->presenceString( uid );
00299 appPresenceStrings->insert( numeric, presence );
00300 }
00301
00302 }
00303 return presence;
00304 }
00305
00306 QPixmap KIMProxy::presenceIcon( const QString& uid )
00307 {
00308 QPixmap presence;
00309 if ( initialize() )
00310 {
00311
00312 pollAll( uid );
00313 AppPresence *existing = m_presence_map.find( uid );
00314
00315 QCString ba = bestAppId( existing );
00316 if ( !ba.isNull() )
00317 {
00318 QString appPresenceKey = QString::number( presenceNumeric( uid ) ).append( ba );
00319 if ( !QPixmapCache::find( appPresenceKey, presence ) )
00320 {
00321 if ( KIMIface_stub* s = stubForUid( uid ) )
00322 {
00323 presence = s->icon( uid );
00324 QPixmapCache::insert( appPresenceKey, presence );
00325 }
00326 }
00327 }
00328 }
00329 return presence;
00330 }
00331
00332 bool KIMProxy::canReceiveFiles( const QString & uid )
00333 {
00334 if ( initialize() )
00335 {
00336 if ( KIMIface_stub* s = stubForUid( uid ) )
00337 return s->canReceiveFiles( uid );
00338 }
00339 return false;
00340 }
00341
00342 bool KIMProxy::canRespond( const QString & uid )
00343 {
00344 if ( initialize() )
00345 {
00346 if ( KIMIface_stub* s = stubForUid( uid ) )
00347 return s->canRespond( uid );
00348 }
00349 return false;
00350 }
00351
00352 QString KIMProxy::context( const QString & uid )
00353 {
00354 if ( initialize() )
00355 {
00356 if ( KIMIface_stub* s = stubForUid( uid ) )
00357 return s->context( uid );
00358 }
00359 return QString::null;
00360 }
00361
00362 void KIMProxy::chatWithContact( const QString& uid )
00363 {
00364 if ( initialize() )
00365 {
00366 if ( KIMIface_stub* s = stubForUid( uid ) )
00367 s->chatWithContact( uid );
00368 }
00369 return;
00370 }
00371
00372 void KIMProxy::messageContact( const QString& uid, const QString& message )
00373 {
00374 if ( initialize() )
00375 {
00376 if ( KIMIface_stub* s = stubForUid( uid ) )
00377 s->messageContact( uid, message );
00378 }
00379 return;
00380 }
00381
00382 void KIMProxy::sendFile(const QString &uid, const KURL &sourceURL, const QString &altFileName, uint fileSize )
00383 {
00384 if ( initialize() )
00385 {
00386 QDictIterator<KIMIface_stub> it( m_im_client_stubs );
00387 for ( ; it.current(); ++it )
00388 {
00389 if ( it.current()->canReceiveFiles( uid ) )
00390 {
00391 it.current()->sendFile( uid, sourceURL, altFileName, fileSize );
00392 break;
00393 }
00394 }
00395 }
00396 return;
00397 }
00398
00399 bool KIMProxy::addContact( const QString &contactId, const QString &protocol )
00400 {
00401 if ( initialize() )
00402 {
00403 if ( KIMIface_stub* s = stubForProtocol( protocol ) )
00404 return s->addContact( contactId, protocol );
00405 }
00406 return false;
00407 }
00408
00409 QString KIMProxy::locate( const QString & contactId, const QString & protocol )
00410 {
00411 if ( initialize() )
00412 {
00413 if ( KIMIface_stub* s = stubForProtocol( protocol ) )
00414 return s->locate( contactId, protocol );
00415 }
00416 return QString::null;
00417 }
00418
00419 bool KIMProxy::imAppsAvailable()
00420 {
00421 kdDebug( 5301 ) << k_funcinfo << " returning " << m_apps_available<< endl;
00422 return m_apps_available;
00423 }
00424
00425 bool KIMProxy::startPreferredApp()
00426 {
00427 QString preferences = QString("[X-DCOP-ServiceName] = '%1'").arg( preferredApp() );
00428
00429 QString error;
00430 QCString dcopService;
00431
00432
00433
00434 preferences = QString::null;
00435 int result = KDCOPServiceStarter::self()->findServiceFor( IM_SERVICE_TYPE, QString::null, preferences, &error, &dcopService );
00436
00437 kdDebug( 5301 ) << k_funcinfo << "error was: " << error << ", dcopService: " << dcopService << endl;
00438
00439 return ( result == 0 );
00440 }
00441
00442 void KIMProxy::unregisteredFromDCOP( const QCString& appId )
00443 {
00444 kdDebug( 5301 ) << k_funcinfo << appId << endl;
00445 if ( m_im_client_stubs.find( appId ) )
00446 {
00447 kdDebug( 5301 ) << "removing references to " << appId << endl;
00448
00449 QDictIterator<AppPresence> it( m_presence_map );
00450 for ( ; it.current(); ++it )
00451 {
00452 AppPresence::iterator apIt;
00453 for ( apIt = it.current()->begin(); apIt != it.current()->end(); ++apIt )
00454 if ( apIt.key() == appId )
00455 {
00456 it.current()->remove( apIt );
00457 }
00458 }
00459 m_im_client_stubs.remove( appId );
00460 emit sigPresenceInfoExpired();
00461 }
00462 }
00463
00464 void KIMProxy::registeredToDCOP( const QCString& appId )
00465 {
00466
00467
00468
00469 if ( appId.isEmpty() )
00470 return;
00471
00472 if ( !KServiceType::serviceType( IM_SERVICE_TYPE ) )
00473 return;
00474
00475 kdDebug( 5301 ) << k_funcinfo << appId << endl;
00476 bool newApp = false;
00477
00478 const KService::List offers = KServiceType::offers( IM_SERVICE_TYPE );
00479 KService::List::const_iterator it;
00480
00481
00482 for ( it = offers.begin(); it != offers.end(); ++it )
00483 {
00484 QCString dcopObjectId = "KIMIface";
00485 QCString dcopService = (*it)->property("X-DCOP-ServiceName").toString().latin1();
00486 kdDebug( 5301 ) << "dcopService: " << dcopService << ", appId: " << appId << endl;
00487 if ( appId.left( dcopService.length() ) == dcopService )
00488 {
00489 m_apps_available = true;
00490
00491 if ( !m_im_client_stubs.find( appId ) )
00492 {
00493 newApp = true;
00494 m_im_client_stubs.insert( appId, new KIMIface_stub( m_dc, appId, dcopObjectId ) );
00495 }
00496 }
00497
00498
00499 }
00500 if ( newApp )
00501 emit sigPresenceInfoExpired();
00502 }
00503
00504 void KIMProxy::contactPresenceChanged( QString uid, QCString appId, int presence )
00505 {
00506
00507 kdDebug( 5301 ) << k_funcinfo << "uid: " << uid << " appId: " << appId << " presence " << presence << endl;
00508 if ( updatePresence( uid, appId, presence ) )
00509 emit sigContactPresenceChanged( uid );
00510 }
00511
00512 bool KIMProxy::updatePresence( const QString &uid, const QCString &appId, int presence )
00513 {
00514
00515 AppPresence *userPresences = 0L;
00516 if ( ( userPresences = m_presence_map.find( uid ) ) )
00517 {
00518
00519 int oldBest = bestPresence( userPresences );
00520 QCString oldBestApp = bestAppId( userPresences );
00521
00522 userPresences->insert( appId, presence );
00523 int newBest = bestPresence( userPresences );
00524
00525 return ( newBest > oldBest || appId == oldBestApp );
00526 }
00527 else
00528 {
00529
00530 userPresences = new AppPresence();
00531 userPresences->insert( appId, presence );
00532 m_presence_map.insert( uid, userPresences );
00533 return true;
00534 }
00535 return false;
00536 }
00537
00538 void KIMProxy::pollAll( const QString &uid )
00539 {
00540
00541
00542
00543 if ( !m_presence_map.find( uid ) )
00544 {
00545 AppPresence *presence = new AppPresence();
00546
00547 QDictIterator<KIMIface_stub> it( m_im_client_stubs );
00548 for ( ; it.current(); ++it )
00549 {
00550 presence->insert( it.currentKey().ascii(), it.current()->presenceStatus( uid ) );
00551 }
00552 m_presence_map.insert( uid, presence );
00553 }
00554 }
00555
00556 KIMIface_stub * KIMProxy::stubForUid( const QString &uid )
00557 {
00558 pollAll( uid );
00559
00560
00561 AppPresence *ap = m_presence_map.find( uid );
00562
00563 if ( ap )
00564 return m_im_client_stubs.find( bestAppId( ap ) );
00565 else
00566 return 0L;
00567 }
00568
00569 KIMIface_stub * KIMProxy::stubForProtocol( const QString &protocol)
00570 {
00571 KIMIface_stub * app;
00572
00573 QString preferred = preferredApp();
00574 if ( ( app = m_im_client_stubs.find( preferred ) ) )
00575 {
00576 if ( app->protocols().grep( protocol ).count() > 0 )
00577 return app;
00578 }
00579
00580 QDictIterator<KIMIface_stub> it( m_im_client_stubs );
00581 for ( ; it.current(); ++it )
00582 {
00583 if ( it.current()->protocols().grep( protocol ).count() > 0 )
00584 return it.current();
00585 }
00586 return 0L;
00587 }
00588
00589 QString KIMProxy::preferredApp()
00590 {
00591 KConfig *store = new KSimpleConfig( IM_CLIENT_PREFERENCES_FILE );
00592 store->setGroup( IM_CLIENT_PREFERENCES_SECTION );
00593 QString preferredApp = store->readEntry( IM_CLIENT_PREFERENCES_ENTRY );
00594
00595 return preferredApp;
00596 }
00597
00598 #include "kimproxy.moc"