a2e6a27ebb7c5aff33c46e20379f957a496f1cf4
[theonering] / src / tp / channelmanager.py
1 # telepathy-python - Base classes defining the interfaces of the Telepathy framework
2 #
3 # Copyright (C) 2009 Collabora Limited
4 #
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.
9 #
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.
14 #
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
18
19 from telepathy.errors import NotImplemented
20
21 from telepathy.interfaces import (CHANNEL_INTERFACE,
22                                  CHANNEL_TYPE_CONTACT_LIST)
23
24 class ChannelManager(object):
25
26     def __init__(self, connection):
27         self._conn = connection
28
29         self._requestable_channel_classes = dict()
30         self._channels = dict()
31         self._fixed_properties = dict()
32         self._available_properties = dict()
33
34     def close(self):
35         """Close channel manager and all the existing channels."""
36         for channel_type in self._requestable_channel_classes:
37             for channels in self._channels[channel_type].values():
38                 for channel in channels:
39                     if channel._type == CHANNEL_TYPE_CONTACT_LIST:
40                         channel.remove_from_connection()
41                     else:
42                         channel.Close()
43
44     def remove_channel(self, channel):
45         "Remove channel from the channel manager"
46         for channel_type in self._requestable_channel_classes:
47             for handle, channels in self._channels[channel_type].items():
48                 if channel in channels :
49                     channels.remove(channel)
50
51     def _get_type_requested_handle(self, props):
52         """Return the type, request and target handle from the requested
53         properties"""
54         type = props[CHANNEL_INTERFACE + '.ChannelType']
55         requested = props[CHANNEL_INTERFACE + '.Requested']
56         target_handle = int(props[CHANNEL_INTERFACE + '.TargetHandle'])
57         target_handle_type = int(props[CHANNEL_INTERFACE + '.TargetHandleType'])
58
59         handle = self._conn._handles[target_handle_type, target_handle]
60
61         return (type, requested, handle)
62
63     def existing_channel(self, props):
64         """ Return a channel corresponding to theses properties if such
65         one exists, otherwhise return None. Default implementation will
66         return the last created channel of the same kind identified by
67         handle and type.
68         Connection Manager should subclass this function
69         to implement more appropriate behaviour. """
70
71         type, _, handle = self._get_type_requested_handle(props)
72
73         if type in self._channels:
74             if handle in self._channels[type]:
75                 if len(self._channels[type][handle]) > 0:
76                     return self._channels[type][handle][-1]
77
78         return None
79
80     def channel_exists(self, props):
81         """ Return True if channel exist with theses props, False otherwhise"""
82         return self.existing_channel(props) != None
83
84     def create_channel_for_props(self, props, signal=True, **args):
85         """Create a new channel with theses properties"""
86         type, _, handle = self._get_type_requested_handle(props)
87
88         if type not in self._requestable_channel_classes:
89             raise NotImplemented('Unknown channel type "%s"' % type)
90
91         channel = self._requestable_channel_classes[type](
92             props, **args)
93
94         self._conn.add_channels([channel], signal=signal)
95         if type in self._channels:
96             if handle in self._channels[type]:
97                 self._channels[type].setdefault(handle, []).append(channel)
98
99         return channel
100
101     def channel_for_props(self, props, signal=True, **args):
102         channel = self.existing_channel(props)
103         """Return an existing channel with theses properties if it already
104         exists, otherwhise return a new one"""
105         if channel:
106             return channel
107         else:
108             return self.create_channel_for_props(props, signal, **args)
109
110     def _implement_channel_class(self, type, make_channel, fixed, available):
111         """Notify channel manager a channel with these properties can be created"""
112         self._requestable_channel_classes[type] = make_channel
113         self._channels.setdefault(type, {})
114
115         self._fixed_properties[type] = fixed
116         self._available_properties[type] = available
117
118     def get_requestable_channel_classes(self):
119         retval = []
120
121         for channel_type in self._requestable_channel_classes:
122             retval.append((self._fixed_properties[channel_type],
123                 self._available_properties[channel_type]))
124
125         return retval