diff --git a/data/glade/zeroconf_contact_context_menu.glade b/data/glade/zeroconf_contact_context_menu.glade index e69c42668..93d901f1c 100644 --- a/data/glade/zeroconf_contact_context_menu.glade +++ b/data/glade/zeroconf_contact_context_menu.glade @@ -1,32 +1,34 @@ - - - + + + + Start _Chat True - Start _Chat True + False - + True gtk-jump-to - 1 + 1 + Send _File True - Send _File True + False - + True gtk-save - 1 + 1 @@ -36,67 +38,85 @@ True + + + Execute Command... + True + False + + + True + gtk-execute + 1 + + + + + _Manage Contact True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - _Manage Contact True + False True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - _Rename + _Rename True + False - + True gtk-refresh - 1 + 1 - Edit _Groups + Edit _Groups True + False - + True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK gtk-edit - 1 + 1 - Assign Open_PGP Key + Assign Open_PGP Key True + False - + True gtk-dialog-authentication - 1 + 1 + Add Special _Notification True - Add Special _Notification True + False - + True gtk-info - 1 + 1 @@ -104,11 +124,10 @@ - + True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK gtk-properties - 1 + 1 @@ -120,20 +139,28 @@ - gtk-info + _Information True - True + False + + + True + gtk-info + 1 + + - _History + _History True + False - + True gtk-justify-fill - 1 + 1 diff --git a/src/common/zeroconf/client_zeroconf.py b/src/common/zeroconf/client_zeroconf.py index 9f910807e..86538c463 100644 --- a/src/common/zeroconf/client_zeroconf.py +++ b/src/common/zeroconf/client_zeroconf.py @@ -167,6 +167,8 @@ class P2PClient(IdleObject): self.conn_holder.ids_of_awaiting_messages[self.fd] = [(id_, thread_id)] + self.on_responses = {} + def add_stanza(self, stanza, is_message=False): if self.Connection: if self.Connection.state == -1: @@ -282,6 +284,9 @@ class P2PClient(IdleObject): self.onreceive(None) return True + def remove_timeout(self): + pass + def _register_handlers(self): self.RegisterHandler('message', lambda conn, data:self._caller._messageCB( self.Server, conn, data)) @@ -297,6 +302,8 @@ class P2PClient(IdleObject): common.xmpp.NS_BYTESTREAM) self.RegisterHandler('iq', self._caller._bytestreamErrorCB, 'error', common.xmpp.NS_BYTESTREAM) + self.RegisterHandler('iq', self._caller._DiscoverItemsGetCB, 'get', + common.xmpp.NS_DISCO_ITEMS) class P2PConnection(IdleObject, PlugIn): def __init__(self, sock_hash, _sock, host=None, port=None, caller=None, @@ -717,4 +724,35 @@ class ClientZeroconf: P2PClient(None, item['address'], item['port'], self, [(stanza, is_message)], to, on_ok=on_ok, on_not_ok=on_not_ok) + def SendAndWaitForResponse(self, stanza, timeout=None, func=None, args=None): + ''' + Send stanza and wait for recipient's response to it. Will call transports + on_timeout callback if response is not retrieved in time. + + Be aware: Only timeout of latest call of SendAndWait is active. + ''' +# if timeout is None: +# timeout = DEFAULT_TIMEOUT_SECONDS + def on_ok(_waitid): +# if timeout: +# self._owner.set_timeout(timeout) + to = stanza.getTo() + conn = None + if to in self.recipient_to_hash: + conn = self.connections[self.recipient_to_hash[to]] + elif item['address'] in self.ip_to_hash: + hash_ = self.ip_to_hash[item['address']] + if self.hash_to_port[hash_] == item['port']: + conn = self.connections[hash_] + if func: + conn.Dispatcher.on_responses[_waitid] = (func, args) + conn.onreceive(conn.Dispatcher._WaitForData) + conn.Dispatcher._expected[_waitid] = None + self.send(stanza, on_ok=on_ok) + + def SendAndCallForResponse(self, stanza, func=None, args=None): + ''' Put stanza on the wire and call back when recipient replies. + Additional callback arguments can be specified in args. ''' + self.SendAndWaitForResponse(stanza, 0, func, args) + # vim: se ts=3: diff --git a/src/common/zeroconf/connection_handlers_zeroconf.py b/src/common/zeroconf/connection_handlers_zeroconf.py index 6b9a0b661..09818be47 100644 --- a/src/common/zeroconf/connection_handlers_zeroconf.py +++ b/src/common/zeroconf/connection_handlers_zeroconf.py @@ -34,6 +34,10 @@ import common.xmpp from common import helpers from common import gajim from common.zeroconf import zeroconf +from common.commands import ConnectionCommands + +import logging +log = logging.getLogger('gajim.c.z.connection_handlers_zeroconf') STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd', 'invisible'] @@ -45,7 +49,7 @@ HAS_IDLE = True try: import idle except Exception: - gajim.log.debug(_('Unable to load idle module')) + log.debug(_('Unable to load idle module')) HAS_IDLE = False from common import connection_handlers @@ -156,7 +160,7 @@ class ConnectionBytestream(connection_handlers.ConnectionBytestream): self.connection.send(iq) def _bytestreamSetCB(self, con, iq_obj): - gajim.log.debug('_bytestreamSetCB') + log.debug('_bytestreamSetCB') target = unicode(iq_obj.getAttr('to')) id_ = unicode(iq_obj.getAttr('id')) query = iq_obj.getTag('query') @@ -198,7 +202,7 @@ class ConnectionBytestream(connection_handlers.ConnectionBytestream): raise common.xmpp.NodeProcessed def _ResultCB(self, con, iq_obj): - gajim.log.debug('_ResultCB') + log.debug('_ResultCB') # if we want to respect jep-0065 we have to check for proxy # activation result in any result iq real_id = unicode(iq_obj.getAttr('id')) @@ -215,7 +219,7 @@ class ConnectionBytestream(connection_handlers.ConnectionBytestream): raise common.xmpp.NodeProcessed def _bytestreamResultCB(self, con, iq_obj): - gajim.log.debug('_bytestreamResultCB') + log.debug('_bytestreamResultCB') frm = unicode(iq_obj.getFrom()) real_id = unicode(iq_obj.getAttr('id')) query = iq_obj.getTag('query') @@ -283,7 +287,7 @@ class ConnectionBytestream(connection_handlers.ConnectionBytestream): raise common.xmpp.NodeProcessed def _siResultCB(self, con, iq_obj): - gajim.log.debug('_siResultCB') + log.debug('_siResultCB') self.peerhost = con._owner.Connection._sock.getsockname() id_ = iq_obj.getAttr('id') if id_ not in self.files_props: @@ -321,7 +325,7 @@ class ConnectionBytestream(connection_handlers.ConnectionBytestream): raise common.xmpp.NodeProcessed def _siSetCB(self, con, iq_obj): - gajim.log.debug('_siSetCB') + log.debug('_siSetCB') jid = unicode(iq_obj.getFrom()) si = iq_obj.getTag('si') profile = si.getAttr('profile') @@ -353,7 +357,7 @@ class ConnectionBytestream(connection_handlers.ConnectionBytestream): raise common.xmpp.NodeProcessed def _siErrorCB(self, con, iq_obj): - gajim.log.debug('_siErrorCB') + log.debug('_siErrorCB') si = iq_obj.getTag('si') profile = si.getAttr('profile') if profile != common.xmpp.NS_FILE: @@ -371,10 +375,12 @@ class ConnectionBytestream(connection_handlers.ConnectionBytestream): self.dispatch('FILE_REQUEST_ERROR', (jid, file_props, '')) raise common.xmpp.NodeProcessed -class ConnectionHandlersZeroconf(ConnectionVcard, ConnectionBytestream, connection_handlers.ConnectionHandlersBase): +class ConnectionHandlersZeroconf(ConnectionVcard, ConnectionBytestream, +ConnectionCommands, connection_handlers.ConnectionHandlersBase): def __init__(self): ConnectionVcard.__init__(self) ConnectionBytestream.__init__(self) + ConnectionCommands.__init__(self) connection_handlers.ConnectionHandlersBase.__init__(self) try: @@ -386,7 +392,7 @@ class ConnectionHandlersZeroconf(ConnectionVcard, ConnectionBytestream, connecti def _messageCB(self, ip, con, msg): '''Called when we receive a message''' - gajim.log.debug('Zeroconf MessageCB') + log.debug('Zeroconf MessageCB') frm = msg.getFrom() mtype = msg.getType() @@ -480,4 +486,21 @@ class ConnectionHandlersZeroconf(ConnectionVcard, ConnectionBytestream, connecti def remove_transfer(self, file_props, remove_from_list = True): pass + def _DiscoverItemsGetCB(self, con, iq_obj): + log.debug('DiscoverItemsGetCB') + + if not self.connection or self.connected < 2: + return + + if self.commandItemsQuery(con, iq_obj): + raise common.xmpp.NodeProcessed + node = iq_obj.getTagAttr('query', 'node') + if node is None: + result = iq_obj.buildReply('result') + self.connection.send(result) + raise common.xmpp.NodeProcessed + if node==common.xmpp.NS_COMMANDS: + self.commandListQuery(con, iq_obj) + raise common.xmpp.NodeProcessed + # vim: se ts=3: diff --git a/src/roster_window.py b/src/roster_window.py index 647b80eca..2089dd7e6 100644 --- a/src/roster_window.py +++ b/src/roster_window.py @@ -5305,6 +5305,7 @@ class RosterWindow: 'zeroconf_contact_context_menu') start_chat_menuitem = xml.get_widget('start_chat_menuitem') + execute_command_menuitem = xml.get_widget('execute_command_menuitem') rename_menuitem = xml.get_widget('rename_menuitem') edit_groups_menuitem = xml.get_widget('edit_groups_menuitem') send_file_menuitem = xml.get_widget('send_file_menuitem') @@ -5364,6 +5365,9 @@ class RosterWindow: else: send_file_menuitem.set_sensitive(False) + execute_command_menuitem.connect('activate', + self.on_execute_command, contact, account) + rename_menuitem.connect('activate', self.on_rename, 'contact', jid, account) if contact.show in ('offline', 'error'):