Refactor VCard code into own modules
This commit is contained in:
		
							parent
							
								
									71a82b5c3e
								
							
						
					
					
						commit
						8b800f4646
					
				
					 14 changed files with 537 additions and 463 deletions
				
			
		|  | @ -397,6 +397,9 @@ def account_is_connected(account): | |||
|     else: | ||||
|         return False | ||||
| 
 | ||||
| def is_invisible(account): | ||||
|     return SHOW_LIST[connections[account].connected] == 'invisible' | ||||
| 
 | ||||
| def account_is_disconnected(account): | ||||
|     return not account_is_connected(account) | ||||
| 
 | ||||
|  |  | |||
|  | @ -71,6 +71,8 @@ from gajim.common.modules.annotations import Annotations | |||
| from gajim.common.modules.roster_item_exchange import RosterItemExchange | ||||
| from gajim.common.modules.last_activity import LastActivity | ||||
| from gajim.common.modules.http_auth import HTTPAuth | ||||
| from gajim.common.modules.vcard_temp import VCardTemp | ||||
| from gajim.common.modules.vcard_avatars import VCardAvatars | ||||
| from gajim.common.connection_handlers import * | ||||
| from gajim.common.contacts import GC_Contact | ||||
| from gajim.gtkgui_helpers import get_action | ||||
|  | @ -666,6 +668,8 @@ class Connection(CommonConnection, ConnectionHandlers): | |||
|         self.register_module('RosterItemExchange', RosterItemExchange, self) | ||||
|         self.register_module('LastActivity', LastActivity, self) | ||||
|         self.register_module('HTTPAuth', HTTPAuth, self) | ||||
|         self.register_module('VCardTemp', VCardTemp, self) | ||||
|         self.register_module('VCardAvatars', VCardAvatars, self) | ||||
| 
 | ||||
|         app.ged.register_event_handler('privacy-list-received', ged.CORE, | ||||
|             self._nec_privacy_list_received) | ||||
|  | @ -756,7 +760,7 @@ class Connection(CommonConnection, ConnectionHandlers): | |||
|         self.connected = 0 | ||||
|         self.time_to_reconnect = None | ||||
|         self.privacy_rules_supported = False | ||||
|         self.avatar_presence_sent = False | ||||
|         self.get_module('VCardAvatars').avatar_advertised = False | ||||
|         if on_purpose: | ||||
|             self.sm = Smacks(self) | ||||
|         if self.connection: | ||||
|  | @ -1768,7 +1772,7 @@ class Connection(CommonConnection, ConnectionHandlers): | |||
|             show='invisible')) | ||||
|         if initial: | ||||
|             # ask our VCard | ||||
|             self.request_vcard(self._on_own_avatar_received) | ||||
|             self.get_module('VCardTemp').request_vcard() | ||||
| 
 | ||||
|             # Get bookmarks from private namespace | ||||
|             self.get_bookmarks() | ||||
|  |  | |||
|  | @ -283,388 +283,6 @@ class ConnectionDisco: | |||
|         app.nec.push_incoming_event(AgentInfoReceivedEvent(None, conn=self, | ||||
|             stanza=iq_obj)) | ||||
| 
 | ||||
| class ConnectionVcard: | ||||
|     def __init__(self): | ||||
|         self.own_vcard = None | ||||
|         self.room_jids = [] | ||||
|         self.avatar_presence_sent = False | ||||
|         self._requested_shas = {} | ||||
| 
 | ||||
|         app.ged.register_event_handler('presence-received', ged.GUI2, | ||||
|                                        self._vcard_presence_received) | ||||
|         app.ged.register_event_handler('gc-presence-received', ged.GUI2, | ||||
|                                        self._vcard_gc_presence_received) | ||||
|         app.ged.register_event_handler('room-avatar-received', ged.GUI2, | ||||
|                                        self._vcard_presence_received) | ||||
| 
 | ||||
|     def _vcard_presence_received(self, obj): | ||||
|         if obj.conn.name != self.name: | ||||
|             return | ||||
| 
 | ||||
|         if obj.avatar_sha is None: | ||||
|             # No Avatar is advertised | ||||
|             return | ||||
| 
 | ||||
|         room_avatar = False | ||||
|         if isinstance(obj, RoomAvatarReceivedEvent): | ||||
|             room_avatar = True | ||||
| 
 | ||||
|         if self.get_own_jid().bareMatch(obj.jid): | ||||
|             app.log('avatar').info('Update (vCard): %s %s', | ||||
|                                    obj.jid, obj.avatar_sha) | ||||
|             current_sha = app.config.get_per( | ||||
|                 'accounts', self.name, 'avatar_sha') | ||||
|             if obj.avatar_sha != current_sha: | ||||
|                 app.log('avatar').info( | ||||
|                     'Request (vCard): %s', obj.jid) | ||||
|                 self.request_vcard(self._on_own_avatar_received) | ||||
|             else: | ||||
|                 app.log('avatar').info( | ||||
|                     'Avatar already known (vCard): %s %s', | ||||
|                     obj.jid, obj.avatar_sha) | ||||
|             return | ||||
| 
 | ||||
|         if obj.avatar_sha == '': | ||||
|             # Empty <photo/> tag, means no avatar is advertised | ||||
|             app.log('avatar').info( | ||||
|                 '%s has no avatar published (vCard)', obj.jid) | ||||
| 
 | ||||
|             # Remove avatar | ||||
|             app.log('avatar').debug('Remove: %s', obj.jid) | ||||
|             app.contacts.set_avatar(self.name, obj.jid, None) | ||||
|             own_jid = self.get_own_jid().getStripped() | ||||
|             if not room_avatar: | ||||
|                 app.logger.set_avatar_sha(own_jid, obj.jid, None) | ||||
|             app.interface.update_avatar( | ||||
|                 self.name, obj.jid, room_avatar=room_avatar) | ||||
|         else: | ||||
|             app.log('avatar').info( | ||||
|                 'Update (vCard): %s %s', obj.jid, obj.avatar_sha) | ||||
|             current_sha = app.contacts.get_avatar_sha(self.name, obj.jid) | ||||
| 
 | ||||
|             if obj.avatar_sha == current_sha: | ||||
|                 app.log('avatar').info( | ||||
|                     'Avatar already known (vCard): %s %s', | ||||
|                     obj.jid, obj.avatar_sha) | ||||
|                 return | ||||
| 
 | ||||
|             if room_avatar: | ||||
|                 # We dont save the room avatar hash in our DB, so check | ||||
|                 # if we previously downloaded it | ||||
|                 if app.interface.avatar_exists(obj.avatar_sha): | ||||
|                     app.contacts.set_avatar(self.name, obj.jid, obj.avatar_sha) | ||||
|                     app.interface.update_avatar( | ||||
|                         self.name, obj.jid, room_avatar=room_avatar) | ||||
|                 elif obj.jid not in self._requested_shas: | ||||
|                     app.log('avatar').info( | ||||
|                         'Request (vCard): %s', obj.jid) | ||||
|                     self._requested_shas[obj.jid] = obj.avatar_sha | ||||
|                     self.request_vcard(self._on_room_avatar_received, obj.jid) | ||||
|                 return | ||||
| 
 | ||||
|             if obj.jid not in self._requested_shas: | ||||
|                 app.log('avatar').info( | ||||
|                     'Request (vCard): %s', obj.jid) | ||||
|                 self._requested_shas[obj.jid] = obj.avatar_sha | ||||
|                 self.request_vcard(self._on_avatar_received, obj.jid) | ||||
| 
 | ||||
| 
 | ||||
|     def _vcard_gc_presence_received(self, obj): | ||||
|         if obj.conn.name != self.name: | ||||
|             return | ||||
| 
 | ||||
|         server = app.get_server_from_jid(obj.room_jid) | ||||
|         if server.startswith('irc') or obj.avatar_sha is None: | ||||
|             return | ||||
| 
 | ||||
|         if obj.show == 'offline': | ||||
|             return | ||||
| 
 | ||||
|         gc_contact = app.contacts.get_gc_contact( | ||||
|             self.name, obj.room_jid, obj.nick) | ||||
| 
 | ||||
|         if gc_contact is None: | ||||
|             app.log('avatar').error('no gc contact found: %s', obj.nick) | ||||
|             return | ||||
| 
 | ||||
|         if obj.avatar_sha == '': | ||||
|             # Empty <photo/> tag, means no avatar is advertised, remove avatar | ||||
|             app.log('avatar').info( | ||||
|                 '%s has no avatar published (vCard)', obj.nick) | ||||
|             app.log('avatar').debug('Remove: %s', obj.nick) | ||||
|             gc_contact.avatar_sha = None | ||||
|             app.interface.update_avatar(contact=gc_contact) | ||||
|         else: | ||||
|             app.log('avatar').info( | ||||
|                 'Update (vCard): %s %s', obj.nick, obj.avatar_sha) | ||||
|             path = os.path.join(configpaths.get('AVATAR'), obj.avatar_sha) | ||||
|             if not os.path.isfile(path): | ||||
|                 if obj.fjid not in self._requested_shas: | ||||
|                     app.log('avatar').info( | ||||
|                         'Request (vCard): %s', obj.nick) | ||||
|                     self._requested_shas[obj.fjid] = obj.avatar_sha | ||||
|                     obj.conn.request_vcard( | ||||
|                         self._on_avatar_received, obj.fjid, room=True) | ||||
|                 return | ||||
| 
 | ||||
|             if gc_contact.avatar_sha != obj.avatar_sha: | ||||
|                 app.log('avatar').info( | ||||
|                     '%s changed his Avatar (vCard): %s', | ||||
|                     obj.nick, obj.avatar_sha) | ||||
|                 gc_contact.avatar_sha = obj.avatar_sha | ||||
|                 app.interface.update_avatar(contact=gc_contact) | ||||
|             else: | ||||
|                 app.log('avatar').info( | ||||
|                     'Avatar already known (vCard): %s', obj.nick) | ||||
| 
 | ||||
|     def send_avatar_presence(self): | ||||
|         show = helpers.get_xmpp_show(app.SHOW_LIST[self.connected]) | ||||
|         p = nbxmpp.Presence(typ=None, priority=self.priority, | ||||
|                             show=show, status=self.status) | ||||
|         p = self.add_sha(p) | ||||
|         self.connection.send(p) | ||||
|         app.interface.update_avatar(self.name, self.get_own_jid().getStripped()) | ||||
| 
 | ||||
|     def _node_to_dict(self, node): | ||||
|         dict_ = {} | ||||
|         for info in node.getChildren(): | ||||
|             name = info.getName() | ||||
|             if name in ('ADR', 'TEL', 'EMAIL'): # we can have several | ||||
|                 dict_.setdefault(name, []) | ||||
|                 entry = {} | ||||
|                 for c in info.getChildren(): | ||||
|                     entry[c.getName()] = c.getData() | ||||
|                 dict_[name].append(entry) | ||||
|             elif info.getChildren() == []: | ||||
|                 dict_[name] = info.getData() | ||||
|             else: | ||||
|                 dict_[name] = {} | ||||
|                 for c in info.getChildren(): | ||||
|                     dict_[name][c.getName()] = c.getData() | ||||
|         return dict_ | ||||
| 
 | ||||
|     def request_vcard(self, callback, jid=None, room=False): | ||||
|         """ | ||||
|         Request the VCARD | ||||
|         """ | ||||
|         if not self.connection or self.connected < 2: | ||||
|             return | ||||
| 
 | ||||
|         if room: | ||||
|             room_jid = app.get_room_from_fjid(jid) | ||||
|             if room_jid not in self.room_jids: | ||||
|                 self.room_jids.append(room_jid) | ||||
| 
 | ||||
|         iq = nbxmpp.Iq(typ='get') | ||||
|         if jid: | ||||
|             iq.setTo(jid) | ||||
|         iq.setQuery('vCard').setNamespace(nbxmpp.NS_VCARD) | ||||
| 
 | ||||
|         self.connection.SendAndCallForResponse( | ||||
|             iq, self._parse_vcard, {'callback': callback}) | ||||
| 
 | ||||
|     def send_vcard(self, vcard, sha): | ||||
|         if not self.connection or self.connected < 2: | ||||
|             return | ||||
|         iq = nbxmpp.Iq(typ='set') | ||||
|         iq2 = iq.setTag(nbxmpp.NS_VCARD + ' vCard') | ||||
|         for i in vcard: | ||||
|             if i == 'jid': | ||||
|                 continue | ||||
|             if isinstance(vcard[i], dict): | ||||
|                 iq3 = iq2.addChild(i) | ||||
|                 for j in vcard[i]: | ||||
|                     iq3.addChild(j).setData(vcard[i][j]) | ||||
|             elif isinstance(vcard[i], list): | ||||
|                 for j in vcard[i]: | ||||
|                     iq3 = iq2.addChild(i) | ||||
|                     for k in j: | ||||
|                         iq3.addChild(k).setData(j[k]) | ||||
|             else: | ||||
|                 iq2.addChild(i).setData(vcard[i]) | ||||
| 
 | ||||
|         self.connection.SendAndCallForResponse( | ||||
|             iq, self._avatar_publish_result, {'sha': sha}) | ||||
| 
 | ||||
|     def upload_room_avatar(self, room_jid, data): | ||||
|         iq = nbxmpp.Iq(typ='set', to=room_jid) | ||||
|         vcard = iq.addChild('vCard', namespace=nbxmpp.NS_VCARD) | ||||
|         photo = vcard.addChild('PHOTO') | ||||
|         photo.addChild('TYPE', payload='image/png') | ||||
|         photo.addChild('BINVAL', payload=data) | ||||
| 
 | ||||
|         self.connection.SendAndCallForResponse( | ||||
|             iq, self._upload_room_avatar_result) | ||||
| 
 | ||||
|     def _upload_room_avatar_result(self, stanza): | ||||
|         if not nbxmpp.isResultNode(stanza): | ||||
|             reason = stanza.getErrorMsg() or stanza.getError() | ||||
|             app.nec.push_incoming_event(InformationEvent( | ||||
|                 None, dialog_name='avatar-upload-error', args=reason)) | ||||
| 
 | ||||
|     def _avatar_publish_result(self, con, stanza, sha): | ||||
|         if stanza.getType() == 'result': | ||||
|             current_sha = app.config.get_per( | ||||
|                 'accounts', self.name, 'avatar_sha') | ||||
|             if (current_sha != sha and | ||||
|                     app.SHOW_LIST[self.connected] != 'invisible'): | ||||
|                 if not self.connection or self.connected < 2: | ||||
|                     return | ||||
|                 app.config.set_per( | ||||
|                     'accounts', self.name, 'avatar_sha', sha or '') | ||||
|                 own_jid = self.get_own_jid().getStripped() | ||||
|                 app.contacts.set_avatar(self.name, own_jid, sha) | ||||
|                 self.send_avatar_presence() | ||||
|             app.log('avatar').info('%s: Published: %s', self.name, sha) | ||||
|             app.nec.push_incoming_event( | ||||
|                 VcardPublishedEvent(None, conn=self)) | ||||
| 
 | ||||
|         elif stanza.getType() == 'error': | ||||
|             app.nec.push_incoming_event( | ||||
|                 VcardNotPublishedEvent(None, conn=self)) | ||||
| 
 | ||||
|     def _get_vcard_photo(self, vcard, jid): | ||||
|         try: | ||||
|             photo = vcard['PHOTO']['BINVAL'] | ||||
|         except (KeyError, AttributeError, TypeError): | ||||
|             avatar_sha = None | ||||
|             photo_decoded = None | ||||
|         else: | ||||
|             if photo == '': | ||||
|                 avatar_sha = None | ||||
|                 photo_decoded = None | ||||
|             else: | ||||
|                 try: | ||||
|                     photo_decoded = base64.b64decode(photo.encode('utf-8')) | ||||
|                 except binascii.Error as error: | ||||
|                     app.log('avatar').warning('Invalid avatar for %s: %s', | ||||
|                                               jid, error) | ||||
|                     return None, None | ||||
|                 avatar_sha = hashlib.sha1(photo_decoded).hexdigest() | ||||
| 
 | ||||
|         return avatar_sha, photo_decoded | ||||
| 
 | ||||
|     def _parse_vcard(self, con, stanza, callback): | ||||
|         frm_jid = stanza.getFrom() | ||||
|         room = False | ||||
|         if frm_jid is None: | ||||
|             frm_jid = self.get_own_jid() | ||||
|         elif frm_jid.getStripped() in self.room_jids: | ||||
|             room = True | ||||
| 
 | ||||
|         resource = frm_jid.getResource() | ||||
|         jid = frm_jid.getStripped() | ||||
| 
 | ||||
|         stanza_error = stanza.getError() | ||||
|         if stanza_error in ('service-unavailable', 'item-not-found', | ||||
|                             'not-allowed'): | ||||
|             app.log('avatar').info('vCard not available: %s %s', | ||||
|                                    frm_jid, stanza_error) | ||||
|             callback(jid, resource, room, {}) | ||||
|             return | ||||
| 
 | ||||
|         vcard_node = stanza.getTag('vCard', namespace=nbxmpp.NS_VCARD) | ||||
|         if vcard_node is None: | ||||
|             app.log('avatar').info('vCard not available: %s', frm_jid) | ||||
|             app.log('avatar').debug(stanza) | ||||
|             return | ||||
|         vcard = self._node_to_dict(vcard_node) | ||||
| 
 | ||||
|         if self.get_own_jid().bareMatch(jid): | ||||
|             if 'NICKNAME' in vcard: | ||||
|                 app.nicks[self.name] = vcard['NICKNAME'] | ||||
|             elif 'FN' in vcard: | ||||
|                 app.nicks[self.name] = vcard['FN'] | ||||
| 
 | ||||
|         app.nec.push_incoming_event( | ||||
|             VcardReceivedEvent(None, conn=self, vcard_dict=vcard)) | ||||
| 
 | ||||
|         callback(jid, resource, room, vcard) | ||||
| 
 | ||||
|     def _on_own_avatar_received(self, jid, resource, room, vcard): | ||||
| 
 | ||||
|         avatar_sha, photo_decoded = self._get_vcard_photo(vcard, jid) | ||||
| 
 | ||||
|         app.log('avatar').info( | ||||
|             'Received own (vCard): %s', avatar_sha) | ||||
| 
 | ||||
|         self.own_vcard = vcard | ||||
|         if avatar_sha is None: | ||||
|             app.log('avatar').info('No avatar found (vCard)') | ||||
|             app.config.set_per('accounts', self.name, 'avatar_sha', '') | ||||
|             self.send_avatar_presence() | ||||
|             return | ||||
| 
 | ||||
|         current_sha = app.config.get_per('accounts', self.name, 'avatar_sha') | ||||
|         if current_sha == avatar_sha: | ||||
|             path = os.path.join(configpaths.get('AVATAR'), current_sha) | ||||
|             if not os.path.isfile(path): | ||||
|                 app.log('avatar').info( | ||||
|                     'Caching (vCard): %s', current_sha) | ||||
|                 app.interface.save_avatar(photo_decoded) | ||||
|             if self.avatar_presence_sent: | ||||
|                 app.log('avatar').debug('Avatar already advertised') | ||||
|                 return | ||||
|         else: | ||||
|             app.interface.save_avatar(photo_decoded) | ||||
| 
 | ||||
|         app.config.set_per('accounts', self.name, 'avatar_sha', avatar_sha) | ||||
|         if app.SHOW_LIST[self.connected] == 'invisible': | ||||
|             app.log('avatar').info( | ||||
|                 'We are invisible, not publishing avatar') | ||||
|             return | ||||
| 
 | ||||
|         self.send_avatar_presence() | ||||
|         self.avatar_presence_sent = True | ||||
| 
 | ||||
|     def _on_room_avatar_received(self, jid, resource, room, vcard): | ||||
|         avatar_sha, photo_decoded = self._get_vcard_photo(vcard, jid) | ||||
|         expected_avatar_sha = self._requested_shas[jid] | ||||
|         if expected_avatar_sha != avatar_sha: | ||||
|             app.log('avatar').warning( | ||||
|                 'Avatar mismatch (vCard): %s %s', jid, avatar_sha) | ||||
|             return | ||||
| 
 | ||||
|         app.interface.save_avatar(photo_decoded) | ||||
|         self._requested_shas.pop(jid) | ||||
| 
 | ||||
|         app.log('avatar').info('Received (vCard): %s %s', jid, avatar_sha) | ||||
|         app.contacts.set_avatar(self.name, jid, avatar_sha) | ||||
|         app.interface.update_avatar(self.name, jid, room_avatar=True) | ||||
| 
 | ||||
|     def _on_avatar_received(self, jid, resource, room, vcard): | ||||
|         """ | ||||
|         Called when we receive a vCard Parse the vCard and trigger Events | ||||
|         """ | ||||
|         request_jid = jid | ||||
|         if room: | ||||
|             request_jid = '%s/%s' % (jid, resource) | ||||
| 
 | ||||
|         avatar_sha, photo_decoded = self._get_vcard_photo(vcard, request_jid) | ||||
|         expected_avatar_sha = self._requested_shas[request_jid] | ||||
|         if expected_avatar_sha != avatar_sha: | ||||
|             app.log('avatar').warning( | ||||
|                 'Avatar mismatch (vCard): %s %s', request_jid, avatar_sha) | ||||
|             return | ||||
| 
 | ||||
|         app.interface.save_avatar(photo_decoded) | ||||
|         self._requested_shas.pop(request_jid) | ||||
| 
 | ||||
|         # Received vCard from a contact | ||||
|         if room: | ||||
|             app.log('avatar').info( | ||||
|                 'Received (vCard): %s %s', resource, avatar_sha) | ||||
|             contact = app.contacts.get_gc_contact(self.name, jid, resource) | ||||
|             if contact is not None: | ||||
|                 contact.avatar_sha = avatar_sha | ||||
|                 app.interface.update_avatar(contact=contact) | ||||
|         else: | ||||
|             app.log('avatar').info('Received (vCard): %s %s', jid, avatar_sha) | ||||
|             own_jid = self.get_own_jid().getStripped() | ||||
|             app.logger.set_avatar_sha(own_jid, jid, avatar_sha) | ||||
|             app.contacts.set_avatar(self.name, jid, avatar_sha) | ||||
|             app.interface.update_avatar(self.name, jid) | ||||
| 
 | ||||
| 
 | ||||
| class ConnectionPEP(object): | ||||
| 
 | ||||
|  | @ -1296,13 +914,12 @@ class ConnectionHandlersBase: | |||
|         return sess | ||||
| 
 | ||||
| class ConnectionHandlers(ConnectionArchive313, | ||||
| ConnectionVcard, ConnectionSocks5Bytestream, ConnectionDisco, | ||||
| ConnectionSocks5Bytestream, ConnectionDisco, | ||||
| ConnectionCommands, ConnectionPubSub, ConnectionPEP, ConnectionCaps, | ||||
| ConnectionHandlersBase, ConnectionJingle, ConnectionIBBytestream, | ||||
| ConnectionHTTPUpload): | ||||
|     def __init__(self): | ||||
|         ConnectionArchive313.__init__(self) | ||||
|         ConnectionVcard.__init__(self) | ||||
|         ConnectionSocks5Bytestream.__init__(self) | ||||
|         ConnectionIBBytestream.__init__(self) | ||||
|         ConnectionCommands.__init__(self) | ||||
|  | @ -1398,11 +1015,7 @@ ConnectionHTTPUpload): | |||
|         app.ged.remove_event_handler('blocking', ged.CORE, self._nec_blocking) | ||||
| 
 | ||||
|     def add_sha(self, p, send_caps=True): | ||||
|         c = p.setTag('x', namespace=nbxmpp.NS_VCARD_UPDATE) | ||||
|         sha = app.config.get_per('accounts', self.name, 'avatar_sha') | ||||
|         app.log('avatar').info( | ||||
|             '%s: Send avatar presence: %s', self.name, sha or 'empty') | ||||
|         c.setTagData('photo', sha) | ||||
|         p = self.get_module('VCardAvatars').add_update_node(p) | ||||
|         if send_caps: | ||||
|             return self._add_caps(p) | ||||
|         return p | ||||
|  | @ -1925,7 +1538,7 @@ ConnectionHTTPUpload): | |||
|             show=show)) | ||||
|         if self.vcard_supported: | ||||
|             # ask our VCard | ||||
|             self.request_vcard(self._on_own_avatar_received) | ||||
|             self.get_module('VCardTemp').request_vcard() | ||||
| 
 | ||||
|         # Get bookmarks from private namespace | ||||
|         self.get_bookmarks() | ||||
|  |  | |||
|  | @ -550,16 +550,6 @@ PresenceHelperEvent): | |||
|             tim = helpers.datetime_tuple(time_str) | ||||
|             self.idle_time = timegm(tim) | ||||
| 
 | ||||
|         # Check if presence is from the room itself, used when the room | ||||
|         # sends a avatar hash | ||||
|         contact = app.contacts.get_groupchat_contact(self.conn.name, self.fjid) | ||||
|         if contact: | ||||
|             app.nec.push_incoming_event( | ||||
|                 RoomAvatarReceivedEvent( | ||||
|                     None, conn=self.conn, stanza=self.stanza, | ||||
|                     contact=contact, jid=self.jid)) | ||||
|             return | ||||
| 
 | ||||
|         xtags = self.stanza.getTags('x') | ||||
|         for x in xtags: | ||||
|             namespace = x.getNamespace() | ||||
|  | @ -567,9 +557,6 @@ PresenceHelperEvent): | |||
|                 self.is_gc = True | ||||
|             elif namespace == nbxmpp.NS_SIGNED: | ||||
|                 sig_tag = x | ||||
|             elif namespace == nbxmpp.NS_VCARD_UPDATE: | ||||
|                 self.avatar_sha = x.getTagData('photo') | ||||
|                 self.contact_nickname = x.getTagData('nickname') | ||||
|             elif namespace == nbxmpp.NS_DELAY and not self.timestamp: | ||||
|                 # XEP-0091 | ||||
|                 self._generate_timestamp(self.stanza.timestamp) | ||||
|  | @ -1770,14 +1757,6 @@ class ConnectionTypeEvent(nec.NetworkIncomingEvent): | |||
|     name = 'connection-type' | ||||
|     base_network_events = [] | ||||
| 
 | ||||
| class VcardPublishedEvent(nec.NetworkIncomingEvent): | ||||
|     name = 'vcard-published' | ||||
|     base_network_events = [] | ||||
| 
 | ||||
| class VcardNotPublishedEvent(nec.NetworkIncomingEvent): | ||||
|     name = 'vcard-not-published' | ||||
|     base_network_events = [] | ||||
| 
 | ||||
| class StanzaReceivedEvent(nec.NetworkIncomingEvent): | ||||
|     name = 'stanza-received' | ||||
|     base_network_events = [] | ||||
|  | @ -1967,13 +1946,6 @@ class NonAnonymousServerErrorEvent(nec.NetworkIncomingEvent): | |||
|     name = 'non-anonymous-server-error' | ||||
|     base_network_events = [] | ||||
| 
 | ||||
| class VcardReceivedEvent(nec.NetworkIncomingEvent): | ||||
|     name = 'vcard-received' | ||||
|     base_network_events = [] | ||||
| 
 | ||||
|     def generate(self): | ||||
|         return True | ||||
| 
 | ||||
| class UpdateGCAvatarEvent(nec.NetworkIncomingEvent): | ||||
|     name = 'update-gc-avatar' | ||||
|     base_network_events = [] | ||||
|  | @ -1995,19 +1967,6 @@ class UpdateRoomAvatarEvent(nec.NetworkIncomingEvent): | |||
|     def generate(self): | ||||
|         return True | ||||
| 
 | ||||
| class RoomAvatarReceivedEvent(nec.NetworkIncomingEvent): | ||||
|     name = 'room-avatar-received' | ||||
|     base_network_events = [] | ||||
| 
 | ||||
|     def generate(self): | ||||
|         vcard = self.stanza.getTag('x', namespace=nbxmpp.NS_VCARD_UPDATE) | ||||
|         if vcard is None: | ||||
|             app.log('avatar').info( | ||||
|                 '%s has no avatar published (vCard)', self.jid) | ||||
|             return | ||||
|         self.avatar_sha = vcard.getTagData('photo') | ||||
|         return True | ||||
| 
 | ||||
| class PEPConfigReceivedEvent(nec.NetworkIncomingEvent): | ||||
|     name = 'pep-config-received' | ||||
|     base_network_events = [] | ||||
|  |  | |||
|  | @ -113,6 +113,12 @@ class IdleState(IntEnum): | |||
|     AWAY = 2 | ||||
|     AWAKE = 3 | ||||
| 
 | ||||
| @unique | ||||
| class RequestAvatar(IntEnum): | ||||
|     SELF = 0 | ||||
|     ROOM = 1 | ||||
|     USER = 2 | ||||
| 
 | ||||
| SSLError = { | ||||
|     2: _("Unable to get issuer certificate"), | ||||
|     3: _("Unable to get certificate CRL"), | ||||
|  |  | |||
|  | @ -1398,15 +1398,7 @@ def get_subscription_request_msg(account=None): | |||
|     s = _('I would like to add you to my contact list.') | ||||
|     if account: | ||||
|         s = _('Hello, I am $name.') + ' ' + s | ||||
|         our_jid = app.get_jid_from_account(account) | ||||
|         vcard = app.connections[account].own_vcard | ||||
|         name = '' | ||||
|         if vcard: | ||||
|             if 'N' in vcard: | ||||
|                 if 'GIVEN' in vcard['N'] and 'FAMILY' in vcard['N']: | ||||
|                     name = vcard['N']['GIVEN'] + ' ' + vcard['N']['FAMILY'] | ||||
|             if not name and 'FN' in vcard: | ||||
|                 name = vcard['FN'] | ||||
|         name = app.connections[account].get_module('VCardTemp').get_vard_name() | ||||
|         nick = app.nicks[account] | ||||
|         if name and nick: | ||||
|             name += ' (%s)' % nick | ||||
|  |  | |||
							
								
								
									
										192
									
								
								gajim/common/modules/vcard_avatars.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								gajim/common/modules/vcard_avatars.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,192 @@ | |||
| # This file is part of Gajim. | ||||
| # | ||||
| # Gajim is free software; you can redistribute it and/or modify | ||||
| # it under the terms of the GNU General Public License as published | ||||
| # by the Free Software Foundation; version 3 only. | ||||
| # | ||||
| # Gajim is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| # GNU General Public License for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with Gajim.  If not, see <http://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| # XEP-0153: vCard-Based Avatars | ||||
| 
 | ||||
| import os | ||||
| import logging | ||||
| 
 | ||||
| import nbxmpp | ||||
| 
 | ||||
| from gajim.common import app | ||||
| from gajim.common import helpers | ||||
| from gajim.common import configpaths | ||||
| from gajim.common.const import RequestAvatar | ||||
| 
 | ||||
| log = logging.getLogger('gajim.c.m.vcard.avatars') | ||||
| 
 | ||||
| 
 | ||||
| class VCardAvatars: | ||||
|     def __init__(self, con): | ||||
|         self._con = con | ||||
|         self._account = con.name | ||||
|         self._requested_shas = [] | ||||
| 
 | ||||
|         self.handlers = [ | ||||
|             ('presence', self._presence_received, '', nbxmpp.NS_VCARD_UPDATE), | ||||
|         ] | ||||
| 
 | ||||
|         self.avatar_advertised = False | ||||
| 
 | ||||
|     def _presence_received(self, con, stanza): | ||||
|         update = stanza.getTag('x', namespace=nbxmpp.NS_VCARD_UPDATE) | ||||
|         if update is None: | ||||
|             return | ||||
| 
 | ||||
|         jid = stanza.getFrom() | ||||
| 
 | ||||
|         avatar_sha = update.getTagData('photo') | ||||
|         if avatar_sha is None: | ||||
|             log.info('%s is not ready to promote an avatar', jid) | ||||
|             # Empty update element, ignore | ||||
|             return | ||||
| 
 | ||||
|         if self._con.get_own_jid().bareMatch(jid): | ||||
|             if self._con.get_own_jid() == jid: | ||||
|                 # Reflection of our own presence | ||||
|                 return | ||||
|             self._self_update_received(jid, avatar_sha) | ||||
|             return | ||||
| 
 | ||||
|         # Check if presence is from a MUC service | ||||
|         contact = app.contacts.get_groupchat_contact(self._account, str(jid)) | ||||
|         if contact is not None: | ||||
|             self._update_received(jid, avatar_sha) | ||||
|         elif stanza.getTag('x', namespace=nbxmpp.NS_MUC_USER): | ||||
|             show = stanza.getShow() | ||||
|             type_ = stanza.getType() | ||||
|             self._gc_update_received(jid, avatar_sha, show, type_) | ||||
|         else: | ||||
|             self._update_received(jid, avatar_sha) | ||||
| 
 | ||||
|     def _self_update_received(self, jid, avatar_sha): | ||||
|         jid = jid.getStripped() | ||||
|         full_jid = jid | ||||
|         if avatar_sha == '': | ||||
|             # Empty <photo/> tag, means no avatar is advertised | ||||
|             log.info('%s has no avatar published', full_jid) | ||||
|             return | ||||
| 
 | ||||
|         log.info('Update: %s %s', jid, avatar_sha) | ||||
|         current_sha = app.config.get_per( | ||||
|             'accounts', self._account, 'avatar_sha') | ||||
| 
 | ||||
|         if avatar_sha != current_sha: | ||||
|             log.info('Request : %s', jid) | ||||
|             self._con.get_module('VCardTemp').request_vcard(RequestAvatar.SELF) | ||||
|         else: | ||||
|             log.info('Avatar already known: %s %s', | ||||
|                      jid, avatar_sha) | ||||
| 
 | ||||
|     def _update_received(self, jid, avatar_sha, room=False): | ||||
|         jid = jid.getStripped() | ||||
|         full_jid = jid | ||||
|         if avatar_sha == '': | ||||
|             # Empty <photo/> tag, means no avatar is advertised | ||||
|             log.info('%s has no avatar published', full_jid) | ||||
| 
 | ||||
|             # Remove avatar | ||||
|             log.debug('Remove: %s', jid) | ||||
|             app.contacts.set_avatar(self._account, jid, None) | ||||
|             acc_jid = self._con.get_own_jid().getStripped() | ||||
|             if not room: | ||||
|                 app.logger.set_avatar_sha(acc_jid, jid, None) | ||||
|             app.interface.update_avatar( | ||||
|                 self._account, jid, room_avatar=room) | ||||
|         else: | ||||
|             log.info('Update: %s %s', full_jid, avatar_sha) | ||||
|             current_sha = app.contacts.get_avatar_sha(self._account, jid) | ||||
| 
 | ||||
|             if avatar_sha == current_sha: | ||||
|                 log.info('Avatar already known: %s %s', jid, avatar_sha) | ||||
|                 return | ||||
| 
 | ||||
|             if room: | ||||
|                 # We dont save the room avatar hash in our DB, so check | ||||
|                 # if we previously downloaded it | ||||
|                 if app.interface.avatar_exists(avatar_sha): | ||||
|                     app.contacts.set_avatar(self._account, jid, avatar_sha) | ||||
|                     app.interface.update_avatar( | ||||
|                         self._account, jid, room_avatar=room) | ||||
|                 return | ||||
| 
 | ||||
|             if avatar_sha not in self._requested_shas: | ||||
|                 self._requested_shas.append(avatar_sha) | ||||
|                 if room: | ||||
|                     self._con.get_module('VCardTemp').request_vcard( | ||||
|                         RequestAvatar.ROOM, jid, sha=avatar_sha) | ||||
|                 else: | ||||
|                     self._con.get_module('VCardTemp').request_vcard( | ||||
|                         RequestAvatar.USER, jid, sha=avatar_sha) | ||||
| 
 | ||||
|     def _gc_update_received(self, jid, avatar_sha, show, type_): | ||||
|         if show == 'offline' or type_ == 'unavailable': | ||||
|             return | ||||
| 
 | ||||
|         nick = jid.getResource() | ||||
| 
 | ||||
|         gc_contact = app.contacts.get_gc_contact( | ||||
|             self._account, jid.getStripped(), nick) | ||||
| 
 | ||||
|         if gc_contact is None: | ||||
|             log.error('no gc contact found: %s', nick) | ||||
|             return | ||||
| 
 | ||||
|         if avatar_sha == '': | ||||
|             # Empty <photo/> tag, means no avatar is advertised, remove avatar | ||||
|             log.info('%s has no avatar published', nick) | ||||
|             log.debug('Remove: %s', nick) | ||||
|             gc_contact.avatar_sha = None | ||||
|             app.interface.update_avatar(contact=gc_contact) | ||||
|         else: | ||||
|             log.info('Update: %s %s', nick, avatar_sha) | ||||
|             path = os.path.join(configpaths.get('AVATAR'), avatar_sha) | ||||
|             if not os.path.isfile(path): | ||||
|                 if avatar_sha not in self._requested_shas: | ||||
|                     app.log('avatar').info('Request: %s', nick) | ||||
|                     self._requested_shas.append(avatar_sha) | ||||
|                     self._con.get_module('VCardTemp').request_vcard( | ||||
|                         RequestAvatar.USER, str(jid), | ||||
|                         room=True, sha=avatar_sha) | ||||
|                 return | ||||
| 
 | ||||
|             if gc_contact.avatar_sha != avatar_sha: | ||||
|                 log.info('%s changed his Avatar: %s', nick, avatar_sha) | ||||
|                 gc_contact.avatar_sha = avatar_sha | ||||
|                 app.interface.update_avatar(contact=gc_contact) | ||||
|             else: | ||||
|                 log.info('Avatar already known: %s', nick) | ||||
| 
 | ||||
|     def send_avatar_presence(self, force=False): | ||||
|         if self.avatar_advertised and not force: | ||||
|             log.debug('Avatar already advertised') | ||||
|             return | ||||
|         show = helpers.get_xmpp_show(app.SHOW_LIST[self._con.connected]) | ||||
|         pres = nbxmpp.Presence(typ=None, priority=self._con.priority, | ||||
|                                show=show, status=self._con.status) | ||||
|         pres = self._con.add_sha(pres) | ||||
|         self._con.connection.send(pres) | ||||
|         self.avatar_advertised = True | ||||
|         app.interface.update_avatar(self._account, | ||||
|                                     self._con.get_own_jid().getStripped()) | ||||
| 
 | ||||
|     def add_update_node(self, node): | ||||
|         update = node.setTag('x', namespace=nbxmpp.NS_VCARD_UPDATE) | ||||
|         if self._con.get_module('VCardTemp').own_vcard_received: | ||||
|             sha = app.config.get_per('accounts', self._account, 'avatar_sha') | ||||
|             own_jid = self._con.get_own_jid() | ||||
|             log.info('Send avatar presence to: %s %s', | ||||
|                      node.getTo() or own_jid, sha or 'no sha advertised') | ||||
|             update.setTagData('photo', sha) | ||||
|         return node | ||||
							
								
								
									
										308
									
								
								gajim/common/modules/vcard_temp.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										308
									
								
								gajim/common/modules/vcard_temp.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,308 @@ | |||
| # This file is part of Gajim. | ||||
| # | ||||
| # Gajim is free software; you can redistribute it and/or modify | ||||
| # it under the terms of the GNU General Public License as published | ||||
| # by the Free Software Foundation; version 3 only. | ||||
| # | ||||
| # Gajim is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| # GNU General Public License for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with Gajim.  If not, see <http://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| # XEP-0054: vcard-temp | ||||
| 
 | ||||
| import os | ||||
| import hashlib | ||||
| import binascii | ||||
| import base64 | ||||
| import logging | ||||
| 
 | ||||
| import nbxmpp | ||||
| 
 | ||||
| from gajim.common import app | ||||
| from gajim.common import configpaths | ||||
| from gajim.common.const import RequestAvatar | ||||
| from gajim.common.nec import NetworkIncomingEvent | ||||
| from gajim.common.connection_handlers_events import InformationEvent | ||||
| 
 | ||||
| log = logging.getLogger('gajim.c.m.vcard') | ||||
| 
 | ||||
| 
 | ||||
| class VCardTemp: | ||||
|     def __init__(self, con): | ||||
|         self._con = con | ||||
|         self._account = con.name | ||||
| 
 | ||||
|         self.handlers = [] | ||||
| 
 | ||||
|         self._own_vcard = None | ||||
|         self.own_vcard_received = False | ||||
|         self.room_jids = [] | ||||
| 
 | ||||
|     def _node_to_dict(self, node): | ||||
|         dict_ = {} | ||||
|         for info in node.getChildren(): | ||||
|             name = info.getName() | ||||
|             if name in ('ADR', 'TEL', 'EMAIL'):  # we can have several | ||||
|                 dict_.setdefault(name, []) | ||||
|                 entry = {} | ||||
|                 for c in info.getChildren(): | ||||
|                     entry[c.getName()] = c.getData() | ||||
|                 dict_[name].append(entry) | ||||
|             elif info.getChildren() == []: | ||||
|                 dict_[name] = info.getData() | ||||
|             else: | ||||
|                 dict_[name] = {} | ||||
|                 for c in info.getChildren(): | ||||
|                     dict_[name][c.getName()] = c.getData() | ||||
|         return dict_ | ||||
| 
 | ||||
|     def request_vcard(self, callback=RequestAvatar.SELF, jid=None, | ||||
|                       room=False, sha=None): | ||||
|         if not app.account_is_connected(self._account): | ||||
|             return | ||||
| 
 | ||||
|         if isinstance(callback, RequestAvatar): | ||||
|             if callback == RequestAvatar.SELF: | ||||
|                 callback = self._on_own_avatar_received | ||||
|             elif callback == RequestAvatar.ROOM: | ||||
|                 callback = self._on_room_avatar_received | ||||
|             elif callback == RequestAvatar.USER: | ||||
|                 callback = self._on_avatar_received | ||||
| 
 | ||||
|         if room: | ||||
|             room_jid = app.get_room_from_fjid(jid) | ||||
|             if room_jid not in self.room_jids: | ||||
|                 self.room_jids.append(room_jid) | ||||
| 
 | ||||
|         iq = nbxmpp.Iq(typ='get') | ||||
|         if jid: | ||||
|             iq.setTo(jid) | ||||
|         iq.setQuery('vCard').setNamespace(nbxmpp.NS_VCARD) | ||||
| 
 | ||||
|         own_jid = self._con.get_own_jid().getStripped() | ||||
|         log.info('Request: %s, expected sha: %s', jid or own_jid, sha) | ||||
| 
 | ||||
|         self._con.connection.SendAndCallForResponse( | ||||
|             iq, self._parse_vcard, {'callback': callback, 'expected_sha': sha}) | ||||
| 
 | ||||
|     def send_vcard(self, vcard, sha): | ||||
|         if not app.account_is_connected(self._account): | ||||
|             return | ||||
| 
 | ||||
|         iq = nbxmpp.Iq(typ='set') | ||||
|         iq2 = iq.setTag(nbxmpp.NS_VCARD + ' vCard') | ||||
|         for i in vcard: | ||||
|             if i == 'jid': | ||||
|                 continue | ||||
|             if isinstance(vcard[i], dict): | ||||
|                 iq3 = iq2.addChild(i) | ||||
|                 for j in vcard[i]: | ||||
|                     iq3.addChild(j).setData(vcard[i][j]) | ||||
|             elif isinstance(vcard[i], list): | ||||
|                 for j in vcard[i]: | ||||
|                     iq3 = iq2.addChild(i) | ||||
|                     for k in j: | ||||
|                         iq3.addChild(k).setData(j[k]) | ||||
|             else: | ||||
|                 iq2.addChild(i).setData(vcard[i]) | ||||
| 
 | ||||
|         log.info('Upload avatar: %s %s', self._account, sha) | ||||
| 
 | ||||
|         self._con.connection.SendAndCallForResponse( | ||||
|             iq, self._avatar_publish_result, {'sha': sha}) | ||||
| 
 | ||||
|     def upload_room_avatar(self, room_jid, data): | ||||
|         iq = nbxmpp.Iq(typ='set', to=room_jid) | ||||
|         vcard = iq.addChild('vCard', namespace=nbxmpp.NS_VCARD) | ||||
|         photo = vcard.addChild('PHOTO') | ||||
|         photo.addChild('TYPE', payload='image/png') | ||||
|         photo.addChild('BINVAL', payload=data) | ||||
| 
 | ||||
|         log.info('Upload avatar: %s %s', room_jid) | ||||
|         self._con.connection.SendAndCallForResponse( | ||||
|             iq, self._upload_room_avatar_result) | ||||
| 
 | ||||
|     def _upload_room_avatar_result(self, stanza): | ||||
|         if not nbxmpp.isResultNode(stanza): | ||||
|             reason = stanza.getErrorMsg() or stanza.getError() | ||||
|             app.nec.push_incoming_event(InformationEvent( | ||||
|                 None, dialog_name='avatar-upload-error', args=reason)) | ||||
| 
 | ||||
|     def _avatar_publish_result(self, con, stanza, sha): | ||||
|         if stanza.getType() == 'result': | ||||
|             current_sha = app.config.get_per( | ||||
|                 'accounts', self._account, 'avatar_sha') | ||||
|             if (current_sha != sha and not app.is_invisible(self._account)): | ||||
|                 if not app.account_is_connected(self._account): | ||||
|                     return | ||||
|                 app.config.set_per( | ||||
|                     'accounts', self._account, 'avatar_sha', sha or '') | ||||
|                 own_jid = self._con.get_own_jid().getStripped() | ||||
|                 app.contacts.set_avatar(self._account, own_jid, sha) | ||||
|                 self._con.get_module('VCardAvatars').send_avatar_presence( | ||||
|                     force=True) | ||||
|             log.info('%s: Published: %s', self._account, sha) | ||||
|             app.nec.push_incoming_event( | ||||
|                 VcardPublishedEvent(None, conn=self._con)) | ||||
| 
 | ||||
|         elif stanza.getType() == 'error': | ||||
|             app.nec.push_incoming_event( | ||||
|                 VcardNotPublishedEvent(None, conn=self._con)) | ||||
| 
 | ||||
|     def _get_vcard_photo(self, vcard, jid): | ||||
|         try: | ||||
|             photo = vcard['PHOTO']['BINVAL'] | ||||
|         except (KeyError, AttributeError, TypeError): | ||||
|             avatar_sha = None | ||||
|             photo_decoded = None | ||||
|         else: | ||||
|             if photo == '': | ||||
|                 avatar_sha = None | ||||
|                 photo_decoded = None | ||||
|             else: | ||||
|                 try: | ||||
|                     photo_decoded = base64.b64decode(photo.encode('utf-8')) | ||||
|                 except binascii.Error as error: | ||||
|                     log.warning('Invalid avatar for %s: %s', jid, error) | ||||
|                     return None, None | ||||
|                 avatar_sha = hashlib.sha1(photo_decoded).hexdigest() | ||||
| 
 | ||||
|         return avatar_sha, photo_decoded | ||||
| 
 | ||||
|     def _parse_vcard(self, con, stanza, callback, expected_sha): | ||||
|         frm_jid = stanza.getFrom() | ||||
|         room = False | ||||
|         if frm_jid is None: | ||||
|             frm_jid = self._con.get_own_jid() | ||||
|         elif frm_jid.getStripped() in self.room_jids: | ||||
|             room = True | ||||
| 
 | ||||
|         resource = frm_jid.getResource() | ||||
|         jid = frm_jid.getStripped() | ||||
| 
 | ||||
|         stanza_error = stanza.getError() | ||||
|         if stanza_error in ('service-unavailable', 'item-not-found', | ||||
|                             'not-allowed'): | ||||
|             log.info('vCard not available: %s %s', frm_jid, stanza_error) | ||||
|             callback(jid, resource, room, {}, expected_sha) | ||||
|             return | ||||
| 
 | ||||
|         vcard_node = stanza.getTag('vCard', namespace=nbxmpp.NS_VCARD) | ||||
|         if vcard_node is None: | ||||
|             log.info('vCard not available: %s', frm_jid) | ||||
|             log.debug(stanza) | ||||
|             return | ||||
|         vcard = self._node_to_dict(vcard_node) | ||||
| 
 | ||||
|         if self._con.get_own_jid().bareMatch(jid): | ||||
|             if 'NICKNAME' in vcard: | ||||
|                 app.nicks[self._account] = vcard['NICKNAME'] | ||||
|             elif 'FN' in vcard: | ||||
|                 app.nicks[self._account] = vcard['FN'] | ||||
| 
 | ||||
|         app.nec.push_incoming_event( | ||||
|             VcardReceivedEvent(None, conn=self._con, vcard_dict=vcard)) | ||||
| 
 | ||||
|         callback(jid, resource, room, vcard, expected_sha) | ||||
| 
 | ||||
|     def _on_own_avatar_received(self, jid, resource, room, vcard, *args): | ||||
|         avatar_sha, photo_decoded = self._get_vcard_photo(vcard, jid) | ||||
| 
 | ||||
|         log.info('Received own vcard, avatar sha is: %s', avatar_sha) | ||||
| 
 | ||||
|         self._own_vcard = vcard | ||||
|         self.own_vcard_received = True | ||||
|         if avatar_sha is None: | ||||
|             log.info('No avatar found') | ||||
|             app.config.set_per('accounts', self._account, 'avatar_sha', '') | ||||
|             self._con.get_module('VCardAvatars').send_avatar_presence(force=True) | ||||
|             return | ||||
| 
 | ||||
|         current_sha = app.config.get_per('accounts', self._account, 'avatar_sha') | ||||
|         if current_sha == avatar_sha: | ||||
|             path = os.path.join(configpaths.get('AVATAR'), current_sha) | ||||
|             if not os.path.isfile(path): | ||||
|                 log.info('Caching: %s', current_sha) | ||||
|                 app.interface.save_avatar(photo_decoded) | ||||
|             self._con.get_module('VCardAvatars').send_avatar_presence() | ||||
|         else: | ||||
|             app.interface.save_avatar(photo_decoded) | ||||
| 
 | ||||
|         app.config.set_per('accounts', self._account, 'avatar_sha', avatar_sha) | ||||
|         if app.is_invisible(self._account): | ||||
|             log.info('We are invisible, not advertising avatar') | ||||
|             return | ||||
| 
 | ||||
|         self._con.get_module('VCardAvatars').send_avatar_presence(force=True) | ||||
| 
 | ||||
|     def _on_room_avatar_received(self, jid, resource, room, vcard, | ||||
|                                  expected_sha): | ||||
|         avatar_sha, photo_decoded = self._get_vcard_photo(vcard, jid) | ||||
|         if expected_sha != avatar_sha: | ||||
|             log.warning('Avatar mismatch: %s %s', jid, avatar_sha) | ||||
|             return | ||||
| 
 | ||||
|         app.interface.save_avatar(photo_decoded) | ||||
| 
 | ||||
|         log.info('Received: %s %s', jid, avatar_sha) | ||||
|         app.contacts.set_avatar(self._account, jid, avatar_sha) | ||||
|         app.interface.update_avatar(self._account, jid, room_avatar=True) | ||||
| 
 | ||||
|     def _on_avatar_received(self, jid, resource, room, vcard, expected_sha): | ||||
|         request_jid = jid | ||||
|         if room: | ||||
|             request_jid = '%s/%s' % (jid, resource) | ||||
| 
 | ||||
|         avatar_sha, photo_decoded = self._get_vcard_photo(vcard, request_jid) | ||||
|         if expected_sha != avatar_sha: | ||||
|             log.warning('Received: avatar mismatch: %s %s', | ||||
|                         request_jid, avatar_sha) | ||||
|             return | ||||
| 
 | ||||
|         app.interface.save_avatar(photo_decoded) | ||||
| 
 | ||||
|         # Received vCard from a contact | ||||
|         if room: | ||||
|             log.info('Received: %s %s', resource, avatar_sha) | ||||
|             contact = app.contacts.get_gc_contact(self._account, jid, resource) | ||||
|             if contact is not None: | ||||
|                 contact.avatar_sha = avatar_sha | ||||
|                 app.interface.update_avatar(contact=contact) | ||||
|         else: | ||||
|             log.info('Received: %s %s', jid, avatar_sha) | ||||
|             own_jid = self._con.get_own_jid().getStripped() | ||||
|             app.logger.set_avatar_sha(own_jid, jid, avatar_sha) | ||||
|             app.contacts.set_avatar(self._account, jid, avatar_sha) | ||||
|             app.interface.update_avatar(self._account, jid) | ||||
| 
 | ||||
|     def get_vard_name(self): | ||||
|         name = '' | ||||
|         vcard = self._own_vcard | ||||
|         if not vcard: | ||||
|             return name | ||||
| 
 | ||||
|         if 'N' in vcard: | ||||
|             if 'GIVEN' in vcard['N'] and 'FAMILY' in vcard['N']: | ||||
|                 name = vcard['N']['GIVEN'] + ' ' + vcard['N']['FAMILY'] | ||||
|         if not name and 'FN' in vcard: | ||||
|             name = vcard['FN'] | ||||
|         return name | ||||
| 
 | ||||
| 
 | ||||
| class VcardPublishedEvent(NetworkIncomingEvent): | ||||
|     name = 'vcard-published' | ||||
|     base_network_events = [] | ||||
| 
 | ||||
| 
 | ||||
| class VcardNotPublishedEvent(NetworkIncomingEvent): | ||||
|     name = 'vcard-not-published' | ||||
|     base_network_events = [] | ||||
| 
 | ||||
| 
 | ||||
| class VcardReceivedEvent(NetworkIncomingEvent): | ||||
|     name = 'vcard-received' | ||||
|     base_network_events = [] | ||||
|  | @ -40,19 +40,13 @@ AGENT_REMOVED = 'agent_removed' | |||
| 
 | ||||
| from gajim.common import connection_handlers | ||||
| 
 | ||||
| class ConnectionVcard(connection_handlers.ConnectionVcard): | ||||
| class ConnectionVcard: | ||||
|     def add_sha(self, p, *args): | ||||
|         return p | ||||
| 
 | ||||
|     def add_caps(self, p): | ||||
|         return p | ||||
| 
 | ||||
|     def request_vcard(self, *args): | ||||
|         pass | ||||
| 
 | ||||
|     def send_vcard(self, *args): | ||||
|         pass | ||||
| 
 | ||||
| 
 | ||||
| class ConnectionHandlersZeroconf(ConnectionVcard, | ||||
| ConnectionSocks5BytestreamZeroconf, ConnectionCommands, | ||||
|  |  | |||
|  | @ -762,8 +762,8 @@ class GroupchatControl(ChatControlBase): | |||
| 
 | ||||
|             publish = app.interface.get_avatar(sha, publish=True) | ||||
|             avatar = base64.b64encode(publish).decode('utf-8') | ||||
| 
 | ||||
|             app.connections[self.account].upload_room_avatar( | ||||
|             con = app.connections[self.account] | ||||
|             con.get_module('VCardTemp').upload_room_avatar( | ||||
|                 self.room_jid, avatar) | ||||
| 
 | ||||
|         AvatarChooserDialog(_on_accept, | ||||
|  |  | |||
|  | @ -77,7 +77,7 @@ class ProfileWindow: | |||
|             self._nec_vcard_not_published) | ||||
|         self.window.show_all() | ||||
|         self.xml.get_object('ok_button').grab_focus() | ||||
|         app.connections[account].request_vcard( | ||||
|         app.connections[account].get_module('VCardTemp').request_vcard( | ||||
|             self._nec_vcard_received, self.jid) | ||||
| 
 | ||||
|     def on_information_notebook_switch_page(self, widget, page, page_num): | ||||
|  | @ -261,7 +261,7 @@ class ProfileWindow: | |||
|             self.progressbar.set_fraction(0) | ||||
|             self.update_progressbar_timeout_id = None | ||||
| 
 | ||||
|     def _nec_vcard_received(self, jid, resource, room, vcard_): | ||||
|     def _nec_vcard_received(self, jid, resource, room, vcard_, *args): | ||||
|         self.set_values(vcard_) | ||||
| 
 | ||||
|     def add_to_vcard(self, vcard_, entry, txt): | ||||
|  | @ -339,7 +339,8 @@ class ProfileWindow: | |||
|             app.connections[self.account].retract_nickname() | ||||
|             nick = app.config.get_per('accounts', self.account, 'name') | ||||
|         app.nicks[self.account] = nick | ||||
|         app.connections[self.account].send_vcard(vcard_, sha) | ||||
|         app.connections[self.account].get_module('VCardTemp').send_vcard( | ||||
|             vcard_, sha) | ||||
|         self.message_id = self.statusbar.push(self.context_id, | ||||
|                 _('Sending profile…')) | ||||
|         self.progressbar.show() | ||||
|  |  | |||
|  | @ -840,10 +840,12 @@ class SignalObject(dbus.service.Object): | |||
|             if avatar_mime_type: | ||||
|                 vcard['PHOTO']['TYPE'] = avatar_mime_type | ||||
|             if account: | ||||
|                 app.connections[account].send_vcard(vcard, sha) | ||||
|                 app.connections[account].get_module('VCardTemp').send_vcard( | ||||
|                     vcard, sha) | ||||
|             else: | ||||
|                 for acc in app.connections: | ||||
|                     app.connections[acc].send_vcard(vcard, sha) | ||||
|                     app.connections[acc].get_module('VCardTemp').send_vcard( | ||||
|                         vcard, sha) | ||||
| 
 | ||||
|     @dbus.service.method(INTERFACE, in_signature='ssss', out_signature='') | ||||
|     def join_room(self, room_jid, nick, password, account): | ||||
|  |  | |||
|  | @ -268,7 +268,7 @@ class VcardWindow: | |||
|                 widget.set_text('') | ||||
|         self.xml.get_object('DESC_textview').get_buffer().set_text('') | ||||
| 
 | ||||
|     def _nec_vcard_received(self, jid, resource, room, vcard): | ||||
|     def _nec_vcard_received(self, jid, resource, room, vcard, *args): | ||||
|         self.clear_values() | ||||
|         self._set_values(vcard, jid) | ||||
| 
 | ||||
|  | @ -477,10 +477,13 @@ class VcardWindow: | |||
|         self.fill_status_label() | ||||
| 
 | ||||
|         if self.gc_contact: | ||||
|             con.request_vcard(self._nec_vcard_received, | ||||
|                               self.gc_contact.get_full_jid(), room=True) | ||||
|             con.get_module('VCardTemp').request_vcard( | ||||
|                 self._nec_vcard_received, | ||||
|                 self.gc_contact.get_full_jid(), | ||||
|                 room=True) | ||||
|         else: | ||||
|             con.request_vcard(self._nec_vcard_received, self.contact.jid) | ||||
|             con.get_module('VCardTemp').request_vcard( | ||||
|                 self._nec_vcard_received, self.contact.jid) | ||||
| 
 | ||||
|     def on_close_button_clicked(self, widget): | ||||
|         self.window.destroy() | ||||
|  |  | |||
|  | @ -47,9 +47,6 @@ class MockConnection(Mock, ConnectionHandlers): | |||
| 
 | ||||
|         app.connections[account] = self | ||||
| 
 | ||||
|     def request_vcard(self, *args): | ||||
|         pass | ||||
| 
 | ||||
| class MockWindow(Mock): | ||||
|     def __init__(self, *args): | ||||
|         Mock.__init__(self, *args) | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue