handle correctly vcards in groupchats : ask them to real jid if we know it, but considere it arrive from fake jid. Fixes #3172, #3173

This commit is contained in:
Yann Leboulanger 2007-05-20 15:41:20 +00:00
parent 241a0f3fda
commit a45a14546a
6 changed files with 124 additions and 89 deletions

View File

@ -1674,24 +1674,34 @@ class ChatControl(ChatControlBase):
if not gajim.config.get('show_avatar_in_chat'):
return
jid = self.contact.jid
jid_with_resource = jid
if resource:
jid_with_resource += '/' + resource
is_fake = False
if self.TYPE_ID == message_control.TYPE_PM:
is_fake = True
jid_with_resource = self.contact.jid # fake jid
else:
jid_with_resource = self.contact.jid
if resource:
jid_with_resource += '/' + resource
# we assume contact has no avatar
scaled_pixbuf = None
pixbuf = None
is_fake = False
if gajim.contacts.is_pm_from_jid(self.account, jid):
is_fake = True
pixbuf = gtkgui_helpers.get_avatar_pixbuf_from_cache(jid_with_resource,
is_fake)
if pixbuf == 'ask':
# we don't have the vcard
gajim.connections[self.account].request_vcard(jid_with_resource,
is_fake)
if self.TYPE_ID == message_control.TYPE_PM:
if self.gc_contact.jid:
# We know the real jid of this contact
real_jid = self.gc_contact.jid
if self.gc_contact.resource:
real_jid += '/' + self.gc_contact.resource
else:
real_jid = jid_with_resource
gajim.connections[self.account].request_vcard(real_jid,
jid_with_resource)
else:
gajim.connections[self.account].request_vcard(jid_with_resource)
return
if pixbuf is not None:
scaled_pixbuf = gtkgui_helpers.get_scaled_pixbuf(pixbuf, 'chat')

View File

@ -811,6 +811,7 @@ class ConnectionVcard:
self.vcard_sha = None
self.vcard_shas = {} # sha of contacts
self.room_jids = [] # list of gc jids so that vcard are saved in a folder
self.groupchat_jids = {} # {ID : groupchat_jid}
def add_sha(self, p, send_caps = True):
c = p.setTag('x', namespace = common.xmpp.NS_VCARD_UPDATE)
@ -906,9 +907,10 @@ class ConnectionVcard:
vcard['resource'] = gajim.get_resource_from_jid(fjid)
return vcard
def request_vcard(self, jid = None, is_fake_jid = False):
'''request the VCARD. If is_fake_jid is True, it means we request a vcard
to a fake jid, like in private messages in groupchat'''
def request_vcard(self, jid = None, groupchat_jid = None):
'''request the VCARD. If groupchat_jid is not nul, it means we request a vcard
to a fake jid, like in private messages in groupchat. jid can be the
real jid of the contact, but we want to consider it comes from a fake jid'''
if not self.connection:
return
iq = common.xmpp.Iq(typ = 'get')
@ -921,13 +923,13 @@ class ConnectionVcard:
j = jid
if not j:
j = gajim.get_jid_from_account(self.name)
self.awaiting_answers[id] = (VCARD_ARRIVED, j)
if is_fake_jid:
room_jid, nick = gajim.get_room_and_nick_from_fjid(jid)
self.awaiting_answers[id] = (VCARD_ARRIVED, j, groupchat_jid)
if groupchat_jid:
room_jid, nick = gajim.get_room_and_nick_from_fjid(groupchat_jid)
if not room_jid in self.room_jids:
self.room_jids.append(room_jid)
self.groupchat_jids[id] = groupchat_jid
self.connection.send(iq)
#('VCARD', {entry1: data, entry2: {entry21: data, ...}, ...})
def send_vcard(self, vcard):
if not self.connection:
@ -1010,17 +1012,22 @@ class ConnectionVcard:
# If vcard is empty, we send to the interface an empty vcard so that
# it knows it arrived
jid = self.awaiting_answers[id][1]
groupchat_jid = self.awaiting_answers[id][2]
frm = jid
if groupchat_jid:
# We do as if it comes from the fake_jid
frm = groupchat_jid
our_jid = gajim.get_jid_from_account(self.name)
if iq_obj.getType() == 'error' and jid == our_jid:
# our server doesn't support vcard
self.vcard_supported = False
if not iq_obj.getTag('vCard') or iq_obj.getType() == 'error':
if jid and jid != our_jid:
if frm and frm != our_jid:
# Write an empty file
self.save_vcard_to_hd(jid, '')
self.dispatch('VCARD', {'jid': jid})
elif jid == our_jid:
self.dispatch('MYVCARD', {'jid': jid})
self.save_vcard_to_hd(frm, '')
self.dispatch('VCARD', {'jid': frm})
elif frm == our_jid:
self.dispatch('MYVCARD', {'jid': frm})
elif self.awaiting_answers[id][0] == AGENT_REMOVED:
jid = self.awaiting_answers[id][1]
self.dispatch('AGENT_REMOVED', jid)
@ -1064,10 +1071,15 @@ class ConnectionVcard:
return
if not vc.getTag('vCard').getNamespace() == common.xmpp.NS_VCARD:
return
id = vc.getID()
frm_iq = vc.getFrom()
our_jid = gajim.get_jid_from_account(self.name)
resource = ''
if frm_iq:
if id in self.groupchat_jids:
who = self.groupchat_jids[id]
frm, resource = gajim.get_room_and_nick_from_fjid(who)
del self.groupchat_jids[id]
elif frm_iq:
who = helpers.get_full_jid_from_iq(vc)
frm, resource = gajim.get_room_and_nick_from_fjid(who)
else:
@ -1139,6 +1151,7 @@ class ConnectionVcard:
p = self.add_sha(p)
self.connection.send(p)
else:
#('VCARD', {entry1: data, entry2: {entry21: data, ...}, ...})
self.dispatch('VCARD', vcard)
class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands, ConnectionPubSub):
@ -1655,7 +1668,8 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
if not ptype or ptype == 'unavailable':
if gajim.config.get('log_contact_status_changes') and self.name\
not in no_log_for and jid_stripped not in no_log_for:
gc_c = gajim.contacts.get_gc_contact(self.name, jid_stripped, resource)
gc_c = gajim.contacts.get_gc_contact(self.name, jid_stripped,
resource)
st = status or ''
if gc_c:
jid = gc_c.jid
@ -1672,25 +1686,6 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
gajim.interface.remove_avatar_files(jid_stripped, puny_nick)
# if it's a gc presence, don't ask vcard here. We may ask it to
# real jid in gui part.
if self.vcard_shas.has_key(who) and not is_gc:
# Verify sha cached in mem
if avatar_sha != self.vcard_shas[who]:
# avatar has been updated
self.request_vcard(who, True)
elif not is_gc: # Verify sha cached in hdd
cached_vcard = self.get_cached_vcard(who, True)
if cached_vcard and cached_vcard.has_key('PHOTO') and \
cached_vcard['PHOTO'].has_key('SHA'):
cached_sha = cached_vcard['PHOTO']['SHA']
else:
cached_sha = ''
if cached_sha != avatar_sha:
# avatar has been updated
# sha in mem will be updated later
self.request_vcard(who, True)
else:
# save sha in mem NOW
self.vcard_shas[who] = avatar_sha
if ns_muc_user_x:
# Room has been destroyed. see
# http://www.xmpp.org/extensions/xep-0045.html#destroyroom
@ -1708,7 +1703,8 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
statusCode = prs.getStatusCode()
self.dispatch('GC_NOTIFY', (jid_stripped, show, status, resource,
prs.getRole(), prs.getAffiliation(), prs.getJid(),
reason, prs.getActor(), statusCode, prs.getNewNick()))
reason, prs.getActor(), statusCode, prs.getNewNick(),
avatar_sha))
return
if ptype == 'subscribe':

View File

@ -814,8 +814,7 @@ class Interface:
show = 'offline'
gc_c = gajim.contacts.create_gc_contact(room_jid = jid,
name = nick, show = show)
c = gajim.contacts.contact_from_gc_contact(gc_c)
self.roster.new_chat(c, account, private_chat = True)
self.roster.new_private_chat(gc_c, account)
ctrl = self.msg_win_mgr.get_control(full_jid_with_resource, account)
ctrl.print_conversation('Error %s: %s' % (array[1], array[2]),
'status')
@ -1053,7 +1052,7 @@ class Interface:
def handle_event_gc_notify(self, account, array):
#'GC_NOTIFY' (account, (room_jid, show, status, nick,
# role, affiliation, jid, reason, actor, statusCode, newNick))
# role, affiliation, jid, reason, actor, statusCode, newNick, avatar_sha))
nick = array[3]
if not nick:
return
@ -1074,7 +1073,7 @@ class Interface:
return
if control:
control.chg_contact_status(nick, show, status, array[4], array[5],
array[6], array[7], array[8], array[9], array[10])
array[6], array[7], array[8], array[9], array[10], array[11])
if control and not control.parent_win:
gajim.interface.roster.draw_contact(room_jid, account)

View File

@ -97,10 +97,11 @@ def tree_cell_data_func(column, renderer, model, iter, tv=None):
class PrivateChatControl(ChatControl):
TYPE_ID = message_control.TYPE_PM
def __init__(self, parent_win, contact, acct):
def __init__(self, parent_win, gc_contact, contact, acct):
room_jid = contact.jid.split('/')[0]
room_ctrl = gajim.interface.msg_win_mgr.get_control(room_jid, acct)
self.room_name = room_ctrl.name
self.gc_contact = gc_contact
ChatControl.__init__(self, parent_win, contact, acct)
self.TYPE_ID = 'pm'
@ -852,7 +853,7 @@ class GroupchatControl(ChatControlBase):
model[iter][C_AVATAR] = scaled_pixbuf
def chg_contact_status(self, nick, show, status, role, affiliation, jid,
reason, actor, statusCode, new_nick, tim = None):
reason, actor, statusCode, new_nick, avatar_sha, tim = None):
'''When an occupant changes his or her status'''
if show == 'invisible':
return
@ -861,7 +862,7 @@ class GroupchatControl(ChatControlBase):
role = 'visitor'
if not affiliation:
affiliation = 'none'
fake_jid = self.room_jid + '/' + nick
newly_created = False
if show in ('offline', 'error'):
if statusCode == '307':
@ -924,8 +925,7 @@ class GroupchatControl(ChatControlBase):
elif statusCode == 'destroyed': # Room has been destroyed
self.print_conversation(reason, 'info', tim)
if len(gajim.events.get_events(self.account,
self.room_jid + '/' + nick)) == 0:
if len(gajim.events.get_events(self.account, fake_jid)) == 0:
self.remove_contact(nick)
else:
c = gajim.contacts.get_gc_contact(self.account, self.room_jid, nick)
@ -948,20 +948,48 @@ class GroupchatControl(ChatControlBase):
if statusCode == '201': # We just created the room
gajim.connections[self.account].request_gc_config(self.room_jid)
else:
gc_c = gajim.contacts.get_gc_contact(self.account, self.room_jid,
nick)
# Re-get vcard if avatar has changed
# We do that here because we may request it to the real JID if we
# knows it. connections.py doesn't know it.
con = gajim.connections[self.account]
if gc_c.jid:
real_jid = gc_c.jid
if gc_c.resource:
real_jid += '/' + gc_c.resource
else:
real_jid = fake_jid
if con.vcard_shas.has_key(fake_jid):
if avatar_sha != con.vcard_shas[fake_jid]:
con.request_vcard(real_jid, fake_jid)
else:
cached_vcard = con.get_cached_vcard(fake_jid, True)
if cached_vcard and cached_vcard.has_key('PHOTO') and \
cached_vcard['PHOTO'].has_key('SHA'):
cached_sha = cached_vcard['PHOTO']['SHA']
else:
cached_sha = ''
if cached_sha != avatar_sha:
# avatar has been updated
# sha in mem will be updated later
con.request_vcard(real_jid, fake_jid)
else:
# save sha in mem NOW
self.vcard_shas[fake_jid] = avatar_sha
actual_role = self.get_role(nick)
if role != actual_role:
self.remove_contact(nick)
self.add_contact_to_roster(nick, show, role,
affiliation, status, jid)
else:
c = gajim.contacts.get_gc_contact(self.account, self.room_jid,
nick)
if c.show == show and c.status == status and \
c.affiliation == affiliation: #no change
if gc_c.show == show and gc_c.status == status and \
gc_c.affiliation == affiliation: # no change
return
c.show = show
c.affiliation = affiliation
c.status = status
gc_c.show = show
gc_c.affiliation = affiliation
gc_c.status = status
self.draw_contact(nick)
if self.parent_win:
self.parent_win.redraw_tab(self)
@ -1028,21 +1056,16 @@ class GroupchatControl(ChatControlBase):
server = gajim.get_server_from_jid(self.room_jid)
if gajim.config.get('ask_avatars_on_startup') and \
not server.startswith('irc'):
if j:
fjid = j
if resource:
fjid += '/' + resource
else:
fjid = self.room_jid + '/' + nick
if j:
pixbuf = gtkgui_helpers.get_avatar_pixbuf_from_cache(fjid)
else:
pixbuf = gtkgui_helpers.get_avatar_pixbuf_from_cache(fjid, True)
fake_jid = self.room_jid + '/' + nick
pixbuf = gtkgui_helpers.get_avatar_pixbuf_from_cache(fake_jid, True)
if pixbuf == 'ask':
if j:
gajim.connections[self.account].request_vcard(fjid)
fjid = j
if resource:
fjid += '/' + resource
gajim.connections[self.account].request_vcard(fjid, fake_jid)
else:
gajim.connections[self.account].request_vcard(fjid, True)
gajim.connections[self.account].request_vcard(fake_jid, fake_jid)
if nick == self.nick: # we became online
self.got_connected()
self.list_treeview.expand_row((model.get_path(role_iter)), False)
@ -1789,12 +1812,11 @@ class GroupchatControl(ChatControlBase):
def _start_private_message(self, nick):
gc_c = gajim.contacts.get_gc_contact(self.account, self.room_jid, nick)
c = gajim.contacts.contact_from_gc_contact(gc_c)
nick_jid = c.jid
nick_jid = gc_c.get_full_jid()
win = gajim.interface.msg_win_mgr.get_window(nick_jid, self.account)
if not win:
gajim.interface.roster.new_chat(c, self.account, private_chat = True)
gajim.interface.roster.new_private_chat(gc_c, self.account)
win = gajim.interface.msg_win_mgr.get_window(nick_jid, self.account)
win.set_active_tab(nick_jid, self.account)
win.window.present()
@ -2008,9 +2030,6 @@ class GroupchatControl(ChatControlBase):
'''Call vcard_information_window class to display user's information'''
c = gajim.contacts.get_gc_contact(self.account, self.room_jid, nick)
c2 = gajim.contacts.contact_from_gc_contact(c)
if c.jid:
c2.jid = c.jid
c2.resource = c.resource
if gajim.interface.instances[self.account]['infos'].has_key(c2.jid):
gajim.interface.instances[self.account]['infos'][c2.jid].window.\
present()

View File

@ -3464,12 +3464,23 @@ class RosterWindow:
self.actions_menu_needs_rebuild = True
self.update_status_combobox()
def new_chat(self, contact, account, private_chat = False, resource = None):
def new_private_chat(self, gc_contact, account):
contact = gajim.contacts.contact_from_gc_contact(gc_contact)
type_ = message_control.TYPE_PM
fjid = gc_contact.room_jid + '/' + gc_contact.name
mw = gajim.interface.msg_win_mgr.get_window(fjid, account)
if not mw:
mw = gajim.interface.msg_win_mgr.create_window(contact, account, type_)
chat_control = PrivateChatControl(mw, gc_contact, contact, account)
mw.new_tab(chat_control)
if len(gajim.events.get_events(account, fjid)):
# We call this here to avoid race conditions with widget validation
chat_control.read_queue()
def new_chat(self, contact, account, resource = None):
# Get target window, create a control, and associate it with the window
if not private_chat:
type_ = message_control.TYPE_CHAT
else:
type_ = message_control.TYPE_PM
type_ = message_control.TYPE_CHAT
fjid = contact.jid
if resource:
@ -3478,10 +3489,7 @@ class RosterWindow:
if not mw:
mw = gajim.interface.msg_win_mgr.create_window(contact, account, type_)
if not private_chat:
chat_control = ChatControl(mw, contact, account, resource)
else:
chat_control = PrivateChatControl(mw, contact, account)
chat_control = ChatControl(mw, contact, account, resource)
mw.new_tab(chat_control)

View File

@ -453,8 +453,11 @@ class VcardWindow:
self.fill_status_label()
gajim.connections[self.account].request_vcard(self.contact.jid,
(self.gc_contact is not None and not self.gc_contact.jid))
if self.gc_contact:
gajim.connections[self.account].request_vcard(self.contact.jid,
self.gc_contact.get_full_jid())
else:
gajim.connections[self.account].request_vcard(self.contact.jid)
def on_close_button_clicked(self, widget):
self.window.destroy()