From: Lennart Poettering Date: Tue, 15 Nov 2005 00:39:45 +0000 (+0000) Subject: move python tools from avahi-utils to avahi-python X-Git-Url: https://git.meshlink.io/?a=commitdiff_plain;h=ced0d86acf70f435ffdadb794db891be63a5b82a;p=catta move python tools from avahi-utils to avahi-python git-svn-id: file:///home/lennart/svn/public/avahi/trunk@969 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- diff --git a/Makefile.am b/Makefile.am index d557c62..f2e3b39 100644 --- a/Makefile.am +++ b/Makefile.am @@ -58,6 +58,7 @@ SUBDIRS = \ initscript \ avahi-dnsconfd \ avahi-utils \ + avahi-python \ examples \ man \ tests \ diff --git a/avahi-python/Makefile.am b/avahi-python/Makefile.am new file mode 100644 index 0000000..efb529e --- /dev/null +++ b/avahi-python/Makefile.am @@ -0,0 +1,73 @@ +# $Id$ + +# This file is part of avahi. +# +# avahi is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# avahi is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +# License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with avahi; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +AM_CFLAGS=-I$(top_srcdir) + +# This cool debug trap works on i386/gcc only +AM_CFLAGS+='-DDEBUG_TRAP=__asm__("int $$3")' + +EXTRA_DIST = \ + avahi-publish-address.in \ + avahi-publish-service.in \ + avahi-bookmarks.in \ + avahi-discover.in \ + avahi-discover.desktop.in + +SUBDIRS=avahi + +if HAVE_PYTHON +if HAVE_PYTHON_DBUS +if HAVE_PYGTK + +pythonscripts = \ + avahi-publish-address \ + avahi-publish-service \ + avahi-bookmarks \ + avahi-discover + +desktopdir = $(datadir)/applications +desktop_DATA = avahi-discover.desktop + +avahi-discover.desktop: avahi-discover.desktop.in + sed -e 's,@bindir\@,$(bindir),g' $< > $@ + chmod +x $@ + +avahi-discover: avahi-discover.in + sed -e 's,@PYTHON\@,$(PYTHON),g' \ + -e 's,@interfacesdir\@,$(interfacesdir),g' $< > $@ + chmod +x $@ + +avahi-publish-address: avahi-publish-address.in + sed -e 's,@PYTHON\@,$(PYTHON),g' $< > $@ + chmod +x $@ + +avahi-publish-service: avahi-publish-service.in + sed -e 's,@PYTHON\@,$(PYTHON),g' $< > $@ + chmod +x $@ + +avahi-bookmarks: avahi-bookmarks.in + sed -e 's,@PYTHON\@,$(PYTHON),g' $< > $@ + chmod +x $@ + +bin_SCRIPTS = $(pythonscripts) +CLEANFILES = $(pythonscripts) $(desktop_DATA) + +endif +endif +endif diff --git a/avahi-python/avahi-bookmarks.in b/avahi-python/avahi-bookmarks.in new file mode 100755 index 0000000..2de9186 --- /dev/null +++ b/avahi-python/avahi-bookmarks.in @@ -0,0 +1,173 @@ +#!@PYTHON@ +# -*-python-*- +# $Id$ + +# This file is part of avahi. +# +# avahi is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# avahi is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +# License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with avahi; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +import sys, getopt + +try: + import avahi, gobject, dbus +except ImportError: + print "Sorry, to use this tool you need to install Avahi, pygtk and python-dbus." + sys.exit(1) + +try: + import dbus.glib +except ImportError: + pass + +try: + from twisted.internet import gtk2reactor + gtk2reactor.install() + from twisted.internet import reactor + from twisted.web import server, resource +except ImportError: + print "Sorry, to use this tool you need to install twisted and twisted.web." + sys.exit(1) + +urlproto = { "_http._tcp" : "http", "_https._tcp" : "https", "_ftp._tcp" : "ftp" } + +port = 8080 +address = "127.0.0.1" +use_host_names = False +domain = "local" + +class AvahiBookmarks(resource.Resource): + isLeaf = True + + services = {} + + def __init__(self): + resource.Resource.__init__(self) + + self.bus = dbus.SystemBus() + self.server = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER), avahi.DBUS_INTERFACE_SERVER) + + self.version_string = self.server.GetVersionString() + + self.browse_service_type("_http._tcp") + + # Hurrah! if I enable one of the following lines, python segfaults. + #self.browse_service_type("_https._tcp") + #self.browse_service_type("_ftp._tcp") + + def browse_service_type(self, stype): + + global domain + + browser = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, self.server.ServiceBrowserNew(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, stype, domain, dbus.UInt32(0))), avahi.DBUS_INTERFACE_SERVICE_BROWSER) + browser.connect_to_signal('ItemNew', self.new_service) + browser.connect_to_signal('ItemRemove', self.remove_service) + + def find_path(self, txt): + + l = avahi.txt_array_to_string_array(txt) + + for k in l: + if k[:5] == "path=": + if k[5:].startswith("/"): + return k[5:] + else: + return "/" + k[5:] + + return "/" + + def render_GET(self, request): + + t = 'Zeroconf Bookmarks

Zeroconf Bookmarks

' + + if len(self.services) == 0: + t += '

Sorry, no web services have been registered on the local LAN.

' + else: + t += '' + + t += '

Served by %s

' % self.version_string + + return t + + + def new_service(self, interface, protocol, name, type, domain, flags): + + interface, protocol, name, type, domain, host, aprotocol, address, port, txt, flags = self.server.ResolveService(interface, protocol, name, type, domain, avahi.PROTO_UNSPEC, dbus.UInt32(0)) + + if use_host_names: + h = host + else: + if aprotocol == avahi.PROTO_INET6: + h = "[" + address + "]" + else: + h = address + + self.services[(interface, protocol, name, type, domain)] = (host, aprotocol, h, port, txt) + + def remove_service(self, interface, protocol, name, type, domain): + del self.services[(interface, protocol, name, type, domain)] + + +def usage(retval = 0): + print "%s [options]\n" % sys.argv[0] + print " -h --help Show this help" + print " -p --port PORT Specify the port to use (default %u)" % port + print " -a --address ADDRESS Specify the address to bind to (default %s)" % address + print " -H --host-names Show all services, regardless of the type" + print " -d --domain DOMAIN Specify the domain to browse" + sys.exit(retval) + +try: + opts, args = getopt.getopt(sys.argv[1:], "hp:a:Hd:", ["help", "port=", "address=", "host-names", "domain="]) +except getopt.GetoptError: + usage(2) + +for o, a in opts: + if o in ("-h", "--help"): + usage() + + if o in ("-p", "--port"): + port = int(a) + + if o in ("-a", "--address"): + address = a + + if o in ("-H", "--host-names"): + use_host_names = True + + if o in ("-d", "--domain"): + domain = a + +site = server.Site(AvahiBookmarks()) +reactor.listenTCP(port, site, interface=address) + +print "Now point your web browser to http://%s:%u/!" % (address, port) + +try: + reactor.run() +except KeyboardInterrupt, k: + pass diff --git a/avahi-python/avahi-discover.desktop.in b/avahi-python/avahi-discover.desktop.in new file mode 100644 index 0000000..2362cd4 --- /dev/null +++ b/avahi-python/avahi-discover.desktop.in @@ -0,0 +1,10 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Avahi Zeroconf Browser +Comment=Browse for Zeroconf services available on your network +Exec=@bindir@/avahi-discover +Terminal=false +Type=Application +Icon=gnome-nettool.png +Categories=GNOME;Application;System;Utility +StartupNotify=false diff --git a/avahi-python/avahi-discover.in b/avahi-python/avahi-discover.in new file mode 100755 index 0000000..00a5602 --- /dev/null +++ b/avahi-python/avahi-discover.in @@ -0,0 +1,244 @@ +#!@PYTHON@ +# -*-python-*- +# $Id$ + +# This file is part of avahi. +# +# avahi is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# avahi is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +# License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with avahi; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +import os, sys + +try: + import avahi, gtk, gobject, dbus, avahi.ServiceTypeDatabase + from avahi.SimpleGladeApp import SimpleGladeApp +except ImportError: + print "Sorry, to use this tool you need to install Avahi, pygtk and python-dbus." + sys.exit(1) + +try: + import dbus.glib +except ImportError, e: + pass + +service_type_browsers = {} +service_browsers = {} + +glade_dir = "@interfacesdir@" + +service_type_db = avahi.ServiceTypeDatabase.ServiceTypeDatabase() + +class Main_window(SimpleGladeApp): + def __init__(self, path="avahi-discover.glade", root="main_window", domain=None, **kwargs): + path = os.path.join(glade_dir, path) + SimpleGladeApp.__init__(self, path, root, domain, **kwargs) + + def on_tree_view_cursor_changed(self, widget, *args): + (model, iter) = widget.get_selection().get_selected() + (name,interface,protocol,stype,domain) = self.treemodel.get(iter,1,2,3,4,5) + if stype == None: + self.info_label.set_markup("No service currently selected.") + return + #Asynchronous resolving + self.server.ResolveService( int(interface), int(protocol), name, stype, domain, avahi.PROTO_UNSPEC, dbus.UInt32(0), reply_handler=self.service_resolved, error_handler=self.print_error) + + + def protoname(self,protocol): + if protocol == avahi.PROTO_INET: + return "IPv4" + if protocol == avahi.PROTO_INET6: + return "IPv6" + + + def siocgifname(self, interface): + if interface <= 0: + return "any" + else: + return self.server.GetNetworkInterfaceNameByIndex(interface) + + def service_resolved(self, interface, protocol, name, stype, domain, host, aprotocol, address, port, txt, flags): + print "Service data for service '%s' of type '%s' in domain '%s' on %i.%i:" % (name, stype, domain, interface, protocol) + + print "\tHost %s (%s), port %i, TXT data: %s" % (host, address, port, str(avahi.txt_array_to_string_array(txt))) + + self.update_label(interface, protocol, name, stype, domain, host, aprotocol, address, port, avahi.txt_array_to_string_array(txt)) + + def print_error(self, err): + error_label = "Error: %s" % (err) + self.info_label.set_markup(error_label) + print "Error:", str(err) + + def lookup_type(self, stype): + global service_type_db + + try: + return service_type_db[stype] + except KeyError: + return stype + + def new_service(self, interface, protocol, name, stype, domain, flags): + print "Found service '%s' of type '%s' in domain '%s' on %i.%i." % (name, stype, domain, interface, protocol) + if self.zc_ifaces.has_key((interface,protocol)) == False: + self.zc_ifaces[(interface,protocol)] = self.insert_row(self.treemodel, None, str(self.siocgifname(interface))+" "+str(self.protoname(protocol)),None,interface,protocol,None,domain) + if self.zc_domains.has_key((interface,protocol,domain)) == False: + self.zc_domains[(interface,protocol,domain)] = self.insert_row(self.treemodel, self.zc_ifaces[(interface,protocol)], domain,None,interface,protocol,None,domain) + if self.zc_types.has_key((interface,protocol,stype,domain)) == False: + thisDomain = self.zc_domains[(interface,protocol,domain)] + self.zc_types[(interface,protocol,stype,domain)] = self.insert_row(self.treemodel, thisDomain, self.lookup_type(stype), name, interface,None,None,None) + treeiter = self.insert_row(self.treemodel,self.zc_types[(interface,protocol,stype,domain)], name, name, interface,protocol,stype,domain) + self.services_browsed[(interface, protocol, name, stype, domain)] = treeiter + # expand the tree of this path + self.tree_view.expand_to_path(self.treemodel.get_path(treeiter)) + + + def remove_service(self, interface, protocol, name, stype, domain, flags): + print "Service '%s' of type '%s' in domain '%s' on %i.%i disappeared." % (name, stype, domain, interface, protocol) + self.info_label.set_markup("") + treeiter=self.services_browsed[(interface, protocol, name, stype, domain)] + parent = self.treemodel.iter_parent(treeiter) + self.treemodel.remove(treeiter) + del self.services_browsed[(interface, protocol, name, stype, domain)] + if self.treemodel.iter_has_child(parent) == False: + treeiter=self.zc_types[(interface,protocol,stype,domain)] + parent = self.treemodel.iter_parent(treeiter) + self.treemodel.remove(treeiter) + del self.zc_types[(interface,protocol,stype,domain)] + if self.treemodel.iter_has_child(parent) == False: + treeiter=self.zc_domains[(interface,protocol,domain)] + parent = self.treemodel.iter_parent(treeiter) + self.treemodel.remove(treeiter) + del self.zc_domains[(interface,protocol,domain)] + if self.treemodel.iter_has_child(parent) == False: + treeiter=self.zc_ifaces[(interface,protocol)] + parent = self.treemodel.iter_parent(treeiter) + self.treemodel.remove(treeiter) + del self.zc_ifaces[(interface,protocol)] + + + def new_service_type(self, interface, protocol, stype, domain, flags): + global service_browsers + + # Are we already browsing this domain for this type? + if service_browsers.has_key((interface, protocol, stype, domain)): + return + + print "Browsing for services of type '%s' in domain '%s' on %i.%i ..." % (stype, domain, interface, protocol) + + b = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, self.server.ServiceBrowserNew(interface, protocol, stype, domain, dbus.UInt32(0))), avahi.DBUS_INTERFACE_SERVICE_BROWSER) + b.connect_to_signal('ItemNew', self.new_service) + b.connect_to_signal('ItemRemove', self.remove_service) + + service_browsers[(interface, protocol, stype, domain)] = b + + def browse_domain(self, interface, protocol, domain): + global service_type_browsers + + # Are we already browsing this domain? + if service_type_browsers.has_key((interface, protocol, domain)): + return + + if self.stype is None: + print "Browsing domain '%s' on %i.%i ..." % (domain, interface, protocol) + + b = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, self.server.ServiceTypeBrowserNew(interface, protocol, domain, dbus.UInt32(0))), avahi.DBUS_INTERFACE_SERVICE_TYPE_BROWSER) + b.connect_to_signal('ItemNew', self.new_service_type) + + service_type_browsers[(interface, protocol, domain)] = b + else: + new_service_type(interface, protocol, stype, domain) + + def new_domain(self,interface, protocol, domain, flags): + if self.zc_ifaces.has_key((interface,protocol)) == False: + self.zc_ifaces[(interface,protocol)] = self.insert_row(self.treemodel, None, str(self.siocgifname(interface))+" "+str(self.protoname(protocol)),None,interface,protocol,None,domain) + if self.zc_domains.has_key((interface,protocol,domain)) == False: + self.zc_domains[(interface,protocol,domain)] = self.insert_row(self.treemodel, self.zc_ifaces[(interface,protocol)], domain,None,interface,protocol,None,domain) + if domain != "local": + self.browse_domain(interface, protocol, domain) + + def pair_to_dict(self, l): + res = dict() + for el in l: + if "=" not in el: + res[el]='' + else: + tmp = el.split('=',1) + if len(tmp[0]) > 0: + res[tmp[0]] = tmp[1] + return res + + + def update_label(self,interface, protocol, name, stype, domain, host, aprotocol, address, port, txt): + if len(txt) != 0: + txts = "" + txtd = self.pair_to_dict(txt) + for k,v in txtd.items(): + txts+="TXT %s = %s\n" % (k,v) + else: + txts = "TXT Data: empty" + + infos = "Service Type: %s\nService Name: %s\nDomain Name: %s\nInterface: %s %s\nAddress: %s/%s:%i\n%s" % (stype, name, domain, self.siocgifname(interface), self.protoname(protocol), host, address, port, txts.strip()) + self.info_label.set_markup(infos) + + def insert_row(self, model,parent, + content, name, interface,protocol,stype,domain): + myiter=model.insert_after(parent,None) + model.set(myiter,0,content,1,name,2,interface,3,protocol,4,stype,5,domain) + return myiter + + def new(self): + print "A new main_window has been created" + self.treemodel=gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING) + self.tree_view.set_model(self.treemodel) + + #creating the columns headers + self.tree_view.set_headers_visible(False) + renderer=gtk.CellRendererText() + column=gtk.TreeViewColumn("",renderer, text=0) + column.set_resizable(True) + column.set_sizing("GTK_TREE_VIEW_COLUMN_GROW_ONLY"); + column.set_expand(True); + self.tree_view.append_column(column) + + self.domain = None + self.stype = None + self.zc_ifaces = {} + self.zc_domains = {} + self.zc_types = {} + self.services_browsed = {} + + self.bus = dbus.SystemBus() + self.server = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER), avahi.DBUS_INTERFACE_SERVER) + + if self.domain is None: + # Explicitly browse .local + self.browse_domain(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, "local") + + # Browse for other browsable domains + db = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, self.server.DomainBrowserNew(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, "", avahi.DOMAIN_BROWSER_BROWSE, dbus.UInt32(0))), avahi.DBUS_INTERFACE_DOMAIN_BROWSER) + db.connect_to_signal('ItemNew', self.new_domain) + else: + # Just browse the domain the user wants us to browse + self.browse_domain(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, domain) + + +def main(): + main_window = Main_window() + + main_window.run() + +if __name__ == "__main__": + main() + + diff --git a/avahi-python/avahi-publish-address.in b/avahi-python/avahi-publish-address.in new file mode 100755 index 0000000..4ffebd7 --- /dev/null +++ b/avahi-python/avahi-publish-address.in @@ -0,0 +1,96 @@ +#!@PYTHON@ +# -*-python-*- +# $Id$ + +# This file is part of avahi. +# +# avahi is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# avahi is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +# License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with avahi; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +import sys, getopt, string + +try: + import avahi, gobject, dbus +except ImportError: + print "Sorry, to use this tool you need to install Avahi, pygtk and python-dbus." + sys.exit(1) + +try: + import dbus.glib +except ImportError, e: + pass + +def usage(retval = 0): + print "%s
" % sys.argv[0] + sys.exit(retval) + +if len(sys.argv) != 3: + usage(2) + +name = sys.argv[1] +address = sys.argv[2] + +group = None +n_rename = 0 + +def remove_address(): + global group + + if not (group is None): + group.Free() + group = None + +def add_address(): + global server, group, name, address + assert group is None + + print "Adding address '%s' for '%s' ..." % (name, address) + group = dbus.Interface(bus.get_object(avahi.DBUS_NAME, server.EntryGroupNew()), avahi.DBUS_INTERFACE_ENTRY_GROUP) + group.connect_to_signal('StateChanged', entry_group_state_changed) + group.AddAddress(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, dbus.UInt32(0), name, address) + group.Commit() + +def entry_group_state_changed(state): + global name, server, n_rename, main_loop + + if state == avahi.ENTRY_GROUP_ESTABLISHED: + print "Address established." + elif state == avahi.ENTRY_GROUP_COLLISION: + + n_rename = n_rename + 1 + if n_rename >= 12: + print "ERROR: No suitable name found after %i retries, exiting." % n_rename + main_loop.quit() + else: + hn = name.split('.') + hn[0] = server.GetAlternativeHostName(hn[0]) + name = string.join(hn, '.') + print "WARNING: Address/host name collision, changing name to '%s' ..." % name + remove_address() + add_address() + +main_loop = gobject.MainLoop() + +bus = dbus.SystemBus() +server = dbus.Interface(bus.get_object(avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER), avahi.DBUS_INTERFACE_SERVER) + +add_address() + +try: + main_loop.run() +except KeyboardInterrupt, k: + pass + +remove_address() diff --git a/avahi-python/avahi-publish-service.in b/avahi-python/avahi-publish-service.in new file mode 100755 index 0000000..3f40fd0 --- /dev/null +++ b/avahi-python/avahi-publish-service.in @@ -0,0 +1,134 @@ +#!@PYTHON@ +# -*-python-*- +# $Id$ + +# This file is part of avahi. +# +# avahi is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# avahi is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +# License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with avahi; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +import sys, getopt + +try: + import avahi, gobject, dbus +except ImportError: + print "Sorry, to use this tool you need to install Avahi, pygtk and python-dbus." + sys.exit(1) + +try: + import dbus.glib +except ImportError, e: + pass + +def usage(retval = 0): + print "%s [options] [ ...]\n" % sys.argv[0] + print " -h --help Show this help" + print " -d --domain Domain where to register this service" + print " -H --host Host where this service resides" + sys.exit(retval) + +try: + opts, args = getopt.getopt(sys.argv[1:], "hd:H:", ["help", "domain=", "host="]) +except getopt.GetoptError: + usage(2) + +domain = "" +host = "" + +for o, a in opts: + if o in ("-h", "--help"): + usage() + + if o in ("-d", "--domain"): + domain = a + + if o in ("-H", "--host"): + host = a + +if len(args) < 3: + usage(2) + +name = args[0] +stype = args[1] +port = int(args[2]) +txt = args[3:] + +# python-dbus doesn't allow transmission of empty arrays, therefore we "fix" it with a bogus entry +if len(txt) == 0: + txt.append("python-dbus=brain-damage") + +group = None +n_rename = 0 + +def remove_service(): + global group + + if not group is None: + group.Reset() + +def add_service(): + global server, group, name, stype, domain, host, port, txt + + if group is None: + group = dbus.Interface(bus.get_object(avahi.DBUS_NAME, server.EntryGroupNew()), avahi.DBUS_INTERFACE_ENTRY_GROUP) + group.connect_to_signal('StateChanged', entry_group_state_changed) + + assert group.IsEmpty() + + print "Adding service '%s' of type '%s' ..." % (name, stype) + + group.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, dbus.UInt32(0), name, stype, domain, host, dbus.UInt16(port), avahi.string_array_to_txt_array(txt)) + group.Commit() + +def entry_group_state_changed(state): + global name, server, n_rename + +# print "state change: %i" % state + + if state == avahi.ENTRY_GROUP_ESTABLISHED: + print "Service established." + elif state == avahi.ENTRY_GROUP_COLLISION: + + n_rename = n_rename + 1 + if n_rename >= 12: + print "ERROR: No suitable service name found after %i retries, exiting." % n_rename + main_loop.quit() + else: + name = server.GetAlternativeServiceName(name) + print "WARNING: Service name collision, changing name to '%s' ..." % name + remove_service() + add_service() + +def server_state_changed(state): + if state == avahi.SERVER_COLLISION: + print "WARNING: Server name collision" + remove_service() + elif state == avahi.SERVER_RUNNING: + add_service() + +main_loop = gobject.MainLoop() + +bus = dbus.SystemBus() +server = dbus.Interface(bus.get_object(avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER), avahi.DBUS_INTERFACE_SERVER) +server.connect_to_signal("StateChanged", server_state_changed) +server_state_changed(server.GetState()) + +try: + main_loop.run() +except KeyboardInterrupt, k: + pass + +if not group is None: + group.Free() diff --git a/avahi-python/avahi/Makefile.am b/avahi-python/avahi/Makefile.am new file mode 100644 index 0000000..b1ebe22 --- /dev/null +++ b/avahi-python/avahi/Makefile.am @@ -0,0 +1,44 @@ +# $Id$ + +# This file is part of avahi. +# +# avahi is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# avahi is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +# License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with avahi; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +EXTRA_DIST = __init__.py SimpleGladeApp.py ServiceTypeDatabase.py.in + +if HAVE_PYTHON + +avahidir = $(pythondir)/avahi + +avahi_SCRIPTS = ServiceTypeDatabase.py + +ServiceTypeDatabase.py: ServiceTypeDatabase.py.in + sed -e 's,@PYTHON\@,$(PYTHON),g' \ + -e 's,@pkgdatadir\@,$(pkgdatadir),g' $< > $@ + chmod +x $@ + +if HAVE_PYGTK +if HAVE_PYTHON_DBUS + +avahi_PYTHON = __init__.py SimpleGladeApp.py + +endif +endif +endif + +CLEANFILES=*.pyc *.pyo ServiceTypeDatabase.py + + diff --git a/avahi-python/avahi/ServiceTypeDatabase.py.in b/avahi-python/avahi/ServiceTypeDatabase.py.in new file mode 100644 index 0000000..9caeebd --- /dev/null +++ b/avahi-python/avahi/ServiceTypeDatabase.py.in @@ -0,0 +1,97 @@ +#!@PYTHON@ +# -*-python-*- +# $Id$ + +# This file is part of avahi. +# +# avahi is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# avahi is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +# License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with avahi; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +import gdbm +import locale + +locale.setlocale(locale.LC_ALL, '') + +class ServiceTypeDatabase: + + def __init__(self, filename = "@pkgdatadir@/service-types.db"): + + self.db = gdbm.open(filename, "r") + + l = locale.getlocale(locale.LC_MESSAGES) + + self.suffixes = () + + if not l[0] is None: + + if not l[1] is None: + self.suffixes += (l[0] + "@" + l[1], ) + + self.suffixes += (l[0], ) + + i = l[0].find("_") + + if i >= 0: + + k = l[0][:i] + + if not l[1] is None: + self.suffixes += (k + "@" + l[1], ) + + self.suffixes += (k, ) + + + self.suffixes = tuple(map(lambda x: "["+x+"]", self.suffixes)) + ("", ) + + def __getitem__(self, key): + + for suffix in self.suffixes: + try: + return self.db[key + suffix] + except KeyError: + pass + + raise KeyError() + + def has_key(self, key): + + for suffix in self.suffixes: + + if self.db.has_key(key + suffix): + return True + + return False + + def __contains__(self, item): + + for suffix in self.suffixes: + + if item+suffix in self.db: + return True + + return False + + + +if __name__ == "__main__": + + b = ServiceTypeDatabase() + + print b["_http._tcp"] + print b["_ftp._tcp"] + print b["_webdav._tcp"] + print b["_webdavs._tcp"] + + print b["gurki._tcp"] diff --git a/avahi-python/avahi/SimpleGladeApp.py b/avahi-python/avahi/SimpleGladeApp.py new file mode 100644 index 0000000..90c598c --- /dev/null +++ b/avahi-python/avahi/SimpleGladeApp.py @@ -0,0 +1,341 @@ +""" + SimpleGladeApp.py + Module that provides an object oriented abstraction to pygtk and libglade. + Copyright (C) 2004 Sandino Flores Moreno +""" + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA + +import os +import sys +import re + +import tokenize +import gtk +import gtk.glade +import weakref +import inspect + +__version__ = "1.0" +__author__ = 'Sandino "tigrux" Flores-Moreno' + +def bindtextdomain(app_name, locale_dir=None): + """ + Bind the domain represented by app_name to the locale directory locale_dir. + It has the effect of loading translations, enabling applications for different + languages. + + app_name: + a domain to look for translations, tipically the name of an application. + + locale_dir: + a directory with locales like locale_dir/lang_isocode/LC_MESSAGES/app_name.mo + If omitted or None, then the current binding for app_name is used. + """ + try: + import locale + import gettext + locale.setlocale(locale.LC_ALL, "") + gtk.glade.bindtextdomain(app_name, locale_dir) + gettext.install(app_name, locale_dir, unicode=1) + except (IOError,locale.Error), e: + print "Warning", app_name, e + __builtins__.__dict__["_"] = lambda x : x + + +class SimpleGladeApp: + + def __init__(self, path, root=None, domain=None, **kwargs): + """ + Load a glade file specified by glade_filename, using root as + root widget and domain as the domain for translations. + + If it receives extra named arguments (argname=value), then they are used + as attributes of the instance. + + path: + path to a glade filename. + If glade_filename cannot be found, then it will be searched in the + same directory of the program (sys.argv[0]) + + root: + the name of the widget that is the root of the user interface, + usually a window or dialog (a top level widget). + If None or ommited, the full user interface is loaded. + + domain: + A domain to use for loading translations. + If None or ommited, no translation is loaded. + + **kwargs: + a dictionary representing the named extra arguments. + It is useful to set attributes of new instances, for example: + glade_app = SimpleGladeApp("ui.glade", foo="some value", bar="another value") + sets two attributes (foo and bar) to glade_app. + """ + if os.path.isfile(path): + self.glade_path = path + else: + glade_dir = os.path.dirname( sys.argv[0] ) + self.glade_path = os.path.join(glade_dir, path) + for key, value in kwargs.items(): + try: + setattr(self, key, weakref.proxy(value) ) + except TypeError: + setattr(self, key, value) + self.glade = None + self.install_custom_handler(self.custom_handler) + self.glade = self.create_glade(self.glade_path, root, domain) + if root: + self.main_widget = self.get_widget(root) + else: + self.main_widget = None + self.normalize_names() + self.add_callbacks(self) + self.new() + + def __repr__(self): + class_name = self.__class__.__name__ + if self.main_widget: + root = gtk.Widget.get_name(self.main_widget) + repr = '%s(path="%s", root="%s")' % (class_name, self.glade_path, root) + else: + repr = '%s(path="%s")' % (class_name, self.glade_path) + return repr + + def new(self): + """ + Method called when the user interface is loaded and ready to be used. + At this moment, the widgets are loaded and can be refered as self.widget_name + """ + pass + + def add_callbacks(self, callbacks_proxy): + """ + It uses the methods of callbacks_proxy as callbacks. + The callbacks are specified by using: + Properties window -> Signals tab + in glade-2 (or any other gui designer like gazpacho). + + Methods of classes inheriting from SimpleGladeApp are used as + callbacks automatically. + + callbacks_proxy: + an instance with methods as code of callbacks. + It means it has methods like on_button1_clicked, on_entry1_activate, etc. + """ + self.glade.signal_autoconnect(callbacks_proxy) + + def normalize_names(self): + """ + It is internally used to normalize the name of the widgets. + It means a widget named foo:vbox-dialog in glade + is refered self.vbox_dialog in the code. + + It also sets a data "prefixes" with the list of + prefixes a widget has for each widget. + """ + for widget in self.get_widgets(): + widget_name = gtk.Widget.get_name(widget) + prefixes_name_l = widget_name.split(":") + prefixes = prefixes_name_l[ : -1] + widget_api_name = prefixes_name_l[-1] + widget_api_name = "_".join( re.findall(tokenize.Name, widget_api_name) ) + gtk.Widget.set_name(widget, widget_api_name) + if hasattr(self, widget_api_name): + raise AttributeError("instance %s already has an attribute %s" % (self,widget_api_name)) + else: + setattr(self, widget_api_name, widget) + if prefixes: + gtk.Widget.set_data(widget, "prefixes", prefixes) + + def add_prefix_actions(self, prefix_actions_proxy): + """ + By using a gui designer (glade-2, gazpacho, etc) + widgets can have a prefix in theirs names + like foo:entry1 or foo:label3 + It means entry1 and label3 has a prefix action named foo. + + Then, prefix_actions_proxy must have a method named prefix_foo which + is called everytime a widget with prefix foo is found, using the found widget + as argument. + + prefix_actions_proxy: + An instance with methods as prefix actions. + It means it has methods like prefix_foo, prefix_bar, etc. + """ + prefix_s = "prefix_" + prefix_pos = len(prefix_s) + + is_method = lambda t : callable( t[1] ) + is_prefix_action = lambda t : t[0].startswith(prefix_s) + drop_prefix = lambda (k,w): (k[prefix_pos:],w) + + members_t = inspect.getmembers(prefix_actions_proxy) + methods_t = filter(is_method, members_t) + prefix_actions_t = filter(is_prefix_action, methods_t) + prefix_actions_d = dict( map(drop_prefix, prefix_actions_t) ) + + for widget in self.get_widgets(): + prefixes = gtk.Widget.get_data(widget, "prefixes") + if prefixes: + for prefix in prefixes: + if prefix in prefix_actions_d: + prefix_action = prefix_actions_d[prefix] + prefix_action(widget) + + def custom_handler(self, + glade, function_name, widget_name, + str1, str2, int1, int2): + """ + Generic handler for creating custom widgets, internally used to + enable custom widgets (custom widgets of glade). + + The custom widgets have a creation function specified in design time. + Those creation functions are always called with str1,str2,int1,int2 as + arguments, that are values specified in design time. + + Methods of classes inheriting from SimpleGladeApp are used as + creation functions automatically. + + If a custom widget has create_foo as creation function, then the + method named create_foo is called with str1,str2,int1,int2 as arguments. + """ + try: + handler = getattr(self, function_name) + return handler(str1, str2, int1, int2) + except AttributeError: + return None + + def gtk_widget_show(self, widget, *args): + """ + Predefined callback. + The widget is showed. + Equivalent to widget.show() + """ + widget.show() + + def gtk_widget_hide(self, widget, *args): + """ + Predefined callback. + The widget is hidden. + Equivalent to widget.hide() + """ + widget.hide() + + def gtk_widget_grab_focus(self, widget, *args): + """ + Predefined callback. + The widget grabs the focus. + Equivalent to widget.grab_focus() + """ + widget.grab_focus() + + def gtk_widget_destroy(self, widget, *args): + """ + Predefined callback. + The widget is destroyed. + Equivalent to widget.destroy() + """ + widget.destroy() + + def gtk_window_activate_default(self, window, *args): + """ + Predefined callback. + The default widget of the window is activated. + Equivalent to window.activate_default() + """ + widget.activate_default() + + def gtk_true(self, *args): + """ + Predefined callback. + Equivalent to return True in a callback. + Useful for stopping propagation of signals. + """ + return True + + def gtk_false(self, *args): + """ + Predefined callback. + Equivalent to return False in a callback. + """ + return False + + def gtk_main_quit(self, *args): + """ + Predefined callback. + Equivalent to self.quit() + """ + self.quit() + + def main(self): + """ + Starts the main loop of processing events. + The default implementation calls gtk.main() + + Useful for applications that needs a non gtk main loop. + For example, applications based on gstreamer needs to override + this method with gst.main() + + Do not directly call this method in your programs. + Use the method run() instead. + """ + gtk.main() + + def quit(self): + """ + Quit processing events. + The default implementation calls gtk.main_quit() + + Useful for applications that needs a non gtk main loop. + For example, applications based on gstreamer needs to override + this method with gst.main_quit() + """ + gtk.main_quit() + + def run(self): + """ + Starts the main loop of processing events checking for Control-C. + + The default implementation checks wheter a Control-C is pressed, + then calls on_keyboard_interrupt(). + + Use this method for starting programs. + """ + try: + self.main() + except KeyboardInterrupt: + self.on_keyboard_interrupt() + + def on_keyboard_interrupt(self): + """ + This method is called by the default implementation of run() + after a program is finished by pressing Control-C. + """ + pass + + def install_custom_handler(self, custom_handler): + gtk.glade.set_custom_handler(custom_handler) + + def create_glade(self, glade_path, root, domain): + return gtk.glade.XML(self.glade_path, root, domain) + + def get_widget(self, widget_name): + return self.glade.get_widget(widget_name) + + def get_widgets(self): + return self.glade.get_widget_prefix("") diff --git a/avahi-python/avahi/__init__.py b/avahi-python/avahi/__init__.py new file mode 100644 index 0000000..c10b85d --- /dev/null +++ b/avahi-python/avahi/__init__.py @@ -0,0 +1,84 @@ +# $Id$ + +# This file is part of avahi. +# +# avahi is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# avahi is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +# License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with avahi; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +# Some definitions matching those in core.h +import socket, dbus + +SERVER_INVALID, SERVER_REGISTERING, SERVER_RUNNING, SERVER_COLLISION = range(0, 4) + +ENTRY_GROUP_UNCOMMITED, ENTRY_GROUP_REGISTERING, ENTRY_GROUP_ESTABLISHED, ENTRY_GROUP_COLLISION = range(0, 4) + +DOMAIN_BROWSER_REGISTER, DOMAIN_BROWSER_REGISTER_DEFAULT, DOMAIN_BROWSER_BROWSE, DOMAIN_BROWSER_BROWSE_DEFAULT, DOMAIN_BROWSER_BROWSE_LEGACY = range(0, 5) + +PROTO_UNSPEC, PROTO_INET, PROTO_INET6 = -1, 0, 1 + +IF_UNSPEC = -1 + +DBUS_NAME = "org.freedesktop.Avahi" +DBUS_INTERFACE_SERVER = DBUS_NAME + ".Server" +DBUS_PATH_SERVER = "/" +DBUS_INTERFACE_ENTRY_GROUP = DBUS_NAME + ".EntryGroup" +DBUS_INTERFACE_DOMAIN_BROWSER = DBUS_NAME + ".DomainBrowser" +DBUS_INTERFACE_SERVICE_TYPE_BROWSER = DBUS_NAME + ".ServiceTypeBrowser" +DBUS_INTERFACE_SERVICE_BROWSER = DBUS_NAME + ".ServiceBrowser" + +def byte_array_to_string(s): + r = "" + + for c in s: + + if c >= 32 and c < 127: + r += "%c" % c + else: + r += "." + + return r + +def txt_array_to_string_array(t): + l = [] + + for s in t: + l.append(byte_array_to_string(s)) + + return l + + +def string_to_byte_array(s): + r = [] + + for c in s: + r.append(dbus.Byte(ord(c))) + + return r + +def string_array_to_txt_array(t): + l = [] + + for s in t: + l.append(string_to_byte_array(s)) + + return l + +def dict_to_txt_array(txt_dict): + l = [] + + for k,v in txt_dict.items(): + l.append(string_to_byte_array("%s=%s" % (k,v))) + + return l diff --git a/avahi-utils/Makefile.am b/avahi-utils/Makefile.am index 2066e4f..846b9ce 100644 --- a/avahi-utils/Makefile.am +++ b/avahi-utils/Makefile.am @@ -22,56 +22,6 @@ AM_CFLAGS=-I$(top_srcdir) # This cool debug trap works on i386/gcc only AM_CFLAGS+='-DDEBUG_TRAP=__asm__("int $$3")' -EXTRA_DIST = \ - avahi-publish-address.in \ - avahi-publish-service.in \ - avahi-bookmarks.in \ - avahi-discover.in \ - avahi-discover.desktop.in - -SUBDIRS=avahi - -if HAVE_PYTHON -if HAVE_PYTHON_DBUS -if HAVE_PYGTK - -pythonscripts = \ - avahi-publish-address \ - avahi-publish-service \ - avahi-bookmarks \ - avahi-discover - -desktopdir = $(datadir)/applications -desktop_DATA = avahi-discover.desktop - -avahi-discover.desktop: avahi-discover.desktop.in - sed -e 's,@bindir\@,$(bindir),g' $< > $@ - chmod +x $@ - -avahi-discover: avahi-discover.in - sed -e 's,@PYTHON\@,$(PYTHON),g' \ - -e 's,@interfacesdir\@,$(interfacesdir),g' $< > $@ - chmod +x $@ - -avahi-publish-address: avahi-publish-address.in - sed -e 's,@PYTHON\@,$(PYTHON),g' $< > $@ - chmod +x $@ - -avahi-publish-service: avahi-publish-service.in - sed -e 's,@PYTHON\@,$(PYTHON),g' $< > $@ - chmod +x $@ - -avahi-bookmarks: avahi-bookmarks.in - sed -e 's,@PYTHON\@,$(PYTHON),g' $< > $@ - chmod +x $@ - -bin_SCRIPTS = $(pythonscripts) -CLEANFILES = $(pythonscripts) $(desktop_DATA) - -endif -endif -endif - if HAVE_DBUS bin_PROGRAMS = avahi-browse avahi-resolve-host-name diff --git a/avahi-utils/avahi-bookmarks.in b/avahi-utils/avahi-bookmarks.in deleted file mode 100755 index 2de9186..0000000 --- a/avahi-utils/avahi-bookmarks.in +++ /dev/null @@ -1,173 +0,0 @@ -#!@PYTHON@ -# -*-python-*- -# $Id$ - -# This file is part of avahi. -# -# avahi is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as -# published by the Free Software Foundation; either version 2 of the -# License, or (at your option) any later version. -# -# avahi is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -# License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with avahi; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -import sys, getopt - -try: - import avahi, gobject, dbus -except ImportError: - print "Sorry, to use this tool you need to install Avahi, pygtk and python-dbus." - sys.exit(1) - -try: - import dbus.glib -except ImportError: - pass - -try: - from twisted.internet import gtk2reactor - gtk2reactor.install() - from twisted.internet import reactor - from twisted.web import server, resource -except ImportError: - print "Sorry, to use this tool you need to install twisted and twisted.web." - sys.exit(1) - -urlproto = { "_http._tcp" : "http", "_https._tcp" : "https", "_ftp._tcp" : "ftp" } - -port = 8080 -address = "127.0.0.1" -use_host_names = False -domain = "local" - -class AvahiBookmarks(resource.Resource): - isLeaf = True - - services = {} - - def __init__(self): - resource.Resource.__init__(self) - - self.bus = dbus.SystemBus() - self.server = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER), avahi.DBUS_INTERFACE_SERVER) - - self.version_string = self.server.GetVersionString() - - self.browse_service_type("_http._tcp") - - # Hurrah! if I enable one of the following lines, python segfaults. - #self.browse_service_type("_https._tcp") - #self.browse_service_type("_ftp._tcp") - - def browse_service_type(self, stype): - - global domain - - browser = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, self.server.ServiceBrowserNew(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, stype, domain, dbus.UInt32(0))), avahi.DBUS_INTERFACE_SERVICE_BROWSER) - browser.connect_to_signal('ItemNew', self.new_service) - browser.connect_to_signal('ItemRemove', self.remove_service) - - def find_path(self, txt): - - l = avahi.txt_array_to_string_array(txt) - - for k in l: - if k[:5] == "path=": - if k[5:].startswith("/"): - return k[5:] - else: - return "/" + k[5:] - - return "/" - - def render_GET(self, request): - - t = 'Zeroconf Bookmarks

Zeroconf Bookmarks

' - - if len(self.services) == 0: - t += '

Sorry, no web services have been registered on the local LAN.

' - else: - t += '
    ' - - for k, v in self.services.iteritems(): - - if v[3] == 80: - port = '' - else: - port = ':%i' % v[3] - - path = self.find_path(v[4]) - t += '
  • %s
  • ' % (urlproto[k[3]], v[2], port, path, k[2]) - - t += '
' - - t += '

Served by %s

' % self.version_string - - return t - - - def new_service(self, interface, protocol, name, type, domain, flags): - - interface, protocol, name, type, domain, host, aprotocol, address, port, txt, flags = self.server.ResolveService(interface, protocol, name, type, domain, avahi.PROTO_UNSPEC, dbus.UInt32(0)) - - if use_host_names: - h = host - else: - if aprotocol == avahi.PROTO_INET6: - h = "[" + address + "]" - else: - h = address - - self.services[(interface, protocol, name, type, domain)] = (host, aprotocol, h, port, txt) - - def remove_service(self, interface, protocol, name, type, domain): - del self.services[(interface, protocol, name, type, domain)] - - -def usage(retval = 0): - print "%s [options]\n" % sys.argv[0] - print " -h --help Show this help" - print " -p --port PORT Specify the port to use (default %u)" % port - print " -a --address ADDRESS Specify the address to bind to (default %s)" % address - print " -H --host-names Show all services, regardless of the type" - print " -d --domain DOMAIN Specify the domain to browse" - sys.exit(retval) - -try: - opts, args = getopt.getopt(sys.argv[1:], "hp:a:Hd:", ["help", "port=", "address=", "host-names", "domain="]) -except getopt.GetoptError: - usage(2) - -for o, a in opts: - if o in ("-h", "--help"): - usage() - - if o in ("-p", "--port"): - port = int(a) - - if o in ("-a", "--address"): - address = a - - if o in ("-H", "--host-names"): - use_host_names = True - - if o in ("-d", "--domain"): - domain = a - -site = server.Site(AvahiBookmarks()) -reactor.listenTCP(port, site, interface=address) - -print "Now point your web browser to http://%s:%u/!" % (address, port) - -try: - reactor.run() -except KeyboardInterrupt, k: - pass diff --git a/avahi-utils/avahi-discover.desktop.in b/avahi-utils/avahi-discover.desktop.in deleted file mode 100644 index 2362cd4..0000000 --- a/avahi-utils/avahi-discover.desktop.in +++ /dev/null @@ -1,10 +0,0 @@ -[Desktop Entry] -Encoding=UTF-8 -Name=Avahi Zeroconf Browser -Comment=Browse for Zeroconf services available on your network -Exec=@bindir@/avahi-discover -Terminal=false -Type=Application -Icon=gnome-nettool.png -Categories=GNOME;Application;System;Utility -StartupNotify=false diff --git a/avahi-utils/avahi-discover.in b/avahi-utils/avahi-discover.in deleted file mode 100755 index 00a5602..0000000 --- a/avahi-utils/avahi-discover.in +++ /dev/null @@ -1,244 +0,0 @@ -#!@PYTHON@ -# -*-python-*- -# $Id$ - -# This file is part of avahi. -# -# avahi is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as -# published by the Free Software Foundation; either version 2 of the -# License, or (at your option) any later version. -# -# avahi is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -# License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with avahi; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -import os, sys - -try: - import avahi, gtk, gobject, dbus, avahi.ServiceTypeDatabase - from avahi.SimpleGladeApp import SimpleGladeApp -except ImportError: - print "Sorry, to use this tool you need to install Avahi, pygtk and python-dbus." - sys.exit(1) - -try: - import dbus.glib -except ImportError, e: - pass - -service_type_browsers = {} -service_browsers = {} - -glade_dir = "@interfacesdir@" - -service_type_db = avahi.ServiceTypeDatabase.ServiceTypeDatabase() - -class Main_window(SimpleGladeApp): - def __init__(self, path="avahi-discover.glade", root="main_window", domain=None, **kwargs): - path = os.path.join(glade_dir, path) - SimpleGladeApp.__init__(self, path, root, domain, **kwargs) - - def on_tree_view_cursor_changed(self, widget, *args): - (model, iter) = widget.get_selection().get_selected() - (name,interface,protocol,stype,domain) = self.treemodel.get(iter,1,2,3,4,5) - if stype == None: - self.info_label.set_markup("No service currently selected.") - return - #Asynchronous resolving - self.server.ResolveService( int(interface), int(protocol), name, stype, domain, avahi.PROTO_UNSPEC, dbus.UInt32(0), reply_handler=self.service_resolved, error_handler=self.print_error) - - - def protoname(self,protocol): - if protocol == avahi.PROTO_INET: - return "IPv4" - if protocol == avahi.PROTO_INET6: - return "IPv6" - - - def siocgifname(self, interface): - if interface <= 0: - return "any" - else: - return self.server.GetNetworkInterfaceNameByIndex(interface) - - def service_resolved(self, interface, protocol, name, stype, domain, host, aprotocol, address, port, txt, flags): - print "Service data for service '%s' of type '%s' in domain '%s' on %i.%i:" % (name, stype, domain, interface, protocol) - - print "\tHost %s (%s), port %i, TXT data: %s" % (host, address, port, str(avahi.txt_array_to_string_array(txt))) - - self.update_label(interface, protocol, name, stype, domain, host, aprotocol, address, port, avahi.txt_array_to_string_array(txt)) - - def print_error(self, err): - error_label = "Error: %s" % (err) - self.info_label.set_markup(error_label) - print "Error:", str(err) - - def lookup_type(self, stype): - global service_type_db - - try: - return service_type_db[stype] - except KeyError: - return stype - - def new_service(self, interface, protocol, name, stype, domain, flags): - print "Found service '%s' of type '%s' in domain '%s' on %i.%i." % (name, stype, domain, interface, protocol) - if self.zc_ifaces.has_key((interface,protocol)) == False: - self.zc_ifaces[(interface,protocol)] = self.insert_row(self.treemodel, None, str(self.siocgifname(interface))+" "+str(self.protoname(protocol)),None,interface,protocol,None,domain) - if self.zc_domains.has_key((interface,protocol,domain)) == False: - self.zc_domains[(interface,protocol,domain)] = self.insert_row(self.treemodel, self.zc_ifaces[(interface,protocol)], domain,None,interface,protocol,None,domain) - if self.zc_types.has_key((interface,protocol,stype,domain)) == False: - thisDomain = self.zc_domains[(interface,protocol,domain)] - self.zc_types[(interface,protocol,stype,domain)] = self.insert_row(self.treemodel, thisDomain, self.lookup_type(stype), name, interface,None,None,None) - treeiter = self.insert_row(self.treemodel,self.zc_types[(interface,protocol,stype,domain)], name, name, interface,protocol,stype,domain) - self.services_browsed[(interface, protocol, name, stype, domain)] = treeiter - # expand the tree of this path - self.tree_view.expand_to_path(self.treemodel.get_path(treeiter)) - - - def remove_service(self, interface, protocol, name, stype, domain, flags): - print "Service '%s' of type '%s' in domain '%s' on %i.%i disappeared." % (name, stype, domain, interface, protocol) - self.info_label.set_markup("") - treeiter=self.services_browsed[(interface, protocol, name, stype, domain)] - parent = self.treemodel.iter_parent(treeiter) - self.treemodel.remove(treeiter) - del self.services_browsed[(interface, protocol, name, stype, domain)] - if self.treemodel.iter_has_child(parent) == False: - treeiter=self.zc_types[(interface,protocol,stype,domain)] - parent = self.treemodel.iter_parent(treeiter) - self.treemodel.remove(treeiter) - del self.zc_types[(interface,protocol,stype,domain)] - if self.treemodel.iter_has_child(parent) == False: - treeiter=self.zc_domains[(interface,protocol,domain)] - parent = self.treemodel.iter_parent(treeiter) - self.treemodel.remove(treeiter) - del self.zc_domains[(interface,protocol,domain)] - if self.treemodel.iter_has_child(parent) == False: - treeiter=self.zc_ifaces[(interface,protocol)] - parent = self.treemodel.iter_parent(treeiter) - self.treemodel.remove(treeiter) - del self.zc_ifaces[(interface,protocol)] - - - def new_service_type(self, interface, protocol, stype, domain, flags): - global service_browsers - - # Are we already browsing this domain for this type? - if service_browsers.has_key((interface, protocol, stype, domain)): - return - - print "Browsing for services of type '%s' in domain '%s' on %i.%i ..." % (stype, domain, interface, protocol) - - b = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, self.server.ServiceBrowserNew(interface, protocol, stype, domain, dbus.UInt32(0))), avahi.DBUS_INTERFACE_SERVICE_BROWSER) - b.connect_to_signal('ItemNew', self.new_service) - b.connect_to_signal('ItemRemove', self.remove_service) - - service_browsers[(interface, protocol, stype, domain)] = b - - def browse_domain(self, interface, protocol, domain): - global service_type_browsers - - # Are we already browsing this domain? - if service_type_browsers.has_key((interface, protocol, domain)): - return - - if self.stype is None: - print "Browsing domain '%s' on %i.%i ..." % (domain, interface, protocol) - - b = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, self.server.ServiceTypeBrowserNew(interface, protocol, domain, dbus.UInt32(0))), avahi.DBUS_INTERFACE_SERVICE_TYPE_BROWSER) - b.connect_to_signal('ItemNew', self.new_service_type) - - service_type_browsers[(interface, protocol, domain)] = b - else: - new_service_type(interface, protocol, stype, domain) - - def new_domain(self,interface, protocol, domain, flags): - if self.zc_ifaces.has_key((interface,protocol)) == False: - self.zc_ifaces[(interface,protocol)] = self.insert_row(self.treemodel, None, str(self.siocgifname(interface))+" "+str(self.protoname(protocol)),None,interface,protocol,None,domain) - if self.zc_domains.has_key((interface,protocol,domain)) == False: - self.zc_domains[(interface,protocol,domain)] = self.insert_row(self.treemodel, self.zc_ifaces[(interface,protocol)], domain,None,interface,protocol,None,domain) - if domain != "local": - self.browse_domain(interface, protocol, domain) - - def pair_to_dict(self, l): - res = dict() - for el in l: - if "=" not in el: - res[el]='' - else: - tmp = el.split('=',1) - if len(tmp[0]) > 0: - res[tmp[0]] = tmp[1] - return res - - - def update_label(self,interface, protocol, name, stype, domain, host, aprotocol, address, port, txt): - if len(txt) != 0: - txts = "" - txtd = self.pair_to_dict(txt) - for k,v in txtd.items(): - txts+="TXT %s = %s\n" % (k,v) - else: - txts = "TXT Data: empty" - - infos = "Service Type: %s\nService Name: %s\nDomain Name: %s\nInterface: %s %s\nAddress: %s/%s:%i\n%s" % (stype, name, domain, self.siocgifname(interface), self.protoname(protocol), host, address, port, txts.strip()) - self.info_label.set_markup(infos) - - def insert_row(self, model,parent, - content, name, interface,protocol,stype,domain): - myiter=model.insert_after(parent,None) - model.set(myiter,0,content,1,name,2,interface,3,protocol,4,stype,5,domain) - return myiter - - def new(self): - print "A new main_window has been created" - self.treemodel=gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING) - self.tree_view.set_model(self.treemodel) - - #creating the columns headers - self.tree_view.set_headers_visible(False) - renderer=gtk.CellRendererText() - column=gtk.TreeViewColumn("",renderer, text=0) - column.set_resizable(True) - column.set_sizing("GTK_TREE_VIEW_COLUMN_GROW_ONLY"); - column.set_expand(True); - self.tree_view.append_column(column) - - self.domain = None - self.stype = None - self.zc_ifaces = {} - self.zc_domains = {} - self.zc_types = {} - self.services_browsed = {} - - self.bus = dbus.SystemBus() - self.server = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER), avahi.DBUS_INTERFACE_SERVER) - - if self.domain is None: - # Explicitly browse .local - self.browse_domain(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, "local") - - # Browse for other browsable domains - db = dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, self.server.DomainBrowserNew(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, "", avahi.DOMAIN_BROWSER_BROWSE, dbus.UInt32(0))), avahi.DBUS_INTERFACE_DOMAIN_BROWSER) - db.connect_to_signal('ItemNew', self.new_domain) - else: - # Just browse the domain the user wants us to browse - self.browse_domain(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, domain) - - -def main(): - main_window = Main_window() - - main_window.run() - -if __name__ == "__main__": - main() - - diff --git a/avahi-utils/avahi-publish-address.in b/avahi-utils/avahi-publish-address.in deleted file mode 100755 index 4ffebd7..0000000 --- a/avahi-utils/avahi-publish-address.in +++ /dev/null @@ -1,96 +0,0 @@ -#!@PYTHON@ -# -*-python-*- -# $Id$ - -# This file is part of avahi. -# -# avahi is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as -# published by the Free Software Foundation; either version 2 of the -# License, or (at your option) any later version. -# -# avahi is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -# License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with avahi; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -import sys, getopt, string - -try: - import avahi, gobject, dbus -except ImportError: - print "Sorry, to use this tool you need to install Avahi, pygtk and python-dbus." - sys.exit(1) - -try: - import dbus.glib -except ImportError, e: - pass - -def usage(retval = 0): - print "%s
" % sys.argv[0] - sys.exit(retval) - -if len(sys.argv) != 3: - usage(2) - -name = sys.argv[1] -address = sys.argv[2] - -group = None -n_rename = 0 - -def remove_address(): - global group - - if not (group is None): - group.Free() - group = None - -def add_address(): - global server, group, name, address - assert group is None - - print "Adding address '%s' for '%s' ..." % (name, address) - group = dbus.Interface(bus.get_object(avahi.DBUS_NAME, server.EntryGroupNew()), avahi.DBUS_INTERFACE_ENTRY_GROUP) - group.connect_to_signal('StateChanged', entry_group_state_changed) - group.AddAddress(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, dbus.UInt32(0), name, address) - group.Commit() - -def entry_group_state_changed(state): - global name, server, n_rename, main_loop - - if state == avahi.ENTRY_GROUP_ESTABLISHED: - print "Address established." - elif state == avahi.ENTRY_GROUP_COLLISION: - - n_rename = n_rename + 1 - if n_rename >= 12: - print "ERROR: No suitable name found after %i retries, exiting." % n_rename - main_loop.quit() - else: - hn = name.split('.') - hn[0] = server.GetAlternativeHostName(hn[0]) - name = string.join(hn, '.') - print "WARNING: Address/host name collision, changing name to '%s' ..." % name - remove_address() - add_address() - -main_loop = gobject.MainLoop() - -bus = dbus.SystemBus() -server = dbus.Interface(bus.get_object(avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER), avahi.DBUS_INTERFACE_SERVER) - -add_address() - -try: - main_loop.run() -except KeyboardInterrupt, k: - pass - -remove_address() diff --git a/avahi-utils/avahi-publish-service.in b/avahi-utils/avahi-publish-service.in deleted file mode 100755 index 3f40fd0..0000000 --- a/avahi-utils/avahi-publish-service.in +++ /dev/null @@ -1,134 +0,0 @@ -#!@PYTHON@ -# -*-python-*- -# $Id$ - -# This file is part of avahi. -# -# avahi is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as -# published by the Free Software Foundation; either version 2 of the -# License, or (at your option) any later version. -# -# avahi is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -# License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with avahi; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -import sys, getopt - -try: - import avahi, gobject, dbus -except ImportError: - print "Sorry, to use this tool you need to install Avahi, pygtk and python-dbus." - sys.exit(1) - -try: - import dbus.glib -except ImportError, e: - pass - -def usage(retval = 0): - print "%s [options] [ ...]\n" % sys.argv[0] - print " -h --help Show this help" - print " -d --domain Domain where to register this service" - print " -H --host Host where this service resides" - sys.exit(retval) - -try: - opts, args = getopt.getopt(sys.argv[1:], "hd:H:", ["help", "domain=", "host="]) -except getopt.GetoptError: - usage(2) - -domain = "" -host = "" - -for o, a in opts: - if o in ("-h", "--help"): - usage() - - if o in ("-d", "--domain"): - domain = a - - if o in ("-H", "--host"): - host = a - -if len(args) < 3: - usage(2) - -name = args[0] -stype = args[1] -port = int(args[2]) -txt = args[3:] - -# python-dbus doesn't allow transmission of empty arrays, therefore we "fix" it with a bogus entry -if len(txt) == 0: - txt.append("python-dbus=brain-damage") - -group = None -n_rename = 0 - -def remove_service(): - global group - - if not group is None: - group.Reset() - -def add_service(): - global server, group, name, stype, domain, host, port, txt - - if group is None: - group = dbus.Interface(bus.get_object(avahi.DBUS_NAME, server.EntryGroupNew()), avahi.DBUS_INTERFACE_ENTRY_GROUP) - group.connect_to_signal('StateChanged', entry_group_state_changed) - - assert group.IsEmpty() - - print "Adding service '%s' of type '%s' ..." % (name, stype) - - group.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, dbus.UInt32(0), name, stype, domain, host, dbus.UInt16(port), avahi.string_array_to_txt_array(txt)) - group.Commit() - -def entry_group_state_changed(state): - global name, server, n_rename - -# print "state change: %i" % state - - if state == avahi.ENTRY_GROUP_ESTABLISHED: - print "Service established." - elif state == avahi.ENTRY_GROUP_COLLISION: - - n_rename = n_rename + 1 - if n_rename >= 12: - print "ERROR: No suitable service name found after %i retries, exiting." % n_rename - main_loop.quit() - else: - name = server.GetAlternativeServiceName(name) - print "WARNING: Service name collision, changing name to '%s' ..." % name - remove_service() - add_service() - -def server_state_changed(state): - if state == avahi.SERVER_COLLISION: - print "WARNING: Server name collision" - remove_service() - elif state == avahi.SERVER_RUNNING: - add_service() - -main_loop = gobject.MainLoop() - -bus = dbus.SystemBus() -server = dbus.Interface(bus.get_object(avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER), avahi.DBUS_INTERFACE_SERVER) -server.connect_to_signal("StateChanged", server_state_changed) -server_state_changed(server.GetState()) - -try: - main_loop.run() -except KeyboardInterrupt, k: - pass - -if not group is None: - group.Free() diff --git a/avahi-utils/avahi/Makefile.am b/avahi-utils/avahi/Makefile.am deleted file mode 100644 index b1ebe22..0000000 --- a/avahi-utils/avahi/Makefile.am +++ /dev/null @@ -1,44 +0,0 @@ -# $Id$ - -# This file is part of avahi. -# -# avahi is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as -# published by the Free Software Foundation; either version 2 of the -# License, or (at your option) any later version. -# -# avahi is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -# License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with avahi; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -EXTRA_DIST = __init__.py SimpleGladeApp.py ServiceTypeDatabase.py.in - -if HAVE_PYTHON - -avahidir = $(pythondir)/avahi - -avahi_SCRIPTS = ServiceTypeDatabase.py - -ServiceTypeDatabase.py: ServiceTypeDatabase.py.in - sed -e 's,@PYTHON\@,$(PYTHON),g' \ - -e 's,@pkgdatadir\@,$(pkgdatadir),g' $< > $@ - chmod +x $@ - -if HAVE_PYGTK -if HAVE_PYTHON_DBUS - -avahi_PYTHON = __init__.py SimpleGladeApp.py - -endif -endif -endif - -CLEANFILES=*.pyc *.pyo ServiceTypeDatabase.py - - diff --git a/avahi-utils/avahi/ServiceTypeDatabase.py.in b/avahi-utils/avahi/ServiceTypeDatabase.py.in deleted file mode 100644 index 9caeebd..0000000 --- a/avahi-utils/avahi/ServiceTypeDatabase.py.in +++ /dev/null @@ -1,97 +0,0 @@ -#!@PYTHON@ -# -*-python-*- -# $Id$ - -# This file is part of avahi. -# -# avahi is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as -# published by the Free Software Foundation; either version 2 of the -# License, or (at your option) any later version. -# -# avahi is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -# License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with avahi; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -import gdbm -import locale - -locale.setlocale(locale.LC_ALL, '') - -class ServiceTypeDatabase: - - def __init__(self, filename = "@pkgdatadir@/service-types.db"): - - self.db = gdbm.open(filename, "r") - - l = locale.getlocale(locale.LC_MESSAGES) - - self.suffixes = () - - if not l[0] is None: - - if not l[1] is None: - self.suffixes += (l[0] + "@" + l[1], ) - - self.suffixes += (l[0], ) - - i = l[0].find("_") - - if i >= 0: - - k = l[0][:i] - - if not l[1] is None: - self.suffixes += (k + "@" + l[1], ) - - self.suffixes += (k, ) - - - self.suffixes = tuple(map(lambda x: "["+x+"]", self.suffixes)) + ("", ) - - def __getitem__(self, key): - - for suffix in self.suffixes: - try: - return self.db[key + suffix] - except KeyError: - pass - - raise KeyError() - - def has_key(self, key): - - for suffix in self.suffixes: - - if self.db.has_key(key + suffix): - return True - - return False - - def __contains__(self, item): - - for suffix in self.suffixes: - - if item+suffix in self.db: - return True - - return False - - - -if __name__ == "__main__": - - b = ServiceTypeDatabase() - - print b["_http._tcp"] - print b["_ftp._tcp"] - print b["_webdav._tcp"] - print b["_webdavs._tcp"] - - print b["gurki._tcp"] diff --git a/avahi-utils/avahi/SimpleGladeApp.py b/avahi-utils/avahi/SimpleGladeApp.py deleted file mode 100644 index 90c598c..0000000 --- a/avahi-utils/avahi/SimpleGladeApp.py +++ /dev/null @@ -1,341 +0,0 @@ -""" - SimpleGladeApp.py - Module that provides an object oriented abstraction to pygtk and libglade. - Copyright (C) 2004 Sandino Flores Moreno -""" - -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA - -import os -import sys -import re - -import tokenize -import gtk -import gtk.glade -import weakref -import inspect - -__version__ = "1.0" -__author__ = 'Sandino "tigrux" Flores-Moreno' - -def bindtextdomain(app_name, locale_dir=None): - """ - Bind the domain represented by app_name to the locale directory locale_dir. - It has the effect of loading translations, enabling applications for different - languages. - - app_name: - a domain to look for translations, tipically the name of an application. - - locale_dir: - a directory with locales like locale_dir/lang_isocode/LC_MESSAGES/app_name.mo - If omitted or None, then the current binding for app_name is used. - """ - try: - import locale - import gettext - locale.setlocale(locale.LC_ALL, "") - gtk.glade.bindtextdomain(app_name, locale_dir) - gettext.install(app_name, locale_dir, unicode=1) - except (IOError,locale.Error), e: - print "Warning", app_name, e - __builtins__.__dict__["_"] = lambda x : x - - -class SimpleGladeApp: - - def __init__(self, path, root=None, domain=None, **kwargs): - """ - Load a glade file specified by glade_filename, using root as - root widget and domain as the domain for translations. - - If it receives extra named arguments (argname=value), then they are used - as attributes of the instance. - - path: - path to a glade filename. - If glade_filename cannot be found, then it will be searched in the - same directory of the program (sys.argv[0]) - - root: - the name of the widget that is the root of the user interface, - usually a window or dialog (a top level widget). - If None or ommited, the full user interface is loaded. - - domain: - A domain to use for loading translations. - If None or ommited, no translation is loaded. - - **kwargs: - a dictionary representing the named extra arguments. - It is useful to set attributes of new instances, for example: - glade_app = SimpleGladeApp("ui.glade", foo="some value", bar="another value") - sets two attributes (foo and bar) to glade_app. - """ - if os.path.isfile(path): - self.glade_path = path - else: - glade_dir = os.path.dirname( sys.argv[0] ) - self.glade_path = os.path.join(glade_dir, path) - for key, value in kwargs.items(): - try: - setattr(self, key, weakref.proxy(value) ) - except TypeError: - setattr(self, key, value) - self.glade = None - self.install_custom_handler(self.custom_handler) - self.glade = self.create_glade(self.glade_path, root, domain) - if root: - self.main_widget = self.get_widget(root) - else: - self.main_widget = None - self.normalize_names() - self.add_callbacks(self) - self.new() - - def __repr__(self): - class_name = self.__class__.__name__ - if self.main_widget: - root = gtk.Widget.get_name(self.main_widget) - repr = '%s(path="%s", root="%s")' % (class_name, self.glade_path, root) - else: - repr = '%s(path="%s")' % (class_name, self.glade_path) - return repr - - def new(self): - """ - Method called when the user interface is loaded and ready to be used. - At this moment, the widgets are loaded and can be refered as self.widget_name - """ - pass - - def add_callbacks(self, callbacks_proxy): - """ - It uses the methods of callbacks_proxy as callbacks. - The callbacks are specified by using: - Properties window -> Signals tab - in glade-2 (or any other gui designer like gazpacho). - - Methods of classes inheriting from SimpleGladeApp are used as - callbacks automatically. - - callbacks_proxy: - an instance with methods as code of callbacks. - It means it has methods like on_button1_clicked, on_entry1_activate, etc. - """ - self.glade.signal_autoconnect(callbacks_proxy) - - def normalize_names(self): - """ - It is internally used to normalize the name of the widgets. - It means a widget named foo:vbox-dialog in glade - is refered self.vbox_dialog in the code. - - It also sets a data "prefixes" with the list of - prefixes a widget has for each widget. - """ - for widget in self.get_widgets(): - widget_name = gtk.Widget.get_name(widget) - prefixes_name_l = widget_name.split(":") - prefixes = prefixes_name_l[ : -1] - widget_api_name = prefixes_name_l[-1] - widget_api_name = "_".join( re.findall(tokenize.Name, widget_api_name) ) - gtk.Widget.set_name(widget, widget_api_name) - if hasattr(self, widget_api_name): - raise AttributeError("instance %s already has an attribute %s" % (self,widget_api_name)) - else: - setattr(self, widget_api_name, widget) - if prefixes: - gtk.Widget.set_data(widget, "prefixes", prefixes) - - def add_prefix_actions(self, prefix_actions_proxy): - """ - By using a gui designer (glade-2, gazpacho, etc) - widgets can have a prefix in theirs names - like foo:entry1 or foo:label3 - It means entry1 and label3 has a prefix action named foo. - - Then, prefix_actions_proxy must have a method named prefix_foo which - is called everytime a widget with prefix foo is found, using the found widget - as argument. - - prefix_actions_proxy: - An instance with methods as prefix actions. - It means it has methods like prefix_foo, prefix_bar, etc. - """ - prefix_s = "prefix_" - prefix_pos = len(prefix_s) - - is_method = lambda t : callable( t[1] ) - is_prefix_action = lambda t : t[0].startswith(prefix_s) - drop_prefix = lambda (k,w): (k[prefix_pos:],w) - - members_t = inspect.getmembers(prefix_actions_proxy) - methods_t = filter(is_method, members_t) - prefix_actions_t = filter(is_prefix_action, methods_t) - prefix_actions_d = dict( map(drop_prefix, prefix_actions_t) ) - - for widget in self.get_widgets(): - prefixes = gtk.Widget.get_data(widget, "prefixes") - if prefixes: - for prefix in prefixes: - if prefix in prefix_actions_d: - prefix_action = prefix_actions_d[prefix] - prefix_action(widget) - - def custom_handler(self, - glade, function_name, widget_name, - str1, str2, int1, int2): - """ - Generic handler for creating custom widgets, internally used to - enable custom widgets (custom widgets of glade). - - The custom widgets have a creation function specified in design time. - Those creation functions are always called with str1,str2,int1,int2 as - arguments, that are values specified in design time. - - Methods of classes inheriting from SimpleGladeApp are used as - creation functions automatically. - - If a custom widget has create_foo as creation function, then the - method named create_foo is called with str1,str2,int1,int2 as arguments. - """ - try: - handler = getattr(self, function_name) - return handler(str1, str2, int1, int2) - except AttributeError: - return None - - def gtk_widget_show(self, widget, *args): - """ - Predefined callback. - The widget is showed. - Equivalent to widget.show() - """ - widget.show() - - def gtk_widget_hide(self, widget, *args): - """ - Predefined callback. - The widget is hidden. - Equivalent to widget.hide() - """ - widget.hide() - - def gtk_widget_grab_focus(self, widget, *args): - """ - Predefined callback. - The widget grabs the focus. - Equivalent to widget.grab_focus() - """ - widget.grab_focus() - - def gtk_widget_destroy(self, widget, *args): - """ - Predefined callback. - The widget is destroyed. - Equivalent to widget.destroy() - """ - widget.destroy() - - def gtk_window_activate_default(self, window, *args): - """ - Predefined callback. - The default widget of the window is activated. - Equivalent to window.activate_default() - """ - widget.activate_default() - - def gtk_true(self, *args): - """ - Predefined callback. - Equivalent to return True in a callback. - Useful for stopping propagation of signals. - """ - return True - - def gtk_false(self, *args): - """ - Predefined callback. - Equivalent to return False in a callback. - """ - return False - - def gtk_main_quit(self, *args): - """ - Predefined callback. - Equivalent to self.quit() - """ - self.quit() - - def main(self): - """ - Starts the main loop of processing events. - The default implementation calls gtk.main() - - Useful for applications that needs a non gtk main loop. - For example, applications based on gstreamer needs to override - this method with gst.main() - - Do not directly call this method in your programs. - Use the method run() instead. - """ - gtk.main() - - def quit(self): - """ - Quit processing events. - The default implementation calls gtk.main_quit() - - Useful for applications that needs a non gtk main loop. - For example, applications based on gstreamer needs to override - this method with gst.main_quit() - """ - gtk.main_quit() - - def run(self): - """ - Starts the main loop of processing events checking for Control-C. - - The default implementation checks wheter a Control-C is pressed, - then calls on_keyboard_interrupt(). - - Use this method for starting programs. - """ - try: - self.main() - except KeyboardInterrupt: - self.on_keyboard_interrupt() - - def on_keyboard_interrupt(self): - """ - This method is called by the default implementation of run() - after a program is finished by pressing Control-C. - """ - pass - - def install_custom_handler(self, custom_handler): - gtk.glade.set_custom_handler(custom_handler) - - def create_glade(self, glade_path, root, domain): - return gtk.glade.XML(self.glade_path, root, domain) - - def get_widget(self, widget_name): - return self.glade.get_widget(widget_name) - - def get_widgets(self): - return self.glade.get_widget_prefix("") diff --git a/avahi-utils/avahi/__init__.py b/avahi-utils/avahi/__init__.py deleted file mode 100644 index c10b85d..0000000 --- a/avahi-utils/avahi/__init__.py +++ /dev/null @@ -1,84 +0,0 @@ -# $Id$ - -# This file is part of avahi. -# -# avahi is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as -# published by the Free Software Foundation; either version 2 of the -# License, or (at your option) any later version. -# -# avahi is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -# License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with avahi; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -# Some definitions matching those in core.h -import socket, dbus - -SERVER_INVALID, SERVER_REGISTERING, SERVER_RUNNING, SERVER_COLLISION = range(0, 4) - -ENTRY_GROUP_UNCOMMITED, ENTRY_GROUP_REGISTERING, ENTRY_GROUP_ESTABLISHED, ENTRY_GROUP_COLLISION = range(0, 4) - -DOMAIN_BROWSER_REGISTER, DOMAIN_BROWSER_REGISTER_DEFAULT, DOMAIN_BROWSER_BROWSE, DOMAIN_BROWSER_BROWSE_DEFAULT, DOMAIN_BROWSER_BROWSE_LEGACY = range(0, 5) - -PROTO_UNSPEC, PROTO_INET, PROTO_INET6 = -1, 0, 1 - -IF_UNSPEC = -1 - -DBUS_NAME = "org.freedesktop.Avahi" -DBUS_INTERFACE_SERVER = DBUS_NAME + ".Server" -DBUS_PATH_SERVER = "/" -DBUS_INTERFACE_ENTRY_GROUP = DBUS_NAME + ".EntryGroup" -DBUS_INTERFACE_DOMAIN_BROWSER = DBUS_NAME + ".DomainBrowser" -DBUS_INTERFACE_SERVICE_TYPE_BROWSER = DBUS_NAME + ".ServiceTypeBrowser" -DBUS_INTERFACE_SERVICE_BROWSER = DBUS_NAME + ".ServiceBrowser" - -def byte_array_to_string(s): - r = "" - - for c in s: - - if c >= 32 and c < 127: - r += "%c" % c - else: - r += "." - - return r - -def txt_array_to_string_array(t): - l = [] - - for s in t: - l.append(byte_array_to_string(s)) - - return l - - -def string_to_byte_array(s): - r = [] - - for c in s: - r.append(dbus.Byte(ord(c))) - - return r - -def string_array_to_txt_array(t): - l = [] - - for s in t: - l.append(string_to_byte_array(s)) - - return l - -def dict_to_txt_array(txt_dict): - l = [] - - for k,v in txt_dict.items(): - l.append(string_to_byte_array("%s=%s" % (k,v))) - - return l diff --git a/configure.ac b/configure.ac index a8a16c4..0f5e28d 100644 --- a/configure.ac +++ b/configure.ac @@ -707,7 +707,8 @@ initscript/fedora/Makefile initscript/darwin/Makefile avahi-dnsconfd/Makefile avahi-utils/Makefile -avahi-utils/avahi/Makefile +avahi-python/Makefile +avahi-python/avahi/Makefile examples/Makefile common/Makefile man/Makefile