diff --git a/src/common/connection.py b/src/common/connection.py index ae902796c..84ab4d1e4 100644 --- a/src/common/connection.py +++ b/src/common/connection.py @@ -1266,7 +1266,7 @@ class Connection: self.connection.send(iq_obj) raise common.xmpp.NodeProcessed - def _IdleCB(self, con, iq_obj): + def _LastCB(self, con, iq_obj): gajim.log.debug('IdleCB') iq_obj = iq_obj.buildReply('result') qp = iq_obj.getTag('query') @@ -1278,6 +1278,19 @@ class Connection: self.connection.send(iq_obj) raise common.xmpp.NodeProcessed + def _LastResultCB(self, con, iq_obj): + gajim.log.debug('LastResultCB') + qp = iq_obj.getTag('query') + seconds = qp.getAttr('seconds') + status = qp.getData() + try: + seconds = int(seconds) + except: + return + who = self.get_full_jid(iq_obj) + jid_stripped, resource = gajim.get_room_and_nick_from_fjid(who) + self.dispatch('LAST_STATUS_TIME', (jid_stripped, resource, seconds, status)) + def _VersionResultCB(self, con, iq_obj): gajim.log.debug('VersionResultCB') client_info = '' @@ -1837,7 +1850,9 @@ class Connection: common.xmpp.NS_DISCO_INFO) con.RegisterHandler('iq', self._VersionCB, 'get', common.xmpp.NS_VERSION) - con.RegisterHandler('iq', self._IdleCB, 'get', + con.RegisterHandler('iq', self._LastCB, 'get', + common.xmpp.NS_LAST) + con.RegisterHandler('iq', self._LastResultCB, 'result', common.xmpp.NS_LAST) con.RegisterHandler('iq', self._VersionResultCB, 'result', common.xmpp.NS_VERSION) @@ -2272,13 +2287,23 @@ class Connection: def account_changed(self, new_name): self.name = new_name + def request_last_status_time(self, jid, resource): + if not self.connection: + return + to_whom_jid = jid + if resource: + to_whom_jid += '/' + resource + iq = common.xmpp.Iq(to = to_whom_jid, typ = 'get', queryNS =\ + common.xmpp.NS_LAST) + self.connection.send(iq) + def request_os_info(self, jid, resource): if not self.connection: return to_whom_jid = jid if resource: to_whom_jid += '/' + resource - iq = common.xmpp.Iq(to=to_whom_jid, typ = 'get', queryNS =\ + iq = common.xmpp.Iq(to = to_whom_jid, typ = 'get', queryNS =\ common.xmpp.NS_VERSION) self.connection.send(iq) diff --git a/src/common/contacts.py b/src/common/contacts.py index e2f6c5608..59134cf72 100644 --- a/src/common/contacts.py +++ b/src/common/contacts.py @@ -28,7 +28,7 @@ class Contact: '''Information concerning each contact''' def __init__(self, jid='', name='', groups=[], show='', status='', sub='', ask='', resource='', priority=5, keyID='', our_chatstate=None, - chatstate=None): + chatstate=None, last_status_time=None): self.jid = jid self.name = name self.groups = groups @@ -50,6 +50,7 @@ class Contact: self.our_chatstate = our_chatstate # this is contact's chatstate self.chatstate = chatstate + self.last_status_time = last_status_time def get_full_jid(self): if self.resource: @@ -118,16 +119,17 @@ class Contacts: def create_contact(self, jid='', name='', groups=[], show='', status='', sub='', ask='', resource='', priority=5, keyID='', our_chatstate=None, - chatstate=None): + chatstate=None, last_status_time=None): return Contact(jid, name, groups, show, status, sub, ask, resource, - priority, keyID, our_chatstate, chatstate) + priority, keyID, our_chatstate, chatstate, last_status_time) def copy_contact(self, contact): return self.create_contact(jid = contact.jid, name = contact.name, groups = contact.groups, show = contact.show, status = contact.status, sub = contact.sub, ask = contact.ask, resource = contact.resource, priority = contact.priority, keyID = contact.keyID, - our_chatstate = contact.our_chatstate, chatstate = contact.chatstate) + our_chatstate = contact.our_chatstate, chatstate = contact.chatstate, + last_status_time = contact.last_status_time) def add_contact(self, account, contact): # No such account before ? diff --git a/src/gajim.py b/src/gajim.py index b3ad08996..989a63043 100755 --- a/src/gajim.py +++ b/src/gajim.py @@ -372,6 +372,8 @@ class Interface: contact1.status = array[2] contact1.priority = priority contact1.keyID = keyID + if contact1.jid not in gajim.newly_added[account]: + contact1.last_status_time = time.localtime() if jid.find('@') <= 0: # It must be an agent if ji in jid_list: @@ -757,6 +759,26 @@ class Interface: if self.remote_ctrl: self.remote_ctrl.raise_signal('VcardInfo', (account, vcard)) + def handle_event_last_status_time(self, account, array): + # ('LAST_STATUS_TIME', account, (jid, resource, seconds, status)) + win = None + if self.instances[account]['infos'].has_key(array[0]): + win = self.instances[account]['infos'][array[0]] + elif self.instances[account]['infos'].has_key(array[0] + '/' + array[1]): + win = self.instances[account]['infos'][array[0] + '/' + array[1]] + if win: + c = gajim.contacts.get_contact(account, array[0], array[1]) + # c is a list when no resource is given. it probably means that contact + # is offline, so only on Contact instance + if isinstance(c, list): + c = c[0] + c.last_status_time = time.localtime(time.time() - array[2]) + if array[3]: + c.status = array[3] + win.set_last_status_time() + if self.remote_ctrl: + self.remote_ctrl.raise_signal('LastStatusTime', (account, array)) + def handle_event_os_info(self, account, array): win = None if self.instances[account]['infos'].has_key(array[0]): @@ -1387,6 +1409,7 @@ class Interface: 'ACC_NOT_OK': self.handle_event_acc_not_ok, 'MYVCARD': self.handle_event_myvcard, 'VCARD': self.handle_event_vcard, + 'LAST_STATUS_TIME': self.handle_event_last_status_time, 'OS_INFO': self.handle_event_os_info, 'GC_NOTIFY': self.handle_event_gc_notify, 'GC_MSG': self.handle_event_gc_msg, diff --git a/src/tooltips.py b/src/tooltips.py index 2cc80f2fc..39ec15b7a 100644 --- a/src/tooltips.py +++ b/src/tooltips.py @@ -27,6 +27,7 @@ import gtk import gobject import os +import time import gtkgui_helpers import message_control @@ -155,7 +156,7 @@ class StatusTable: str_status += ' - ' + status return gtkgui_helpers.escape_for_pango_markup(str_status) - def add_status_row(self, file_path, show, str_status): + def add_status_row(self, file_path, show, str_status, status_time = None): ''' appends a new row with status icon to the table ''' self.current_row += 1 state_file = show.replace(' ', '_') @@ -179,6 +180,11 @@ class StatusTable: status_label.set_alignment(0, 0) self.table.attach(status_label, 3, 4, self.current_row, self.current_row + 1, gtk.EXPAND | gtk.FILL, 0, 0, 0) + if status_time: + self.current_row += 1 + status_time_label = gtk.Label(time.strftime("%c", status_time)) + self.table.attach(status_time_label, 2, 4, self.current_row, + self.current_row + 1, gtk.EXPAND | gtk.FILL, 0, 0, 0) class NotificationAreaTooltip(BaseTooltip, StatusTable): ''' Tooltip that is shown in the notification area ''' @@ -441,7 +447,8 @@ class RosterTooltip(NotificationAreaTooltip): status_line = self.get_status_info(contact.resource, contact.priority, contact.show, contact.status) icon_name = helpers.get_icon_name_to_show(contact) - self.add_status_row(file_path, icon_name, status_line) + self.add_status_row(file_path, icon_name, status_line, + contact.last_status_time) else: # only one resource if contact.resource: @@ -459,6 +466,9 @@ class RosterTooltip(NotificationAreaTooltip): status = gtkgui_helpers.reduce_chars_newlines(status, 130, 5) # escape markup entities. info += ' - ' + gtkgui_helpers.escape_for_pango_markup(status) + if contact.last_status_time: + info += '\n' + _('Status time: ') + '%s'\ + % time.strftime('%c', contact.last_status_time) for type_ in ('jpeg', 'png'): file = os.path.join(gajim.AVATAR_PATH, prim_contact.jid + '.' + type_) diff --git a/src/vcard.py b/src/vcard.py index 8a322ad4e..676116859 100644 --- a/src/vcard.py +++ b/src/vcard.py @@ -31,6 +31,7 @@ import base64 import mimetypes import os import sys +import time import gtkgui_helpers import dialogs @@ -274,7 +275,10 @@ class VcardWindow: vcard[i], 0) else: self.set_value(i + '_entry', vcard[i]) - + + def set_last_status_time(self): + self.fill_status_label() + def set_os_info(self, resource, client_info, os_info): i = 0 client = '' @@ -298,6 +302,30 @@ class VcardWindow: self.xml.get_widget('client_name_version_label').set_text(client) self.xml.get_widget('os_label').set_text(os) + def fill_status_label(self): + contact_list = gajim.contacts.get_contact(self.account, self.contact.jid) + # stats holds show and status message + stats = '' + one = True # Are we adding the first line ? + if contact_list: + for c in contact_list: + if not one: + stats += '\n' + stats += helpers.get_uf_show(c.show) + if c.status: + stats += ': ' + c.status + if c.last_status_time: + stats += '\n ' + _('since') + time.strftime(' %c', + c.last_status_time) + one = False + status_label = self.xml.get_widget('status_label') + status_label.set_max_width_chars(15) + status_label.set_text(stats) + + tip = gtk.Tooltips() + status_label_eventbox = self.xml.get_widget('status_label_eventbox') + tip.set_tip(status_label_eventbox, stats) + def fill_jabber_page(self): tooltips = gtk.Tooltips() self.xml.get_widget('nickname_label').set_text( @@ -338,13 +366,15 @@ class VcardWindow: + unicode(self.contact.priority) if not self.contact.status: self.contact.status = '' - - # stats holds show and status message - stats = helpers.get_uf_show(self.contact.show) - if self.contact.status: - stats += ': ' + self.contact.status - gajim.connections[self.account].request_os_info(self.contact.jid, + + # Request list time status + gajim.connections[self.account].request_last_status_time(self.contact.jid, self.contact.resource) + + # Request os info in contact is connected + if self.contact.show not in ('offline', 'error'): + gajim.connections[self.account].request_os_info(self.contact.jid, + self.contact.resource) self.os_info = {0: {'resource': self.contact.resource, 'client': '', 'os': ''}} i = 1 @@ -354,29 +384,23 @@ class VcardWindow: if c.resource != self.contact.resource: resources += '\n%s (%s)' % (c.resource, unicode(c.priority)) - uf_resources += '\n' + c.resource + _(' resource with priority ')\ - + unicode(c.priority) - if not c.status: - c.status = '' - stats += '\n' + c.show + ': ' + c.status - gajim.connections[self.account].request_os_info(self.contact.jid, + uf_resources += '\n' + c.resource + \ + _(' resource with priority ') + unicode(c.priority) + if c.show not in ('offline', 'error'): + gajim.connections[self.account].request_os_info(c.jid, + c.resource) + gajim.connections[self.account].request_last_status_time(c.jid, c.resource) self.os_info[i] = {'resource': c.resource, 'client': '', 'os': ''} i += 1 self.xml.get_widget('resource_prio_label').set_text(resources) - tip = gtk.Tooltips() resource_prio_label_eventbox = self.xml.get_widget( 'resource_prio_label_eventbox') - tip.set_tip(resource_prio_label_eventbox, uf_resources) - - tip = gtk.Tooltips() - status_label_eventbox = self.xml.get_widget('status_label_eventbox') - tip.set_tip(status_label_eventbox, stats) - status_label = self.xml.get_widget('status_label') - status_label.set_max_width_chars(15) - status_label.set_text(stats) - + tooltips.set_tip(resource_prio_label_eventbox, uf_resources) + + self.fill_status_label() + gajim.connections[self.account].request_vcard(self.contact.jid) def add_to_vcard(self, vcard, entry, txt):