diff --git a/src/common/connection.py b/src/common/connection.py
index c72ef1bcc14fbc19a80d2272c85a7ba35df5c55e..d8877c275e4423a02635a0291bcfd91f2ed9cef5 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 6ff35703269c741404ee11368c6835c69d3e2021..69b54ef1db52861f36c592947e87f8252603b292 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 e7824a348f8cc3d961c930362cf0f27b8d617672..1211ccb0652288668f7cbeab5b7f61b1c160b787 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
-
-				w = gajim.config.get('avatar_width')
-				h = gajim.config.get('avatar_height')
-
-				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']]
-
-				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
+	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
+
+		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)
+
+		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]
+
+		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