diff --git a/src/common/connection.py b/src/common/connection.py index c72ef1bcc..d8877c275 100644 --- a/src/common/connection.py +++ b/src/common/connection.py @@ -1185,14 +1185,14 @@ class Connection: del roster[jid] self.dispatch('ROSTER', roster) - #continue connection + # continue connection if self.connected > 1 and self.continue_connect_info: show = self.continue_connect_info[0] msg = self.continue_connect_info[1] signed = self.continue_connect_info[2] self.connected = STATUS_LIST.index(show) sshow = helpers.get_xmpp_show(show) - #send our presence + # send our presence if show == 'invisible': self.send_invisible_presence(msg, signed, True) return @@ -1208,10 +1208,10 @@ class Connection: if self.connection: self.connection.send(p) self.dispatch('STATUS', show) - #ask our VCard + # ask our VCard self.request_vcard(None) - #Get bookmarks from private namespace + # Get bookmarks from private namespace self.get_bookmarks() self.continue_connect_info = None diff --git a/src/gajim.py b/src/gajim.py index 6ff357032..69b54ef1d 100755 --- a/src/gajim.py +++ b/src/gajim.py @@ -66,11 +66,13 @@ import gtkexcepthook import gobject if sys.version[:4] >= '2.4': gobject.threads_init() + import pango import sre import signal import getopt import time +import base64 from common import socks5 import gtkgui_helpers @@ -621,29 +623,30 @@ class Interface: win = self.windows[account]['infos'][array['jid']] win.set_values(array) - def handle_event_vcard(self, account, array): + def handle_event_vcard(self, account, vcard): + '''vcard holds the vcard data''' + jid = vcard['jid'] + self.store_avatar(vcard) + + # vcard window win = None - if self.windows[account]['infos'].has_key(array['jid']): - win = self.windows[account]['infos'][array['jid']] - elif self.windows[account]['infos'].has_key(array['jid'] + '/' + \ - array['resource']): - win = self.windows[account]['infos'][array['jid'] + '/' + \ - array['resource']] + if self.windows[account]['infos'].has_key(jid): + win = self.windows[account]['infos'][jid] + elif self.windows[account]['infos'].has_key(jid + '/' +vcard['resource']): + win = self.windows[account]['infos'][jid + '/' + vcard['resource']] if win: - win.set_values(array) + win.set_values(vcard) #FIXME: maybe store all vcard data? - #show avatar in chat + # show avatar in chat win = None - if self.windows[account]['chats'].has_key(array['jid']): - win = self.windows[account]['chats'][array['jid']] - elif self.windows[account]['chats'].has_key(array['jid'] + '/' + \ - array['resource']): - win = self.windows[account]['chats'][array['jid'] + '/' + \ - array['resource']] + if self.windows[account]['chats'].has_key(jid): + win = self.windows[account]['chats'][jid] + elif self.windows[account]['chats'].has_key(jid + '/' +vcard['resource']): + win = self.windows[account]['chats'][jid + '/' + vcard['resource']] if win: - win.set_avatar(array) + win.show_avatar(jid) if self.remote is not None: - self.remote.raise_signal('VcardInfo', (account, array)) + self.remote.raise_signal('VcardInfo', (account, vcard)) def handle_event_os_info(self, account, array): win = None @@ -863,6 +866,42 @@ class Interface: def handle_event_vcard_not_published(self, account, array): dialogs.InformationDialog(_('vCard publication failed'), _('There was an error while publishing your personal information, try again later.')) + def store_avatar(self, vcard): + '''stores avatar per jid so we do not have to ask everytime for vcard''' + jid = vcard['jid'] + # we assume contact has no avatar + self.avatar_pixbufs[jid] = None + if not vcard.has_key('PHOTO'): + return + if not isinstance(vcard['PHOTO'], dict): + return + img_decoded = None + if vcard['PHOTO'].has_key('BINVAL'): + try: + img_decoded = base64.decodestring(vcard['PHOTO']['BINVAL']) + except: + pass + elif vcard['PHOTO'].has_key('EXTVAL'): + url = vcard['PHOTO']['EXTVAL'] + try: + fd = urllib.urlopen(url) + img_decoded = fd.read() + except: + pass + if img_decoded: + pixbufloader = gtk.gdk.PixbufLoader() + try: + pixbufloader.write(img_decoded) + pixbuf = pixbufloader.get_pixbuf() + pixbufloader.close() + + # store avatar for jid + self.avatar_pixbufs[jid] = pixbuf + + # we may get "unknown image format" and/or something like pixbuf can be None + except (gobject.GError, AttributeError): + pass + def read_sleepy(self): '''Check idle status and change that status if needed''' if not self.sleeper.poll(): @@ -1121,6 +1160,7 @@ class Interface: 'outmsgcolor': gajim.config.get('outmsgcolor'), 'statusmsgcolor': gajim.config.get('statusmsgcolor'), } + parser.read() # Do not set gajim.verbose to False if -v option was given if gajim.config.get('verbose'): @@ -1172,7 +1212,11 @@ class Interface: gtk.about_dialog_set_email_hook(self.on_launch_browser_mailer, 'mail') gtk.about_dialog_set_url_hook(self.on_launch_browser_mailer, 'url') - self.windows = {'logs':{}} + + self.windows = {'logs': {}} + + # keep avatar (pixbuf) per jid + self.avatar_pixbufs = {} for a in gajim.connections: self.windows[a] = {'infos': {}, 'chats': {}, 'gc': {}, 'gc_config': {}} diff --git a/src/tabbed_chat_window.py b/src/tabbed_chat_window.py index e7824a348..1211ccb06 100644 --- a/src/tabbed_chat_window.py +++ b/src/tabbed_chat_window.py @@ -58,8 +58,9 @@ class TabbedChatWindow(chat.Chat): self.show_bigger_avatar_timeout_id = None self.bigger_avatar_window = None - # keep avatar (pixbuf) per jid. FIXME: move this when we cache avatars - self.avatar_pixbufs = {} + # list that holds all the jid we have asked vcard once + # (so we do not have to ask again) + self.jids_for_which_we_asked_vcard_already = list() self.TARGET_TYPE_URI_LIST = 80 self.dnd_list = [ ( 'text/uri-list', 0, self.TARGET_TYPE_URI_LIST ) ] @@ -221,51 +222,30 @@ timestamp, contact): def get_specific_unread(self, jid): return 0 # FIXME: always zero why?? - def set_avatar(self, vcard): - if not vcard.has_key('PHOTO'): - return - if not isinstance(vcard['PHOTO'], dict): - return - img_decoded = None - if vcard['PHOTO'].has_key('BINVAL'): - try: - img_decoded = base64.decodestring(vcard['PHOTO']['BINVAL']) - except: - pass - elif vcard['PHOTO'].has_key('EXTVAL'): - url = vcard['PHOTO']['EXTVAL'] - try: - fd = urllib.urlopen(url) - img_decoded = fd.read() - except: - pass - if img_decoded: - pixbufloader = gtk.gdk.PixbufLoader() - try: - pixbufloader.write(img_decoded) - pixbuf = pixbufloader.get_pixbuf() - pixbufloader.close() - - jid = vcard['jid'] - self.avatar_pixbufs[jid] = pixbuf + def show_avatar(self, jid): + assert(not self.plugin.avatar_pixbufs.has_key(jid)) + if not self.plugin.avatar_pixbufs.has_key(jid) or\ + self.plugin.avatar_pixbufs[jid] is None: + return # contact does not have avatar stored (can this happen?) or has no avatar - w = gajim.config.get('avatar_width') - h = gajim.config.get('avatar_height') + pixbuf = self.plugin.avatar_pixbufs[jid] + w = gajim.config.get('avatar_width') + h = gajim.config.get('avatar_height') + scaled_buf = pixbuf.scale_simple(w, h, gtk.gdk.INTERP_HYPER) - scaled_buf = pixbuf.scale_simple(w, h, gtk.gdk.INTERP_HYPER) - x = None - if self.xmls.has_key(jid): - x = self.xmls[jid] - # it can be xmls[jid/resource] if it's a vcard from pm - elif self.xmls.has_key(jid + '/' + vcard['resource']): - x = self.xmls[jid + '/' + vcard['resource']] + x = None + if self.xmls.has_key(jid): + x = self.xmls[jid] + else: + # it can be xmls[jid/resource] if it's a vcard from pm + jid_with_resource = jid + '/' + vcard['resource'] + if self.xmls.has_key(jid_with_resource): + x = self.xmls[jid_with_resource] - image = x.get_widget('avatar_image') - image.set_from_pixbuf(scaled_buf) - image.show_all() - # we may get "unknown image format" and/or something like pixbuf can be None - except (gobject.GError, AttributeError): - pass + if x is not None: + image = x.get_widget('avatar_image') + image.set_from_pixbuf(scaled_buf) + image.show_all() def set_state_image(self, jid): prio = 0 @@ -399,6 +379,18 @@ timestamp, contact): self.childs[contact.jid] = self.xmls[contact.jid].get_widget('chats_vbox') self.contacts[contact.jid] = contact + #FIXME: request in thread or idle and show in roster + + # this is to prove cache code works: + # should we ask vcard? (only the first time we should ask) + if not self.plugin.avatar_pixbufs.has_key(contact.jid): + # it's the first time, so we should ask vcard + gajim.connections[self.account].request_vcard(contact.jid) + #please do not remove this commented print until I'm done with showing + #avatars in roster + #print 'REQUESTING VCARD for', contact.jid + else: + self.show_avatar(contact.jid) # show avatar from stored place self.childs[contact.jid].connect('drag_data_received', self.on_drag_data_received, contact) @@ -428,7 +420,6 @@ timestamp, contact): if gajim.awaiting_messages[self.account].has_key(contact.jid): self.read_queue(contact.jid) - gajim.connections[self.account].request_vcard(contact.jid) self.childs[contact.jid].show_all() # chatstates