1 # telepathy-python - Base classes defining the interfaces of the Telepathy framework
3 # Copyright (C) 2009-2010 Collabora Limited
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License, or (at your option) any later version.
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 from telepathy.errors import NotImplemented
23 from telepathy.interfaces import (CHANNEL_INTERFACE,
24 CHANNEL_TYPE_CONTACT_LIST)
26 from telepathy.constants import HANDLE_TYPE_NONE
28 from handle import NoneHandle
30 class ChannelManager(object):
31 def __init__(self, connection):
32 self._conn = connection
34 self._requestable_channels = dict()
35 self._channels = dict()
37 self._fixed_properties = dict()
38 self._available_properties = dict()
40 self._requestables = dict()
43 """Close channel manager and all the existing channels."""
44 for channel_type in self._requestable_channels:
45 for channels in self._channels[channel_type].values():
46 for channel in channels:
47 if channel._type == CHANNEL_TYPE_CONTACT_LIST:
48 channel.remove_from_connection()
52 def remove_channel(self, channel):
53 "Remove channel from the channel manager"
54 for channel_type in self._requestable_channels:
55 for handle, channels in self._channels[channel_type].items():
56 if channel in channels :
57 channels.remove(channel)
59 def _get_type_requested_handle(self, props):
60 """Return the type, request and target handle from the requested
62 type = props[CHANNEL_INTERFACE + '.ChannelType']
63 requested = props[CHANNEL_INTERFACE + '.Requested']
65 target_handle_type = \
66 props.get(CHANNEL_INTERFACE + '.TargetHandleType', HANDLE_TYPE_NONE)
68 if target_handle_type == HANDLE_TYPE_NONE:
71 target_handle = props[CHANNEL_INTERFACE + '.TargetHandle']
72 handle = self._conn._handles[target_handle_type, target_handle]
74 return (type, requested, handle)
76 def existing_channel(self, props):
77 """ Return a channel corresponding to theses properties if such
78 one exists, otherwhise return None. Default implementation will
79 return the last created channel of the same kind identified by
81 Connection Manager should subclass this function
82 to implement more appropriate behaviour. """
84 type, _, handle = self._get_type_requested_handle(props)
86 if type in self._channels:
87 if handle in self._channels[type]:
88 if len(self._channels[type][handle]) > 0:
89 return self._channels[type][handle][-1]
93 def channel_exists(self, props):
94 """ Return True if channel exist with theses props, False otherwhise"""
95 return self.existing_channel(props) != None
97 def create_channel_for_props(self, props, signal=True, **args):
98 """Create a new channel with theses properties"""
99 type, _, handle = self._get_type_requested_handle(props)
101 if type not in self._requestable_channels:
102 raise NotImplemented('Unknown channel type "%s"' % type)
104 channel = self._requestable_channels[type](
107 self._conn.add_channels([channel], signal=signal)
108 if handle.get_type() != HANDLE_TYPE_NONE and type in self._channels:
109 self._channels[type].setdefault(handle, []).append(channel)
113 def channel_for_props(self, props, signal=True, **args):
114 channel = self.existing_channel(props)
115 """Return an existing channel with theses properties if it already
116 exists, otherwhise return a new one"""
120 return self.create_channel_for_props(props, signal, **args)
122 # Should use implement_channel_classes instead.
123 def _implement_channel_class(self, type, make_channel, fixed, available):
124 """Implement channel types in the channel manager, and add one channel
125 class that is retrieved in RequestableChannelClasses.
127 self.implement_channel_classes should be used instead, as it allows
128 implementing multiple channel classes."""
129 warnings.warn('deprecated in favour of implement_channel_classes',
132 self._requestable_channels[type] = make_channel
133 self._channels.setdefault(type, {})
135 self._fixed_properties[type] = fixed
136 self._available_properties[type] = available
138 # Use this function instead of _implement_channel_class.
139 def implement_channel_classes(self, type, make_channel, classes):
140 """Implement channel types in the channel manager, and add channel
141 classes that are retrieved in RequestableChannelClasses.
143 @type: the channel type
144 @make_channel: a function to call which returns a Channel object
145 @classes: a list of channel classes. E.g.
147 [ ( { '...ChannelType': '...Text', '...TargetHandleType': HANDLE_TYPE_CONTACT },
148 ['...TargetHandle'] )
151 See the spec for more documentation on the
152 Requestable_Channel_Class struct.
154 self._requestable_channels[type] = make_channel
155 self._channels.setdefault(type, {})
157 self._requestables[type] = classes
159 def get_requestable_channel_classes(self):
160 """Return all the channel types that can be created"""
163 for channel_type in self._requestable_channels:
164 retval.extend(self._requestables.get(channel_type, []))
166 # _implement_channel_class was used.
167 if channel_type in self._fixed_properties:
168 retval.append((self._fixed_properties[channel_type],
169 self._available_properties.get(channel_type, [])))