#!/usr/bin/python2

"""
 avahi-publish-ssh-service
 Publish services found in the configuration files of OpenSSH via DNS-SD.
 Copyright (C) 2006 Mathias Hasselmann
"""

# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2.0
# of the License, or (at your option) any later version.
#
# This program 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 General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

import avahi, dbus, gobject

verbose = True

class Host:
    def __init__(self, name):
        from os import getlogin

        self.alias = name
        self.name = name
        self.port = 22
        self.user = getlogin()

    def __str__(self):
        return "ssh://%(user)s@%(name)s:%(port)d/"%vars(self)

    def publish(self, group):
        if verbose:
            print '- publishing %s'%self

        group.AddService(
            avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, 0,
            'Remote Terminal on %s'%self.alias, '_ssh._tcp',
            'local', self.name, self.port, ['u=%s'%self.user])
        group.AddService(
            avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, 0,
            'Remote Terminal on %s'%self.alias, '_sftp-ssh._tcp',
            'local', self.name, self.port, ['u=%s'%self.user])

def find_host_entries():
    from re import compile
    from os import path

    config_files = ('/etc/ssh/ssh_config', '~/.ssh/config')
    config_files = map(path.expanduser, config_files)
    config_files = filter(path.exists, config_files)
    option_regex = compile('^\s*(\w+)\s+(.+)\s*$')
    host_entries = []

    for filename in config_files:
        file = open(filename)
        host = None

        try:
            for line in file:
                match = option_regex.match(line)
                if not match: continue

                key, value = match.group(1, 2)

                if 'Host' == key:
                    if '*' != value:
                        if host: host_entries+= [host]
                        host = Host(value)

                elif host:
                    if 'HostName' == key:
                        host.name = value
                    elif 'Port' == key:
                        host.port = int(value)
                    elif 'User' == key:
                        host.user = value
        
            if host: host_entries+= [host]

        finally:
            file.close()

    return host_entries

def publish_host_entries():
    host_entries = find_host_entries()
    
    if len(host_entries):
        bus = dbus.SystemBus()

        server_proxy = bus.get_object(avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER)
        server = dbus.Interface(server_proxy, avahi.DBUS_INTERFACE_SERVER)

        group_proxy = bus.get_object(avahi.DBUS_NAME, server.EntryGroupNew())
        group = dbus.Interface(group_proxy, avahi.DBUS_INTERFACE_ENTRY_GROUP)

        if verbose:
            print 'talking to %s...'%server.GetVersionString()
        
        for host in host_entries:
            host.publish(group)

        try:
            group.Commit()
            gobject.MainLoop().run()

        finally:
            group.Free()

if '__main__' == __name__:
    try: publish_host_entries()
    except KeyboardInterrupt: pass

# vim: sw=4 sta et
