9 except (ImportError, OSError):
15 except (ImportError, OSError):
19 import util.coroutines as coroutines
20 import util.go_utils as gobject_utils
21 import util.tp_utils as telepathy_utils
22 import util.misc as misc_utils
26 _moduleLogger = logging.getLogger(__name__)
29 class NewGVConversations(object):
31 def __init__(self, connRef):
32 self._connRef = connRef
33 self.__callback = None
36 self.__callback = coroutines.func_sink(
37 coroutines.expand_positional(
38 self._on_conversations_updated
41 self._connRef().session.voicemails.updateSignalHandler.register_sink(
44 self._connRef().session.texts.updateSignalHandler.register_sink(
49 if self.__callback is None:
50 _moduleLogger.info("New conversation monitor stopped without starting")
52 self._connRef().session.voicemails.updateSignalHandler.unregister_sink(
55 self._connRef().session.texts.updateSignalHandler.unregister_sink(
58 self.__callback = None
60 @misc_utils.log_exception(_moduleLogger)
61 def _on_conversations_updated(self, conv, conversationIds):
62 _moduleLogger.debug("Incoming messages from: %r" % (conversationIds, ))
63 for phoneNumber in conversationIds:
64 h = self._connRef().get_handle_by_name(telepathy.HANDLE_TYPE_CONTACT, phoneNumber)
65 # Just let the TextChannel decide whether it should be reported to the user or not
66 props = self._connRef().generate_props(telepathy.CHANNEL_TYPE_TEXT, h, False)
67 if self._connRef()._channel_manager.channel_exists(props):
68 _moduleLogger.debug("Chat box already open for texting conversation with %s" % phoneNumber)
71 # Maemo 4.1's RTComm opens a window for a chat regardless if a
72 # message is received or not, so we need to do some filtering here
73 mergedConv = conv.get_conversation(phoneNumber)
74 newConversations = mergedConv.conversations
75 newConversations = gvoice.conversations.filter_out_read(newConversations)
76 newConversations = gvoice.conversations.filter_out_self(newConversations)
77 newConversations = list(newConversations)
78 if not newConversations:
79 _moduleLogger.debug("Not opening chat box for %s, all new messages are either read or from yourself" % phoneNumber)
82 chan = self._connRef()._channel_manager.channel_for_props(props, signal=True)
85 class RefreshVoicemail(object):
87 def __init__(self, connRef):
88 self._isStarted = False
89 self._connRef = connRef
91 self._newChannelSignaller = telepathy_utils.NewChannelSignaller(self._on_new_channel)
92 self._outstandingRequests = []
95 self._newChannelSignaller.start()
96 self._isStarted = True
99 if not self._isStarted:
100 _moduleLogger.info("voicemail monitor stopped without starting")
102 _moduleLogger.info("Stopping voicemail refresh")
103 self._newChannelSignaller.stop()
105 # I don't want to trust whether the cancel happens within the current
106 # callback or not which could be the deciding factor between invalid
107 # iterators or infinite loops
108 localRequests = [r for r in self._outstandingRequests]
109 for request in localRequests:
110 localRequests.cancel()
112 self._isStarted = False
114 @misc_utils.log_exception(_moduleLogger)
115 def _on_new_channel(self, bus, serviceName, connObjectPath, channelObjectPath, channelType):
116 if channelType != telepathy.interfaces.CHANNEL_TYPE_STREAMED_MEDIA:
119 cmName = telepathy_utils.cm_from_path(connObjectPath)
120 if cmName == constants._telepathy_implementation_name_:
121 _moduleLogger.debug("Ignoring channels from self to prevent deadlock")
124 conn = telepathy.client.Connection(serviceName, connObjectPath)
126 chan = telepathy.client.Channel(serviceName, channelObjectPath)
127 except dbus.exceptions.UnknownMethodException:
128 _moduleLogger.exception("Client might not have implemented a deprecated method")
130 missDetection = telepathy_utils.WasMissedCall(
131 bus, conn, chan, self._on_missed_call, self._on_error_for_missed
133 self._outstandingRequests.append(missDetection)
135 @misc_utils.log_exception(_moduleLogger)
136 def _on_missed_call(self, missDetection):
137 _moduleLogger.info("Missed a call")
138 self._connRef().session.voicemailsStateMachine.reset_timers()
139 self._outstandingRequests.remove(missDetection)
141 @misc_utils.log_exception(_moduleLogger)
142 def _on_error_for_missed(self, missDetection, reason):
143 _moduleLogger.debug("Error: %r claims %r" % (missDetection, reason))
144 self._outstandingRequests.remove(missDetection)
147 class AutoAcceptGVCall(object):
149 def __init__(self, connRef):
150 self._connRef = connRef
151 self._isStarted = False
152 self._incomingCall = False
153 self._incomingChannel = False
155 self._newChannelSignaller = telepathy_utils.NewChannelSignaller(self._on_new_channel)
157 self._bus = dbus.SystemBus()
158 self._bus.add_signal_receiver(
160 path='/com/nokia/csd/call',
161 dbus_interface='com.nokia.csd.Call',
164 self._callObject = self._bus.get_object('com.nokia.csd.Call', '/com/nokia/csd/call/1')
165 self._callInstance = dbus.Interface(self._callObject, 'com.nokia.csd.Call.Instance')
168 self._newChannelSignaller.start()
169 self._isStarted = True
172 if not self._isStarted:
173 _moduleLogger.info("auto-accept monitor stopped without starting")
175 _moduleLogger.info("Stopping auto-accepting")
176 self._newChannelSignaller.stop()
178 self._incomingCall = False
179 self._incomingChannel = False
180 self._isStarted = False
182 @misc_utils.log_exception(_moduleLogger)
183 def _on_new_channel(self, bus, serviceName, connObjectPath, channelObjectPath, channelType):
184 if channelType != telepathy.interfaces.CHANNEL_TYPE_STREAMED_MEDIA:
187 cmName = telepathy_utils.cm_from_path(connObjectPath)
188 if cmName == constants._telepathy_implementation_name_:
189 _moduleLogger.debug("Ignoring channels from self to prevent deadlock")
192 conn = telepathy.client.Connection(serviceName, connObjectPath)
194 chan = telepathy.client.Channel(serviceName, channelObjectPath)
195 except dbus.exceptions.UnknownMethodException:
196 _moduleLogger.exception("Client might not have implemented a deprecated method")
199 chan[telepathy.interfaces.CHANNEL].connect_to_signal(
204 self._incomingChannel = True
205 self._accept_if_ready()
207 @misc_utils.log_exception(_moduleLogger)
208 def _on_incoming(self, objPath, callerNumber):
210 self._incomingCall = True
211 self._accept_if_ready()
213 @misc_utils.log_exception(_moduleLogger)
214 def _on_closed(self):
215 self._incomingCall = False
216 self._incomingChannel = False
219 class TimedDisconnect(object):
221 def __init__(self, connRef):
222 self._connRef = connRef
223 self.__delayedDisconnect = gobject_utils.Timeout(self._on_delayed_disconnect)
226 self.__delayedDisconnect.start(seconds=60)
229 self.__delayedDisconnect.cancel()
231 @misc_utils.log_exception(_moduleLogger)
232 def _on_delayed_disconnect(self):
233 _moduleLogger.info("Timed disconnect occurred")
234 self._connRef().disconnect(telepathy.CONNECTION_STATUS_REASON_NETWORK_ERROR)
237 class AutoDisconnect(object):
239 def __init__(self, connRef):
240 self._connRef = connRef
241 if conic is not None:
242 self.__connection = conic.Connection()
244 self.__connection = None
246 self.__connectionEventId = None
247 self.__delayedDisconnect = gobject_utils.Timeout(self._on_delayed_disconnect)
250 if self.__connection is not None:
251 self.__connectionEventId = self.__connection.connect("connection-event", self._on_connection_change)
254 self._cancel_delayed_disconnect()
256 @misc_utils.log_exception(_moduleLogger)
257 def _on_connection_change(self, connection, event):
261 status = event.get_status()
262 error = event.get_error()
263 iap_id = event.get_iap_id()
264 bearer = event.get_bearer_type()
266 if status == conic.STATUS_DISCONNECTED:
267 _moduleLogger.info("Disconnected from network, starting countdown to logoff")
268 self.__delayedDisconnect.start(seconds=5)
269 elif status == conic.STATUS_CONNECTED:
270 _moduleLogger.info("Connected to network")
271 self._cancel_delayed_disconnect()
273 _moduleLogger.info("Other status: %r" % (status, ))
275 @misc_utils.log_exception(_moduleLogger)
276 def _cancel_delayed_disconnect(self):
277 _moduleLogger.info("Cancelling auto-log off")
278 self.__delayedDisconnect.cancel()
280 @misc_utils.log_exception(_moduleLogger)
281 def _on_delayed_disconnect(self):
282 if not self._connRef().session.is_logged_in():
283 _moduleLogger.info("Received connection change event when not logged in")
286 self._connRef().disconnect(telepathy.CONNECTION_STATUS_REASON_NETWORK_ERROR)
288 _moduleLogger.exception("Error durring disconnect")
291 class DisconnectOnShutdown(object):
293 I'm unsure when I get notified of shutdown or if I have enough time to do
294 anything about it, but thought this might help
297 def __init__(self, connRef):
298 self._connRef = connRef
301 self._deviceState = None
305 self._osso = osso.Context(constants.__app_name__, constants.__version__, False)
306 self._deviceState = osso.DeviceState(self._osso)
307 self._deviceState.set_device_state_callback(self._on_device_state_change, 0)
309 _moduleLogger.warning("No device state support")
313 self._deviceState.close()
314 except AttributeError:
315 pass # Either None or close was removed (in Fremantle)
316 self._deviceState = None
319 except AttributeError:
320 pass # Either None or close was removed (in Fremantle)
323 @misc_utils.log_exception(_moduleLogger)
324 def _on_device_state_change(self, shutdown, save_unsaved_data, memory_low, system_inactivity, message, userData):
326 @note Hildon specific
329 self._connRef().disconnect(telepathy.CONNECTION_STATUS_REASON_REQUESTED)
331 _moduleLogger.exception("Error durring disconnect")
334 class DelayEnableContactIntegration(object):
336 def __init__(self, protocolName):
337 self.__enableSystemContactSupport = telepathy_utils.EnableSystemContactIntegration(
340 self.__delayedEnable = gobject_utils.Async(self._on_delayed_enable)
343 self.__delayedEnable.start()
346 self.__delayedEnable.cancel()
348 @misc_utils.log_exception(_moduleLogger)
349 def _on_delayed_enable(self):
351 self.__enableSystemContactSupport.start()
352 except dbus.DBusException, e:
353 _moduleLogger.info("Contact integration seems to not be supported (%s)" % e)