9ae525b60fafbea10799413b235a88a75f7fd235
[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 misc
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._onTimeout = misc.Timeout(self._on_timeout)
29                 self._onTimeout.start(seconds=10)
30
31                 chan[telepathy.interfaces.CHANNEL_INTERFACE_GROUP].connect_to_signal(
32                         "MembersChanged",
33                         self._on_members_changed,
34                 )
35
36                 chan[telepathy.interfaces.CHANNEL].connect_to_signal(
37                         "Closed",
38                         self._on_closed,
39                 )
40
41                 chan[DBUS_PROPERTIES].GetAll(
42                         telepathy.interfaces.CHANNEL_INTERFACE,
43                         reply_handler = self._on_got_all,
44                         error_handler = self._on_got_all,
45                 )
46
47         def cancel(self):
48                 self._report_error("by request")
49
50         def _report_missed_if_ready(self):
51                 if self._didReport:
52                         pass
53                 elif self._requested is not None and (self._didMembersChange or self._didClose):
54                         if self._requested:
55                                 self._report_error("wrong direction")
56                         elif self._didClose:
57                                 self._report_success()
58                         else:
59                                 self._report_error("members added")
60                 else:
61                         if self._didClose:
62                                 self._report_error("closed too early")
63
64         def _report_success(self):
65                 assert not self._didReport
66                 self._didReport = True
67                 self._onTimeout.cancel()
68                 self._on_success(self)
69
70         def _report_error(self, reason):
71                 assert not self._didReport
72                 self._didReport = True
73                 self._onTimeout.cancel()
74                 self._on_error(self, reason)
75
76         @misc.log_exception(_moduleLogger)
77         def _on_got_all(self, properties):
78                 self._requested = properties["Requested"]
79                 self._report_missed_if_ready()
80
81         @misc.log_exception(_moduleLogger)
82         def _on_members_changed(self, message, added, removed, lp, rp, actor, reason):
83                 if added:
84                         self._didMembersChange = True
85                         self._report_missed_if_ready()
86
87         @misc.log_exception(_moduleLogger)
88         def _on_closed(self):
89                 self._didClose = True
90                 self._report_missed_if_ready()
91
92         @misc.log_exception(_moduleLogger)
93         def _on_error(self, *args):
94                 self._report_error(args)
95
96         @misc.log_exception(_moduleLogger)
97         def _on_timeout(self):
98                 self._report_error("timeout")
99                 return False
100
101
102 class NewChannelSignaller(object):
103
104         def __init__(self, on_new_channel):
105                 self._sessionBus = dbus.SessionBus()
106                 self._on_user_new_channel = on_new_channel
107
108         def start(self):
109                 self._sessionBus.add_signal_receiver(
110                         self._on_new_channel,
111                         "NewChannel",
112                         "org.freedesktop.Telepathy.Connection",
113                         None,
114                         None
115                 )
116
117         def stop(self):
118                 self._sessionBus.remove_signal_receiver(
119                         self._on_new_channel,
120                         "NewChannel",
121                         "org.freedesktop.Telepathy.Connection",
122                         None,
123                         None
124                 )
125
126         @misc.log_exception(_moduleLogger)
127         def _on_new_channel(
128                 self, channelObjectPath, channelType, handleType, handle, supressHandler
129         ):
130                 connObjectPath = channel_path_to_conn_path(channelObjectPath)
131                 serviceName = path_to_service_name(channelObjectPath)
132                 self._on_user_new_channel(
133                         self._sessionBus, serviceName, connObjectPath, channelObjectPath, channelType
134                 )
135
136
137 def channel_path_to_conn_path(channelObjectPath):
138         """
139         >>> channel_path_to_conn_path("/org/freedesktop/Telepathy/ConnectionManager/theonering/sip/USERNAME/Channel1")
140         '/org/freedesktop/Telepathy/ConnectionManager/theonering/sip/USERNAME'
141         """
142         return channelObjectPath.rsplit("/", 1)[0]
143
144
145 def path_to_service_name(path):
146         """
147         >>> path_to_service_name("/org/freedesktop/Telepathy/ConnectionManager/theonering/sip/USERNAME/Channel1")
148         'org.freedesktop.Telepathy.ConnectionManager.theonering.sip.USERNAME'
149         """
150         return ".".join(path[1:].split("/")[0:7])
151
152
153 def cm_from_path(path):
154         """
155         >>> cm_from_path("/org/freedesktop/Telepathy/ConnectionManager/theonering/sip/USERNAME/Channel1")
156         'theonering'
157         """
158         return path[1:].split("/")[4]