summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis-Francis Ratté-Boulianne <louis-francis.ratte-boulianne@collabora.co.uk>2010-11-09 14:34:38 -0500
committerLouis-Francis Ratté-Boulianne <louis-francis.ratte-boulianne@collabora.co.uk>2010-12-03 15:50:39 -0500
commitb57867b794a7e7a8ae6671bac5e1d76303b82ba8 (patch)
treec16172e745509f83d438bda23d8472c88a48e0e4
parentd5f8ed4a22ab5e25ab408e59d770b4872ab9e9c4 (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.py17
-rw-r--r--butterfly/avatars.py16
-rw-r--r--butterfly/capabilities.py29
-rw-r--r--butterfly/channel/__init__.py4
-rw-r--r--butterfly/channel/conference.py6
-rw-r--r--butterfly/channel/contact_list.py19
-rw-r--r--butterfly/channel/file_transfer.py1
-rw-r--r--butterfly/channel/group.py7
-rw-r--r--butterfly/channel/im.py10
-rw-r--r--butterfly/channel/media.py11
-rw-r--r--butterfly/channel/muc.py14
-rw-r--r--butterfly/channel/text.py24
-rw-r--r--butterfly/connection.py101
-rw-r--r--butterfly/handle.py81
-rw-r--r--butterfly/presence.py16
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