• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

Interfaces

kimproxy.cpp

Go to the documentation of this file.
00001 /*
00002     kimproxy.cpp
00003 
00004     IM service library for KDE
00005 
00006     Copyright (c) 2004 Will Stephenson   <lists@stevello.free-online.co.uk>
00007 
00008     This library is free software; you can redistribute it and/or
00009     modify it under the terms of the GNU Library General Public
00010     License as published by the Free Software Foundation; either
00011     version 2 of the License, or (at your option) any later version.
00012 
00013     This library is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016     Library General Public License for more details.
00017 
00018     You should have received a copy of the GNU Library General Public License
00019     along with this library; see the file COPYING.LIB.  If not, write to
00020     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00021     Boston, MA 02110-1301, USA.
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         // return value indicates if the supplied parameter was better than any existing presence
00053         bool update( const AppPresenceCurrent );
00054         AppPresenceCurrent best();
00055 };
00056 
00057 
00058 class KIMProxy::Private
00059 {
00060 public:
00061     // list of the strings in use by KIMIface
00062     QStringList presence_strings;
00063     // list of the icon names in use by KIMIface
00064     QStringList presence_icons;
00065     // map of presences
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     // if it's still -1 here, we have no presence data, so we return Unknown
00118     if ( best.presence == -1 )
00119         best.presence = 0;
00120     return best;
00121 }
00122 
00123 // int bestPresence( AppPresence* ap )
00124 // {
00125 //  Q_ASSERT( ap );
00126 //  AppPresence::const_iterator it;
00127 //  it = ap->begin();
00128 //  int best = 0; // unknown
00129 //  if ( it != ap->end() )
00130 //  {
00131 //      best = it.data();
00132 //      ++it;
00133 //      for ( ; it != ap->end(); ++it )
00134 //      {
00135 //          if ( it.data() > best )
00136 //              best = it.data();
00137 //      }
00138 //  }
00139 //  return best;
00140 // }
00141 //
00142 // QCString bestAppId( AppPresence* ap )
00143 // {
00144 //  Q_ASSERT( ap );
00145 //  AppPresence::const_iterator it;
00146 //  QCString bestAppId;
00147 //  it = ap->begin();
00148 //  if ( it != ap->end() )
00149 //  {
00150 //      int best = it.data();
00151 //      bestAppId = it.key();
00152 //      ++it;
00153 //      for ( ; it != ap->end(); ++it )
00154 //      {
00155 //          if ( it.data() > best )
00156 //          {
00157 //              best = it.data();
00158 //              bestAppId = it.key();
00159 //          }
00160 //      }
00161 //  }
00162 //  return bestAppId;
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     //QDBus::sessionBus().registerObject( "/KIMProxy", this);
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     //QCString senderApp = "Kopete";
00197     //QCString senderObjectId = "KIMIface";
00198     //DCOPCString method = "contactPresenceChanged( QString, QCString, int )";
00199     //QCString receiverObjectId = "KIMProxyIface";
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; // we should only do this once, as registeredToDCOP() will catch any new starts
00215         // So there is no error from a failed query when using kdelibs 3.2, which don't have this servicetype
00216         if ( KServiceType::serviceType( IM_SERVICE_TYPE ) )
00217         {
00218             // see what apps implementing our service type are out there
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                 //kDebug( 790 ) << " considering: " << *app;
00225                 //for each offer
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                         //kDebug( 790 ) << " is it: " << dcopService << "?";
00232                         // if the application implements the dcop service, add it
00233                         if ( app.startsWith( dcopService ) )
00234                         {
00235                             m_apps_available = true;
00236                             //kDebug( 790 ) << " app name: " << (*offer)->name() << ", has instance " << *app << ", dcopService: " << dcopService;
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     // unregister...
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     // reregister...
00279     if ( !newOwner.isEmpty() ) { // application registered
00280         bool newApp = false;
00281         // get an up to date list of offers in case a new app was installed
00282         // and check each of the offers that implement the service type we're looking for,
00283         // to see if any of them are the app that just registered
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                 // if it's not already known, insert it
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             //else
00300             //  kDebug( 790 ) << "App doesn't implement our ServiceType";
00301         }
00302         //if ( newApp )
00303         //  emit sigPresenceInfoExpired();
00304     }
00305 }
00306 
00307 void KIMProxy::contactPresenceChanged( const QString& uid, const QString& appId, int presence )
00308 {
00309     // update the presence map
00310     //kDebug( 790 ) << "uid: " << uid << " appId: " << appId << " presence " << presence;
00311     ContactPresenceListCurrent current;
00312     current = d->presence_map[ uid ];
00313   //kDebug( 790 ) << "current best presence from : " << current.best().appId << " is: " << current.best().presence;
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         //kDebug( 790 ) << "returning a null QPixmap because we were asked for an icon for a uid we know nothing about";
00364         return QPixmap();
00365     }
00366     else
00367     {
00368         //kDebug( 790 ) << "returning this: " << d->presence_icons[ ap.presence ];
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 /*Better than Connecting, ie Away or Online*/ )
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     //kDebug( 790 ) << name;
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     // start/find an instance of DBUS/InstantMessenger
00547     QString error;
00548     QString dbusService;
00549     // Get a preferred IM client.
00550     // The app will notify itself to us using nameOwnerChanged, so we don't need to record a stub for it here
00551     // FIXME: error in preferences, see debug output
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 /*  // We only need to call this function if we don't have any data at all
00565     // otherwise, the data will be kept fresh by received presence change
00566     // DCOP signals
00567     if ( !d->presence_map.contains( uid ) )
00568     {
00569         AppPresence *presence = new AppPresence();
00570         // record current presence from known clients
00571         QDictIterator<OrgKdeKIMInterface> it( m_im_client_stubs );
00572         for ( ; it.current(); ++it )
00573         {
00574             presence->insert( it.currentKey().toAscii().constData(), it.current()->presenceStatus( uid ) ); // m_im_client_stubs has qstring keys...
00575         }
00576         d->presence_map.insert( uid, presence );
00577     }*/
00578 }
00579 
00580 void KIMProxy::pollApp( const QString & appId )
00581 {
00582     //kDebug( 790 ) ;
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         //ap.presence = appStub->presenceStatus( *it );
00596         current.append( ap );
00597 
00598         d->presence_map.insert( *it, current );
00599         if ( current.update( ap ) )
00600             emit sigContactPresenceChanged( *it );
00601         //kDebug( 790 ) << " uid: " << *it << " presence: " << ap.presence;
00602     }
00603 }
00604 
00605 OrgKdeKIMInterface * KIMProxy::stubForUid( const QString &uid )
00606 {
00607     // get best appPresence
00608     AppPresenceCurrent ap = d->presence_map[ uid ].best();
00609     // look up the presence string from that app
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     // see if the preferred client supports this protocol
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     // preferred doesn't do this protocol, try the first of the others that says it does
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     //kDebug( 790 ) << "found preferred app: " << preferredApp;
00645     return preferredApp;
00646 }
00647 
00648 #include "kimproxy.moc"

Interfaces

Skip menu "Interfaces"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal