diff --git a/data/glade/chat_control_popup_menu.glade b/data/glade/chat_control_popup_menu.glade index 8219a42b2..ca43baf26 100644 --- a/data/glade/chat_control_popup_menu.glade +++ b/data/glade/chat_control_popup_menu.glade @@ -95,6 +95,15 @@ + + + + True + Ping + True + + + diff --git a/src/chat_control.py b/src/chat_control.py index 298e549b3..34926f175 100644 --- a/src/chat_control.py +++ b/src/chat_control.py @@ -498,6 +498,11 @@ class ChatControlBase(MessageControl): if message_array == ['']: message_array = [] + if command == 'ping' and not len(message_array): + gajim.connections[self.account].sendPing(self.contact) + self.clear(self.msg_textview) + return True + if command == 'clear' and not len(message_array): self.conv_textview.clear() # clear conversation self.clear(self.msg_textview) # clear message textview too @@ -1388,6 +1393,7 @@ class ChatControl(ChatControlBase): toggle_gpg_menuitem = xml.get_widget('toggle_gpg_menuitem') add_to_roster_menuitem = xml.get_widget('add_to_roster_menuitem') send_file_menuitem = xml.get_widget('send_file_menuitem') + ping_menuitem = xml.get_widget('ping_menuitem') compact_view_menuitem = xml.get_widget('compact_view_menuitem') information_menuitem = xml.get_widget('information_menuitem') @@ -1428,6 +1434,8 @@ class ChatControl(ChatControlBase): id = history_menuitem.connect('activate', self._on_history_menuitem_activate) self.handlers[id] = history_menuitem + id = ping_menuitem.connect('activate', + self._on_ping_menuitem_activate) id = send_file_menuitem.connect('activate', self._on_send_file_menuitem_activate) self.handlers[id] = send_file_menuitem @@ -1822,6 +1830,9 @@ class ChatControl(ChatControlBase): cursor = gtk.gdk.Cursor(gtk.gdk.LEFT_PTR) self.bigger_avatar_window.window.set_cursor(cursor) + def _on_ping_menuitem_activate(self, widget): + gajim.connections[self.account].sendPing(self.contact) + def _on_send_file_menuitem_activate(self, widget): gajim.interface.instances['file_transfers'].show_file_send_request( self.account, self.contact) diff --git a/src/common/connection.py b/src/common/connection.py index d02441973..6c4c1ddd0 100644 --- a/src/common/connection.py +++ b/src/common/connection.py @@ -572,6 +572,22 @@ class Connection(ConnectionHandlers): return common.xmpp.features_nb.getPrivacyLists(self.connection) + def sendPing(self, pingTo): + if not self.connection: + return + iq = common.xmpp.Iq('get', to = pingTo.get_full_jid()) + iq.addChild(name = 'ping', namespace = common.xmpp.NS_PING) + def _on_response(resp): + timePong = time.time() + if not common.xmpp.isResultNode(resp): + self.dispatch('PING_ERROR', (pingTo)) + return + timeDiff = round(timePong - timePing,2) + self.dispatch('PING_REPLY', (pingTo, timeDiff)) + self.dispatch('PING_SENT', (pingTo)) + timePing = time.time() + self.connection.SendAndCallForResponse(iq, _on_response) + def get_active_default_lists(self): if not self.connection: return diff --git a/src/gajim.py b/src/gajim.py index 21119a2db..2b0d29de2 100755 --- a/src/gajim.py +++ b/src/gajim.py @@ -1651,6 +1651,26 @@ class Interface: else: gajim.connections[account].change_status('offline','') + def handle_event_ping_sent(self, account, contact): + ctrl = self.msg_win_mgr.get_control(contact.get_full_jid(), account) + if ctrl == None: + ctrl = self.msg_win_mgr.get_control(contact.jid, account) + ctrl.print_conversation(_('Ping?'), 'status') + + def handle_event_ping_reply(self, account, data): + contact = data[0] + seconds = data[1] + ctrl = self.msg_win_mgr.get_control(contact.get_full_jid(), account) + if ctrl == None: + ctrl = self.msg_win_mgr.get_control(contact.jid, account) + ctrl.print_conversation(_('Pong! (%s s.)') % seconds, 'status') + + def handle_event_ping_error(self, account, contact): + ctrl = self.msg_win_mgr.get_control(contact.get_full_jid(), account) + if ctrl == None: + ctrl = self.msg_win_mgr.get_control(contact.jid, account) + ctrl.print_conversation(_('Error.'), 'status') + def read_sleepy(self): '''Check idle status and change that status if needed''' if not self.sleeper.poll(): @@ -1963,6 +1983,9 @@ class Interface: self.handle_event_privacy_lists_active_default, 'PRIVACY_LIST_REMOVED': self.handle_event_privacy_list_removed, 'ZC_NAME_CONFLICT': self.handle_event_zc_name_conflict, + 'PING_SENT': self.handle_event_ping_sent, + 'PING_REPLY': self.handle_event_ping_reply, + 'PING_ERROR': self.handle_event_ping_error, } gajim.handlers = self.handlers