add ad hoc commands for zeroconf. Fixes #2819

This commit is contained in:
Yann Leboulanger 2009-08-30 00:57:49 +02:00
parent 1e76981322
commit da799bcb59
4 changed files with 132 additions and 40 deletions

View File

@ -1,32 +1,34 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--*- mode: xml -*-->
<?xml version="1.0"?>
<glade-interface>
<!-- interface-requires gtk+ 2.16 -->
<!-- interface-naming-policy toplevel-contextual -->
<widget class="GtkMenu" id="zeroconf_contact_context_menu">
<child>
<widget class="GtkImageMenuItem" id="start_chat_menuitem">
<property name="label">Start _Chat</property>
<property name="visible">True</property>
<property name="label" translatable="yes">Start _Chat</property>
<property name="use_underline">True</property>
<property name="use_stock">False</property>
<child internal-child="image">
<widget class="GtkImage" id="image1701">
<widget class="GtkImage" id="image9">
<property name="visible">True</property>
<property name="stock">gtk-jump-to</property>
<property name="icon_size">1</property>
<property name="icon-size">1</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="send_file_menuitem">
<property name="label">Send _File</property>
<property name="visible">True</property>
<property name="label" translatable="yes">Send _File</property>
<property name="use_underline">True</property>
<property name="use_stock">False</property>
<child internal-child="image">
<widget class="GtkImage" id="image1706">
<widget class="GtkImage" id="image10">
<property name="visible">True</property>
<property name="stock">gtk-save</property>
<property name="icon_size">1</property>
<property name="icon-size">1</property>
</widget>
</child>
</widget>
@ -36,67 +38,85 @@
<property name="visible">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="execute_command_menuitem">
<property name="label" translatable="yes">Execute Command...</property>
<property name="visible">True</property>
<property name="use_stock">False</property>
<child internal-child="image">
<widget class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="stock">gtk-execute</property>
<property name="icon-size">1</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="manage_contact">
<property name="label">_Manage Contact</property>
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">_Manage Contact</property>
<property name="use_underline">True</property>
<property name="use_stock">False</property>
<child>
<widget class="GtkMenu" id="menu2">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkImageMenuItem" id="rename_menuitem">
<property name="label" translatable="yes">_Rename</property>
<property name="label">_Rename</property>
<property name="use_underline">True</property>
<property name="use_stock">False</property>
<child internal-child="image">
<widget class="GtkImage" id="image1705">
<widget class="GtkImage" id="image7">
<property name="visible">True</property>
<property name="stock">gtk-refresh</property>
<property name="icon_size">1</property>
<property name="icon-size">1</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="edit_groups_menuitem">
<property name="label" translatable="yes">Edit _Groups</property>
<property name="label">Edit _Groups</property>
<property name="use_underline">True</property>
<property name="use_stock">False</property>
<child internal-child="image">
<widget class="GtkImage" id="menu-item-image21">
<widget class="GtkImage" id="image6">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="stock">gtk-edit</property>
<property name="icon_size">1</property>
<property name="icon-size">1</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="assign_openpgp_key_menuitem">
<property name="label" translatable="yes">Assign Open_PGP Key</property>
<property name="label">Assign Open_PGP Key</property>
<property name="use_underline">True</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_assign_openpgp_key_menuitem_activate"/>
<child internal-child="image">
<widget class="GtkImage" id="image1707">
<widget class="GtkImage" id="image5">
<property name="visible">True</property>
<property name="stock">gtk-dialog-authentication</property>
<property name="icon_size">1</property>
<property name="icon-size">1</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="add_special_notification_menuitem">
<property name="label">Add Special _Notification</property>
<property name="no_show_all">True</property>
<property name="label" translatable="yes">Add Special _Notification</property>
<property name="use_underline">True</property>
<property name="use_stock">False</property>
<child internal-child="image">
<widget class="GtkImage" id="image1708">
<widget class="GtkImage" id="image3">
<property name="visible">True</property>
<property name="stock">gtk-info</property>
<property name="icon_size">1</property>
<property name="icon-size">1</property>
</widget>
</child>
</widget>
@ -104,11 +124,10 @@
</widget>
</child>
<child internal-child="image">
<widget class="GtkImage" id="menu-item-image19">
<widget class="GtkImage" id="image8">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="stock">gtk-properties</property>
<property name="icon_size">1</property>
<property name="icon-size">1</property>
</widget>
</child>
</widget>
@ -120,20 +139,28 @@
</child>
<child>
<widget class="GtkImageMenuItem" id="information_menuitem">
<property name="label">gtk-info</property>
<property name="label">_Information</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<property name="use_stock">False</property>
<child internal-child="image">
<widget class="GtkImage" id="image4">
<property name="visible">True</property>
<property name="stock">gtk-info</property>
<property name="icon-size">1</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="history_menuitem">
<property name="label" translatable="yes">_History</property>
<property name="label">_History</property>
<property name="use_underline">True</property>
<property name="use_stock">False</property>
<child internal-child="image">
<widget class="GtkImage" id="image1718">
<widget class="GtkImage" id="image2">
<property name="visible">True</property>
<property name="stock">gtk-justify-fill</property>
<property name="icon_size">1</property>
<property name="icon-size">1</property>
</widget>
</child>
</widget>

View File

@ -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:

View File

@ -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:

View File

@ -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'):