remoteservice.cpp
00001 /* This file is part of the KDE project 00002 * 00003 * Copyright (C) 2004, 2005 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 <config.h> 00022 00023 #include <tqeventloop.h> 00024 #include <tqapplication.h> 00025 #include <kurl.h> 00026 #ifdef HAVE_SYS_TYPES_H 00027 #include <sys/types.h> 00028 #endif 00029 #include <netinet/in.h> 00030 #ifdef HAVE_DNSSD 00031 #include <avahi-client/client.h> 00032 #include <avahi-common/strlst.h> 00033 #ifdef AVAHI_API_0_6 00034 #include <avahi-client/lookup.h> 00035 #endif 00036 #endif 00037 #include "remoteservice.h" 00038 #include "responder.h" 00039 #include "sdevent.h" 00040 00041 namespace DNSSD 00042 { 00043 #ifdef HAVE_DNSSD 00044 #ifdef AVAHI_API_0_6 00045 void resolve_callback(AvahiServiceResolver*, AvahiIfIndex, AvahiProtocol proto, AvahiResolverEvent e, 00046 const char* name, const char* type, const char* domain, const char* hostname, const AvahiAddress* a, 00047 uint16_t port, AvahiStringList* txt, AvahiLookupResultFlags, void* context); 00048 #else 00049 void resolve_callback(AvahiServiceResolver*, AvahiIfIndex, AvahiProtocol proto, AvahiResolverEvent e, 00050 const char* name, const char* type, const char* domain, const char* hostname, const AvahiAddress* a, 00051 uint16_t port, AvahiStringList* txt, void* context); 00052 #endif 00053 #endif 00054 00055 class RemoteServicePrivate : public Responder 00056 { 00057 public: 00058 RemoteServicePrivate() : m_resolved(false), m_running(false) 00059 #ifdef HAVE_DNSSD 00060 , m_resolver(0) 00061 #endif 00062 {} 00063 bool m_resolved; 00064 bool m_running; 00065 #ifdef HAVE_DNSSD 00066 AvahiServiceResolver* m_resolver; 00067 void stop() { 00068 m_running = false; 00069 if (m_resolver) avahi_service_resolver_free(m_resolver); 00070 m_resolver=0; 00071 } 00072 #endif 00073 }; 00074 00075 RemoteService::RemoteService(const TQString& label) 00076 { 00077 decode(label); 00078 d = new RemoteServicePrivate(); 00079 } 00080 RemoteService::RemoteService(const TQString& name,const TQString& type,const TQString& domain) 00081 : ServiceBase(name, type, domain) 00082 { 00083 d = new RemoteServicePrivate(); 00084 } 00085 00086 RemoteService::RemoteService(const KURL& url) 00087 { 00088 d = new RemoteServicePrivate(); 00089 if (!url.isValid()) return; 00090 if (url.protocol()!="invitation") return; 00091 if (!url.hasPath()) return; 00092 m_hostName = url.host(); 00093 m_port = url.port(); 00094 m_type = url.path().section('/',1,1); 00095 m_serviceName = url.path().section('/',2); 00096 m_textData = url.queryItems(); 00097 d->m_resolved=true; 00098 } 00099 00100 RemoteService::~RemoteService() 00101 { 00102 #ifdef HAVE_DNSSD 00103 if (d->m_resolver) avahi_service_resolver_free(d->m_resolver); 00104 #endif 00105 delete d; 00106 } 00107 00108 bool RemoteService::resolve() 00109 { 00110 resolveAsync(); 00111 while (d->m_running && !d->m_resolved) Responder::self().process(); 00112 #ifdef HAVE_DNSSD 00113 d->stop(); 00114 #endif 00115 return d->m_resolved; 00116 } 00117 00118 void RemoteService::resolveAsync() 00119 { 00120 if (d->m_running) return; 00121 d->m_resolved = false; 00122 // FIXME: first protocol should be set? 00123 #ifdef HAVE_DNSSD 00124 #ifdef AVAHI_API_0_6 00125 d->m_resolver = avahi_service_resolver_new(Responder::self().client(),AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 00126 m_serviceName.utf8(), m_type.ascii(), domainToDNS(m_domain), AVAHI_PROTO_UNSPEC, AVAHI_LOOKUP_NO_ADDRESS, 00127 resolve_callback, this); 00128 #else 00129 d->m_resolver = avahi_service_resolver_new(Responder::self().client(),AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 00130 m_serviceName.utf8(), m_type.ascii(), m_domain.utf8(), AVAHI_PROTO_UNSPEC, resolve_callback, this); 00131 #endif 00132 if (d->m_resolver) d->m_running=true; 00133 else emit resolved(false); 00134 #endif 00135 } 00136 00137 bool RemoteService::isResolved() const 00138 { 00139 return d->m_resolved; 00140 } 00141 00142 void RemoteService::customEvent(TQCustomEvent* event) 00143 { 00144 if (event->type() == TQEvent::User+SD_ERROR) { 00145 #ifdef HAVE_DNSSD 00146 d->stop(); 00147 #endif 00148 d->m_resolved=false; 00149 emit resolved(false); 00150 } 00151 if (event->type() == TQEvent::User+SD_RESOLVE) { 00152 ResolveEvent* rev = static_cast<ResolveEvent*>(event); 00153 m_hostName = rev->m_hostname; 00154 m_port = rev->m_port; 00155 m_textData = rev->m_txtdata; 00156 d->m_resolved = true; 00157 emit resolved(true); 00158 } 00159 } 00160 00161 void RemoteService::virtual_hook(int, void*) 00162 { 00163 // BASE::virtual_hook(int, void*); 00164 } 00165 00166 TQDataStream & operator<< (TQDataStream & s, const RemoteService & a) 00167 { 00168 s << (static_cast<ServiceBase>(a)); 00169 TQ_INT8 resolved = a.d->m_resolved ? 1:0; 00170 s << resolved; 00171 return s; 00172 } 00173 00174 TQDataStream & operator>> (TQDataStream & s, RemoteService & a) 00175 { 00176 // stop any possible resolve going on 00177 #ifdef HAVE_DNSSD 00178 a.d->stop(); 00179 #endif 00180 TQ_INT8 resolved; 00181 operator>>(s,(static_cast<ServiceBase&>(a))); 00182 s >> resolved; 00183 a.d->m_resolved = (resolved == 1); 00184 return s; 00185 } 00186 00187 #ifdef HAVE_DNSSD 00188 #ifdef AVAHI_API_0_6 00189 void resolve_callback(AvahiServiceResolver*, AvahiIfIndex, AvahiProtocol, AvahiResolverEvent e, 00190 const char*, const char*, const char*, const char* hostname, const AvahiAddress*, 00191 uint16_t port, AvahiStringList* txt, AvahiLookupResultFlags, void* context) 00192 #else 00193 void resolve_callback(AvahiServiceResolver*, AvahiIfIndex, AvahiProtocol, AvahiResolverEvent e, 00194 const char*, const char*, const char*, const char* hostname, const AvahiAddress*, 00195 uint16_t port, AvahiStringList* txt, void* context) 00196 #endif 00197 { 00198 TQObject *obj = reinterpret_cast<TQObject*>(context); 00199 if (e != AVAHI_RESOLVER_FOUND) { 00200 ErrorEvent err; 00201 TQApplication::sendEvent(obj, &err); 00202 return; 00203 } 00204 TQMap<TQString,TQString> map; 00205 while (txt) { 00206 char *key, *value; 00207 size_t size; 00208 if (avahi_string_list_get_pair(txt,&key,&value,&size)) break; 00209 map[TQString::fromUtf8(key)]=(value) ? TQString::fromUtf8(value) : TQString::null; 00210 txt = txt->next; 00211 } 00212 ResolveEvent rev(DNSToDomain(hostname),port,map); 00213 TQApplication::sendEvent(obj, &rev); 00214 } 00215 #endif 00216 00217 00218 } 00219 00220 #include "remoteservice.moc"