8 except (ImportError, OSError):
14 except (ImportError, OSError):
18 import util.coroutines as coroutines
19 import util.go_utils as gobject_utils
20 import util.tp_utils as telepathy_utils
21 import util.misc as misc_utils
25 _moduleLogger = logging.getLogger("autogv")
28 class NewGVConversations(object):
30 def __init__(self, connRef):
31 self._connRef = connRef
32 self.__callback = None
35 self.__callback = coroutines.func_sink(
36 coroutines.expand_positional(
37 self._on_conversations_updated
40 self._connRef().session.voicemails.updateSignalHandler.register_sink(
43 self._connRef().session.texts.updateSignalHandler.register_sink(
48 if self.__callback is None:
49 _moduleLogger.info("New conversation monitor stopped without starting")
51 self._connRef().session.voicemails.updateSignalHandler.unregister_sink(
54 self._connRef().session.texts.updateSignalHandler.unregister_sink(
57 self.__callback = None
59 @misc_utils.log_exception(_moduleLogger)
60 def _on_conversations_updated(self, conv, conversationIds):
61 _moduleLogger.debug("Incoming messages from: %r" % (conversationIds, ))
62 for phoneNumber in conversationIds:
63 h = self._connRef().get_handle_by_name(telepathy.HANDLE_TYPE_CONTACT, phoneNumber)
64 # Just let the TextChannel decide whether it should be reported to the user or not
65 props = self._connRef().generate_props(telepathy.CHANNEL_TYPE_TEXT, h, False)
66 if self._connRef()._channel_manager.channel_exists(props):
69 # Maemo 4.1's RTComm opens a window for a chat regardless if a
70 # message is received or not, so we need to do some filtering here
71 mergedConv = conv.get_conversation(phoneNumber)
72 newConversations = mergedConv.conversations
73 newConversations = gvoice.conversations.filter_out_read(newConversations)
74 newConversations = gvoice.conversations.filter_out_self(newConversations)
75 newConversations = list(newConversations)
76 if not newConversations:
79 chan = self._connRef()._channel_manager.channel_for_props(props, signal=True)
82 class RefreshVoicemail(object):
84 def __init__(self, connRef):
85 self._connRef = connRef
86 self._newChannelSignaller = telepathy_utils.NewChannelSignaller(self._on_new_channel)
87 self._outstandingRequests = []
88 self._isStarted = False
91 self._newChannelSignaller.start()
92 self._isStarted = True
95 if not self._isStarted:
96 _moduleLogger.info("voicemail monitor stopped without starting")
98 _moduleLogger.info("Stopping voicemail refresh")
99 self._newChannelSignaller.stop()
101 # I don't want to trust whether the cancel happens within the current
102 # callback or not which could be the deciding factor between invalid
103 # iterators or infinite loops
104 localRequests = [r for r in self._outstandingRequests]
105 for request in localRequests:
106 localRequests.cancel()
108 self._isStarted = False
110 @misc_utils.log_exception(_moduleLogger)
111 def _on_new_channel(self, bus, serviceName, connObjectPath, channelObjectPath, channelType):
112 if channelType != telepathy.interfaces.CHANNEL_TYPE_STREAMED_MEDIA:
115 cmName = telepathy_utils.cm_from_path(connObjectPath)
116 if cmName == constants._telepathy_implementation_name_:
117 _moduleLogger.debug("Ignoring channels from self to prevent deadlock")
120 conn = telepathy.client.Connection(serviceName, connObjectPath)
121 chan = telepathy.client.Channel(serviceName, channelObjectPath)
122 missDetection = telepathy_utils.WasMissedCall(
123 bus, conn, chan, self._on_missed_call, self._on_error_for_missed
125 self._outstandingRequests.append(missDetection)
127 @misc_utils.log_exception(_moduleLogger)
128 def _on_missed_call(self, missDetection):
129 _moduleLogger.info("Missed a call")
130 self._connRef().session.voicemailsStateMachine.reset_timers()
131 self._outstandingRequests.remove(missDetection)
133 @misc_utils.log_exception(_moduleLogger)
134 def _on_error_for_missed(self, missDetection, reason):
135 _moduleLogger.debug("Error: %r claims %r" % (missDetection, reason))
136 self._outstandingRequests.remove(missDetection)
139 class AutoDisconnect(object):
141 def __init__(self, connRef):
142 self._connRef = connRef
143 if conic is not None:
144 self.__connection = conic.Connection()
146 self.__connection = None
148 self.__connectionEventId = None
149 self.__delayedDisconnect = gobject_utils.Timeout(self._on_delayed_disconnect)
152 if self.__connection is not None:
153 self.__connectionEventId = self.__connection.connect("connection-event", self._on_connection_change)
156 self._cancel_delayed_disconnect()
158 @misc_utils.log_exception(_moduleLogger)
159 def _on_connection_change(self, connection, event):
163 status = event.get_status()
164 error = event.get_error()
165 iap_id = event.get_iap_id()
166 bearer = event.get_bearer_type()
168 if status == conic.STATUS_DISCONNECTED:
169 _moduleLogger.info("Disconnected from network, starting countdown to logoff")
170 self.__delayedDisconnect.start(seconds=5)
171 elif status == conic.STATUS_CONNECTED:
172 _moduleLogger.info("Connected to network")
173 self._cancel_delayed_disconnect()
175 _moduleLogger.info("Other status: %r" % (status, ))
177 def _cancel_delayed_disconnect(self):
178 _moduleLogger.info("Cancelling auto-log off")
179 self.__delayedDisconnect.cancel()
181 @misc_utils.log_exception(_moduleLogger)
182 def _on_delayed_disconnect(self):
183 if not self._connRef().session.is_logged_in():
184 _moduleLogger.info("Received connection change event when not logged in")
187 self._connRef().disconnect(telepathy.CONNECTION_STATUS_REASON_NETWORK_ERROR)
189 _moduleLogger.exception("Error durring disconnect")
192 class DisconnectOnShutdown(object):
194 I'm unsure when I get notified of shutdown or if I have enough time to do
195 anything about it, but thought this might help
198 def __init__(self, connRef):
199 self._connRef = connRef
202 self._deviceState = None
206 self._osso = osso.Context(constants.__app_name__, constants.__version__, False)
207 self._deviceState = osso.DeviceState(self._osso)
208 self._deviceState.set_device_state_callback(self._on_device_state_change, 0)
210 _moduleLogger.warning("No device state support")
214 self._deviceState.close()
215 except AttributeError:
216 pass # Either None or close was removed (in Fremantle)
217 self._deviceState = None
220 except AttributeError:
221 pass # Either None or close was removed (in Fremantle)
224 @misc_utils.log_exception(_moduleLogger)
225 def _on_device_state_change(self, shutdown, save_unsaved_data, memory_low, system_inactivity, message, userData):
227 @note Hildon specific
230 self._connRef().disconnect(telepathy.CONNECTION_STATUS_REASON_REQUESTED)
232 _moduleLogger.exception("Error durring disconnect")