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"