summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/default_config.cfg3
-rw-r--r--doc/source/dev/xep.rst6
-rw-r--r--poezio/config.py1
-rw-r--r--poezio/connection.py2
-rw-r--r--poezio/contact.py1
-rw-r--r--poezio/core/core.py5
-rw-r--r--poezio/core/handlers.py37
-rw-r--r--poezio/tabs/rostertab.py20
8 files changed, 68 insertions, 7 deletions
diff --git a/data/default_config.cfg b/data/default_config.cfg
index 96472f49..7efded0b 100644
--- a/data/default_config.cfg
+++ b/data/default_config.cfg
@@ -425,6 +425,9 @@ use_bookmarks_method =
# Ask for message delivery receipts (XEP-0184)
#request_message_receipts = true
+# Display your contacts’ avatar in the roster if true.
+#enable_avatars = true
+
# Extract base64 images received in XHTML-IM messages
# if true.
#extract_inline_images = true
diff --git a/doc/source/dev/xep.rst b/doc/source/dev/xep.rst
index a0a2c558..558602ad 100644
--- a/doc/source/dev/xep.rst
+++ b/doc/source/dev/xep.rst
@@ -23,7 +23,7 @@ Table of all XEPs implemented in poezio.
+----------+-------------------------+---------------------+
|0050 |Ad-Hoc Commands |70% |
+----------+-------------------------+---------------------+
-|0054 |vcard-temp |30% |
+|0054 |vcard-temp |70% |
+----------+-------------------------+---------------------+
|0060 |Publish-Subscribe |10% |
+----------+-------------------------+---------------------+
@@ -33,6 +33,8 @@ Table of all XEPs implemented in poezio.
+----------+-------------------------+---------------------+
|0077 |In-Band Registration |50% |
+----------+-------------------------+---------------------+
+|0084 |User Avatar |50% |
++----------+-------------------------+---------------------+
|0085 |Chat State Notifications |100% |
+----------+-------------------------+---------------------+
|0092 |Software Version |100% |
@@ -45,6 +47,8 @@ Table of all XEPs implemented in poezio.
+----------+-------------------------+---------------------+
|0118 |User Tune |90% |
+----------+-------------------------+---------------------+
+|0153 |vCard-Based Avatars |50% |
++----------+-------------------------+---------------------+
|0163 |Personal Eventing |100% |
| |Protocol | |
+----------+-------------------------+---------------------+
diff --git a/poezio/config.py b/poezio/config.py
index ade9f740..b1d09810 100644
--- a/poezio/config.py
+++ b/poezio/config.py
@@ -50,6 +50,7 @@ DEFAULT_CONFIG = {
'display_mood_notifications': False,
'display_tune_notifications': False,
'display_user_color_in_join_part': True,
+ 'enable_avatars': True,
'enable_carbons': True,
'enable_user_activity': True,
'enable_user_gaming': True,
diff --git a/poezio/connection.py b/poezio/connection.py
index 45667ab7..d00f714f 100644
--- a/poezio/connection.py
+++ b/poezio/connection.py
@@ -106,8 +106,10 @@ class Connection(slixmpp.ClientXMPP):
self.register_plugin('xep_0071')
self.register_plugin('xep_0077')
self.plugin['xep_0077'].create_account = False
+ self.register_plugin('xep_0084')
self.register_plugin('xep_0085')
self.register_plugin('xep_0115')
+ self.register_plugin('xep_0153')
# monkey-patch xep_0184 to avoid requesting receipts for messages
# without a body
diff --git a/poezio/contact.py b/poezio/contact.py
index 6e01e41e..090fed92 100644
--- a/poezio/contact.py
+++ b/poezio/contact.py
@@ -65,6 +65,7 @@ class Contact(object):
self.__item = item
self.folded_states = defaultdict(lambda: True)
self._name = ''
+ self.avatar = None
self.error = None
self.tune = {}
self.gaming = {}
diff --git a/poezio/core/core.py b/poezio/core/core.py
index 410ac83b..7d4e46e5 100644
--- a/poezio/core/core.py
+++ b/poezio/core/core.py
@@ -261,6 +261,11 @@ class Core(object):
connection.MatchAll(None),
self.handler.incoming_stanza)
self.xmpp.register_handler(all_stanzas)
+ if config.get('enable_avatars'):
+ self.xmpp.add_event_handler("vcard_avatar_update",
+ self.handler.on_vcard_avatar)
+ self.xmpp.add_event_handler("avatar_metadata_publish",
+ self.handler.on_0084_avatar)
if config.get('enable_user_tune'):
self.xmpp.add_event_handler("user_tune_publish",
self.handler.on_tune_event)
diff --git a/poezio/core/handlers.py b/poezio/core/handlers.py
index a3d447bd..d8983041 100644
--- a/poezio/core/handlers.py
+++ b/poezio/core/handlers.py
@@ -355,6 +355,43 @@ class HandlerCore:
else:
self.core.refresh_window()
+ @asyncio.coroutine
+ def on_0084_avatar(self, msg):
+ jid = msg['from'].bare
+ contact = roster[jid]
+ if not contact:
+ return
+ log.debug('Received 0084 avatar update from %s', jid)
+ try:
+ metadata = msg['pubsub_event']['items']['item']['avatar_metadata']['items']
+ except Exception:
+ return
+ for info in metadata:
+ if not info['url']:
+ try:
+ result = yield from self.core.xmpp['xep_0084'].retrieve_avatar(jid,
+ info['id'],
+ timeout=10)
+ contact.avatar = result['pubsub']['items']['item']['avatar_data']['value']
+ except Exception:
+ log.exception('Failed retrieving 0084 data from %s:', jid)
+ return
+ log.debug('Received %s avatar: %s', jid, info['type'])
+
+ @asyncio.coroutine
+ def on_vcard_avatar(self, pres):
+ jid = pres['from'].bare
+ log.debug('Received vCard avatar update from %s', jid)
+ try:
+ result = yield from self.core.xmpp['xep_0054'].get_vcard(jid,
+ cached=True,
+ timeout=10)
+ contact.avatar = result['vcard_temp']['PHOTO']
+ except Exception:
+ log.exception('Failed retrieving vCard from %s:', jid)
+ return
+ log.debug('Received %s avatar: %s', jid, avatar['TYPE'])
+
def on_nick_received(self, message):
"""
Called when a pep notification for an user nickname
diff --git a/poezio/tabs/rostertab.py b/poezio/tabs/rostertab.py
index 00992e3c..2aa2fa5a 100644
--- a/poezio/tabs/rostertab.py
+++ b/poezio/tabs/rostertab.py
@@ -44,6 +44,7 @@ class RosterInfoTab(Tab):
self.core.information_buffer.add_window(self.information_win)
self.roster_win = windows.RosterWin()
self.contact_info_win = windows.ContactInfoWin()
+ self.avatar_win = windows.ImageWin()
self.default_help_message = windows.HelpText("Enter commands with “/”. “o”: toggle offline show")
self.input = self.default_help_message
self.state = 'normal'
@@ -513,11 +514,14 @@ class RosterInfoTab(Tab):
info_width, 0, roster_width + 1,
self.core.information_buffer)
if display_contact_win:
+ y = self.height - tab_win_height - contact_win_h - 1
+ avatar_width = contact_win_h * 2
self.contact_info_win.resize(contact_win_h,
- info_width,
- self.height - tab_win_height
- - contact_win_h - 1,
- roster_width + 1)
+ info_width - avatar_width,
+ y, roster_width + 1)
+ self.avatar_win.resize(contact_win_h,
+ avatar_width,
+ y, self.width - avatar_width)
self.roster_win.resize(self.height - 1 - Tab.tab_win_height(),
roster_width, 0, 0)
self.input.resize(1, self.width, self.height-1, 0)
@@ -989,8 +993,12 @@ class RosterInfoTab(Tab):
self.v_separator.refresh()
self.information_win.refresh()
if display_contact_win:
- self.contact_info_win.refresh(
- self.roster_win.get_selected_row())
+ row = self.roster_win.get_selected_row()
+ self.contact_info_win.refresh(row)
+ if isinstance(row, Contact):
+ self.avatar_win.refresh(row.avatar)
+ else:
+ self.avatar_win.refresh(None)
self.refresh_tab_win()
self.input.refresh()