Added detection of missed calls. As part of this I moved some of the connections...
[theonering] / src / util / tp_utils.py
1 #!/usr/bin/env python
2
3 import logging
4
5 import gobject
6 import dbus
7 import telepathy
8
9 import util.go_utils as gobject_utils
10 import gtk_toolbox
11
12
13 _moduleLogger = logging.getLogger("tp_utils")
14 DBUS_PROPERTIES = 'org.freedesktop.DBus.Properties'
15
16
17 class WasMissedCall(object):
18
19         def __init__(self, bus, conn, chan, on_success, on_error):
20                 self._on_success = on_success
21                 self._on_error = on_error
22
23                 self._requested = None
24                 self._didMembersChange = False
25                 self._didClose = False
26                 self._didReport = False
27
28                 self._timeoutId = gobject_utils.timeout_add_seconds(10, self._on_timeout)
29
30                 chan[telepathy.interfaces.CHANNEL_INTERFACE_GROUP].connect_to_signal(
31                         "MembersChanged",
32                         self._on_members_changed,
33                 )
34
35                 chan[telepathy.interfaces.CHANNEL].connect_to_signal(
36                         "Closed",
37                         self._on_closed,
38                 )
39
40                 chan[DBUS_PROPERTIES].GetAll(
41                         telepathy.interfaces.CHANNEL_INTERFACE,
42                         reply_handler = self._on_got_all,
43                         error_handler = self._on_got_all,
44                 )
45
46         def cancel(self):
47                 self._report_error("by request")
48
49         def _report_missed_if_ready(self):
50                 if self._didReport:
51                         pass
52                 elif self._requested is not None and (self._didMembersChange or self._didClose):
53                         if self._requested:
54                                 self._report_error("wrong direction")
55                         elif self._didClose:
56                                 self._report_success()
57                         else:
58                                 self._report_error("members added")
59                 else:
60                         if self._didClose:
61                                 self._report_error("closed too early")
62
63         def _report_success(self):
64                 assert not self._didReport
65                 self._didReport = True
66                 if self._timeoutId:
67                         gobject.source_remove(self._timeoutId)
68                         self._timeoutId = None
69                 self._on_success(self)
70
71         def _report_error(self, reason):
72                 assert not self._didReport
73                 self._didReport = True
74                 if self._timeoutId:
75                         gobject.source_remove(self._timeoutId)
76                         self._timeoutId = None
77                 self._on_error(self, reason)
78
79         @gtk_toolbox.log_exception(_moduleLogger)
80         def _on_got_all(self, properties):
81                 self._requested = properties["Requested"]
82                 self._report_missed_if_ready()
83
84         @gtk_toolbox.log_exception(_moduleLogger)
85         def _on_members_changed(self, message, added, removed, lp, rp, actor, reason):
86                 if added:
87                         self._didMembersChange = True
88                         self._report_missed_if_ready()
89
90         @gtk_toolbox.log_exception(_moduleLogger)
91         def _on_closed(self):
92                 self._didClose = True
93                 self._report_missed_if_ready()
94
95         @gtk_toolbox.log_exception(_moduleLogger)
96         def _on_error(self, *args):
97                 self._report_error(args)
98
99         @gtk_toolbox.log_exception(_moduleLogger)
100         def _on_timeout(self):
101                 self._report_error("timeout")
102                 return False
103
104
105 class NewChannelSignaller(object):
106
107         def __init__(self, on_new_channel):
108                 self._sessionBus = dbus.SessionBus()
109                 self._on_user_new_channel = on_new_channel
110
111         def start(self):
112                 self._sessionBus.add_signal_receiver(
113                         self._on_new_channel,
114                         "NewChannel",
115                         "org.freedesktop.Telepathy.Connection",
116                         None,
117                         None
118                 )
119
120         def stop(self):
121                 self._sessionBus.remove_signal_receiver(
122                         self._on_new_channel,
123                         "NewChannel",
124                         "org.freedesktop.Telepathy.Connection",
125                         None,
126                         None
127                 )
128
129         @gtk_toolbox.log_exception(_moduleLogger)
130         def _on_new_channel(
131                 self, channelObjectPath, channelType, handleType, handle, supressHandler
132         ):
133                 connObjectPath = channel_path_to_conn_path(channelObjectPath)
134                 serviceName = path_to_service_name(channelObjectPath)
135                 self._on_user_new_channel(
136                         self._sessionBus, serviceName, connObjectPath, channelObjectPath, channelType
137                 )
138
139
140 def channel_path_to_conn_path(channelObjectPath):
141         """
142         >>> channel_path_to_conn_path("/org/freedesktop/Telepathy/ConnectionManager/theonering/sip/USERNAME/Channel1")
143         '/org/freedesktop/Telepathy/ConnectionManager/theonering/sip/USERNAME'
144         """
145         return channelObjectPath.rsplit("/", 1)[0]
146
147
148 def path_to_service_name(path):
149         """
150         >>> path_to_service_name("/org/freedesktop/Telepathy/ConnectionManager/theonering/sip/USERNAME/Channel1")
151         'org.freedesktop.Telepathy.ConnectionManager.theonering.sip.USERNAME'
152         """
153         return ".".join(path[1:].split("/")[0:7])
154
155
156 def cm_from_path(path):
157         """
158         >>> cm_from_path("/org/freedesktop/Telepathy/ConnectionManager/theonering/sip/USERNAME/Channel1")
159         'theonering'
160         """
161         return path[1:].split("/")[4]