# telepathy-python - Base classes defining the interfaces of the Telepathy framework
#
-# Copyright (C) 2009 Collabora Limited
+# Copyright (C) 2009-2010 Collabora Limited
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+import warnings
+
from telepathy.errors import NotImplemented
from telepathy.interfaces import (CHANNEL_INTERFACE,
- CHANNEL_TYPE_CONTACT_LIST,
- CHANNEL_TYPE_TEXT)
+ CHANNEL_TYPE_CONTACT_LIST)
-class ChannelManager(object):
+from telepathy.constants import HANDLE_TYPE_NONE
+
+from handle import NoneHandle
+class ChannelManager(object):
def __init__(self, connection):
self._conn = connection
- self._requestable_channel_classes = dict()
+ self._requestable_channels = dict()
self._channels = dict()
+
self._fixed_properties = dict()
self._available_properties = dict()
+ self._requestables = dict()
+
def close(self):
- for channel_type in self._requestable_channel_classes:
- for channel in self._channels[channel_type].values():
- if channel._type == CHANNEL_TYPE_CONTACT_LIST:
- channel.remove_from_connection()
- else:
- channel.Close()
+ """Close channel manager and all the existing channels."""
+ for channel_type in self._requestable_channels:
+ for channels in self._channels[channel_type].values():
+ for channel in channels:
+ if channel._type == CHANNEL_TYPE_CONTACT_LIST:
+ channel.remove_from_connection()
+ else:
+ channel.Close()
def remove_channel(self, channel):
- for channel_type in self._requestable_channel_classes:
- for handle, chan in self._channels[channel_type].items():
- if channel == chan:
- del self._channels[channel_type][handle]
+ "Remove channel from the channel manager"
+ for channel_type in self._requestable_channels:
+ for handle, channels in self._channels[channel_type].items():
+ if channel in channels :
+ channels.remove(channel)
def _get_type_requested_handle(self, props):
+ """Return the type, request and target handle from the requested
+ properties"""
type = props[CHANNEL_INTERFACE + '.ChannelType']
requested = props[CHANNEL_INTERFACE + '.Requested']
- target_handle = int(props[CHANNEL_INTERFACE + '.TargetHandle'])
- target_handle_type = int(props[CHANNEL_INTERFACE + '.TargetHandleType'])
- handle = self._conn._handles[target_handle_type, target_handle]
+ target_handle_type = \
+ props.get(CHANNEL_INTERFACE + '.TargetHandleType', HANDLE_TYPE_NONE)
+
+ if target_handle_type == HANDLE_TYPE_NONE:
+ handle = NoneHandle()
+ else:
+ target_handle = props[CHANNEL_INTERFACE + '.TargetHandle']
+ handle = self._conn._handles[target_handle_type, target_handle]
return (type, requested, handle)
- def channel_exists(self, props):
+ def existing_channel(self, props):
+ """ Return a channel corresponding to theses properties if such
+ one exists, otherwhise return None. Default implementation will
+ return the last created channel of the same kind identified by
+ handle and type.
+ Connection Manager should subclass this function
+ to implement more appropriate behaviour. """
+
type, _, handle = self._get_type_requested_handle(props)
if type in self._channels:
if handle in self._channels[type]:
- return True
+ if len(self._channels[type][handle]) > 0:
+ return self._channels[type][handle][-1]
- return False
+ return None
- def channel_for_props(self, props, signal=True, **args):
+ def channel_exists(self, props):
+ """ Return True if channel exist with theses props, False otherwhise"""
+ return self.existing_channel(props) != None
+
+ def create_channel_for_props(self, props, signal=True, **args):
+ """Create a new channel with theses properties"""
type, _, handle = self._get_type_requested_handle(props)
- if type not in self._requestable_channel_classes:
+ if type not in self._requestable_channels:
raise NotImplemented('Unknown channel type "%s"' % type)
- if self.channel_exists(props):
- return self._channels[type][handle]
-
- channel = self._requestable_channel_classes[type](
+ channel = self._requestable_channels[type](
props, **args)
self._conn.add_channels([channel], signal=signal)
- self._channels[type][handle] = channel
+ if handle.get_type() != HANDLE_TYPE_NONE and type in self._channels:
+ self._channels[type].setdefault(handle, []).append(channel)
return channel
+ def channel_for_props(self, props, signal=True, **args):
+ channel = self.existing_channel(props)
+ """Return an existing channel with theses properties if it already
+ exists, otherwhise return a new one"""
+ if channel:
+ return channel
+ else:
+ return self.create_channel_for_props(props, signal, **args)
+
+ # Should use implement_channel_classes instead.
def _implement_channel_class(self, type, make_channel, fixed, available):
- self._requestable_channel_classes[type] = make_channel
+ """Implement channel types in the channel manager, and add one channel
+ class that is retrieved in RequestableChannelClasses.
+
+ self.implement_channel_classes should be used instead, as it allows
+ implementing multiple channel classes."""
+ warnings.warn('deprecated in favour of implement_channel_classes',
+ DeprecationWarning)
+
+ self._requestable_channels[type] = make_channel
self._channels.setdefault(type, {})
self._fixed_properties[type] = fixed
self._available_properties[type] = available
+ # Use this function instead of _implement_channel_class.
+ def implement_channel_classes(self, type, make_channel, classes):
+ """Implement channel types in the channel manager, and add channel
+ classes that are retrieved in RequestableChannelClasses.
+
+ @type: the channel type
+ @make_channel: a function to call which returns a Channel object
+ @classes: a list of channel classes. E.g.
+
+ [ ( { '...ChannelType': '...Text', '...TargetHandleType': HANDLE_TYPE_CONTACT },
+ ['...TargetHandle'] )
+ ]
+
+ See the spec for more documentation on the
+ Requestable_Channel_Class struct.
+ """
+ self._requestable_channels[type] = make_channel
+ self._channels.setdefault(type, {})
+
+ self._requestables[type] = classes
+
def get_requestable_channel_classes(self):
+ """Return all the channel types that can be created"""
retval = []
- for channel_type in self._requestable_channel_classes:
- retval.append((self._fixed_properties[channel_type],
- self._available_properties[channel_type]))
+ for channel_type in self._requestable_channels:
+ retval.extend(self._requestables.get(channel_type, []))
+
+ # _implement_channel_class was used.
+ if channel_type in self._fixed_properties:
+ retval.append((self._fixed_properties[channel_type],
+ self._available_properties.get(channel_type, [])))
+
return retval