bind to next available port

updating port also publishes the new port
keep 1st, last as unicode
This commit is contained in:
Dimitur Kirov 2006-10-02 20:45:49 +00:00
parent ac53b4537c
commit b7ceb9ddf7
4 changed files with 150 additions and 107 deletions

View File

@ -18,7 +18,8 @@ from common.xmpp.idlequeue import IdleObject
from common.xmpp import dispatcher_nb, simplexml from common.xmpp import dispatcher_nb, simplexml
from common.xmpp.client import * from common.xmpp.client import *
from common.xmpp.simplexml import ustr from common.xmpp.simplexml import ustr
from dialogs import BindPortError from common.zeroconf import zeroconf
from common.xmpp.protocol import * from common.xmpp.protocol import *
import socket import socket
import errno import errno
@ -459,13 +460,86 @@ class P2PConnection(IdleObject, PlugIn):
class ClientZeroconf: class ClientZeroconf:
def __init__(self, zeroconf, caller): def __init__(self, caller):
self.roster = roster_zeroconf.Roster(zeroconf)
self.caller = caller self.caller = caller
self.start_listener(zeroconf.port) self.zeroconf = None
self.roster = None
self.last_msg = ''
self.connections = {} self.connections = {}
self.recipient_to_hash = {} self.recipient_to_hash = {}
self.ip_to_hash = {} self.ip_to_hash = {}
def test_avahi(self):
#~ self.avahi_error = False
try:
import avahi
except ImportError:
#~ self.avahi_error = True
return False
return True
def connect(self, show, msg):
self.port = self.start_listener(self.caller.port)
if not self.port:
return
self.zeroconf_init(show, msg)
if not self.zeroconf.connect():
self.disconnect()
return
self.roster = roster_zeroconf.Roster(self.zeroconf)
def remove_announce(self):
return self.zeroconf.remove_announce()
def announce(self):
return self.zeroconf.announce()
def set_show_msg(self, show, msg):
self.zeroconf.txt['msg'] = msg
self.last_msg = msg
return self.zeroconf.update_txt(show)
def resolve_all(self):
self.zeroconf.resolve_all()
def reannounce(self, txt):
#~ if self.zeroconf:
self.remove_announce()
self.zeroconf.txt = txt
self.zeroconf.port = self.port
self.zeroconf.username = self.caller.username
return self.announce()
def zeroconf_init(self, show, msg):
self.zeroconf = zeroconf.Zeroconf(self.caller._on_new_service,
self.caller._on_remove_service, self.caller._on_name_conflictCB,
self.caller._on_disconnected, self.caller.username, self.caller.host,
self.port)
self.zeroconf.txt['msg'] = msg
self.zeroconf.txt['status'] = show
self.zeroconf.txt['1st'] = self.caller.first
self.zeroconf.txt['last'] = self.caller.last
self.zeroconf.txt['jid'] = self.caller.jabber_id
self.zeroconf.txt['email'] = self.caller.email
self.zeroconf.username = self.caller.username
self.zeroconf.host = self.caller.host
self.zeroconf.port = self.port
self.last_msg = msg
def disconnect(self):
if self.listener:
self.listener.disconnect()
self.listener = None
if self.zeroconf:
self.zeroconf.disconnect()
self.zeroconf = None
if self.roster:
self.roster.zeroconf = None
self.roster._data = None
self.roster = None
#~ self.caller.show = 'offline'
#~ self.caller.dispatch('STATUS', 'offline')
def kill_all_connections(self): def kill_all_connections(self):
for connection in self.connections.values(): for connection in self.connections.values():
@ -492,14 +566,13 @@ class ClientZeroconf:
break break
def start_listener(self, port): def start_listener(self, port):
self.listener = ZeroconfListener(port, self) for p in range(port, port + 5):
self.listener.bind() self.listener = ZeroconfListener(p, self)
if self.listener.started is False: self.listener.bind()
self.listener = None if self.listener.started:
# We cannot bind port, call error return p
# dialog from dialogs.py and fail self.listener = None
BindPortError(port) return False
return None
def getRoster(self): def getRoster(self):
return self.roster.getRoster() return self.roster.getRoster()

View File

@ -42,7 +42,6 @@ import notify
from common import helpers from common import helpers
from common import gajim from common import gajim
from common import GnuPG from common import GnuPG
from common.zeroconf import zeroconf
from common.zeroconf import connection_handlers_zeroconf from common.zeroconf import connection_handlers_zeroconf
from common.zeroconf import client_zeroconf from common.zeroconf import client_zeroconf
from connection_handlers_zeroconf import * from connection_handlers_zeroconf import *
@ -87,17 +86,6 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
self.get_config_values_or_default() self.get_config_values_or_default()
self.avahi_error = False
try:
import avahi
except ImportError:
self.avahi_error = True
if not self.avahi_error:
self.zeroconf = zeroconf.Zeroconf(self._on_new_service,
self._on_remove_service, self._on_name_conflictCB,
self._on_disconnected, self.username, self.host, self.port)
self.muc_jid = {} # jid of muc server for each transport type self.muc_jid = {} # jid of muc server for each transport type
self.vcard_supported = False self.vcard_supported = False
@ -185,7 +173,7 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
def _on_resolve_timeout(self): def _on_resolve_timeout(self):
if self.connected: if self.connected:
self.zeroconf.resolve_all() self.connection.resolve_all()
diffs = self.roster.getDiffs() diffs = self.roster.getDiffs()
for key in diffs: for key in diffs:
self.roster.setItem(key) self.roster.setItem(key)
@ -218,71 +206,72 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
def connect(self, data = None, show = 'online', msg = ''): def connect(self, data = None, show = 'online', msg = ''):
self.get_config_values_or_default() self.get_config_values_or_default()
if not self.connection:
self.zeroconf.txt['status'] = show self.connection = client_zeroconf.ClientZeroconf(self)
self.zeroconf.txt['msg'] = msg if not self.connection.test_avahi():
self.zeroconf.txt['1st'] = self.first self.dispatch('STATUS', 'offline')
self.zeroconf.txt['last'] = self.last self.status = 'offline'
self.zeroconf.txt['jid'] = self.jabber_id self.dispatch('CONNECTION_LOST',
self.zeroconf.txt['email'] = self.email (_('Could not connect to "%s"') % self.name,
self.zeroconf.username = self.username _('Please check if Avahi is installed.')))
self.zeroconf.host = self.host return
self.zeroconf.port = self.port self.connection.connect(show, msg)
if not self.connection.listener:
if self.zeroconf.connect(): self.status = 'offline'
if not self.connection: self.dispatch('CONNECTION_LOST',
self.connection = client_zeroconf.ClientZeroconf(self.zeroconf, self) (_('Could not start local service') % self.name,
else: _('Unable to bind to port "%d".' % self.port)))
self.zeroconf.announce() return
self.roster = self.connection.getRoster()
self.dispatch('ROSTER', self.roster)
#display contacts already detected and resolved
for jid in self.roster.keys():
self.dispatch('ROSTER_INFO', (jid, self.roster.getName(jid), 'both', 'no', self.roster.getGroups(jid)))
self.dispatch('NOTIFY', (jid, self.roster.getStatus(jid), self.roster.getMessage(jid), 'local', 0, None, 0))
self.connected = STATUS_LIST.index(show)
# refresh all contacts data every five seconds
self.call_resolve_timeout = True
gobject.timeout_add(5000, self._on_resolve_timeout)
else: else:
self.dispatch('STATUS', 'offline') self.connection.announce()
self.status = 'offline' self.roster = self.connection.getRoster()
self.dispatch('ROSTER', self.roster)
#display contacts already detected and resolved
for jid in self.roster.keys():
self.dispatch('ROSTER_INFO', (jid, self.roster.getName(jid), 'both', 'no', self.roster.getGroups(jid)))
self.dispatch('NOTIFY', (jid, self.roster.getStatus(jid), self.roster.getMessage(jid), 'local', 0, None, 0))
self.connected = STATUS_LIST.index(show)
# refresh all contacts data every five seconds
self.call_resolve_timeout = True
gobject.timeout_add(5000, self._on_resolve_timeout)
return True
def disconnect(self, on_purpose = False): def disconnect(self, on_purpose = False):
self.connected = 0 self.connected = 0
self.time_to_reconnect = None self.time_to_reconnect = None
if self.connection: if self.connection:
if self.connection.listener: self.connection.disconnect()
self.connection.listener.disconnect()
self.connection = None self.connection = None
# stop calling the timeout # stop calling the timeout
self.call_resolve_timeout = False self.call_resolve_timeout = False
self.zeroconf.disconnect()
def reconnect(self): def reannounce(self):
if self.connected: if self.connected:
txt = {} txt = {}
txt['1st'] = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, 'zeroconf_first_name') txt['1st'] = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, 'zeroconf_first_name')
txt['last'] = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, 'zeroconf_last_name') txt['last'] = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, 'zeroconf_last_name')
txt['jid'] = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, 'zeroconf_jabber_id') txt['jid'] = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, 'zeroconf_jabber_id')
txt['email'] = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, 'zeroconf_email') txt['email'] = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, 'zeroconf_email')
self.connection.reannounce(txt)
self.zeroconf.remove_announce()
self.zeroconf.txt = txt
self.zeroconf.port = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, 'custom_port')
self.zeroconf.username = self.username
self.zeroconf.announce()
def restart_listener(self): def update_details(self):
if self.connection: if self.connection:
port = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, 'custom_port') port = gajim.config.get_per('accounts', gajim.ZEROCONF_ACC_NAME, 'custom_port')
self.connection.kill_all_connections() if self.connection:
if self.connection.listener: if port != self.port:
self.connection.listener.disconnect() self.port = port
self.connection.start_listener(port) last_msg = self.connection.last_msg
self.disconnect()
if not self.connect(show = self.status, msg = last_msg):
return
if self.status != 'invisible':
self.connection.announce()
else:
self.reannounce()
def change_status(self, show, msg, sync = False, auto = False): def change_status(self, show, msg, sync = False, auto = False):
if not show in STATUS_LIST: if not show in STATUS_LIST:
@ -290,22 +279,14 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
self.status = show self.status = show
check = True #to check for errors from zeroconf check = True #to check for errors from zeroconf
if self.avahi_error:
self.dispatch('STATUS', 'offline')
self.status = 'offline'
self.dispatch('CONNECTION_LOST',
(_('Could not connect to "%s"') % self.name,
_('Please check if Avahi is installed.')))
return
# 'connect' # 'connect'
if show != 'offline' and not self.connected: if show != 'offline' and not self.connected:
self.connect(None, show, msg) if not self.connect(None, show, msg):
return
if show != 'invisible': if show != 'invisible':
check = self.zeroconf.announce() check = self.connection.announce()
else: else:
self.connected = STATUS_LIST.index(show) self.connected = STATUS_LIST.index(show)
# 'disconnect' # 'disconnect'
elif show == 'offline' and self.connected: elif show == 'offline' and self.connected:
@ -317,14 +298,11 @@ class ConnectionZeroconf(ConnectionHandlersZeroconf):
was_invisible = self.connected == STATUS_LIST.index('invisible') was_invisible = self.connected == STATUS_LIST.index('invisible')
self.connected = STATUS_LIST.index(show) self.connected = STATUS_LIST.index(show)
if show == 'invisible': if show == 'invisible':
check = check and self.zeroconf.remove_announce() check = check and self.connection.remove_announce()
elif was_invisible: elif was_invisible:
check = check and self.zeroconf.announce() check = check and self.connection.announce()
if self.connection and not show == 'invisible': if self.connection and not show == 'invisible':
txt = {} check = check and self.connection.set_show_msg(show, msg)
txt['status'] = show
txt['msg'] = msg
check = check and self.zeroconf.update_txt(txt)
#stay offline when zeroconf does something wrong #stay offline when zeroconf does something wrong
if check: if check:

View File

@ -324,14 +324,9 @@ class Zeroconf:
def get_contact(self, jid): def get_contact(self, jid):
return self.contacts[jid] return self.contacts[jid]
def update_txt(self, txt): def update_txt(self, show = None):
# update only new non-empty keys if show:
for key in txt.keys(): self.txt['status'] = self.replace_show(show)
if txt[key]:
self.txt[key]=txt[key]
if txt.has_key('status'):
self.txt['status'] = self.replace_show(txt['status'])
txt = avahi.dict_to_txt_array(self.txt) txt = avahi.dict_to_txt_array(self.txt)
if self.connected and self.entrygroup: if self.connected and self.entrygroup:

View File

@ -3215,16 +3215,16 @@ class ZeroconfPropertiesWindow:
config['sync_with_global_status'] = st config['sync_with_global_status'] = st
st = self.xml.get_widget('first_name_entry').get_text() st = self.xml.get_widget('first_name_entry').get_text()
config['zeroconf_first_name'] = st config['zeroconf_first_name'] = st.decode('utf-8')
st = self.xml.get_widget('last_name_entry').get_text() st = self.xml.get_widget('last_name_entry').get_text()
config['zeroconf_last_name'] = st config['zeroconf_last_name'] = st.decode('utf-8')
st = self.xml.get_widget('jabber_id_entry').get_text() st = self.xml.get_widget('jabber_id_entry').get_text()
config['zeroconf_jabber_id'] = st config['zeroconf_jabber_id'] = st.decode('utf-8')
st = self.xml.get_widget('email_entry').get_text() st = self.xml.get_widget('email_entry').get_text()
config['zeroconf_email'] = st config['zeroconf_email'] = st.decode('utf-8')
use_custom_port = self.xml.get_widget('custom_port_checkbutton').get_active() use_custom_port = self.xml.get_widget('custom_port_checkbutton').get_active()
config['use_custom_host'] = use_custom_port config['use_custom_host'] = use_custom_port
@ -3258,12 +3258,9 @@ class ZeroconfPropertiesWindow:
gajim.config.set_per('accounts', gajim.ZEROCONF_ACC_NAME, opt, config[opt]) gajim.config.set_per('accounts', gajim.ZEROCONF_ACC_NAME, opt, config[opt])
if gajim.connections.has_key(gajim.ZEROCONF_ACC_NAME): if gajim.connections.has_key(gajim.ZEROCONF_ACC_NAME):
if port != old_port: if port != old_port or reconnect:
# restart listener if port has changed gajim.connections[gajim.ZEROCONF_ACC_NAME].update_details()
gajim.connections[gajim.ZEROCONF_ACC_NAME].restart_listener()
if reconnect:
gajim.connections[gajim.ZEROCONF_ACC_NAME].reconnect()
self.window.destroy() self.window.destroy()
def on_gpg_choose_button_clicked(self, widget, data = None): def on_gpg_choose_button_clicked(self, widget, data = None):