• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • 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 static int debugArea() {
00050     static int s_area = KDebug::registerArea("kimproxy (kdelibs)");
00051     return s_area;
00052 }
00053 
00054 class ContactPresenceListCurrent : public QList<AppPresenceCurrent>
00055 {
00056     public:
00057         // return value indicates if the supplied parameter was better than any existing presence
00058         bool update( const AppPresenceCurrent );
00059         AppPresenceCurrent best();
00060 };
00061 
00062 
00063 class KIMProxy::Private
00064 {
00065 public:
00066     // list of the strings in use by KIMIface
00067     QStringList presence_strings;
00068     // list of the icon names in use by KIMIface
00069     QStringList presence_icons;
00070     // map of presences
00071     PresenceStringMap presence_map;
00072 };
00073 
00074 bool ContactPresenceListCurrent::update( AppPresenceCurrent ap )
00075 {
00076     if ( isEmpty() )
00077     {
00078         append( ap );
00079         return true;
00080     }
00081 
00082     bool bestChanged = false;
00083     AppPresenceCurrent best;
00084     best.presence = -1;
00085     ContactPresenceListCurrent::iterator it = begin();
00086     const ContactPresenceListCurrent::iterator itEnd = end();
00087     ContactPresenceListCurrent::iterator existing = itEnd;
00088 
00089     while ( it != itEnd )
00090     {
00091         if ( (*it).presence > best.presence )
00092             best = (*it);
00093         if ( (*it).appId == ap.appId )
00094             existing = it;
00095         ++it;
00096     }
00097 
00098     if ( ap.presence > best.presence ||
00099       best.appId == ap.appId )
00100         bestChanged = true;
00101 
00102     if ( existing != itEnd )
00103     {
00104         erase( existing );
00105         append( ap );
00106     }
00107     return bestChanged;
00108 }
00109 
00110 AppPresenceCurrent ContactPresenceListCurrent::best()
00111 {
00112     AppPresenceCurrent best;
00113     best.presence = -1;
00114     ContactPresenceListCurrent::iterator it = begin();
00115     const ContactPresenceListCurrent::iterator itEnd = end();
00116     while ( it != itEnd )
00117     {
00118         if ( (*it).presence > best.presence )
00119             best = (*it);
00120         ++it;
00121     }
00122     // if it's still -1 here, we have no presence data, so we return Unknown
00123     if ( best.presence == -1 )
00124         best.presence = 0;
00125     return best;
00126 }
00127 
00128 // int bestPresence( AppPresence* ap )
00129 // {
00130 //  Q_ASSERT( ap );
00131 //  AppPresence::const_iterator it;
00132 //  it = ap->begin();
00133 //  int best = 0; // unknown
00134 //  if ( it != ap->end() )
00135 //  {
00136 //      best = it.data();
00137 //      ++it;
00138 //      for ( ; it != ap->end(); ++it )
00139 //      {
00140 //          if ( it.data() > best )
00141 //              best = it.data();
00142 //      }
00143 //  }
00144 //  return best;
00145 // }
00146 //
00147 // QCString bestAppId( AppPresence* ap )
00148 // {
00149 //  Q_ASSERT( ap );
00150 //  AppPresence::const_iterator it;
00151 //  QCString bestAppId;
00152 //  it = ap->begin();
00153 //  if ( it != ap->end() )
00154 //  {
00155 //      int best = it.data();
00156 //      bestAppId = it.key();
00157 //      ++it;
00158 //      for ( ; it != ap->end(); ++it )
00159 //      {
00160 //          if ( it.data() > best )
00161 //          {
00162 //              best = it.data();
00163 //              bestAppId = it.key();
00164 //          }
00165 //      }
00166 //  }
00167 //  return bestAppId;
00168 // }
00169 
00170 OrgKdeKIMInterface * findInterface( const QString & app )
00171 {
00172         return new OrgKdeKIMInterface( app, "/KIMIface", QDBusConnection::sessionBus() );
00173 }
00174 
00175 KIMProxy * KIMProxy::instance()
00176 {
00177     K_GLOBAL_STATIC(KIMProxy, s_instance)
00178     return s_instance;
00179 }
00180 
00181 KIMProxy::KIMProxy() : QObject(), d( new Private )
00182 {
00183     //QDBus::sessionBus().registerObject( "/KIMProxy", this);
00184     m_initialized = false;
00185     connect( QDBusConnection::sessionBus().interface(),
00186          SIGNAL(serviceOwnerChanged(QString,QString,QString)),
00187          SLOT(nameOwnerChanged(QString,QString,QString)) );
00188 
00189     d->presence_strings.append( "Unknown" );
00190     d->presence_strings.append( "Offline" );
00191     d->presence_strings.append( "Connecting" );
00192     d->presence_strings.append( "Away" );
00193     d->presence_strings.append( "Online" );
00194 
00195     d->presence_icons.append( "presence_unknown" );
00196     d->presence_icons.append( "presence_offline" );
00197     d->presence_icons.append( "presence_connecting" );
00198     d->presence_icons.append( "presence_away" );
00199     d->presence_icons.append( "presence_online" );
00200 
00201     //QCString senderApp = "Kopete";
00202     //QCString senderObjectId = "KIMIface";
00203     //DCOPCString method = "contactPresenceChanged( QString, QCString, int )";
00204     //QCString receiverObjectId = "KIMProxyIface";
00205 
00206     QDBusConnection::sessionBus().connect( QString(), "/KIMIface", "org.kde.KIM", "contactPresenceChanged",
00207                      this, SLOT(contactPresenceChanged(QString,QString,int)) );
00208 }
00209 
00210 KIMProxy::~KIMProxy( )
00211 {
00212     qDeleteAll(m_im_client_stubs);
00213 }
00214 
00215 bool KIMProxy::initialize()
00216 {
00217     if ( !m_initialized )
00218     {
00219         m_initialized = true; // we should only do this once, as registeredToDCOP() will catch any new starts
00220         // So there is no error from a failed query when using kdelibs 3.2, which don't have this servicetype
00221         if ( KServiceType::serviceType( IM_SERVICE_TYPE ) )
00222         {
00223             // see what apps implementing our service type are out there
00224             const KService::List offers = KServiceTypeTrader::self()->query( IM_SERVICE_TYPE );
00225             KService::List::const_iterator offer;
00226             QStringList registeredApps = QDBusConnection::sessionBus().interface()->registeredServiceNames();
00227             foreach (const QString &app, registeredApps)
00228             {
00229                 //kDebug( debugArea() ) << " considering: " << *app;
00230                 //for each offer
00231                 for ( offer = offers.begin(); offer != offers.end(); ++offer )
00232                 {
00233                     QString dbusService = (*offer)->property("X-DBUS-ServiceName").toString();
00234                     if ( !dbusService.isEmpty() )
00235                     {
00236                         //kDebug( debugArea() ) << " is it: " << dbusService << "?";
00237                         // if the application implements the dcop service, add it
00238                         if ( app.startsWith( dbusService ) )
00239                         {
00240                             m_apps_available = true;
00241                             //kDebug( debugArea() ) << " app name: " << (*offer)->name() << ", has instance " << *app << ", dbusService: " << dbusService;
00242                             if ( !m_im_client_stubs.contains( dbusService ) )
00243                             {
00244                                 kDebug( debugArea() ) << "App " << app << ", found, using it for presence info.";
00245                                 m_im_client_stubs.insert( app, findInterface( app ) );
00246                                 pollApp( app );
00247                             }
00248                         }
00249                     }
00250                 }
00251             }
00252         }
00253     }
00254     return !m_im_client_stubs.isEmpty();
00255 }
00256 
00257 void KIMProxy::nameOwnerChanged( const QString & appId, const QString &, const QString & newOwner )
00258 {
00259     // unregister...
00260     if ( m_im_client_stubs.contains( appId ) )
00261     {
00262         kDebug( debugArea() ) << appId << " quit, removing its presence info.";
00263 
00264         PresenceStringMap::Iterator it = d->presence_map.begin();
00265         const PresenceStringMap::Iterator end = d->presence_map.end();
00266         for ( ; it != end; ++it )
00267         {
00268             ContactPresenceListCurrent list = it.value();
00269             ContactPresenceListCurrent::iterator cpIt = list.begin();
00270             while( cpIt != list.end() )
00271             {
00272                 ContactPresenceListCurrent::iterator gone = cpIt++;
00273                 if ( (*gone).appId == appId )
00274                 {
00275                     list.erase( gone );
00276                 }
00277             }
00278         }
00279         delete m_im_client_stubs.take( appId );
00280         emit sigPresenceInfoExpired();
00281     }
00282 
00283     // reregister...
00284     if ( !newOwner.isEmpty() ) { // application registered
00285         bool newApp = false;
00286         // get an up to date list of offers in case a new app was installed
00287         // and check each of the offers that implement the service type we're looking for,
00288         // to see if any of them are the app that just registered
00289         const KService::List offers = KServiceTypeTrader::self()->query( IM_SERVICE_TYPE );
00290         KService::List::const_iterator it;
00291         for ( it = offers.begin(); it != offers.end(); ++it )
00292         {
00293             QString dbusService = (*it)->property("X-DBUS-ServiceName").toString();
00294             if ( appId.startsWith( dbusService ) )
00295             {
00296                 // if it's not already known, insert it
00297                 if ( !m_im_client_stubs.contains( appId ) )
00298                 {
00299                     newApp = true;
00300                     kDebug( debugArea() ) << "App: " << appId << ", dbusService: " << dbusService << " started, using it for presence info.";
00301                     m_im_client_stubs.insert( appId, findInterface( appId ) );
00302                 }
00303             }
00304             //else
00305             //  kDebug( debugArea() ) << "App doesn't implement our ServiceType";
00306         }
00307         //if ( newApp )
00308         //  emit sigPresenceInfoExpired();
00309     }
00310 }
00311 
00312 void KIMProxy::contactPresenceChanged( const QString& uid, const QString& appId, int presence )
00313 {
00314     // update the presence map
00315     //kDebug( debugArea() ) << "uid: " << uid << " appId: " << appId << " presence " << presence;
00316     ContactPresenceListCurrent current;
00317     current = d->presence_map[ uid ];
00318   //kDebug( debugArea() ) << "current best presence from : " << current.best().appId << " is: " << current.best().presence;
00319     AppPresenceCurrent newPresence;
00320     newPresence.appId = appId;
00321     newPresence.presence = presence;
00322 
00323     if ( current.update( newPresence ) )
00324     {
00325         d->presence_map.insert( uid, current );
00326         emit sigContactPresenceChanged( uid );
00327     }
00328 }
00329 
00330 int KIMProxy::presenceNumeric( const QString& uid )
00331 {
00332     AppPresenceCurrent ap;
00333     ap.presence = 0;
00334     if ( initialize() )
00335     {
00336         ContactPresenceListCurrent presence = d->presence_map[ uid ];
00337         ap = presence.best();
00338     }
00339     return ap.presence;
00340 }
00341 
00342 QString KIMProxy::presenceString( const QString& uid )
00343 {
00344     AppPresenceCurrent ap;
00345     ap.presence = 0;
00346     if ( initialize() )
00347     {
00348         ContactPresenceListCurrent presence = d->presence_map[ uid ];
00349         ap = presence.best();
00350     }
00351     if ( ap.appId.isEmpty() )
00352         return QString();
00353     else
00354         return d->presence_strings[ ap.presence ];
00355 }
00356 
00357 QPixmap KIMProxy::presenceIcon( const QString& uid )
00358 {
00359     AppPresenceCurrent ap;
00360     ap.presence = 0;
00361     if ( initialize() )
00362     {
00363         ContactPresenceListCurrent presence = d->presence_map[ uid ];
00364         ap = presence.best();
00365     }
00366     if ( ap.appId.isEmpty() )
00367     {
00368         //kDebug( debugArea() ) << "returning a null QPixmap because we were asked for an icon for a uid we know nothing about";
00369         return QPixmap();
00370     }
00371     else
00372     {
00373         //kDebug( debugArea() ) << "returning this: " << d->presence_icons[ ap.presence ];
00374         return SmallIcon( d->presence_icons[ ap.presence ]);
00375     }
00376 }
00377 
00378 QStringList KIMProxy::allContacts()
00379 {
00380     QStringList value = d->presence_map.keys();
00381     return value;
00382 }
00383 
00384 QStringList KIMProxy::reachableContacts()
00385 {
00386     QStringList value;
00387 
00388     if ( initialize() )
00389     {
00390         QHashIterator<QString, OrgKdeKIMInterface*> it( m_im_client_stubs );
00391         while (it.hasNext())
00392         {
00393             it.next();
00394             value += it.value()->reachableContacts( );
00395         }
00396     }
00397     return value;
00398 }
00399 
00400 QStringList KIMProxy::onlineContacts()
00401 {
00402     QStringList value;
00403     PresenceStringMap::iterator it = d->presence_map.begin();
00404     const PresenceStringMap::iterator end= d->presence_map.end();
00405     for ( ; it != end; ++it )
00406         if ( it.value().best().presence > 2 /*Better than Connecting, ie Away or Online*/ )
00407             value.append( it.key() );
00408 
00409     return value;
00410 }
00411 
00412 QStringList KIMProxy::fileTransferContacts()
00413 {
00414     QStringList value;
00415 
00416     if ( initialize() )
00417     {
00418         QHashIterator<QString, OrgKdeKIMInterface*> it( m_im_client_stubs );
00419         while (it.hasNext())
00420         {
00421             it.next();
00422             value += it.value()->fileTransferContacts( );
00423         }
00424     }
00425     return value;
00426 }
00427 
00428 bool KIMProxy::isPresent( const QString& uid )
00429 {
00430     return ( !d->presence_map[ uid ].isEmpty() );
00431 }
00432 
00433 QString KIMProxy::displayName( const QString& uid )
00434 {
00435     QString name;
00436     if ( initialize() )
00437     {
00438         if ( OrgKdeKIMInterface* s = stubForUid( uid ) )
00439             name = s->displayName( uid );
00440     }
00441     //kDebug( debugArea() ) << name;
00442     return name;
00443 }
00444 
00445 bool KIMProxy::canReceiveFiles( const QString & uid )
00446 {
00447     if ( initialize() )
00448     {
00449         if ( OrgKdeKIMInterface* s = stubForUid( uid ) )
00450             return s->canReceiveFiles( uid );
00451     }
00452     return false;
00453 }
00454 
00455 bool KIMProxy::canRespond( const QString & uid )
00456 {
00457     if ( initialize() )
00458     {
00459         if ( OrgKdeKIMInterface* s = stubForUid( uid ) )
00460             return s->canRespond( uid );
00461     }
00462     return false;
00463 }
00464 
00465 QString KIMProxy::context( const QString & uid )
00466 {
00467     if ( initialize() )
00468     {
00469         if ( OrgKdeKIMInterface* s = stubForUid( uid ) )
00470             return s->context( uid );
00471     }
00472     return QString();
00473 }
00474 
00475 void KIMProxy::chatWithContact( const QString& uid )
00476 {
00477     if ( initialize() )
00478     {
00479         if ( OrgKdeKIMInterface* s = stubForUid( uid ) )
00480         {
00481             kapp->updateRemoteUserTimestamp( s->service() );
00482             s->chatWithContact( uid );
00483         }
00484     }
00485     return;
00486 }
00487 
00488 void KIMProxy::messageContact( const QString& uid, const QString& message )
00489 {
00490     if ( initialize() )
00491     {
00492         if ( OrgKdeKIMInterface* s = stubForUid( uid ) )
00493         {
00494             kapp->updateRemoteUserTimestamp( s->service() );
00495             s->messageContact( uid, message );
00496         }
00497     }
00498     return;
00499 }
00500 
00501 void KIMProxy::sendFile(const QString &uid, const QString &sourceURL, const QString &altFileName, uint fileSize )
00502 {
00503     if ( initialize() )
00504     {
00505         QHashIterator<QString,OrgKdeKIMInterface*> it( m_im_client_stubs );
00506         while ( it.hasNext() )
00507         {
00508       it.next();
00509             if ( it.value()->canReceiveFiles( uid ) )
00510             {
00511                 kapp->updateRemoteUserTimestamp( it.value()->service() );
00512                 it.value()->sendFile( uid, sourceURL, altFileName, fileSize );
00513                 break;
00514             }
00515         }
00516     }
00517     return;
00518 }
00519 
00520 bool KIMProxy::addContact( const QString &contactId, const QString &protocol )
00521 {
00522     if ( initialize() )
00523     {
00524         if ( OrgKdeKIMInterface* s = stubForProtocol( protocol ) )
00525         return s->addContact( contactId, protocol );
00526     }
00527     return false;
00528 }
00529 
00530 QString KIMProxy::locate( const QString & contactId, const QString & protocol )
00531 {
00532     if ( initialize() )
00533     {
00534         if ( OrgKdeKIMInterface* s = stubForProtocol( protocol ) )
00535         return s->locate( contactId, protocol );
00536     }
00537     return QString();
00538 }
00539 
00540 bool KIMProxy::imAppsAvailable()
00541 {
00542     return ( !m_im_client_stubs.isEmpty() );
00543 }
00544 
00545 bool KIMProxy::startPreferredApp()
00546 {
00547 #ifdef __GNUC__
00548 # warning "unused variable: preferences"
00549 #endif
00550     QString preferences = QString("[X-DBUS-ServiceName] = '%1'").arg( preferredApp() );
00551     // start/find an instance of DBUS/InstantMessenger
00552     QString error;
00553     QString dbusService;
00554     // Get a preferred IM client.
00555     // The app will notify itself to us using nameOwnerChanged, so we don't need to record a stub for it here
00556     // FIXME: error in preferences, see debug output
00557     preferences.clear();
00558     int result = KDBusServiceStarter::self()->findServiceFor( IM_SERVICE_TYPE, QString("Application"), &error, &dbusService );
00559 
00560     kDebug( debugArea() ) << "error was: " << error << ", dbusService: " << dbusService;
00561 
00562     return ( result == 0 );
00563 }
00564 
00565 
00566 void KIMProxy::pollAll( const QString &uid )
00567 {
00568     Q_UNUSED(uid);
00569 /*  // We only need to call this function if we don't have any data at all
00570     // otherwise, the data will be kept fresh by received presence change
00571     // DCOP signals
00572     if ( !d->presence_map.contains( uid ) )
00573     {
00574         AppPresence *presence = new AppPresence();
00575         // record current presence from known clients
00576         QDictIterator<OrgKdeKIMInterface> it( m_im_client_stubs );
00577         for ( ; it.current(); ++it )
00578         {
00579             presence->insert( it.currentKey().toAscii().constData(), it.current()->presenceStatus( uid ) ); // m_im_client_stubs has qstring keys...
00580         }
00581         d->presence_map.insert( uid, presence );
00582     }*/
00583 }
00584 
00585 void KIMProxy::pollApp( const QString & appId )
00586 {
00587     //kDebug( debugArea() ) ;
00588     OrgKdeKIMInterface * appStub = m_im_client_stubs.value( appId );
00589     QStringList contacts = m_im_client_stubs.value( appId )->allContacts();
00590     QStringList::iterator it = contacts.begin();
00591     QStringList::iterator end = contacts.end();
00592     for ( ; it != end; ++it )
00593     {
00594         ContactPresenceListCurrent current = d->presence_map[ *it ];
00595         AppPresenceCurrent ap;
00596         ap.appId = appId;
00597 #ifdef __GNUC__
00598 # warning "KIMProxy::pollApp( const QString & appId ).presenceStatus() function doesn't exist Need to fix it"
00599 #endif
00600         //ap.presence = appStub->presenceStatus( *it );
00601         current.append( ap );
00602 
00603         d->presence_map.insert( *it, current );
00604         if ( current.update( ap ) )
00605             emit sigContactPresenceChanged( *it );
00606         //kDebug( debugArea() ) << " uid: " << *it << " presence: " << ap.presence;
00607     }
00608 }
00609 
00610 OrgKdeKIMInterface * KIMProxy::stubForUid( const QString &uid )
00611 {
00612     // get best appPresence
00613     AppPresenceCurrent ap = d->presence_map[ uid ].best();
00614     // look up the presence string from that app
00615         return m_im_client_stubs.value( ap.appId );
00616 }
00617 
00618 OrgKdeKIMInterface * KIMProxy::stubForProtocol( const QString &protocol)
00619 {
00620     Q_UNUSED(protocol)
00621 #ifdef __GNUC__
00622 # warning "KIMProxy::stubForProtocol( const QString &protocol) code disabled: protocols() function doesn't exist. Need to fix it"
00623 #endif
00624 #if 0
00625     OrgKdeKIMInterface * app;
00626     // see if the preferred client supports this protocol
00627     QString preferred = preferredApp();
00628     if ( ( app = m_im_client_stubs.value( preferred ) ) )
00629     {
00630         if ( app->protocols().value().filter( protocol ).count() > 0 )
00631             return app;
00632     }
00633     // preferred doesn't do this protocol, try the first of the others that says it does
00634     QHashIterator<QString, OrgKdeKIMInterface*> it( m_im_client_stubs );
00635     while ( it.hasNext() )
00636     {
00637         it.next();
00638         if ( it.value()->protocols().value().filter( protocol ).count() > 0 )
00639             return it.value();
00640     }
00641 #endif
00642     return 0L;
00643 }
00644 
00645 QString KIMProxy::preferredApp()
00646 {
00647     KConfig cfg( IM_CLIENT_PREFERENCES_FILE, KConfig::SimpleConfig );
00648     KConfigGroup cg(&cfg, IM_CLIENT_PREFERENCES_SECTION );
00649     QString preferredApp = cg.readEntry( IM_CLIENT_PREFERENCES_ENTRY );
00650     //kDebug( debugArea() ) << "found preferred app: " << preferredApp;
00651     return preferredApp;
00652 }
00653 
00654 #include "kimproxy.moc"

Interfaces

Skip menu "Interfaces"
  • Main Page
  • Namespace List
  • 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
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
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