4 sys.path.insert(0,"../src")
10 import dbus.mainloop.glib
13 import util.go_utils as gobject_utils
17 _moduleLogger = logging.getLogger("receptionist")
18 DBUS_PROPERTIES = 'org.freedesktop.DBus.Properties'
21 class AutoAcceptCall(object):
23 def __init__(self, bus, conn, chan, on_success, on_error):
24 self._sessionBus = bus
27 self._outstandingRequests = []
28 self._on_success = on_success
29 self._on_error = on_error
31 self._initiatorHandle = None
32 self._initiatorID = None
33 self._targetHandle = None
35 self._requested = None
36 self._pendingHandles = None
38 self._chan[DBUS_PROPERTIES].GetAll(
39 telepathy.interfaces.CHANNEL_INTERFACE,
40 reply_handler = self._on_got_all,
41 error_handler = self._custom_error(self._on_got_all),
43 self._outstandingRequests.append(self._on_got_all)
46 # @bug Unsure why this isn't working
47 self._chan[DBUS_PROPERTIES].Get(
48 telepathy.interfaces.CHANNEL_INTERFACE_GROUP,
49 'LocalPendingMembers',
50 reply_handler = self._on_got_pending_members,
51 error_handler = self._custom_error(self._on_got_pending_members),
54 self._chan[telepathy.interfaces.CHANNEL_INTERFACE_GROUP].GetLocalPendingMembersWithInfo(
55 reply_handler = self._on_got_pending_members,
56 error_handler = self._custom_error(self._on_got_pending_members),
58 self._outstandingRequests.append(self._on_got_pending_members)
61 return not self._requested
62 isInbound = self._targetHandle == self._initiatorHandle
67 return self._initiatorID
73 def accept_call(self, on_accepted, on_error):
74 self._chan[telepathy.interfaces.CHANNEL_INTERFACE_GROUP].AddMembers(
77 reply_handler = self._custom_on_accept(on_accepted),
78 error_handler = self._custom_on_accept_error(on_error),
81 def _custom_on_accept(self, callback):
88 def _custom_on_accept_error(self, callback):
95 def _custom_error(self, action):
98 _moduleLogger.error("Failed for %r (%r)" % (action, args))
99 self._outstandingRequests.remove(action)
100 if self._outstandingRequests:
107 def _report_callback_done(self, action):
108 _moduleLogger.debug("Succeded with %r" % (action, ))
109 self._outstandingRequests.remove(action)
110 if self._outstandingRequests:
114 self._initiatorHandle,
118 self._pendingHandles,
122 self._on_success(self)
124 @gtk_toolbox.log_exception(_moduleLogger)
125 def _on_got_all(self, properties):
126 self._initiatorID = properties["InitiatorID"]
127 self._initiatorHandle = properties["InitiatorHandle"]
128 self._targetID = properties["InitiatorID"]
129 self._targetHandle = properties["InitiatorHandle"]
130 self._requested = properties["Requested"]
132 self._report_callback_done(self._on_got_all)
134 @gtk_toolbox.log_exception(_moduleLogger)
135 def _on_got_pending_members(self, pendings):
136 for pendingHandle, instigatorHandle, reason, message in pendings:
137 print pendingHandle, instigatorHandle, reason, message
139 self._pendingHandles = [pendingWithInfo[0] for pendingWithInfo in pendings]
141 self._report_callback_done(self._on_got_pending_members)
144 class WasMissedCall(object):
146 def __init__(self, bus, conn, chan, on_success, on_error):
147 self._sessionBus = bus
150 self._on_success = on_success
151 self._on_error = on_error
153 self._requested = None
154 self._didMembersChange = False
155 self._didClose = False
156 self._didReport = False
158 self._timeoutId = gobject_utils.timeout_add_seconds(10, self._on_timeout)
160 self._chan[telepathy.interfaces.CHANNEL_INTERFACE_GROUP].connect_to_signal(
162 self._on_members_changed,
165 self._chan[telepathy.interfaces.CHANNEL].connect_to_signal(
170 self._chan[DBUS_PROPERTIES].GetAll(
171 telepathy.interfaces.CHANNEL_INTERFACE,
172 reply_handler = self._on_got_all,
173 error_handler = self._on_got_all,
176 def _report_missed_if_ready(self):
179 elif self._requested is not None and (self._didMembersChange or self._didClose):
181 self._report_error("wrong direction")
183 self._report_success()
185 self._report_error("members added")
188 self._report_error("closed too early")
190 def _report_success(self):
191 assert not self._didReport
192 self._didReport = True
194 gobject.source_remove(self._timeoutId)
195 self._timeoutId = None
196 self._on_success(self)
198 def _report_error(self, reason):
199 assert not self._didReport
200 self._didReport = True
202 gobject.source_remove(self._timeoutId)
203 self._timeoutId = None
204 self._on_error(self, reason)
206 @gtk_toolbox.log_exception(_moduleLogger)
207 @gtk_toolbox.trace(_moduleLogger)
208 def _on_got_all(self, properties):
209 self._requested = properties["Requested"]
210 self._report_missed_if_ready()
212 @gtk_toolbox.log_exception(_moduleLogger)
213 @gtk_toolbox.trace(_moduleLogger)
214 def _on_members_changed(self, message, added, removed, lp, rp, actor, reason):
215 pprint.pprint((message, added, removed, lp, rp, actor, reason))
217 self._didMembersChange = True
218 self._report_missed_if_ready()
220 @gtk_toolbox.log_exception(_moduleLogger)
221 @gtk_toolbox.trace(_moduleLogger)
222 def _on_closed(self):
223 self._didClose = True
224 self._report_missed_if_ready()
226 @gtk_toolbox.log_exception(_moduleLogger)
227 @gtk_toolbox.trace(_moduleLogger)
228 def _on_error(self, *args):
229 self._report_error(args)
231 @gtk_toolbox.log_exception(_moduleLogger)
232 @gtk_toolbox.trace(_moduleLogger)
233 def _on_timeout(self):
234 self._report_error("timeout")
238 class NewChannelSignaller(object):
240 def __init__(self, on_new_channel):
241 self._sessionBus = dbus.SessionBus()
242 self._on_user_new_channel = on_new_channel
245 self._sessionBus.add_signal_receiver(
246 self._on_new_channel,
248 "org.freedesktop.Telepathy.Connection",
254 self._sessionBus.remove_signal_receiver(
255 self._on_new_channel,
257 "org.freedesktop.Telepathy.Connection",
262 @gtk_toolbox.log_exception(_moduleLogger)
264 self, channelObjectPath, channelType, handleType, handle, supressHandler
266 connObjectPath = channelObjectPath.rsplit("/", 1)[0]
267 serviceName = connObjectPath[1:].replace("/", ".")
268 conn = telepathy.client.Connection(serviceName, connObjectPath)
269 chan = telepathy.client.Channel(serviceName, channelObjectPath)
270 self._on_user_new_channel(self._sessionBus, conn, chan, channelType)
273 class AutoAcceptManager(object):
276 self._newChannelSignaller = NewChannelSignaller(self._on_new_channel)
279 self._newChannelSignaller.start()
281 @gtk_toolbox.log_exception(_moduleLogger)
282 def _on_new_channel(self, bus, conn, chan, channelType):
283 pprint.pprint((bus, conn, chan, channelType))
284 if channelType != telepathy.interfaces.CHANNEL_TYPE_STREAMED_MEDIA:
287 # @todo distinguish between preferred CMs
288 attemptPickup = AutoAcceptCall(bus, conn, chan, self._on_inbound_call, self._on_inbound_call_error)
290 @gtk_toolbox.log_exception(_moduleLogger)
291 def _on_inbound_call(self, autoAcceptCall):
292 # @todo Add a comparison for picking up for only certain contacts
293 print autoAcceptCall.initiator, autoAcceptCall.target
294 if autoAcceptCall.is_inbound():
295 autoAcceptCall.accept_call(self._on_call_pickedup, self._on_pickup_error)
298 "Not an inbound call (initiator=%r, target=%r)" % (autoAcceptCall.initiator, autoAcceptCall.target)
301 @gtk_toolbox.log_exception(_moduleLogger)
302 def _on_inbound_call_error(self, *args):
303 _moduleLogger.info("Inbound call error")
305 @gtk_toolbox.log_exception(_moduleLogger)
306 def _on_call_pickedup(self, autoAcceptCall):
307 _moduleLogger.info("Call picked up")
309 @gtk_toolbox.log_exception(_moduleLogger)
310 def _on_pickup_error(self, autoAcceptCall, *args):
311 _moduleLogger.info("Call failed to pick up (%r)" % (args, ))
314 class MissedManager(object):
317 self._newChannelSignaller = NewChannelSignaller(self._on_new_channel)
320 self._newChannelSignaller.start()
322 @gtk_toolbox.log_exception(_moduleLogger)
323 def _on_new_channel(self, bus, conn, chan, channelType):
324 pprint.pprint((bus, conn, chan, channelType))
325 if channelType != telepathy.interfaces.CHANNEL_TYPE_STREAMED_MEDIA:
328 missDetection = WasMissedCall(
329 bus, conn, chan, self._on_missed_call, self._on_error_for_missed
332 @gtk_toolbox.log_exception(_moduleLogger)
333 def _on_missed_call(self, missDetection):
334 _moduleLogger.info("Missed a call")
336 @gtk_toolbox.log_exception(_moduleLogger)
337 def _on_error_for_missed(self, missDetection, reason):
338 _moduleLogger.info("Error: %r claims %r" % (missDetection, reason))
341 if __name__ == "__main__":
342 logging.basicConfig(level=logging.DEBUG)
343 l = dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
345 manager = AutoAcceptManager()
347 manager = MissedManager()
349 gobject.threads_init()
350 gobject.idle_add(manager.start)
352 mainloop = gobject.MainLoop(is_running=True)