Fixing a bug with deny lists
[theonering] / src / tp / channel.py
1 # telepathy-python - Base classes defining the interfaces of the Telepathy framework
2 #
3 # Copyright (C) 2005, 2006 Collabora Limited
4 # Copyright (C) 2005, 2006 Nokia Corporation
5 #
6 # This library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2.1 of the License, or (at your option) any later version.
10 #
11 # This library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # Lesser General Public License for more details.
15 #
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this library; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
20 import dbus
21 import dbus.service
22
23 from telepathy.constants import (CONNECTION_HANDLE_TYPE_NONE,
24                                  CHANNEL_TEXT_MESSAGE_TYPE_NORMAL)
25
26 from telepathy.errors import InvalidArgument
27
28 from telepathy.interfaces import (CHANNEL_INTERFACE,
29                                   CHANNEL_INTERFACE_DTMF,
30                                   CHANNEL_INTERFACE_GROUP,
31                                   CHANNEL_INTERFACE_HOLD,
32                                   CHANNEL_INTERFACE_PASSWORD,
33                                   CHANNEL_TYPE_CONTACT_LIST,
34                                   CHANNEL_TYPE_FILE_TRANSFER,
35                                   CHANNEL_TYPE_ROOM_LIST,
36                                   CHANNEL_TYPE_STREAMED_MEDIA,
37                                   CHANNEL_TYPE_TEXT,
38                                   MEDIA_SESSION_HANDLER,
39                                   MEDIA_STREAM_HANDLER)
40
41 from telepathy._generated.Channel import Channel as _Channel
42
43 from properties import DBusProperties
44
45 class Channel(_Channel, DBusProperties):
46
47     def __init__(self, connection, manager, props):
48         """
49         Initialise the base channel object.
50
51         Parameters:
52         connection - the parent Connection object
53         props - initial channel properties
54         """
55         self._conn = connection
56         self._chan_manager = manager
57         object_path = self._conn.get_channel_path()
58         _Channel.__init__(self, self._conn._name, object_path)
59
60         self._type = props[CHANNEL_INTERFACE + '.ChannelType']
61         self._requested = props[CHANNEL_INTERFACE + '.Requested']
62
63         self._immutable_properties = dict()
64
65         self._handle = self._conn.get_handle_by_id(
66             props[CHANNEL_INTERFACE + '.TargetHandleType'],
67             props[CHANNEL_INTERFACE + '.TargetHandle'])
68         self._interfaces = set()
69
70         DBusProperties.__init__(self)
71         self._implement_property_get(CHANNEL_INTERFACE,
72             {'ChannelType': lambda: dbus.String(self.GetChannelType()),
73              'Interfaces': lambda: dbus.Array(self.GetInterfaces(), signature='s'),
74              'TargetHandle': lambda: dbus.UInt32(self._handle.get_id()),
75              'TargetHandleType': lambda: dbus.UInt32(self._get_handle_type()),
76              'TargetID': lambda: dbus.String(self._get_target_id()),
77              'Requested': lambda: self._requested})
78
79         self._add_immutables({
80             'ChannelType': CHANNEL_INTERFACE,
81             'TargetHandle': CHANNEL_INTERFACE,
82             'Interfaces': CHANNEL_INTERFACE,
83             'TargetHandleType': CHANNEL_INTERFACE,
84             'TargetID': CHANNEL_INTERFACE,
85             'Requested': CHANNEL_INTERFACE
86             })
87
88     def _add_immutables(self, props):
89         self._immutable_properties.update(props)
90
91     def _get_handle_type(self):
92         if self._handle:
93             return self._handle.get_type()
94         else:
95             return CONNECTION_HANDLE_TYPE_NONE
96
97     def _get_target_id(self):
98         if self._handle:
99             return self._handle.get_name()
100         else:
101             return ''
102
103     def get_props(self):
104         props = dict()
105         for prop, iface in self._immutable_properties.items():
106             props[iface + '.' + prop] = \
107                 self._prop_getters[iface][prop]()
108         return props
109
110     @dbus.service.method(CHANNEL_INTERFACE, in_signature='', out_signature='')
111     def Close(self):
112         self.Closed()
113         self._chan_manager.remove_channel(self)
114         self._conn.remove_channel(self)
115
116     @dbus.service.method(CHANNEL_INTERFACE, in_signature='', out_signature='s')
117     def GetChannelType(self):
118         """ Returns the interface name for the type of this channel. """
119         return self._type
120
121     @dbus.service.method(CHANNEL_INTERFACE, in_signature='', out_signature='uu')
122     def GetHandle(self):
123         """ Returns the handle type and number if this channel represents a
124         communication with a particular contact, room or server-stored list, or
125         zero if it is transient and defined only by its contents. """
126         if self._handle:
127             return self._handle.get_type(), self._handle
128         else:
129             return (CONNECTION_HANDLE_TYPE_NONE, 0)
130
131     @dbus.service.method(CHANNEL_INTERFACE, in_signature='', out_signature='as')
132     def GetInterfaces(self):
133         """
134         Get the optional interfaces implemented by the channel.
135
136         Returns:
137         an array of the D-Bus interface names
138         """
139         return self._interfaces
140
141 from telepathy._generated.Channel_Type_Contact_List \
142         import ChannelTypeContactList as _ChannelTypeContactListIface
143
144 class ChannelTypeContactList(Channel, _ChannelTypeContactListIface):
145     __doc__ = _ChannelTypeContactListIface.__doc__
146
147     def __init__(self, connection, manager, props):
148         """
149         Initialise the channel.
150
151         Parameters:
152         connection - the parent Telepathy Connection object
153         """
154         Channel.__init__(self, connection, manager, props)
155
156
157 from telepathy._generated.Channel_Type_File_Transfer \
158         import ChannelTypeFileTransfer as _ChannelTypeFileTransferIface
159
160 class ChannelTypeFileTransfer(Channel, _ChannelTypeFileTransferIface):
161     __doc__ = _ChannelTypeFileTransferIface.__doc__
162
163     def __init__(self, connection, manager, props):
164         """
165         Initialise the channel.
166
167         Parameters:
168         connection - the parent Telepathy Connection object
169         """
170         Channel.__init__(self, connection, manager, props)
171
172
173 from telepathy._generated.Channel_Type_File_Transfer \
174         import ChannelTypeFileTransfer as _ChannelTypeFileTransferIface
175
176 class ChannelTypeFileTransfer(Channel, _ChannelTypeFileTransferIface):
177     __doc__ = _ChannelTypeFileTransferIface.__doc__
178
179     def __init__(self, connection, manager, props):
180         """
181         Initialise the channel.
182
183         Parameters:
184         connection - the parent Telepathy Connection object
185         """
186         Channel.__init__(self, connection, manager, props)
187
188
189 from telepathy._generated.Channel_Type_Streamed_Media \
190         import ChannelTypeStreamedMedia as _ChannelTypeStreamedMediaIface
191
192 class ChannelTypeStreamedMedia(Channel, _ChannelTypeStreamedMediaIface):
193     __doc__ = _ChannelTypeStreamedMediaIface.__doc__
194
195     def __init__(self, connection, manager, props):
196         """
197         Initialise the channel.
198
199         Parameters:
200         connection - the parent Telepathy Connection object
201         """
202         Channel.__init__(self, connection, manager, props)
203
204
205 from telepathy._generated.Channel_Type_Room_List \
206         import ChannelTypeRoomList as _ChannelTypeRoomListIface
207
208 class ChannelTypeRoomList(Channel, _ChannelTypeRoomListIface):
209     __doc__ = _ChannelTypeRoomListIface.__doc__
210
211     def __init__(self, connection, manager, props):
212         """
213         Initialise the channel.
214
215         Parameters:
216         connection - the parent Telepathy Connection object
217         """
218         Channel.__init__(self, connection, manager, props)
219         self._listing_rooms = False
220         self._rooms = {}
221
222         self._add_immutables(self, {'Server': CHANNEL_TYPE_ROOM_LIST})
223
224     @dbus.service.method(CHANNEL_TYPE_ROOM_LIST, in_signature='', out_signature='b')
225     def GetListingRooms(self):
226         return self._listing_rooms
227
228     @dbus.service.signal(CHANNEL_TYPE_ROOM_LIST, signature='b')
229     def ListingRooms(self, listing):
230         self._listing_rooms = listing
231
232
233 from telepathy._generated.Channel_Type_Text \
234         import ChannelTypeText as _ChannelTypeTextIface
235
236 class ChannelTypeText(Channel, _ChannelTypeTextIface):
237     __doc__ = _ChannelTypeTextIface.__doc__
238
239     def __init__(self, connection, manager, props):
240         """
241         Initialise the channel.
242
243         Parameters:
244         connection - the parent Telepathy Connection object
245         """
246         Channel.__init__(self, connection, manager, props)
247
248         self._pending_messages = {}
249         self._message_types = [CHANNEL_TEXT_MESSAGE_TYPE_NORMAL]
250
251     @dbus.service.method(CHANNEL_TYPE_TEXT, in_signature='', out_signature='au')
252     def GetMessageTypes(self):
253         """
254         Return an array indicating which types of message may be sent on this
255         channel.
256
257         Returns:
258         an array of integer message types as defined above
259         """
260         return self._message_types
261
262     @dbus.service.method(CHANNEL_TYPE_TEXT, in_signature='au', out_signature='')
263     def AcknowledgePendingMessages(self, ids):
264         """
265         Inform the channel that you have handled messages by displaying them to
266         the user (or equivalent), so they can be removed from the pending queue.
267
268         Parameters:
269         ids - the message to acknowledge
270
271         Possible Errors:
272         InvalidArgument (a given message ID was not found, no action taken)
273         """
274         for id in ids:
275             if id not in self._pending_messages:
276                 raise InvalidArgument("the given message ID was not found")
277
278         for id in ids:
279             del self._pending_messages[id]
280
281     @dbus.service.method(CHANNEL_TYPE_TEXT, in_signature='b', out_signature='a(uuuuus)')
282     def ListPendingMessages(self, clear):
283         """
284         List the messages currently in the pending queue, and optionally
285         remove then all.
286
287         Parameters:
288         clear - a boolean indicating whether the queue should be cleared
289
290         Returns:
291         an array of structs containing:
292             a numeric identifier
293             a unix timestamp indicating when the message was received
294             an integer handle of the contact who sent the message
295             an integer of the message type
296             a bitwise OR of the message flags
297             a string of the text of the message
298         """
299         messages = []
300         for id in self._pending_messages.keys():
301             (timestamp, sender, type, flags, text) = self._pending_messages[id]
302             message = (id, timestamp, sender, type, flags, text)
303             messages.append(message)
304             if clear:
305                 del self._pending_messages[id]
306         messages.sort(cmp=lambda x,y:cmp(x[1], y[1]))
307         return messages
308
309     @dbus.service.signal(CHANNEL_TYPE_TEXT, signature='uuuuus')
310     def Received(self, id, timestamp, sender, type, flags, text):
311         self._pending_messages[id] = (timestamp, sender, type, flags, text)
312
313
314 from telepathy._generated.Channel_Interface_Chat_State \
315         import ChannelInterfaceChatState
316
317
318 from telepathy._generated.Channel_Interface_DTMF import ChannelInterfaceDTMF
319
320
321 from telepathy._generated.Channel_Interface_Group \
322         import ChannelInterfaceGroup as _ChannelInterfaceGroup
323
324 class ChannelInterfaceGroup(_ChannelInterfaceGroup, DBusProperties):
325
326     def __init__(self):
327         _ChannelInterfaceGroup.__init__(self)
328         DBusProperties.__init__(self)
329
330         self._implement_property_get(CHANNEL_INTERFACE_GROUP,
331             {'GroupFlags': lambda: dbus.UInt32(self.GetGroupFlags()),
332              'Members': lambda: dbus.Array(self.GetMembers(), signature='u'),
333              'RemotePendingMembers': lambda: dbus.Array(self.GetRemotePendingMembers(), signature='u'),
334              'SelfHandle': lambda: dbus.UInt32(self.GetSelfHandle())})
335
336         self._group_flags = 0
337         self._members = set()
338         self._local_pending = set()
339         self._remote_pending = set()
340
341     @dbus.service.method(CHANNEL_INTERFACE_GROUP, in_signature='', out_signature='u')
342     def GetGroupFlags(self):
343         return self._group_flags
344
345     @dbus.service.signal(CHANNEL_INTERFACE_GROUP, signature='uu')
346     def GroupFlagsChanged(self, added, removed):
347         self._group_flags |= added
348         self._group_flags &= ~removed
349
350     @dbus.service.method(CHANNEL_INTERFACE_GROUP, in_signature='', out_signature='au')
351     def GetMembers(self):
352         return self._members
353
354     @dbus.service.method(CHANNEL_INTERFACE_GROUP, in_signature='', out_signature='u')
355     def GetSelfHandle(self):
356         self_handle = self._conn.GetSelfHandle()
357         if (self_handle in self._members or
358             self_handle in self._local_pending or
359             self_handle in self._remote_pending):
360             return self_handle
361         else:
362             return 0
363
364     @dbus.service.method(CHANNEL_INTERFACE_GROUP, in_signature='', out_signature='au')
365     def GetLocalPendingMembers(self):
366         return self._local_pending
367
368     @dbus.service.method(CHANNEL_INTERFACE_GROUP, in_signature='', out_signature='au')
369     def GetRemotePendingMembers(self):
370         return self._remote_pending
371
372     @dbus.service.method(CHANNEL_INTERFACE_GROUP, in_signature='', out_signature='auauau')
373     def GetAllMembers(self):
374         return (self._members, self._local_pending, self._remote_pending)
375
376     @dbus.service.signal(CHANNEL_INTERFACE_GROUP, signature='sauauauauuu')
377     def MembersChanged(self, message, added, removed, local_pending, remote_pending, actor, reason):
378
379         self._members.update(added)
380         self._members.difference_update(removed)
381
382         self._local_pending.update(local_pending)
383         self._local_pending.difference_update(added)
384         self._local_pending.difference_update(removed)
385
386         self._remote_pending.update(remote_pending)
387         self._remote_pending.difference_update(added)
388         self._remote_pending.difference_update(removed)
389
390
391 from telepathy._generated.Channel_Interface_Hold import ChannelInterfaceHold
392
393
394 # ChannelInterfaceMediaSignalling is in telepathy.server.media
395
396
397 from telepathy._generated.Channel_Interface_Password \
398         import ChannelInterfacePassword as _ChannelInterfacePassword
399
400 class ChannelInterfacePassword(_ChannelInterfacePassword):
401     def __init__(self):
402         _ChannelInterfacePassword.__init__(self)
403         self._password_flags = 0
404         self._password = ''
405
406     @dbus.service.method(CHANNEL_INTERFACE_PASSWORD, in_signature='', out_signature='u')
407     def GetPasswordFlags(self):
408         return self._password_flags
409
410     @dbus.service.signal(CHANNEL_INTERFACE_PASSWORD, signature='uu')
411     def PasswordFlagsChanged(self, added, removed):
412         self._password_flags |= added
413         self._password_flags &= ~removed
414
415
416 from telepathy._generated.Channel_Interface_Call_State import ChannelInterfaceCallState