diff options
author | Louis-Francis Ratté-Boulianne <louis-francis.ratte-boulianne@collabora.co.uk> | 2010-11-09 14:34:38 -0500 |
---|---|---|
committer | Louis-Francis Ratté-Boulianne <louis-francis.ratte-boulianne@collabora.co.uk> | 2010-12-03 15:50:39 -0500 |
commit | b57867b794a7e7a8ae6671bac5e1d76303b82ba8 (patch) | |
tree | c16172e745509f83d438bda23d8472c88a48e0e4 | |
parent | d5f8ed4a22ab5e25ab408e59d770b4872ab9e9c4 (diff) |
bugfix: correctly normalize and ensure handles
We use new methods of tp-python to ensure a handle exists (it's created if needed). That means only the connection keeps a set of all the handles and there is no more dict persistent between connections.
We make sure the handle name is normalized. This is particularly critical for contact handles because the account name might not always be in the same case.
-rw-r--r-- | butterfly/aliasing.py | 17 | ||||
-rw-r--r-- | butterfly/avatars.py | 16 | ||||
-rw-r--r-- | butterfly/capabilities.py | 29 | ||||
-rw-r--r-- | butterfly/channel/__init__.py | 4 | ||||
-rw-r--r-- | butterfly/channel/conference.py | 6 | ||||
-rw-r--r-- | butterfly/channel/contact_list.py | 19 | ||||
-rw-r--r-- | butterfly/channel/file_transfer.py | 1 | ||||
-rw-r--r-- | butterfly/channel/group.py | 7 | ||||
-rw-r--r-- | butterfly/channel/im.py | 10 | ||||
-rw-r--r-- | butterfly/channel/media.py | 11 | ||||
-rw-r--r-- | butterfly/channel/muc.py | 14 | ||||
-rw-r--r-- | butterfly/channel/text.py | 24 | ||||
-rw-r--r-- | butterfly/connection.py | 101 | ||||
-rw-r--r-- | butterfly/handle.py | 81 | ||||
-rw-r--r-- | butterfly/presence.py | 16 |
15 files changed, 141 insertions, 215 deletions
diff --git a/butterfly/aliasing.py b/butterfly/aliasing.py index 8b73416..19c6d1e 100644 --- a/butterfly/aliasing.py +++ b/butterfly/aliasing.py @@ -25,7 +25,6 @@ import papyon from papyon.service.description.AB.constants import \ ContactGeneral, ContactAnnotations -from butterfly.handle import ButterflyHandleFactory from butterfly.util.decorator import async __all__ = ['ButterflyAliasing'] @@ -60,7 +59,7 @@ class ButterflyAliasing( def SetAliases(self, aliases): for handle_id, alias in aliases.iteritems(): handle = self.handle(telepathy.HANDLE_TYPE_CONTACT, handle_id) - if handle != ButterflyHandleFactory(self, 'self'): + if handle != self._self_handle: if alias == handle.name: alias = u"" contact = handle.contact @@ -82,7 +81,7 @@ class ButterflyAliasing( else: self.msn_client.profile.display_name = alias.encode('utf-8') logger.info("Self alias changed to '%s'" % alias) - self.AliasesChanged(((ButterflyHandleFactory(self, 'self'), alias), )) + self.AliasesChanged(((self._self_handle, alias), )) # papyon.event.ContactEventInterface def on_contact_display_name_changed(self, contact): @@ -98,8 +97,7 @@ class ButterflyAliasing( # papyon.event.ContactEventInterface def on_contact_memberships_changed(self, contact): - handle = ButterflyHandleFactory(self, 'contact', - contact.account, contact.network_id) + handle = self.ensure_contact_handle(contact) if contact.is_member(papyon.Membership.FORWARD): alias = handle.pending_alias if alias is not None: @@ -117,7 +115,7 @@ class ButterflyAliasing( def _get_alias(self, handle_id): """Get the alias from one handle id""" handle = self.handle(telepathy.HANDLE_TYPE_CONTACT, handle_id) - if handle == ButterflyHandleFactory(self, 'self'): + if handle == self._self_handle: display_name = self.msn_client.profile.display_name if display_name == "": display_name = handle.get_name().split('@', 1)[0] @@ -141,13 +139,10 @@ class ButterflyAliasing( def _contact_alias_changed(self, contact): alias = None - if contact.account != self.msn_client.profile.account: - handle = ButterflyHandleFactory(self, 'contact', - contact.account, contact.network_id) + handle = self.ensure_contact_handle(contact) + if handle != self._self_handle: alias = contact.infos.get(ContactGeneral.ANNOTATIONS, {}).\ get(ContactAnnotations.NICKNAME, None) - else: - handle = ButterflyHandleFactory(self, 'self') if alias == "" or alias is None: alias = contact.display_name diff --git a/butterfly/avatars.py b/butterfly/avatars.py index 14b6be0..596b54f 100644 --- a/butterfly/avatars.py +++ b/butterfly/avatars.py @@ -26,7 +26,6 @@ import papyon import papyon.event import papyon.util.string_io as StringIO -from butterfly.handle import ButterflyHandleFactory from butterfly.util.decorator import async __all__ = ['ButterflyAvatars'] @@ -74,10 +73,7 @@ class ButterflyAvatars(\ result = {} for handle_id in contacts: handle = self.handle(telepathy.HANDLE_TYPE_CONTACT, handle_id) - if handle == self.GetSelfHandle(): - contact = handle.profile - else: - contact = handle.contact + contact = handle.contact if contact is not None: msn_object = contact.msn_object @@ -93,7 +89,7 @@ class ButterflyAvatars(\ def RequestAvatars(self, contacts): for handle_id in contacts: handle = self.handle(telepathy.HANDLE_TYPE_CONTACT, handle_id) - if handle == self.GetSelfHandle(): + if handle == self._self_handle: contact = self.msn_client.profile else: contact = handle.contact @@ -127,11 +123,7 @@ class ButterflyAvatars(\ avatar_token = contact.msn_object._data_sha.encode("hex") else: avatar_token = "" - if contact is self.msn_client.profile: - handle = ButterflyHandleFactory(self, 'self') - else: - handle = ButterflyHandleFactory(self, 'contact', - contact.account, contact.network_id) + handle = self.ensure_contact_handle(contact) self.AvatarUpdated(handle, avatar_token) # papyon.event.ProfileEventInterface @@ -140,7 +132,7 @@ class ButterflyAvatars(\ if msn_object is not None: avatar_token = msn_object._data_sha.encode("hex") logger.info("Self avatar changed to %s" % avatar_token) - handle = ButterflyHandleFactory(self, 'self') + handle = self._self_handle self.AvatarUpdated(handle, avatar_token) @async diff --git a/butterfly/capabilities.py b/butterfly/capabilities.py index 5b7a4d9..7177861 100644 --- a/butterfly/capabilities.py +++ b/butterfly/capabilities.py @@ -27,7 +27,6 @@ from telepathy._generated.Connection_Interface_Contact_Capabilities \ import ConnectionInterfaceContactCapabilities from butterfly.util.decorator import async -from butterfly.handle import ButterflyHandleFactory __all__ = ['ButterflyCapabilities'] @@ -92,11 +91,11 @@ class ButterflyCapabilities( for caps, specs in add: if caps == telepathy.CHANNEL_TYPE_STREAMED_MEDIA: if specs & telepathy.CHANNEL_MEDIA_CAPABILITY_VIDEO: - self._self_handle.profile.client_id.has_webcam = True - self._self_handle.profile.client_id.supports_rtc_video = True + self._msn_client.profile.client_id.has_webcam = True + self._msn_client.profile.client_id.supports_rtc_video = True for caps in remove: if caps == telepathy.CHANNEL_TYPE_STREAMED_MEDIA: - self._self_handle.profile.client_id.has_webcam = False + self._msn_client.profile.client_id.has_webcam = False return telepathy.server.ConnectionInterfaceCapabilities.\ AdvertiseCapabilities(self, add, remove) @@ -144,14 +143,14 @@ class ButterflyCapabilities( # We've got no more clients that support video; remove the cap. if not video and not self._video_clients: - self._self_handle.profile.client_id.has_webcam = False + self._msn_client.profile.client_id.has_webcam = False changed = True # We want video. - if video and (not self._self_handle.profile.client_id.has_webcam or - not self._self_handle.profile.client_id.supports_rtc_video): - self._self_handle.profile.client_id.has_webcam = True - self._self_handle.profile.client_id.supports_rtc_video = True + if video and (not self._msn_client.profile.client_id.has_webcam or + not self._msn_client.profile.client_id.supports_rtc_video): + self._msn_client.profile.client_id.has_webcam = True + self._msn_client.profile.client_id.supports_rtc_video = True changed = True # Signal. @@ -169,9 +168,9 @@ class ButterflyCapabilities( """When we add a contact in our contact list, add the default capabilities to the contact""" if contact.is_member(papyon.Membership.FORWARD): - handle = ButterflyHandleFactory(self, 'contact', - contact.account, contact.network_id) - self.add_default_capabilities([handle]) + handle = self.ensure_contact_handle(contact) + self._add_default_capabilities([handle]) + def _diff_capabilities(self, handle, ctype, new_gen=None, new_spec=None, added_gen=None, added_spec=None): @@ -222,8 +221,7 @@ class ButterflyCapabilities( self.ContactCapabilitiesChanged(cc_ret) def _update_capabilities(self, contact): - handle = ButterflyHandleFactory(self, 'contact', - contact.account, contact.network_id) + handle = self.ensure_contact_handle(contact) ctype = telepathy.CHANNEL_TYPE_STREAMED_MEDIA new_gen, new_spec, rcc = self._get_capabilities(contact) @@ -279,8 +277,7 @@ class ButterflyCapabilities( handles = set([self._self_handle]) for contact in self.msn_client.address_book.contacts: if contact.is_member(papyon.Membership.FORWARD): - handle = ButterflyHandleFactory(self, 'contact', - contact.account, contact.network_id) + handle = self.ensure_contact_handle(contact) handles.add(handle) self._add_default_capabilities(handles) diff --git a/butterfly/channel/__init__.py b/butterfly/channel/__init__.py index bccedc6..a2ddbc5 100644 --- a/butterfly/channel/__init__.py +++ b/butterfly/channel/__init__.py @@ -36,8 +36,8 @@ class ButterflyChannel(object): # otherwise use InitiatorID. elif telepathy.CHANNEL_INTERFACE + '.InitiatorID' in props: - self._initiator = ButterflyHandleFactory(conn, 'contact', - id=props[telepathy.CHANNEL_INTERFACE + '.InitiatorID']) + self._initiator = conn.ensure_handle(telepathy.HANDLE_TYPE_CONTACT, + props[telepathy.CHANNEL_INTERFACE + '.InitiatorID']) # If we don't have either of the above but we requested the channel, # then we're the initiator. diff --git a/butterfly/channel/conference.py b/butterfly/channel/conference.py index ed974a1..c7e0454 100644 --- a/butterfly/channel/conference.py +++ b/butterfly/channel/conference.py @@ -137,11 +137,7 @@ class ButterflyConferenceChannel( # Get InitialInviteeIDs for invitee_id in props.get(CHANNEL_INTERFACE_CONFERENCE + '.InitialInviteeIDs', []): - handle = None - for h in self._conn_ref()._handles.itervalues(): - if h.get_name() == invitee_id: - handle = h - break + handle = self._conn_ref().ensure_handle(telepathy.HANDLE_TYPE_CONTACT, invitee_id) if handle is None or handle.contact is None: raise telepathy.NotAvailable('Contact "%s" not available' % invitee_id) diff --git a/butterfly/channel/contact_list.py b/butterfly/channel/contact_list.py index c2f1de3..b7e2689 100644 --- a/butterfly/channel/contact_list.py +++ b/butterfly/channel/contact_list.py @@ -24,7 +24,6 @@ import papyon import papyon.event from butterfly.util.decorator import async -from butterfly.handle import ButterflyHandleFactory from butterfly.channel import ButterflyChannel __all__ = ['ButterflyContactListChannelFactory'] @@ -142,8 +141,7 @@ class ButterflyListChannel( ad, lp, rp = self._filter_contact(contact) if ad or lp or rp: - handle = ButterflyHandleFactory(self._conn_ref(), 'contact', - contact.account, contact.network_id) + handle = self._conn.ensure_contact_handle(contact) if ad: added.add(handle) if lp: local_pending.add(handle) if rp: remote_pending.add(handle) @@ -153,8 +151,7 @@ class ButterflyListChannel( # papyon.event.AddressBookEventInterface def on_addressbook_contact_deleted(self, contact): - handle = ButterflyHandleFactory(self._conn_ref(), 'contact', - contact.account, contact.network_id) + handle = self._conn.ensure_contact_handle(contact) ad, lp, rp = self._filter_contact(contact) if self._contains_handle(handle) and not ad: self.MembersChanged('', (), [handle], (), (), 0, @@ -177,8 +174,7 @@ class ButterflyListChannel( for contact in connection.msn_client.address_book.contacts: ad, lp, rp = self._filter_contact(contact) if ad or lp or rp: - handle = ButterflyHandleFactory(self._conn_ref(), 'contact', - contact.account, contact.network_id) + handle = self._conn.ensure_contact_handle(contact) if ad: added.add(handle) if lp: local_pending.add(handle) if rp: remote_pending.add(handle) @@ -299,8 +295,7 @@ class ButterflySubscribeListChannel(ButterflyListChannel, # papyon.event.ContactEventInterface def on_contact_memberships_changed(self, contact): - handle = ButterflyHandleFactory(self._conn_ref(), 'contact', - contact.account, contact.network_id) + handle = self._conn.ensure_contact_handle(contact) if contact.is_member(papyon.Membership.FORWARD): self.MembersChanged('', [handle], (), (), (), 0, telepathy.CHANNEL_GROUP_CHANGE_REASON_INVITED) @@ -334,8 +329,7 @@ class ButterflyPublishListChannel(ButterflyListChannel, for contact in self._conn.msn_client.address_book.contacts: if not contact.is_member(papyon.Membership.PENDING): continue - handle = ButterflyHandleFactory(self._conn_ref(), 'contact', - contact.account, contact.network_id) + handle = self._conn.ensure_contact_handle(contact) result.append((handle, handle, telepathy.CHANNEL_GROUP_CHANGE_REASON_INVITED, contact.attributes.get('invite_message', ''))) @@ -385,8 +379,7 @@ class ButterflyPublishListChannel(ButterflyListChannel, # papyon.event.ContactEventInterface def on_contact_memberships_changed(self, contact): - handle = ButterflyHandleFactory(self._conn_ref(), 'contact', - contact.account, contact.network_id) + handle = self._conn.ensure_contact_handle(contact) if self._contains_handle(handle): if contact.is_member(papyon.Membership.PENDING): # Nothing worth our attention diff --git a/butterfly/channel/file_transfer.py b/butterfly/channel/file_transfer.py index 96c56bf..3062953 100644 --- a/butterfly/channel/file_transfer.py +++ b/butterfly/channel/file_transfer.py @@ -31,7 +31,6 @@ import papyon.event import socket from butterfly.util.decorator import async -from butterfly.handle import ButterflyHandleFactory from telepathy.interfaces import CHANNEL_TYPE_FILE_TRANSFER diff --git a/butterfly/channel/group.py b/butterfly/channel/group.py index a9f2f51..848c099 100644 --- a/butterfly/channel/group.py +++ b/butterfly/channel/group.py @@ -24,7 +24,6 @@ import papyon import papyon.event from butterfly.util.decorator import async -from butterfly.handle import ButterflyHandleFactory from butterfly.channel.contact_list import ButterflyListChannel __all__ = ['ButterflyGroupChannel'] @@ -132,8 +131,7 @@ class ButterflyGroupChannel(ButterflyListChannel, def on_addressbook_group_contact_added(self, group, contact): group_name = group.name.decode("utf-8") if group_name == self._handle.name: - handle = ButterflyHandleFactory(self._conn_ref(), 'contact', - contact.account, contact.network_id) + handle = self._conn.ensure_contact_handle(contact) added = set() added.add(handle) @@ -147,8 +145,7 @@ class ButterflyGroupChannel(ButterflyListChannel, def on_addressbook_group_contact_deleted(self, group, contact): group_name = group.name.decode("utf-8") if group_name == self._handle.name: - handle = ButterflyHandleFactory(self._conn_ref(), 'contact', - contact.account, contact.network_id) + handle = self._conn.ensure_contact_handle(contact) removed = set() removed.add(handle) diff --git a/butterfly/channel/im.py b/butterfly/channel/im.py index 696d99d..1781234 100644 --- a/butterfly/channel/im.py +++ b/butterfly/channel/im.py @@ -28,7 +28,6 @@ import telepathy import papyon import papyon.event -from butterfly.handle import ButterflyHandleFactory from butterfly.channel.text import ButterflyTextChannel from butterfly.Channel_Interface_Conference import CHANNEL_INTERFACE_CONFERENCE @@ -136,8 +135,7 @@ class ButterflyImChannel(ButterflyTextChannel): # papyon.event.ConversationEventInterface def on_conversation_user_joined(self, contact): - handle = ButterflyHandleFactory(self._conn_ref(), 'contact', - contact.account, contact.network_id) + handle = self._conn.ensure_contact_handle(contact) logger.info("User %s joined" % unicode(handle)) if self._initial_handle == handle: @@ -166,8 +164,7 @@ class ButterflyImChannel(ButterflyTextChannel): # papyon.event.ContactEventInterface def on_contact_presence_changed(self, contact): - handle = ButterflyHandleFactory(self._conn_ref(), 'contact', - contact.account, contact.network_id) + handle = self._conn.ensure_contact_handle(contact) # Recreate a conversation if our contact join if self._offline_contact == contact and contact.presence != papyon.Presence.OFFLINE: logger.info('Contact %s connected, inviting him to the text channel' % unicode(handle)) @@ -193,8 +190,7 @@ class ButterflyImChannel(ButterflyTextChannel): # when acked by the client self._pending_offline_messages[id] = message - handle = ButterflyHandleFactory(self._conn_ref(), 'contact', - sender.account, sender.network_id) + handle = self._conn.ensure_contact_handle(sender) type = telepathy.CHANNEL_TEXT_MESSAGE_TYPE_NORMAL logger.info("User %r sent a offline message" % handle) self._signal_text_received(id, timestamp, handle, type, 0, message.display_name, text) diff --git a/butterfly/channel/media.py b/butterfly/channel/media.py index d75aad8..dc98ed1 100644 --- a/butterfly/channel/media.py +++ b/butterfly/channel/media.py @@ -25,7 +25,6 @@ import papyon import papyon.event from butterfly.util.decorator import async -from butterfly.handle import ButterflyHandleFactory from butterfly.media import ButterflySessionHandler from butterfly.channel import ButterflyChannel @@ -157,9 +156,9 @@ class ButterflyMediaChannel( def AddMembers(self, handles, message): logger.info("Add members %r: %s" % (handles, message)) for handle in handles: - print handle, self.GetSelfHandle() - if handle == int(self.GetSelfHandle()): - if self.GetSelfHandle() in self._local_pending: + print handle, int(self._conn.self_handle) + if handle == int(self._conn.self_handle): + if self._conn.self_handle in self._local_pending: self._call.accept() for handler in self._session_handler.ListStreams(): handler.send_candidates() @@ -242,11 +241,11 @@ class ButterflyMediaChannel( remote_pending = [] if self._call.incoming: - local_pending.append(self._conn.GetSelfHandle()) + local_pending.append(self._conn.self_handle) added.append(self._handle) else: remote_pending.append(self._handle) - added.append(self._conn.GetSelfHandle()) + added.append(self._conn.self_handle) self.MembersChanged('', added, [], local_pending, remote_pending, 0, telepathy.CHANNEL_GROUP_CHANGE_REASON_NONE) diff --git a/butterfly/channel/muc.py b/butterfly/channel/muc.py index 553834f..04332e5 100644 --- a/butterfly/channel/muc.py +++ b/butterfly/channel/muc.py @@ -25,7 +25,6 @@ import papyon import papyon.event from butterfly.util.decorator import async -from butterfly.handle import ButterflyHandleFactory from butterfly.channel.text import ButterflyTextChannel __all__ = ['ButterflyMucChannel'] @@ -55,15 +54,14 @@ class ButterflyMucChannel( def RemoveMembers(self, contacts, message): # Group interface, only removing ourself is supported - if int(self.GetSelfHandle()) in contacts: + if int(self._conn.self_handle) in contacts: self.Close() else : raise telepathy.PermissionDenied # papyon.event.ConversationEventInterface def on_conversation_user_joined(self, contact): - handle = ButterflyHandleFactory(self._conn_ref(), 'contact', - contact.account, contact.network_id) + handle = self._conn.ensure_contact_handle(contact) logger.info("User %s joined" % unicode(handle)) if handle not in self._members: @@ -72,8 +70,7 @@ class ButterflyMucChannel( # papyon.event.ConversationEventInterface def on_conversation_user_left(self, contact): - handle = ButterflyHandleFactory(self._conn_ref(), 'contact', - contact.account, contact.network_id) + handle = self._conn.ensure_contact_handle(contact) logger.info("User %s left" % unicode(handle)) self.MembersChanged('', [], [handle], [], [], @@ -88,11 +85,10 @@ class ButterflyMucChannel( @async def __add_initial_participants(self): handles = [] - handles.append(self._conn.GetSelfHandle()) + handles.append(self._conn.self_handle) if self._conversation: for participant in self._conversation.participants: - handle = ButterflyHandleFactory(self._conn_ref(), 'contact', - participant.account, participant.network_id) + handle = self._conn.ensure_contact_handle(contact) handles.append(handle) if handles: diff --git a/butterfly/channel/text.py b/butterfly/channel/text.py index 8c6f04b..7e5821b 100644 --- a/butterfly/channel/text.py +++ b/butterfly/channel/text.py @@ -31,7 +31,6 @@ import papyon.event from telepathy._generated.Channel_Interface_Messages import ChannelInterfaceMessages from telepathy.interfaces import CHANNEL_INTERFACE_MESSAGES -from butterfly.handle import ButterflyHandleFactory from butterfly.channel import ButterflyChannel __all__ = ['ButterflyTextChannel'] @@ -81,11 +80,10 @@ class ButterflyTextChannel( def _remove_typing_timeouts(self): # Remove any timeouts we had running. - handle = ButterflyHandleFactory(self._conn_ref(), 'self') - if self._send_typing_notification_timeout != 0: gobject.source_remove(self._send_typing_notification_timeout) self._send_typing_notification_timeout = 0 + handle = self._conn.self_handle self.ChatStateChanged(handle, telepathy.CHANNEL_CHAT_STATE_ACTIVE) for handle, tag in self._typing_notifications.items(): @@ -117,14 +115,6 @@ class ButterflyTextChannel( else: return set() - def _get_handle(self, account, network_id): - profile = self._conn_ref().msn_client.profile - if account == profile.account and network_id == profile.network_id: - return ButterflyHandleFactory(self._conn_ref(), 'self') - else: - return ButterflyHandleFactory(self._conn_ref(), 'contact', - account, network_id) - def _send_typing_notification(self): # No need to emit ChatStateChanged in this method because it will not # have changed from composing otherwise this source will have been @@ -200,8 +190,7 @@ class ButterflyTextChannel( gobject.source_remove(self._send_typing_notification_timeout) self._send_typing_notification_timeout = 0 - handle = ButterflyHandleFactory(self._conn_ref(), 'self') - self.ChatStateChanged(handle, state) + self.ChatStateChanged(self._conn.GetSelfHandle(), state) @dbus.service.method(telepathy.CHANNEL_TYPE_TEXT, in_signature='us', out_signature='', async_callbacks=('_success', '_error')) @@ -263,7 +252,7 @@ class ButterflyTextChannel( # Redefine GetSelfHandle since we use our own handle # as Butterfly doesn't have channel specific handles def GetSelfHandle(self): - return self._conn_ref().GetSelfHandle() + return self._conn.GetSelfHandle() def _contact_typing_notification_timeout(self, handle): # Contact hasn't sent a typing notification for ten seconds. He or she @@ -274,7 +263,7 @@ class ButterflyTextChannel( # papyon.event.ConversationEventInterface def on_conversation_user_typing(self, contact): - handle = self._get_handle(contact.account, contact.network_id) + handle = self._conn.ensure_contact_handle(contact) logger.info("User %s is typing" % unicode(handle)) # Remove any previous timeout. @@ -294,7 +283,7 @@ class ButterflyTextChannel( def on_conversation_message_received(self, sender, message): id = self._recv_id timestamp = int(time.time()) - handle = self._get_handle(sender.account, sender.network_id) + handle = self._conn.ensure_contact_handle(sender) type = telepathy.CHANNEL_TEXT_MESSAGE_TYPE_NORMAL logger.info("User %s sent a message" % unicode(handle)) content = re.sub('\r\n', '\n', message.content) @@ -307,7 +296,7 @@ class ButterflyTextChannel( # We used to use (MESSAGE_TYPE_ACTION, "nudge") to send nudges, and our own # "$contact sent you a nudge" string when receiving, but that's not very nice. # We should implement this properly at some point. See fd.o#24699. - handle = self._get_handle(sender.account, sender.network_id) + handle = self._conn.ensure_contact_handle(sender) logger.info("User %s sent a nudge" % unicode(handle)) # papyon.event.ConversationEventInterface @@ -323,4 +312,3 @@ class ButterflyTextChannel( def MessageReceived(self, message): id = message[0]['pending-message-id'] self._pending_messages2[id] = dbus.Array(message, signature='a{sv}') - diff --git a/butterfly/connection.py b/butterfly/connection.py index 4922e47..40f94fc 100644 --- a/butterfly/connection.py +++ b/butterfly/connection.py @@ -121,7 +121,9 @@ class ButterflyConnection(telepathy.server.Connection, ButterflyContacts.__init__(self) ButterflyMailNotification.__init__(self) - self.set_self_handle(ButterflyHandleFactory(self, 'self')) + self_handle = self.create_handle(telepathy.HANDLE_TYPE_CONTACT, + self._account[0]) + self.set_self_handle(self_handle) self.__disconnect_reason = telepathy.CONNECTION_STATUS_REASON_NONE_SPECIFIED self._initial_presence = papyon.Presence.INVISIBLE @@ -250,6 +252,44 @@ class ButterflyConnection(telepathy.server.Connection, self.check_handle(handle_type, handle_id) return self._handles[handle_type, handle_id] + def create_handle(self, handle_type, handle_name, **kwargs): + """Create new handle with given type and name.""" + handle_id = self.get_handle_id() + handle = ButterflyHandleFactory(self, handle_type, handle_id, + handle_name, **kwargs) + if handle is None: + raise telepathy.NotAvailable('Handle type unsupported %d' % handle_type) + logger.info("New Handle %s" % unicode(handle)) + self._handles[handle_type, handle_id] = handle + return handle + + def is_valid_handle_name(self, handle_type, handle_name): + """Make sure the name is valid for this type of handle.""" + if handle_type == telepathy.HANDLE_TYPE_CONTACT: + if '@' not in handle_name: + return False + if '.' not in handle_name.split("@", 1)[1]: + return False + return True + + def normalize_handle_name(self, handle_type, handle_name): + """Normalize handle name so the name is consistent everywhere.""" + if not self.is_valid_handle_name(handle_type, handle_name): + raise telepathy.InvalidHandle('TargetID %s not valid for type %d' % + (name, handle_type)) + if handle_type == telepathy.HANDLE_TYPE_CONTACT: + return handle_name.lower().strip() + return handle_name + + def ensure_contact_handle(self, contact): + """Build handle name for contact and ensure handle.""" + if contact is None: + return telepathy.NoneHandler() + handle_type = telepathy.HANDLE_TYPE_CONTACT + extension = network_to_extension.get(contact.network_id, "") + handle_name = contact.account.lower() + extension + return self.ensure_handle(handle_type, handle_name, contact=contact) + def Connect(self): if self._status == telepathy.CONNECTION_STATUS_DISCONNECTED: logger.info("Connecting") @@ -285,34 +325,6 @@ class ButterflyConnection(telepathy.server.Connection, return self._interfaces - def RequestHandles(self, handle_type, names, sender): - self.check_connected() - self.check_handle_type(handle_type) - - handles = [] - for name in names: - if handle_type == telepathy.HANDLE_TYPE_CONTACT: - network_id = papyon.NetworkID.MSN - for network, extension in network_to_extension.items(): - if name.endswith(extension): - name = name[0:-len(extension)] - network_id = network - break - contacts = self.msn_client.address_book.contacts.\ - search_by_account(name).\ - search_by_network_id(network_id) - handle = ButterflyHandleFactory(self, 'contact', - name, network_id) - elif handle_type == telepathy.HANDLE_TYPE_LIST: - handle = ButterflyHandleFactory(self, 'list', name) - elif handle_type == telepathy.HANDLE_TYPE_GROUP: - handle = ButterflyHandleFactory(self, 'group', name) - else: - raise telepathy.NotAvailable('Handle type unsupported %d' % handle_type) - handles.append(handle.id) - self.add_client_handle(handle, sender) - return handles - def _generate_props(self, channel_type, handle, suppress_handler, initiator_handle=None): props = { telepathy.CHANNEL_INTERFACE + '.ChannelType': channel_type, @@ -354,33 +366,33 @@ class ButterflyConnection(telepathy.server.Connection, self.StatusChanged(telepathy.CONNECTION_STATUS_CONNECTING, telepathy.CONNECTION_STATUS_REASON_REQUESTED) elif state == papyon.event.ClientState.SYNCHRONIZED: - handle = ButterflyHandleFactory(self, 'list', 'subscribe') + handle = self.ensure_handle(telepathy.HANDLE_TYPE_LIST, 'subscribe') props = self._generate_props(telepathy.CHANNEL_TYPE_CONTACT_LIST, handle, False) self._channel_manager.channel_for_props(props, signal=True) - handle = ButterflyHandleFactory(self, 'list', 'publish') + handle = self.ensure_handle(telepathy.HANDLE_TYPE_LIST, 'publish') props = self._generate_props(telepathy.CHANNEL_TYPE_CONTACT_LIST, handle, False) self._channel_manager.channel_for_props(props, signal=True) - #handle = ButterflyHandleFactory(self, 'list', 'hide') + #handle = self.ensure_handle(telepathy.HANDLE_TYPE_LIST, 'hide') #props = self._generate_props(telepathy.CHANNEL_TYPE_CONTACT_LIST, # handle, False) #self._channel_manager.channel_for_props(props, signal=True) - #handle = ButterflyHandleFactory(self, 'list', 'allow') + #handle = self.ensure_handle(telepathy.HANDLE_TYPE_LIST, 'allow') #props = self._generate_propstelepathy.CHANNEL_TYPE_CONTACT_LIST, # handle, False) #self._channel_manager.channel_for_props(props, signal=True) - #handle = ButterflyHandleFactory(self, 'list', 'deny') + #handle = self.ensure_handle(telepathy.HANDLE_TYPE_LIST, 'deny') #props = self._generate_props(telepathy.CHANNEL_TYPE_CONTACT_LIST, # handle, False) #self._channel_manager.channel_for_props(props, signal=True) for group in self.msn_client.address_book.groups: - handle = ButterflyHandleFactory(self, 'group', + handle = self.ensure_handle(telepathy.HANDLE_TYPE_GROUP, group.name.decode("utf-8")) props = self._generate_props( telepathy.CHANNEL_TYPE_CONTACT_LIST, handle, False) @@ -400,7 +412,7 @@ class ButterflyConnection(telepathy.server.Connection, self._client.profile.end_point_name = "PAPYON" if (presence is not None) or (message is not None): - self._presence_changed(ButterflyHandleFactory(self, 'self'), + self._presence_changed(self._self_handle, self._client.profile.presence, self._client.profile.personal_message) elif state == papyon.event.ClientState.CLOSED: @@ -435,8 +447,7 @@ class ButterflyConnection(telepathy.server.Connection, if len(conversation.participants) == 1: p = list(conversation.participants)[0] - handle = ButterflyHandleFactory(self, 'contact', - p.account, p.network_id) + handle = self.ensure_contact_handle(p) else: handle = telepathy.server.handle.NoneHandle() @@ -453,12 +464,10 @@ class ButterflyConnection(telepathy.server.Connection, # papyon.event.InviteEventInterface def on_invite_conference(self, call): logger.debug("Call invite") - handle = ButterflyHandleFactory(self, 'contact', call.peer.account, - call.peer.network_id) + handle = self.ensure_contact_handle(call.peer) props = self._generate_props(telepathy.CHANNEL_TYPE_STREAMED_MEDIA, handle, False, initiator_handle=handle) - channel = self._channel_manager.channel_for_props(props, signal=True, call=call) @@ -467,8 +476,7 @@ class ButterflyConnection(telepathy.server.Connection, direction = (producer and "send") or "receive" logger.debug("Invitation to %s webcam" % direction) - handle = ButterflyHandleFactory(self, 'contact', session.peer.account, - session.peer.network_id) + handle = self.ensure_contact_handle(session.peer) props = self._generate_props(telepathy.CHANNEL_TYPE_STREAMED_MEDIA, handle, False, initiator_handle=handle) channel = self._channel_manager.channel_for_props(props, signal=True, @@ -488,8 +496,8 @@ class ButterflyConnection(telepathy.server.Connection, # Request butterfly text channel (creation, what happen when it exist) sender = message.sender logger.info('received offline message from %s : %s' % (sender.account, message.text)) - handle = ButterflyHandleFactory(self, 'contact', - sender.account, sender.network_id) + + handle = self.ensure_contact_handle(sender) props = self._generate_props(telepathy.CHANNEL_TYPE_TEXT, handle, False) channel = self._channel_manager.channel_for_props(props, @@ -500,9 +508,8 @@ class ButterflyConnection(telepathy.server.Connection, # papyon.event.InviteEventInterface def on_invite_file_transfer(self, session): logger.debug("File transfer invite") - handle = ButterflyHandleFactory(self, 'contact', session.peer.account, - session.peer.network_id) + handle = self.ensure_contact_handle(session.peer) props = self._generate_props(telepathy.CHANNEL_TYPE_FILE_TRANSFER, handle, False) channel = self._channel_manager.create_channel_for_props(props, diff --git a/butterfly/handle.py b/butterfly/handle.py index 1d23d58..b2ef6e0 100644 --- a/butterfly/handle.py +++ b/butterfly/handle.py @@ -29,37 +29,16 @@ logger = logging.getLogger('Butterfly.Handle') network_to_extension = {papyon.NetworkID.EXTERNAL: "#yahoo"} -def ButterflyHandleFactory(connection, type, *args): - mapping = {'self': ButterflySelfHandle, - 'contact': ButterflyContactHandle, - 'list': ButterflyListHandle, - 'group': ButterflyGroupHandle} - handle = mapping[type](connection, *args) - connection._handles[handle.get_type(), handle.get_id()] = handle +def ButterflyHandleFactory(connection, type, id, name, **kwargs): + mapping = {telepathy.HANDLE_TYPE_CONTACT: ButterflyContactHandle, + telepathy.HANDLE_TYPE_LIST: ButterflyListHandle, + telepathy.HANDLE_TYPE_GROUP: ButterflyGroupHandle} + handle = mapping[type](connection, id, name, **kwargs) + connection._handles[handle.type, handle.id] = handle return handle -class ButterflyHandleMeta(type): - def __call__(cls, connection, *args): - obj, newly_created = cls.__new__(cls, connection, *args) - if newly_created: - obj.__init__(connection, connection.get_handle_id(), *args) - logger.info("New Handle %s" % unicode(obj)) - return obj - - class ButterflyHandle(telepathy.server.Handle): - __metaclass__ = ButterflyHandleMeta - - instances = weakref.WeakValueDictionary() - def __new__(cls, connection, *args): - key = (cls, connection._account[0], args) - if key not in cls.instances.keys(): - instance = object.__new__(cls) - cls.instances[key] = instance # TRICKY: instances is a weakdict - return instance, True - return cls.instances[key], False - def __init__(self, connection, id, handle_type, name): telepathy.server.Handle.__init__(self, id, handle_type, name) self._conn = weakref.proxy(connection) @@ -73,30 +52,25 @@ class ButterflyHandle(telepathy.server.Handle): return "<Butterfly%sHandle id=%u name='%s'>" % \ (type_str, self.id, self.name) - id = property(telepathy.server.Handle.get_id) - type = property(telepathy.server.Handle.get_type) - name = property(telepathy.server.Handle.get_name) - - -class ButterflySelfHandle(ButterflyHandle): - instance = None - - def __init__(self, connection, id): - handle_type = telepathy.HANDLE_TYPE_CONTACT - handle_name = connection._account[0] - self._connection = connection - ButterflyHandle.__init__(self, connection, id, handle_type, handle_name) - - @property - def profile(self): - return self._connection.msn_client.profile - class ButterflyContactHandle(ButterflyHandle): - def __init__(self, connection, id, contact_account, contact_network): - extension = network_to_extension.get(contact_network, "") + def __init__(self, connection, id, contact_name, contact=None): handle_type = telepathy.HANDLE_TYPE_CONTACT - handle_name = contact_account + extension + handle_name = contact_name + self._contact = contact + + if contact is None: + contact_account = contact_name.lower() + contact_network = papyon.NetworkID.MSN + for network, extension in network_to_extension.items(): + if contact_name.endswith(extension): + contact_account = contact_name[0:-len(extension)] + contact_network = network + break + else: + contact_account = contact.account + contact_network = contact.network_id + self.account = contact_account self.network = contact_network self.pending_groups = set() @@ -105,8 +79,14 @@ class ButterflyContactHandle(ButterflyHandle): @property def contact(self): - return self._conn.msn_client.address_book.search_contact(self.account, - self.network) + if self._contact is None: + if self.account == self._conn._msn_client.profile.account.lower() and \ + self.network == papyon.NetworkID.MSN: + self._contact = self._conn.msn_client.profile + else: + self._contact = self._conn.msn_client.address_book.search_contact( + self.account, self.network) + return self._contact class ButterflyListHandle(ButterflyHandle): @@ -129,4 +109,3 @@ class ButterflyGroupHandle(ButterflyHandle): if group.name.decode("utf-8").lower() == self.name.lower(): return group return None - diff --git a/butterfly/presence.py b/butterfly/presence.py index 5ed7868..dd1ecac 100644 --- a/butterfly/presence.py +++ b/butterfly/presence.py @@ -28,7 +28,6 @@ import telepathy.constants import telepathy.errors import papyon -from butterfly.handle import ButterflyHandleFactory from butterfly.util.decorator import async __all__ = ['ButterflyPresence'] @@ -166,10 +165,7 @@ class ButterflyPresence(telepathy.server.ConnectionInterfacePresence, presences = {} for handle_id in contacts: handle = self.handle(telepathy.HANDLE_TYPE_CONTACT, handle_id) - try: - contact = handle.contact - except AttributeError: - contact = handle.profile + contact = handle.contact if contact is not None: presence = ButterflyPresenceMapping.to_telepathy[contact.presence] @@ -216,10 +212,7 @@ class ButterflyPresence(telepathy.server.ConnectionInterfacePresence, presences = dbus.Dictionary(signature='u(uss)') for handle_id in contacts: handle = self.handle(telepathy.HANDLE_TYPE_CONTACT, handle_id) - try: - contact = handle.contact - except AttributeError: - contact = handle.profile + contact = handle.contact if contact is not None: presence = ButterflyPresenceMapping.to_telepathy[contact.presence] @@ -269,8 +262,7 @@ class ButterflyPresence(telepathy.server.ConnectionInterfacePresence, # papyon.event.ContactEventInterface def on_contact_presence_changed(self, contact): - handle = ButterflyHandleFactory(self, 'contact', - contact.account, contact.network_id) + handle = self.ensure_contact_handle(contact) logger.info("Contact %s presence changed to '%s'" % (unicode(handle), contact.presence)) self._presence_changed(handle, contact.presence, contact.personal_message) @@ -281,7 +273,7 @@ class ButterflyPresence(telepathy.server.ConnectionInterfacePresence, # papyon.event.ProfileEventInterface def on_profile_presence_changed(self): profile = self.msn_client.profile - self._presence_changed(ButterflyHandleFactory(self, 'self'), + self._presence_changed(self._self_handle, profile.presence, profile.personal_message) # papyon.event.ProfileEventInterface |