servicebrowser.cpp

00001 /* This file is part of the KDE project
00002  *
00003  * Copyright (C) 2004 Jakub Stachowski <qbast@go2.pl>
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Library General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Library General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Library General Public License
00016  * along with this library; see the file COPYING.LIB.  If not, write to
00017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019  */
00020 
00021 #include <signal.h>
00022 #include <errno.h>
00023 #include <qstringlist.h>
00024 #include <qfile.h>
00025 #include "domainbrowser.h"
00026 #include "responder.h"
00027 #include "query.h"
00028 #include "servicebrowser.h"
00029 #include <avahi-client/client.h>
00030 #include <config.h>
00031 
00032 namespace DNSSD
00033 {
00034 
00035 const QString ServiceBrowser::AllServices = "_services._dns-sd._udp";
00036 
00037 class ServiceBrowserPrivate 
00038 {
00039 public: 
00040     ServiceBrowserPrivate() : m_running(false) 
00041     {}
00042     QValueList<RemoteService::Ptr> m_services;
00043     QValueList<RemoteService::Ptr> m_duringResolve;
00044     QStringList m_types;
00045     DomainBrowser* m_domains;
00046     int m_flags;
00047     bool m_running;
00048     bool m_finished;
00049     QDict<Query> resolvers;
00050 };
00051 
00052 ServiceBrowser::ServiceBrowser(const QString& type,DomainBrowser* domains,bool autoResolve)
00053 {
00054     if (domains) init(type,domains,autoResolve ? AutoResolve : 0);
00055         else init(type,new DomainBrowser(this),autoResolve ?  AutoResolve|AutoDelete : AutoDelete);
00056 }
00057 ServiceBrowser::ServiceBrowser(const QStringList& types,DomainBrowser* domains,int flags)
00058 {
00059     if (domains) init(types,domains,flags);
00060         else init(types,new DomainBrowser(this),flags|AutoDelete);
00061 }
00062 
00063 void ServiceBrowser::init(const QStringList& type,DomainBrowser* domains,int flags)
00064 {
00065     d = new ServiceBrowserPrivate();
00066     d->resolvers.setAutoDelete(true);
00067     d->m_types=type;
00068     d->m_flags=flags;
00069     d->m_domains = domains;
00070     connect(d->m_domains,SIGNAL(domainAdded(const QString& )),this,SLOT(addDomain(const QString& )));
00071     connect(d->m_domains,SIGNAL(domainRemoved(const QString& )),this,
00072         SLOT(removeDomain(const QString& )));
00073 }
00074 ServiceBrowser::ServiceBrowser(const QString& type,const QString& domain,bool autoResolve)
00075 {
00076     init(type,new DomainBrowser(domain,false,this),autoResolve ? AutoResolve|AutoDelete : AutoDelete);
00077 }
00078 ServiceBrowser::ServiceBrowser(const QString& type,const QString& domain,int flags)
00079 {
00080     init(type,new DomainBrowser(domain,false,this),flags | AutoDelete);
00081 }
00082 
00083 const ServiceBrowser::State ServiceBrowser::isAvailable()
00084 {
00085     AvahiClientState s = Responder::self().state();
00086 #ifdef AVAHI_API_0_6
00087     return (s==AVAHI_CLIENT_FAILURE) ? Stopped : Working;
00088 #else
00089     return (s==AVAHI_CLIENT_S_INVALID || s==AVAHI_CLIENT_DISCONNECTED) ? Stopped : Working;
00090 #endif 
00091 }
00092 ServiceBrowser::~ ServiceBrowser()
00093 {
00094     if (d->m_flags & AutoDelete) delete d->m_domains;
00095     delete d;
00096 }
00097 
00098 const DomainBrowser* ServiceBrowser::browsedDomains() const
00099 {
00100     return d->m_domains;
00101 }
00102 
00103 void ServiceBrowser::serviceResolved(bool success)
00104 {
00105     QObject* sender_obj = const_cast<QObject*>(sender());
00106     RemoteService* svr = static_cast<RemoteService*>(sender_obj);
00107     disconnect(svr,SIGNAL(resolved(bool)),this,SLOT(serviceResolved(bool)));
00108     QValueList<RemoteService::Ptr>::Iterator it = d->m_duringResolve.begin();
00109     QValueList<RemoteService::Ptr>::Iterator itEnd = d->m_duringResolve.end();
00110     while ( it!= itEnd && svr!= (*it)) ++it;
00111     if (it != itEnd) {
00112         if (success) {
00113             d->m_services+=(*it);
00114             emit serviceAdded(svr);
00115         }
00116         d->m_duringResolve.remove(it);
00117         queryFinished();
00118     }
00119 }
00120 
00121 void ServiceBrowser::startBrowse()
00122 {
00123     if (d->m_running) return;
00124     d->m_running=true;
00125     if (isAvailable()!=Working) return;
00126     if (d->m_domains->isRunning()) {
00127         QStringList::const_iterator itEnd  = d->m_domains->domains().end();
00128         for ( QStringList::const_iterator it = d->m_domains->domains().begin(); it != itEnd; ++it )
00129             addDomain(*it);
00130     } else d->m_domains->startBrowse();
00131 }
00132 
00133 void ServiceBrowser::gotNewService(RemoteService::Ptr svr)
00134 {
00135     if (findDuplicate(svr)==(d->m_services.end()))  {
00136         if (d->m_flags & AutoResolve) {
00137             connect(svr,SIGNAL(resolved(bool )),this,SLOT(serviceResolved(bool )));
00138             d->m_duringResolve+=svr;
00139             svr->resolveAsync();
00140         } else  {
00141             d->m_services+=svr;
00142             emit serviceAdded(svr);
00143         }
00144     }
00145 }
00146 
00147 void ServiceBrowser::gotRemoveService(RemoteService::Ptr svr)
00148 {
00149     QValueList<RemoteService::Ptr>::Iterator it = findDuplicate(svr);
00150     if (it!=(d->m_services.end())) {
00151         emit serviceRemoved(*it);
00152         d->m_services.remove(it);
00153     }
00154 }
00155 
00156 
00157 void ServiceBrowser::removeDomain(const QString& domain)
00158 {
00159     while (d->resolvers[domain]) d->resolvers.remove(domain);
00160     QValueList<RemoteService::Ptr>::Iterator it = d->m_services.begin();
00161     while (it!=d->m_services.end()) 
00162         // use section to skip possible trailing dot
00163         if ((*it)->domain().section('.',0) == domain.section('.',0)) {
00164             emit serviceRemoved(*it);
00165             it = d->m_services.remove(it);
00166         } else ++it;
00167 }
00168 
00169 void ServiceBrowser::addDomain(const QString& domain)
00170 {
00171     if (!d->m_running) return;
00172     if (!(d->resolvers[domain])) {
00173         QStringList::ConstIterator itEnd = d->m_types.end();
00174         for (QStringList::ConstIterator it=d->m_types.begin(); it!=itEnd; ++it) {
00175             Query* b = new Query((*it),domain);
00176             connect(b,SIGNAL(serviceAdded(DNSSD::RemoteService::Ptr)),this,
00177                 SLOT(gotNewService(DNSSD::RemoteService::Ptr)));
00178             connect(b,SIGNAL(serviceRemoved(DNSSD::RemoteService::Ptr )),this,
00179                 SLOT(gotRemoveService(DNSSD::RemoteService::Ptr)));
00180             connect(b,SIGNAL(finished()),this,SLOT(queryFinished()));
00181             b->startQuery();
00182             d->resolvers.insert(domain,b);
00183         }
00184     }
00185 }
00186 
00187 void ServiceBrowser::queryFinished()
00188 {
00189     if (allFinished()) emit finished();
00190 }
00191 
00192 bool ServiceBrowser::allFinished()
00193 {
00194     if  (d->m_duringResolve.count()) return false;
00195     bool all = true;
00196     QDictIterator<Query> it(d->resolvers);
00197     for ( ; it.current(); ++it) all&=(*it)->isFinished();
00198     return all;
00199 }
00200 
00201 const QValueList<RemoteService::Ptr>& ServiceBrowser::services() const
00202 {
00203     return d->m_services;
00204 }
00205 
00206 void ServiceBrowser::virtual_hook(int, void*)
00207 {}
00208 
00209 QValueList<RemoteService::Ptr>::Iterator ServiceBrowser::findDuplicate(RemoteService::Ptr src)
00210 {
00211     QValueList<RemoteService::Ptr>::Iterator itEnd = d->m_services.end();
00212     for (QValueList<RemoteService::Ptr>::Iterator it = d->m_services.begin(); it!=itEnd; ++it) 
00213         if ((src->type()==(*it)->type()) && (src->serviceName()==(*it)->serviceName()) &&
00214                    (src->domain() == (*it)->domain())) return it;
00215     return itEnd;
00216 }
00217 
00218 
00219 }
00220 
00221 #include "servicebrowser.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys