Auto-enabled system contacts for all contacts
[theonering] / src / autogv.py
index 0a960c8..9a0f61e 100644 (file)
@@ -1,6 +1,6 @@
 import logging
 
-import gobject
+import dbus
 import telepathy
 
 try:
@@ -9,14 +9,21 @@ try:
 except (ImportError, OSError):
        conic = None
 
+try:
+       import osso as _osso
+       osso = _osso
+except (ImportError, OSError):
+       osso = None
+
 import constants
 import util.coroutines as coroutines
 import util.go_utils as gobject_utils
 import util.tp_utils as telepathy_utils
-import gtk_toolbox
+import util.misc as misc_utils
+import gvoice
 
 
-_moduleLogger = logging.getLogger("autogv")
+_moduleLogger = logging.getLogger(__name__)
 
 
 class NewGVConversations(object):
@@ -39,6 +46,9 @@ class NewGVConversations(object):
                )
 
        def stop(self):
+               if self.__callback is None:
+                       _moduleLogger.info("New conversation monitor stopped without starting")
+                       return
                self._connRef().session.voicemails.updateSignalHandler.unregister_sink(
                        self.__callback
                )
@@ -47,7 +57,7 @@ class NewGVConversations(object):
                )
                self.__callback = None
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def _on_conversations_updated(self, conv, conversationIds):
                _moduleLogger.debug("Incoming messages from: %r" % (conversationIds, ))
                for phoneNumber in conversationIds:
@@ -60,12 +70,11 @@ class NewGVConversations(object):
                        # Maemo 4.1's RTComm opens a window for a chat regardless if a
                        # message is received or not, so we need to do some filtering here
                        mergedConv = conv.get_conversation(phoneNumber)
-                       unreadConvs = [
-                               conversation
-                               for conversation in mergedConv.conversations
-                               if not conversation.isRead and not conversation.isArchived
-                       ]
-                       if not unreadConvs:
+                       newConversations = mergedConv.conversations
+                       newConversations = gvoice.conversations.filter_out_read(newConversations)
+                       newConversations = gvoice.conversations.filter_out_self(newConversations)
+                       newConversations = list(newConversations)
+                       if not newConversations:
                                continue
 
                        chan = self._connRef()._channel_manager.channel_for_props(props, signal=True)
@@ -77,11 +86,16 @@ class RefreshVoicemail(object):
                self._connRef = connRef
                self._newChannelSignaller = telepathy_utils.NewChannelSignaller(self._on_new_channel)
                self._outstandingRequests = []
+               self._isStarted = False
 
        def start(self):
                self._newChannelSignaller.start()
+               self._isStarted = True
 
        def stop(self):
+               if not self._isStarted:
+                       _moduleLogger.info("voicemail monitor stopped without starting")
+                       return
                _moduleLogger.info("Stopping voicemail refresh")
                self._newChannelSignaller.stop()
 
@@ -92,7 +106,9 @@ class RefreshVoicemail(object):
                for request in localRequests:
                        localRequests.cancel()
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+               self._isStarted = False
+
+       @misc_utils.log_exception(_moduleLogger)
        def _on_new_channel(self, bus, serviceName, connObjectPath, channelObjectPath, channelType):
                if channelType != telepathy.interfaces.CHANNEL_TYPE_STREAMED_MEDIA:
                        return
@@ -103,24 +119,46 @@ class RefreshVoicemail(object):
                        return
 
                conn = telepathy.client.Connection(serviceName, connObjectPath)
-               chan = telepathy.client.Channel(serviceName, channelObjectPath)
+               try:
+                       chan = telepathy.client.Channel(serviceName, channelObjectPath)
+               except dbus.exceptions.UnknownMethodException:
+                       _moduleLogger.exception("Client might not have implemented a deprecated method")
+                       return
                missDetection = telepathy_utils.WasMissedCall(
                        bus, conn, chan, self._on_missed_call, self._on_error_for_missed
                )
                self._outstandingRequests.append(missDetection)
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def _on_missed_call(self, missDetection):
                _moduleLogger.info("Missed a call")
                self._connRef().session.voicemailsStateMachine.reset_timers()
                self._outstandingRequests.remove(missDetection)
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def _on_error_for_missed(self, missDetection, reason):
                _moduleLogger.debug("Error: %r claims %r" % (missDetection, reason))
                self._outstandingRequests.remove(missDetection)
 
 
+class TimedDisconnect(object):
+
+       def __init__(self, connRef):
+               self._connRef = connRef
+               self.__delayedDisconnect = gobject_utils.Timeout(self._on_delayed_disconnect)
+
+       def start(self):
+               self.__delayedDisconnect.start(seconds=20)
+
+       def stop(self):
+               self.__delayedDisconnect.cancel()
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_delayed_disconnect(self):
+               _moduleLogger.info("Timed disconnect occurred")
+               self._connRef().disconnect(telepathy.CONNECTION_STATUS_REASON_NETWORK_ERROR)
+
+
 class AutoDisconnect(object):
 
        def __init__(self, connRef):
@@ -131,7 +169,7 @@ class AutoDisconnect(object):
                        self.__connection = None
 
                self.__connectionEventId = None
-               self.__delayedDisconnectEventId = None
+               self.__delayedDisconnect = gobject_utils.Timeout(self._on_delayed_disconnect)
 
        def start(self):
                if self.__connection is not None:
@@ -140,7 +178,7 @@ class AutoDisconnect(object):
        def stop(self):
                self._cancel_delayed_disconnect()
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def _on_connection_change(self, connection, event):
                """
                @note Maemo specific
@@ -152,31 +190,86 @@ class AutoDisconnect(object):
 
                if status == conic.STATUS_DISCONNECTED:
                        _moduleLogger.info("Disconnected from network, starting countdown to logoff")
-                       self.__delayedDisconnectEventId = gobject_utils.timeout_add_seconds(
-                               5, self._on_delayed_disconnect
-                       )
+                       self.__delayedDisconnect.start(seconds=5)
                elif status == conic.STATUS_CONNECTED:
                        _moduleLogger.info("Connected to network")
                        self._cancel_delayed_disconnect()
                else:
                        _moduleLogger.info("Other status: %r" % (status, ))
 
+       @misc_utils.log_exception(_moduleLogger)
        def _cancel_delayed_disconnect(self):
-               if self.__delayedDisconnectEventId is None:
-                       return
                _moduleLogger.info("Cancelling auto-log off")
-               gobject.source_reove(self.__delayedDisconnectEventId)
-               self.__delayedDisconnectEventId = None
+               self.__delayedDisconnect.cancel()
 
-       @gtk_toolbox.log_exception(_moduleLogger)
+       @misc_utils.log_exception(_moduleLogger)
        def _on_delayed_disconnect(self):
-               if not self.session.is_logged_in():
+               if not self._connRef().session.is_logged_in():
                        _moduleLogger.info("Received connection change event when not logged in")
                        return
                try:
                        self._connRef().disconnect(telepathy.CONNECTION_STATUS_REASON_NETWORK_ERROR)
                except Exception:
                        _moduleLogger.exception("Error durring disconnect")
-               self.__delayedDisconnectEventId = None
-               return False
 
+
+class DisconnectOnShutdown(object):
+       """
+       I'm unsure when I get notified of shutdown or if I have enough time to do
+       anything about it, but thought this might help
+       """
+
+       def __init__(self, connRef):
+               self._connRef = connRef
+
+               self._osso = None
+               self._deviceState = None
+
+       def start(self):
+               if osso is not None:
+                       self._osso = osso.Context(constants.__app_name__, constants.__version__, False)
+                       self._deviceState = osso.DeviceState(self._osso)
+                       self._deviceState.set_device_state_callback(self._on_device_state_change, 0)
+               else:
+                       _moduleLogger.warning("No device state support")
+
+       def stop(self):
+               try:
+                       self._deviceState.close()
+               except AttributeError:
+                       pass # Either None or close was removed (in Fremantle)
+               self._deviceState = None
+               try:
+                       self._osso.close()
+               except AttributeError:
+                       pass # Either None or close was removed (in Fremantle)
+               self._osso = None
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_device_state_change(self, shutdown, save_unsaved_data, memory_low, system_inactivity, message, userData):
+               """
+               @note Hildon specific
+               """
+               try:
+                       self._connRef().disconnect(telepathy.CONNECTION_STATUS_REASON_REQUESTED)
+               except Exception:
+                       _moduleLogger.exception("Error durring disconnect")
+
+
+class DelayEnableContactIntegration(object):
+
+       def __init__(self, protocolName):
+               self.__enableSystemContactSupport = telepathy_utils.EnableSystemContactIntegration(
+                       protocolName
+               )
+               self.__delayedEnable = gobject_utils.Async(self._on_delayed_enable)
+
+       def start(self):
+               self.__delayedEnable.start()
+
+       def stop(self):
+               self.__delayedEnable.cancel()
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_delayed_enable(self):
+               self.__enableSystemContactSupport.start()