Imitiating buttfly in being explicitly typed
[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                                  HANDLE_TYPE_NONE)
26
27 from telepathy.errors import InvalidArgument
28
29 from telepathy.interfaces import (CHANNEL_INTERFACE,
30                                   CHANNEL_INTERFACE_DTMF,
31                                   CHANNEL_INTERFACE_GROUP,
32                                   CHANNEL_INTERFACE_HOLD,
33                                   CHANNEL_INTERFACE_PASSWORD,
34                                   CHANNEL_TYPE_CONTACT_LIST,
35                                   CHANNEL_TYPE_FILE_TRANSFER,
36                                   CHANNEL_TYPE_ROOM_LIST,
37                                   CHANNEL_TYPE_STREAMED_MEDIA,
38                                   CHANNEL_TYPE_TEXT,
39                                   MEDIA_SESSION_HANDLER,
40                                   MEDIA_STREAM_HANDLER)
41
42 from telepathy._generated.Channel import Channel as _Channel
43
44 from properties import DBusProperties
45
46 from handle import NoneHandle
47
48 class Channel(_Channel, DBusProperties):
49
50     def __init__(self, connection, manager, props, object_path=None):
51         """
52         Initialise the base channel object.
53
54         Parameters:
55         connection - the parent Connection object
56         props - initial channel properties
57         """
58         self._conn = connection
59         self._chan_manager = manager
60
61         object_path = self._conn.get_channel_path(object_path)
62         _Channel.__init__(self, self._conn._name, object_path)
63
64         self._type = props[CHANNEL_INTERFACE + '.ChannelType']
65         self._requested = props[CHANNEL_INTERFACE + '.Requested']
66
67         self._immutable_properties = dict()
68
69         tht = props.get(CHANNEL_INTERFACE + '.TargetHandleType', HANDLE_TYPE_NONE)
70
71         if tht == HANDLE_TYPE_NONE:
72             self._handle = NoneHandle()
73         else:
74             self._handle = self._conn.get_handle_by_id(
75                 props[CHANNEL_INTERFACE + '.TargetHandleType'],
76                 props[CHANNEL_INTERFACE + '.TargetHandle'])
77
78         self._interfaces = set()
79
80         DBusProperties.__init__(self)
81         self._implement_property_get(CHANNEL_INTERFACE,
82             {'ChannelType': lambda: dbus.String(self.GetChannelType()),
83              'Interfaces': lambda: dbus.Array(self.GetInterfaces(), signature='s'),
84              'TargetHandle': lambda: dbus.UInt32(self._handle.get_id()),
85              'TargetHandleType': lambda: dbus.UInt32(self._handle.get_type()),
86              'TargetID': lambda: dbus.String(self._handle.get_name()),
87              'Requested': lambda: self._requested})
88
89         self._add_immutables({
90             'ChannelType': CHANNEL_INTERFACE,
91             'TargetHandle': CHANNEL_INTERFACE,
92             'Interfaces': CHANNEL_INTERFACE,
93             'TargetHandleType': CHANNEL_INTERFACE,
94             'TargetID': CHANNEL_INTERFACE,
95             'Requested': CHANNEL_INTERFACE
96             })
97
98     def _add_immutables(self, props):
99         self._immutable_properties.update(props)
100
101     def get_props(self):
102         """Despite its name, this function actually only returns immutable channel
103         properties."""
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         return (self._handle.get_type(), self._handle.get_id())
127
128     @dbus.service.method(CHANNEL_INTERFACE, in_signature='', out_signature='as')
129     def GetInterfaces(self):
130         """
131         Get the optional interfaces implemented by the channel.
132
133         Returns:
134         an array of the D-Bus interface names
135         """
136         return self._interfaces
137
138 from telepathy._generated.Channel_Type_Contact_List \
139         import ChannelTypeContactList as _ChannelTypeContactListIface
140
141 class ChannelTypeContactList(Channel, _ChannelTypeContactListIface):
142     __doc__ = _ChannelTypeContactListIface.__doc__
143
144     def __init__(self, connection, manager, props, object_path=None):
145         """
146         Initialise the channel.
147
148         Parameters:
149         connection - the parent Telepathy Connection object
150         """
151         Channel.__init__(self, connection, manager, props,
152             object_path=object_path)
153
154
155 from telepathy._generated.Channel_Type_File_Transfer \
156         import ChannelTypeFileTransfer as _ChannelTypeFileTransferIface
157
158 class ChannelTypeFileTransfer(Channel, _ChannelTypeFileTransferIface):
159     __doc__ = _ChannelTypeFileTransferIface.__doc__
160
161     def __init__(self, connection, manager, props, object_path=None):
162         """
163         Initialise the channel.
164
165         Parameters:
166         connection - the parent Telepathy Connection object
167         """
168         Channel.__init__(self, connection, manager, props,
169             object_path=object_path)
170
171
172 from telepathy._generated.Channel_Type_Streamed_Media \
173         import ChannelTypeStreamedMedia as _ChannelTypeStreamedMediaIface
174
175 class ChannelTypeStreamedMedia(Channel, _ChannelTypeStreamedMediaIface):
176     __doc__ = _ChannelTypeStreamedMediaIface.__doc__
177
178     def __init__(self, connection, manager, props, object_path=None):
179         """
180         Initialise the channel.
181
182         Parameters:
183         connection - the parent Telepathy Connection object
184         """
185         Channel.__init__(self, connection, manager, props,
186             object_path=object_path)
187
188
189 from telepathy._generated.Channel_Type_Room_List \
190         import ChannelTypeRoomList as _ChannelTypeRoomListIface
191
192 class ChannelTypeRoomList(Channel, _ChannelTypeRoomListIface):
193     __doc__ = _ChannelTypeRoomListIface.__doc__
194
195     def __init__(self, connection, manager, props, object_path=None):
196         """
197         Initialise the channel.
198
199         Parameters:
200         connection - the parent Telepathy Connection object
201         """
202         Channel.__init__(self, connection, manager, props,
203             object_path=object_path)
204         self._listing_rooms = False
205         self._rooms = {}
206
207         self._add_immutables({'Server': CHANNEL_TYPE_ROOM_LIST})
208
209     @dbus.service.method(CHANNEL_TYPE_ROOM_LIST, in_signature='', out_signature='b')
210     def GetListingRooms(self):
211         return self._listing_rooms
212
213     @dbus.service.signal(CHANNEL_TYPE_ROOM_LIST, signature='b')
214     def ListingRooms(self, listing):
215         self._listing_rooms = listing
216
217
218 from telepathy._generated.Channel_Type_Text \
219         import ChannelTypeText as _ChannelTypeTextIface
220
221 class ChannelTypeText(Channel, _ChannelTypeTextIface):
222     __doc__ = _ChannelTypeTextIface.__doc__
223
224     def __init__(self, connection, manager, props, object_path=None):
225         """
226         Initialise the channel.
227
228         Parameters:
229         connection - the parent Telepathy Connection object
230         """
231         Channel.__init__(self, connection, manager, props,
232             object_path=object_path)
233
234         self._pending_messages = {}
235         self._message_types = [CHANNEL_TEXT_MESSAGE_TYPE_NORMAL]
236
237     @dbus.service.method(CHANNEL_TYPE_TEXT, in_signature='', out_signature='au')
238     def GetMessageTypes(self):
239         """
240         Return an array indicating which types of message may be sent on this
241         channel.
242
243         Returns:
244         an array of integer message types as defined above
245         """
246         return self._message_types
247
248     @dbus.service.method(CHANNEL_TYPE_TEXT, in_signature='au', out_signature='')
249     def AcknowledgePendingMessages(self, ids):
250         """
251         Inform the channel that you have handled messages by displaying them to
252         the user (or equivalent), so they can be removed from the pending queue.
253
254         Parameters:
255         ids - the message to acknowledge
256
257         Possible Errors:
258         InvalidArgument (a given message ID was not found, no action taken)
259         """
260         for id in ids:
261             if id not in self._pending_messages:
262                 raise InvalidArgument("the given message ID was not found")
263
264         for id in ids:
265             del self._pending_messages[id]
266
267     @dbus.service.method(CHANNEL_TYPE_TEXT, in_signature='b', out_signature='a(uuuuus)')
268     def ListPendingMessages(self, clear):
269         """
270         List the messages currently in the pending queue, and optionally
271         remove then all.
272
273         Parameters:
274         clear - a boolean indicating whether the queue should be cleared
275
276         Returns:
277         an array of structs containing:
278             a numeric identifier
279             a unix timestamp indicating when the message was received
280             an integer handle of the contact who sent the message
281             an integer of the message type
282             a bitwise OR of the message flags
283             a string of the text of the message
284         """
285         messages = []
286         for id in self._pending_messages.keys():
287             (timestamp, sender, type, flags, text) = self._pending_messages[id]
288             message = (id, timestamp, sender, type, flags, text)
289             messages.append(message)
290             if clear:
291                 del self._pending_messages[id]
292         messages.sort(cmp=lambda x,y:cmp(x[1], y[1]))
293         return messages
294
295     @dbus.service.signal(CHANNEL_TYPE_TEXT, signature='uuuuus')
296     def Received(self, id, timestamp, sender, type, flags, text):
297         self._pending_messages[id] = (timestamp, sender, type, flags, text)
298
299
300 from telepathy._generated.Channel_Interface_Chat_State \
301         import ChannelInterfaceChatState
302
303
304 from telepathy._generated.Channel_Interface_DTMF import ChannelInterfaceDTMF
305
306
307 from telepathy._generated.Channel_Interface_Group \
308         import ChannelInterfaceGroup as _ChannelInterfaceGroup
309
310 class ChannelInterfaceGroup(_ChannelInterfaceGroup, DBusProperties):
311
312     def __init__(self):
313         _ChannelInterfaceGroup.__init__(self)
314         DBusProperties.__init__(self)
315
316         self._implement_property_get(CHANNEL_INTERFACE_GROUP,
317             {'GroupFlags': lambda: dbus.UInt32(self.GetGroupFlags()),
318              'Members': lambda: dbus.Array(self.GetMembers(), signature='u'),
319              'RemotePendingMembers': lambda: dbus.Array(self.GetRemotePendingMembers(), signature='u'),
320              'SelfHandle': lambda: dbus.UInt32(self.GetSelfHandle())})
321
322         self._group_flags = 0
323         self._members = set()
324         self._local_pending = set()
325         self._remote_pending = set()
326
327     @dbus.service.method(CHANNEL_INTERFACE_GROUP, in_signature='', out_signature='u')
328     def GetGroupFlags(self):
329         return self._group_flags
330
331     @dbus.service.signal(CHANNEL_INTERFACE_GROUP, signature='uu')
332     def GroupFlagsChanged(self, added, removed):
333         self._group_flags |= added
334         self._group_flags &= ~removed
335
336     @dbus.service.method(CHANNEL_INTERFACE_GROUP, in_signature='', out_signature='au')
337     def GetMembers(self):
338         return self._members
339
340     @dbus.service.method(CHANNEL_INTERFACE_GROUP, in_signature='', out_signature='u')
341     def GetSelfHandle(self):
342         self_handle = self._conn.GetSelfHandle()
343         if (self_handle in self._members or
344             self_handle in self._local_pending or
345             self_handle in self._remote_pending):
346             return self_handle
347         else:
348             return 0
349
350     @dbus.service.method(CHANNEL_INTERFACE_GROUP, in_signature='', out_signature='au')
351     def GetLocalPendingMembers(self):
352         return self._local_pending
353
354     @dbus.service.method(CHANNEL_INTERFACE_GROUP, in_signature='', out_signature='au')
355     def GetRemotePendingMembers(self):
356         return self._remote_pending
357
358     @dbus.service.method(CHANNEL_INTERFACE_GROUP, in_signature='', out_signature='auauau')
359     def GetAllMembers(self):
360         return (self._members, self._local_pending, self._remote_pending)
361
362     @dbus.service.signal(CHANNEL_INTERFACE_GROUP, signature='sauauauauuu')
363     def MembersChanged(self, message, added, removed, local_pending, remote_pending, actor, reason):
364
365         self._members.update(added)
366         self._members.difference_update(removed)
367
368         self._local_pending.update(local_pending)
369         self._local_pending.difference_update(added)
370         self._local_pending.difference_update(removed)
371
372         self._remote_pending.update(remote_pending)
373         self._remote_pending.difference_update(added)
374         self._remote_pending.difference_update(removed)
375
376
377 from telepathy._generated.Channel_Interface_Hold import ChannelInterfaceHold
378
379
380 # ChannelInterfaceMediaSignalling is in telepathy.server.media
381
382
383 from telepathy._generated.Channel_Interface_Password \
384         import ChannelInterfacePassword as _ChannelInterfacePassword
385
386 class ChannelInterfacePassword(_ChannelInterfacePassword):
387     def __init__(self):
388         _ChannelInterfacePassword.__init__(self)
389         self._password_flags = 0
390         self._password = ''
391
392     @dbus.service.method(CHANNEL_INTERFACE_PASSWORD, in_signature='', out_signature='u')
393     def GetPasswordFlags(self):
394         return self._password_flags
395
396     @dbus.service.signal(CHANNEL_INTERFACE_PASSWORD, signature='uu')
397     def PasswordFlagsChanged(self, added, removed):
398         self._password_flags |= added
399         self._password_flags &= ~removed
400
401
402 from telepathy._generated.Channel_Interface_Call_State import ChannelInterfaceCallState