query.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 "query.h" 00022 #include "responder.h" 00023 #include "remoteservice.h" 00024 #include "sdevent.h" 00025 #include <qdatetime.h> 00026 #include <qapplication.h> 00027 #include <qtimer.h> 00028 00029 #include <avahi-client/client.h> 00030 #ifdef AVAHI_API_0_6 00031 #include <avahi-client/lookup.h> 00032 #endif 00033 00034 #define TIMEOUT_LAN 200 00035 00036 namespace DNSSD 00037 { 00038 #ifdef AVAHI_API_0_6 00039 00040 void services_callback(AvahiServiceBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, const char* name, 00041 const char* regtype, const char* domain, AvahiLookupResultFlags, void* context); 00042 void types_callback(AvahiServiceTypeBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, const char* regtype, 00043 const char* replyDomain, AvahiLookupResultFlags, void* context); 00044 #else 00045 void services_callback(AvahiServiceBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, const char* name, 00046 const char* regtype, const char* domain, void* context); 00047 void types_callback(AvahiServiceTypeBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, const char* regtype, 00048 const char* replyDomain, void* context); 00049 void domains_callback(AvahiDomainBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, const char* replyDomain, 00050 void* context); 00051 #endif 00052 00053 enum BrowserType { Types, Services }; 00054 00055 class QueryPrivate 00056 { 00057 public: 00058 QueryPrivate(const QString& type, const QString& domain) : m_finished(false), m_browser(0), 00059 m_running(false), m_domain(domain), m_type(type) {} 00060 00061 bool m_finished; 00062 BrowserType m_browserType; 00063 void* m_browser; 00064 bool m_running; 00065 QString m_domain; 00066 QTimer timeout; 00067 QString m_type; 00068 }; 00069 00070 Query::Query(const QString& type, const QString& domain) 00071 { 00072 d = new QueryPrivate(type,domain); 00073 connect(&d->timeout,SIGNAL(timeout()),this,SLOT(timeout())); 00074 } 00075 00076 00077 Query::~Query() 00078 { 00079 if (d->m_browser) { 00080 switch (d->m_browserType) { 00081 case Services: avahi_service_browser_free((AvahiServiceBrowser*)d->m_browser); break; 00082 case Types: avahi_service_type_browser_free((AvahiServiceTypeBrowser*)d->m_browser); break; 00083 } 00084 } 00085 delete d; 00086 } 00087 00088 bool Query::isRunning() const 00089 { 00090 return d->m_running; 00091 } 00092 00093 bool Query::isFinished() const 00094 { 00095 return d->m_finished; 00096 } 00097 00098 const QString& Query::domain() const 00099 { 00100 return d->m_domain; 00101 } 00102 00103 void Query::startQuery() 00104 { 00105 if (d->m_running) return; 00106 d->m_finished = false; 00107 if (d->m_type=="_services._dns-sd._udp") { 00108 d->m_browserType = Types; 00109 #ifdef AVAHI_API_0_6 00110 d->m_browser = avahi_service_type_browser_new(Responder::self().client(), AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 00111 domainToDNS(d->m_domain), (AvahiLookupFlags)0, types_callback, this); 00112 #else 00113 d->m_browser = avahi_service_type_browser_new(Responder::self().client(), AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 00114 d->m_domain.utf8(), types_callback, this); 00115 #endif 00116 } else { 00117 d->m_browserType = Services; 00118 #ifdef AVAHI_API_0_6 00119 d->m_browser = avahi_service_browser_new(Responder::self().client(), AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 00120 d->m_type.ascii(),domainToDNS(d->m_domain), (AvahiLookupFlags)0, services_callback,this); 00121 #else 00122 d->m_browser = avahi_service_browser_new(Responder::self().client(), AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 00123 d->m_type.ascii(),d->m_domain.utf8(),services_callback,this); 00124 #endif 00125 } 00126 if (d->m_browser) { 00127 d->m_running=true; 00128 d->timeout.start(TIMEOUT_LAN,true); 00129 } else emit finished(); 00130 } 00131 void Query::virtual_hook(int, void*) 00132 { 00133 } 00134 00135 void Query::customEvent(QCustomEvent* event) 00136 { 00137 if (event->type()==QEvent::User+SD_ADDREMOVE) { 00138 d->timeout.start(TIMEOUT_LAN,true); 00139 d->m_finished=false; 00140 AddRemoveEvent *aev = static_cast<AddRemoveEvent*>(event); 00141 // m_type has useless trailing dot 00142 RemoteService* svr = new RemoteService(aev->m_name, 00143 aev->m_type,aev->m_domain); 00144 if (aev->m_op==AddRemoveEvent::Add) emit serviceAdded(svr); 00145 else emit serviceRemoved(svr); 00146 } 00147 } 00148 00149 void Query::timeout() 00150 { 00151 d->m_finished=true; 00152 emit finished(); 00153 } 00154 00155 #ifdef AVAHI_API_0_6 00156 void services_callback (AvahiServiceBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, 00157 const char* serviceName, const char* regtype, const char* replyDomain, AvahiLookupResultFlags, void* context) 00158 #else 00159 void services_callback (AvahiServiceBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, 00160 const char* serviceName, const char* regtype, const char* replyDomain, void* context) 00161 #endif 00162 { 00163 QObject *obj = reinterpret_cast<QObject*>(context); 00164 AddRemoveEvent* arev = new AddRemoveEvent((event==AVAHI_BROWSER_NEW) ? AddRemoveEvent::Add : 00165 AddRemoveEvent::Remove, QString::fromUtf8(serviceName), regtype, 00166 DNSToDomain(replyDomain)); 00167 QApplication::postEvent(obj, arev); 00168 } 00169 00170 #ifdef AVAHI_API_0_6 00171 void types_callback(AvahiServiceTypeBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, const char* regtype, 00172 const char* replyDomain, AvahiLookupResultFlags, void* context) 00173 #else 00174 void types_callback(AvahiServiceTypeBrowser*, AvahiIfIndex, AvahiProtocol, AvahiBrowserEvent event, const char* regtype, 00175 const char* replyDomain, void* context) 00176 #endif 00177 { 00178 QObject *obj = reinterpret_cast<QObject*>(context); 00179 AddRemoveEvent* arev = new AddRemoveEvent((event==AVAHI_BROWSER_NEW) ? AddRemoveEvent::Add : 00180 AddRemoveEvent::Remove, QString::null, regtype, 00181 DNSToDomain(replyDomain)); 00182 QApplication::postEvent(obj, arev); 00183 } 00184 00185 } 00186 #include "query.moc"