]> git.0d.be Git - empathy.git/blobdiff - libempathy/empathy-idle.c
Merge branch 'sasl'
[empathy.git] / libempathy / empathy-idle.c
index 17813473869cbf306dfbc778260fd351cfdf8c84..12686daa4e449472395bb4f8cee6fb611d3ac43e 100644 (file)
@@ -15,7 +15,7 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- * 
+ *
  * Authors: Xavier Claessens <xclaesse@gmail.com>
  */
 
 #include <glib/gi18n-lib.h>
 #include <dbus/dbus-glib.h>
 
+#include <telepathy-glib/account-manager.h>
 #include <telepathy-glib/dbus.h>
 #include <telepathy-glib/util.h>
-#include <libmissioncontrol/mc-enum-types.h>
 
 #include "empathy-idle.h"
-#include "empathy-utils.h" 
+#include "empathy-utils.h"
+#include "empathy-connectivity.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
 #include "empathy-debug.h"
 /* Number of seconds before entering extended autoaway. */
 #define EXT_AWAY_TIME (30*60)
 
+/* Number of seconds to consider an account in the "just connected" state
+ * for. */
+#define ACCOUNT_IS_JUST_CONNECTED_SECONDS 10
+
 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyIdle)
 typedef struct {
-       MissionControl *mc;
        DBusGProxy     *gs_proxy;
-       DBusGProxy     *nm_proxy;
+       EmpathyConnectivity *connectivity;
+       gulong state_change_signal_id;
+
+       gboolean ready;
 
-       McPresence      state;
+       TpConnectionPresenceType      state;
        gchar          *status;
-       McPresence      flash_state;
        gboolean        auto_away;
-       gboolean        use_nm;
 
-       McPresence      away_saved_state;
-       McPresence      nm_saved_state;
-       gchar          *nm_saved_status;
+       TpConnectionPresenceType      away_saved_state;
+       TpConnectionPresenceType      saved_state;
+       gchar          *saved_status;
 
        gboolean        is_idle;
-       gboolean        nm_connected;
        guint           ext_away_timeout;
+
+       TpAccountManager *manager;
+       gulong idle_presence_changed_id;
+
+       /* pointer to a TpAccount --> glong of time of connection */
+       GHashTable *connect_times;
+
+       TpConnectionPresenceType requested_presence_type;
+       gchar *requested_status_message;
+
 } EmpathyIdlePriv;
 
 typedef enum {
-       NM_STATE_UNKNOWN,
-       NM_STATE_ASLEEP,
-       NM_STATE_CONNECTING,
-       NM_STATE_CONNECTED,
-       NM_STATE_DISCONNECTED
-} NMState;
+       SESSION_STATUS_AVAILABLE,
+       SESSION_STATUS_INVISIBLE,
+       SESSION_STATUS_BUSY,
+       SESSION_STATUS_IDLE,
+       SESSION_STATUS_UNKNOWN
+} SessionStatus;
 
 enum {
        PROP_0,
        PROP_STATE,
        PROP_STATUS,
-       PROP_FLASH_STATE,
-       PROP_AUTO_AWAY,
-       PROP_USE_NM
+       PROP_AUTO_AWAY
 };
 
 G_DEFINE_TYPE (EmpathyIdle, empathy_idle, G_TYPE_OBJECT);
 
 static EmpathyIdle * idle_singleton = NULL;
 
+static const gchar *presence_type_to_status[NUM_TP_CONNECTION_PRESENCE_TYPES] = {
+       NULL,
+       "offline",
+       "available",
+       "away",
+       "xa",
+       "hidden",
+       "busy",
+       NULL,
+       NULL,
+};
+
 static void
-idle_presence_changed_cb (MissionControl *mc,
-                         McPresence      state,
+idle_presence_changed_cb (TpAccountManager *manager,
+                         TpConnectionPresenceType state,
                          gchar          *status,
+                         gchar          *status_message,
                          EmpathyIdle    *idle)
 {
        EmpathyIdlePriv *priv;
 
        priv = GET_PRIV (idle);
 
-       DEBUG ("Presence changed to '%s' (%d)", status, state);
+       if (state == TP_CONNECTION_PRESENCE_TYPE_UNSET)
+               /* Assume our presence is offline if MC reports UNSET */
+               state = TP_CONNECTION_PRESENCE_TYPE_OFFLINE;
+
+       DEBUG ("Presence changed to '%s' (%d) \"%s\"", status, state,
+               status_message);
 
        g_free (priv->status);
        priv->state = state;
-       priv->status = NULL;
-       if (!EMP_STR_EMPTY (status)) {
-               priv->status = g_strdup (status);
-       }
+       if (EMP_STR_EMPTY (status_message))
+               priv->status = NULL;
+       else
+               priv->status = g_strdup (status_message);
 
        g_object_notify (G_OBJECT (idle), "state");
        g_object_notify (G_OBJECT (idle), "status");
@@ -112,7 +142,7 @@ idle_ext_away_cb (EmpathyIdle *idle)
        priv = GET_PRIV (idle);
 
        DEBUG ("Going to extended autoaway");
-       empathy_idle_set_state (idle, MC_PRESENCE_EXTENDED_AWAY);
+       empathy_idle_set_state (idle, TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY);
        priv->ext_away_timeout = 0;
 
        return FALSE;
@@ -147,22 +177,25 @@ idle_ext_away_start (EmpathyIdle *idle)
 }
 
 static void
-idle_session_idle_changed_cb (DBusGProxy  *gs_proxy,
-                             gboolean     is_idle,
-                             EmpathyIdle *idle)
+idle_session_status_changed_cb (DBusGProxy    *gs_proxy,
+                               SessionStatus  status,
+                               EmpathyIdle   *idle)
 {
        EmpathyIdlePriv *priv;
+       gboolean is_idle;
 
        priv = GET_PRIV (idle);
 
+       is_idle = (status == SESSION_STATUS_IDLE);
+
        DEBUG ("Session idle state changed, %s -> %s",
                priv->is_idle ? "yes" : "no",
                is_idle ? "yes" : "no");
 
        if (!priv->auto_away ||
-           (priv->nm_saved_state == MC_PRESENCE_UNSET &&
-            (priv->state <= MC_PRESENCE_OFFLINE ||
-             priv->state == MC_PRESENCE_HIDDEN))) {
+           (priv->saved_state == TP_CONNECTION_PRESENCE_TYPE_UNSET &&
+            (priv->state <= TP_CONNECTION_PRESENCE_TYPE_OFFLINE ||
+             priv->state == TP_CONNECTION_PRESENCE_TYPE_HIDDEN))) {
                /* We don't want to go auto away OR we explicitely asked to be
                 * offline, nothing to do here */
                priv->is_idle = is_idle;
@@ -170,99 +203,85 @@ idle_session_idle_changed_cb (DBusGProxy  *gs_proxy,
        }
 
        if (is_idle && !priv->is_idle) {
-               McPresence new_state;
+               TpConnectionPresenceType new_state;
                /* We are now idle */
 
                idle_ext_away_start (idle);
 
-               if (priv->nm_saved_state != MC_PRESENCE_UNSET) {
+               if (priv->saved_state != TP_CONNECTION_PRESENCE_TYPE_UNSET) {
                        /* We are disconnected, when coming back from away
                         * we want to restore the presence before the
                         * disconnection. */
-                       priv->away_saved_state = priv->nm_saved_state;
+                       priv->away_saved_state = priv->saved_state;
                } else {
                        priv->away_saved_state = priv->state;
                }
 
-               new_state = MC_PRESENCE_AWAY;
-               if (priv->state == MC_PRESENCE_EXTENDED_AWAY) {
-                       new_state = MC_PRESENCE_EXTENDED_AWAY;
+               new_state = TP_CONNECTION_PRESENCE_TYPE_AWAY;
+               if (priv->state == TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY) {
+                       new_state = TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY;
                }
 
                DEBUG ("Going to autoaway. Saved state=%d, new state=%d",
                        priv->away_saved_state, new_state);
                empathy_idle_set_state (idle, new_state);
        } else if (!is_idle && priv->is_idle) {
-               const gchar *new_status;
                /* We are no more idle, restore state */
 
                idle_ext_away_stop (idle);
 
-               if (priv->away_saved_state == MC_PRESENCE_AWAY ||
-                   priv->away_saved_state == MC_PRESENCE_EXTENDED_AWAY) {
-                       priv->away_saved_state = MC_PRESENCE_AVAILABLE;
-                       new_status = NULL;
+               /* Only try and set the presence if the away saved state is not
+                * unset. This is an odd case because it means that the session
+                * didn't notify us of the state change to idle, and as a
+                * result, we couldn't save the current state at that time.
+                */
+               if (priv->away_saved_state != TP_CONNECTION_PRESENCE_TYPE_UNSET) {
+                       DEBUG ("Restoring state to %d",
+                               priv->away_saved_state);
+
+                       empathy_idle_set_state (idle,priv->away_saved_state);
                } else {
-                       new_status = priv->status;
+                       DEBUG ("Away saved state is unset. This means that we "
+                              "weren't told when the session went idle. "
+                              "As a result, I'm not trying to set presence");
                }
 
-               DEBUG ("Restoring state to %d, reset status to %s",
-                       priv->away_saved_state, new_status);
-
-               empathy_idle_set_presence (idle,
-                                          priv->away_saved_state,
-                                          new_status);
-
-               priv->away_saved_state = MC_PRESENCE_UNSET;
+               priv->away_saved_state = TP_CONNECTION_PRESENCE_TYPE_UNSET;
        }
 
        priv->is_idle = is_idle;
 }
 
 static void
-idle_nm_state_change_cb (DBusGProxy  *proxy,
-                        guint        state,
-                        EmpathyIdle *idle)
+idle_state_change_cb (EmpathyConnectivity *connectivity,
+                     gboolean new_online,
+                     EmpathyIdle *idle)
 {
        EmpathyIdlePriv *priv;
-       gboolean         old_nm_connected;
-       gboolean         new_nm_connected;
 
        priv = GET_PRIV (idle);
 
-       if (!priv->use_nm) {
-               return;
-       }
-
-       old_nm_connected = priv->nm_connected;
-       new_nm_connected = !(state == NM_STATE_CONNECTING ||
-                            state == NM_STATE_DISCONNECTED);
-       priv->nm_connected = TRUE; /* To be sure _set_state will work */
-
-       DEBUG ("New network state %d", state);
-
-       if (old_nm_connected && !new_nm_connected) {
-               /* We are no more connected */
+       if (!new_online) {
+               /* We are no longer connected */
                DEBUG ("Disconnected: Save state %d (%s)",
                                priv->state, priv->status);
-               priv->nm_saved_state = priv->state;
-               g_free (priv->nm_saved_status);
-               priv->nm_saved_status = g_strdup (priv->status);
-               empathy_idle_set_state (idle, MC_PRESENCE_OFFLINE);
+               priv->saved_state = priv->state;
+               g_free (priv->saved_status);
+               priv->saved_status = g_strdup (priv->status);
+               empathy_idle_set_state (idle, TP_CONNECTION_PRESENCE_TYPE_OFFLINE);
        }
-       else if (!old_nm_connected && new_nm_connected) {
+       else if (new_online
+                       && priv->saved_state != TP_CONNECTION_PRESENCE_TYPE_UNSET) {
                /* We are now connected */
                DEBUG ("Reconnected: Restore state %d (%s)",
-                               priv->nm_saved_state, priv->nm_saved_status);
+                               priv->saved_state, priv->saved_status);
                empathy_idle_set_presence (idle,
-                               priv->nm_saved_state,
-                               priv->nm_saved_status);
-               priv->nm_saved_state = MC_PRESENCE_UNSET;
-               g_free (priv->nm_saved_status);
-               priv->nm_saved_status = NULL;
+                               priv->saved_state,
+                               priv->saved_status);
+               priv->saved_state = TP_CONNECTION_PRESENCE_TYPE_UNSET;
+               g_free (priv->saved_status);
+               priv->saved_status = NULL;
        }
-
-       priv->nm_connected = new_nm_connected;
 }
 
 static void
@@ -273,12 +292,27 @@ idle_finalize (GObject *object)
        priv = GET_PRIV (object);
 
        g_free (priv->status);
-       g_object_unref (priv->mc);
+       g_free (priv->requested_status_message);
 
        if (priv->gs_proxy) {
                g_object_unref (priv->gs_proxy);
        }
 
+       g_signal_handler_disconnect (priv->connectivity,
+                                    priv->state_change_signal_id);
+       priv->state_change_signal_id = 0;
+
+       if (priv->manager != NULL) {
+               g_signal_handler_disconnect (priv->manager,
+                       priv->idle_presence_changed_id);
+               g_object_unref (priv->manager);
+       }
+
+       g_object_unref (priv->connectivity);
+
+       g_hash_table_destroy (priv->connect_times);
+       priv->connect_times = NULL;
+
        idle_ext_away_stop (EMPATHY_IDLE (object));
 }
 
@@ -296,12 +330,30 @@ idle_constructor (GType type,
                        (type, n_props, props);
 
                idle_singleton = EMPATHY_IDLE (retval);
-               g_object_add_weak_pointer (retval, (gpointer *) &idle_singleton);
+               g_object_add_weak_pointer (retval, (gpointer) &idle_singleton);
        }
 
        return retval;
 }
 
+static const gchar *
+empathy_idle_get_status (EmpathyIdle *idle)
+{
+       EmpathyIdlePriv *priv;
+
+       priv = GET_PRIV (idle);
+
+       if (G_UNLIKELY (!priv->ready))
+               g_critical (G_STRLOC ": %s called before AccountManager ready",
+                               G_STRFUNC);
+
+       if (!priv->status) {
+               return empathy_presence_get_default_message (priv->state);
+       }
+
+       return priv->status;
+}
+
 static void
 idle_get_property (GObject    *object,
                   guint       param_id,
@@ -321,15 +373,9 @@ idle_get_property (GObject    *object,
        case PROP_STATUS:
                g_value_set_string (value, empathy_idle_get_status (idle));
                break;
-       case PROP_FLASH_STATE:
-               g_value_set_enum (value, empathy_idle_get_flash_state (idle));
-               break;
        case PROP_AUTO_AWAY:
                g_value_set_boolean (value, empathy_idle_get_auto_away (idle));
                break;
-       case PROP_USE_NM:
-               g_value_set_boolean (value, empathy_idle_get_use_nm (idle));
-               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
                break;
@@ -355,15 +401,9 @@ idle_set_property (GObject      *object,
        case PROP_STATUS:
                empathy_idle_set_status (idle, g_value_get_string (value));
                break;
-       case PROP_FLASH_STATE:
-               empathy_idle_set_flash_state (idle, g_value_get_enum (value));
-               break;
        case PROP_AUTO_AWAY:
                empathy_idle_set_auto_away (idle, g_value_get_boolean (value));
                break;
-       case PROP_USE_NM:
-               empathy_idle_set_use_nm (idle, g_value_get_boolean (value));
-               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
                break;
@@ -382,11 +422,11 @@ empathy_idle_class_init (EmpathyIdleClass *klass)
 
        g_object_class_install_property (object_class,
                                         PROP_STATE,
-                                        g_param_spec_enum ("state",
+                                        g_param_spec_uint ("state",
                                                            "state",
                                                            "state",
-                                                           MC_TYPE_PRESENCE,
-                                                           MC_PRESENCE_AVAILABLE,
+                                                           0, NUM_TP_CONNECTION_PRESENCE_TYPES,
+                                                           TP_CONNECTION_PRESENCE_TYPE_UNSET,
                                                            G_PARAM_READWRITE));
        g_object_class_install_property (object_class,
                                         PROP_STATUS,
@@ -395,14 +435,6 @@ empathy_idle_class_init (EmpathyIdleClass *klass)
                                                              "status",
                                                              NULL,
                                                              G_PARAM_READWRITE));
-       g_object_class_install_property (object_class,
-                                        PROP_FLASH_STATE,
-                                        g_param_spec_enum ("flash-state",
-                                                           "flash-state",
-                                                           "flash-state",
-                                                           MC_TYPE_PRESENCE,
-                                                           MC_PRESENCE_UNSET,
-                                                           G_PARAM_READWRITE));
 
         g_object_class_install_property (object_class,
                                          PROP_AUTO_AWAY,
@@ -412,88 +444,118 @@ empathy_idle_class_init (EmpathyIdleClass *klass)
                                                                FALSE,
                                                                G_PARAM_READWRITE));
 
-        g_object_class_install_property (object_class,
-                                         PROP_USE_NM,
-                                         g_param_spec_boolean ("use-nm",
-                                                               "Use Network Manager",
-                                                               "Set presence according to Network Manager",
-                                                               FALSE,
-                                                               G_PARAM_READWRITE));
-
        g_type_class_add_private (object_class, sizeof (EmpathyIdlePriv));
 }
 
+static void
+account_status_changed_cb (TpAccount  *account,
+                          guint       old_status,
+                          guint       new_status,
+                          guint       reason,
+                          gchar      *dbus_error_name,
+                          GHashTable *details,
+                          gpointer    user_data)
+{
+       EmpathyIdle *idle = EMPATHY_IDLE (user_data);
+       EmpathyIdlePriv *priv = GET_PRIV (idle);
+       GTimeVal val;
+
+       if (new_status == TP_CONNECTION_STATUS_CONNECTED) {
+               g_get_current_time (&val);
+               g_hash_table_insert (priv->connect_times, account,
+                                    GINT_TO_POINTER (val.tv_sec));
+       } else if (new_status == TP_CONNECTION_STATUS_DISCONNECTED) {
+               g_hash_table_remove (priv->connect_times, account);
+       }
+}
+
+static void
+account_manager_ready_cb (GObject *source_object,
+                         GAsyncResult *result,
+                         gpointer user_data)
+{
+       EmpathyIdle *idle = user_data;
+       TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object);
+       EmpathyIdlePriv *priv;
+       TpConnectionPresenceType state;
+       gchar *status, *status_message;
+       GList *accounts, *l;
+       GError *error = NULL;
+
+       /* In case we've been finalized before reading this callback */
+       if (idle_singleton == NULL)
+               return;
+
+       priv = GET_PRIV (idle);
+       priv->ready = TRUE;
+
+       if (!tp_account_manager_prepare_finish (account_manager, result, &error)) {
+               DEBUG ("Failed to prepare account manager: %s", error->message);
+               g_error_free (error);
+               return;
+       }
+
+       state = tp_account_manager_get_most_available_presence (priv->manager,
+               &status, &status_message);
+
+       idle_presence_changed_cb (account_manager, state, status,
+               status_message, idle);
+
+       accounts = tp_account_manager_get_valid_accounts (priv->manager);
+       for (l = accounts; l != NULL; l = l->next) {
+               tp_g_signal_connect_object (l->data, "status-changed",
+                                            G_CALLBACK (account_status_changed_cb),
+                                            idle, 0);
+       }
+       g_list_free (accounts);
+
+       g_free (status);
+       g_free (status_message);
+}
+
 static void
 empathy_idle_init (EmpathyIdle *idle)
 {
-       DBusGConnection *system_bus;
-       GError          *error = NULL;
        EmpathyIdlePriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (idle,
                EMPATHY_TYPE_IDLE, EmpathyIdlePriv);
+       TpDBusDaemon *dbus;
 
        idle->priv = priv;
        priv->is_idle = FALSE;
-       priv->mc = empathy_mission_control_dup_singleton ();
-       priv->state = mission_control_get_presence_actual (priv->mc, &error);
-       if (error) {
-               DEBUG ("Error getting actual presence: %s", error->message);
 
-               priv->state = MC_PRESENCE_UNSET;
-               g_clear_error (&error);
-       }
-       priv->status = mission_control_get_presence_message_actual (priv->mc, &error);
-       if (error || EMP_STR_EMPTY (priv->status)) {
-               g_free (priv->status);
-               priv->status = NULL;
+       priv->manager = tp_account_manager_dup ();
 
-               if (error) {
-                       DEBUG ("Error getting actual presence message: %s", error->message);
-                       g_clear_error (&error);
-               }
-       }
+       tp_account_manager_prepare_async (priv->manager, NULL,
+           account_manager_ready_cb, idle);
+
+       priv->idle_presence_changed_id = g_signal_connect (priv->manager,
+               "most-available-presence-changed",
+               G_CALLBACK (idle_presence_changed_cb), idle);
 
-       dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc),
-                                    "PresenceChanged",
-                                    G_CALLBACK (idle_presence_changed_cb),
-                                    idle, NULL);
+       dbus = tp_dbus_daemon_dup (NULL);
 
-       priv->gs_proxy = dbus_g_proxy_new_for_name (tp_get_bus (),
-                                                   "org.gnome.ScreenSaver",
-                                                   "/org/gnome/ScreenSaver",
-                                                   "org.gnome.ScreenSaver");
+       priv->gs_proxy = dbus_g_proxy_new_for_name (
+                                                   tp_proxy_get_dbus_connection (dbus),
+                                                   "org.gnome.SessionManager",
+                                                   "/org/gnome/SessionManager/Presence",
+                                                   "org.gnome.SessionManager.Presence");
        if (priv->gs_proxy) {
-               dbus_g_proxy_add_signal (priv->gs_proxy, "SessionIdleChanged",
-                                        G_TYPE_BOOLEAN,
-                                        G_TYPE_INVALID);
-               dbus_g_proxy_connect_signal (priv->gs_proxy, "SessionIdleChanged",
-                                            G_CALLBACK (idle_session_idle_changed_cb),
+               dbus_g_proxy_add_signal (priv->gs_proxy, "StatusChanged",
+                                        G_TYPE_UINT, G_TYPE_INVALID);
+               dbus_g_proxy_connect_signal (priv->gs_proxy, "StatusChanged",
+                                            G_CALLBACK (idle_session_status_changed_cb),
                                             idle, NULL);
        } else {
                DEBUG ("Failed to get gs proxy");
        }
 
+       g_object_unref (dbus);
 
-       system_bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
-       if (!system_bus) {
-               DEBUG ("Failed to get system bus: %s",
-                       error ? error->message : "No error given");
-       } else {
-               priv->nm_proxy = dbus_g_proxy_new_for_name (system_bus,
-                                                           "org.freedesktop.NetworkManager",
-                                                           "/org/freedesktop/NetworkManager",
-                                                           "org.freedesktop.NetworkManager");
-       }
-       if (priv->nm_proxy) {
-               dbus_g_proxy_add_signal (priv->nm_proxy, "StateChange",
-                                        G_TYPE_UINT, G_TYPE_INVALID);
-               dbus_g_proxy_connect_signal (priv->nm_proxy, "StateChange",
-                                            G_CALLBACK (idle_nm_state_change_cb),
-                                            idle, NULL);
-       } else {
-               DEBUG ("Failed to get nm proxy");
-       }
+       priv->connectivity = empathy_connectivity_dup_singleton ();
+       priv->state_change_signal_id = g_signal_connect (priv->connectivity,
+           "state-change", G_CALLBACK (idle_state_change_cb), idle);
 
-       priv->nm_connected = TRUE;
+       priv->connect_times = g_hash_table_new (g_direct_hash, g_direct_equal);
 }
 
 EmpathyIdle *
@@ -502,19 +564,23 @@ empathy_idle_dup_singleton (void)
        return g_object_new (EMPATHY_TYPE_IDLE, NULL);
 }
 
-McPresence
+TpConnectionPresenceType
 empathy_idle_get_state (EmpathyIdle *idle)
 {
        EmpathyIdlePriv *priv;
 
        priv = GET_PRIV (idle);
 
+       if (G_UNLIKELY (!priv->ready))
+               g_critical (G_STRLOC ": %s called before AccountManager ready",
+                               G_STRFUNC);
+
        return priv->state;
 }
 
 void
 empathy_idle_set_state (EmpathyIdle *idle,
-                       McPresence   state)
+                       TpConnectionPresenceType   state)
 {
        EmpathyIdlePriv *priv;
 
@@ -523,20 +589,6 @@ empathy_idle_set_state (EmpathyIdle *idle,
        empathy_idle_set_presence (idle, state, priv->status);
 }
 
-const gchar *
-empathy_idle_get_status (EmpathyIdle *idle)
-{
-       EmpathyIdlePriv *priv;
-
-       priv = GET_PRIV (idle);
-
-       if (!priv->status) {
-               return empathy_presence_get_default_message (priv->state);
-       }
-
-       return priv->status;
-}
-
 void
 empathy_idle_set_status (EmpathyIdle *idle,
                         const gchar *status)
@@ -548,35 +600,33 @@ empathy_idle_set_status (EmpathyIdle *idle,
        empathy_idle_set_presence (idle, priv->state, status);
 }
 
-McPresence
-empathy_idle_get_flash_state (EmpathyIdle *idle)
-{
-       EmpathyIdlePriv *priv;
-
-       priv = GET_PRIV (idle);
-
-       return priv->flash_state;
-}
-
-void
-empathy_idle_set_flash_state (EmpathyIdle *idle,
-                             McPresence   state)
+static void
+empathy_idle_do_set_presence (EmpathyIdle *idle,
+                          TpConnectionPresenceType status_type,
+                          const gchar *status_message)
 {
-       EmpathyIdlePriv *priv;
+       EmpathyIdlePriv *priv = GET_PRIV (idle);
+       const gchar *status;
 
-       priv = GET_PRIV (idle);
+       g_assert (status_type > 0 && status_type < NUM_TP_CONNECTION_PRESENCE_TYPES);
 
-       priv->flash_state = state;
+       status = presence_type_to_status[status_type];
 
-       if (state == MC_PRESENCE_UNSET) {
-       }
+       g_return_if_fail (status != NULL);
 
-       g_object_notify (G_OBJECT (idle), "flash-state");
+       /* We possibly should be sure that the account manager is prepared, but
+        * sometimes this isn't possible, like when exiting. In other words,
+        * we need a callback to empathy_idle_set_presence to be sure the
+        * presence is set on all accounts successfully.
+        * However, in practice, this is fine as we've already prepared the
+        * account manager here in _init. */
+       tp_account_manager_set_all_requested_presences (priv->manager,
+               status_type, status, status_message);
 }
 
 void
 empathy_idle_set_presence (EmpathyIdle *idle,
-                          McPresence   state,
+                          TpConnectionPresenceType   state,
                           const gchar *status)
 {
        EmpathyIdlePriv *priv;
@@ -586,29 +636,32 @@ empathy_idle_set_presence (EmpathyIdle *idle,
 
        DEBUG ("Changing presence to %s (%d)", status, state);
 
+       g_free (priv->requested_status_message);
+       priv->requested_presence_type = state;
+       priv->requested_status_message = g_strdup (status);
+
        /* Do not set translated default messages */
        default_status = empathy_presence_get_default_message (state);
        if (!tp_strdiff (status, default_status)) {
                status = NULL;
        }
 
-       if (!priv->nm_connected) {
-               DEBUG ("NM not connected");
+       if (state != TP_CONNECTION_PRESENCE_TYPE_OFFLINE &&
+                       !empathy_connectivity_is_online (priv->connectivity)) {
+               DEBUG ("Empathy is not online");
 
-               priv->nm_saved_state = state;
+               priv->saved_state = state;
                if (tp_strdiff (priv->status, status)) {
-                       g_free (priv->status);
-                       priv->status = NULL;
+                       g_free (priv->saved_status);
+                       priv->saved_status = NULL;
                        if (!EMP_STR_EMPTY (status)) {
-                               priv->status = g_strdup (status);
+                               priv->saved_status = g_strdup (status);
                        }
-                       g_object_notify (G_OBJECT (idle), "status");
                }
-
                return;
        }
 
-       mission_control_set_presence (priv->mc, state, status, NULL, NULL);
+       empathy_idle_do_set_presence (idle, state, status);
 }
 
 gboolean
@@ -630,51 +683,50 @@ empathy_idle_set_auto_away (EmpathyIdle *idle,
        g_object_notify (G_OBJECT (idle), "auto-away");
 }
 
-gboolean
-empathy_idle_get_use_nm (EmpathyIdle *idle)
+TpConnectionPresenceType
+empathy_idle_get_requested_presence (EmpathyIdle *idle,
+    gchar **status,
+    gchar **status_message)
 {
        EmpathyIdlePriv *priv = GET_PRIV (idle);
 
-       return priv->use_nm;
+       if (status != NULL) {
+               *status = g_strdup (presence_type_to_status[priv->requested_presence_type]);
+       }
+
+       if (status_message != NULL) {
+               *status_message = g_strdup (priv->requested_status_message);
+       }
+
+       return priv->requested_presence_type;
 }
 
-void
-empathy_idle_set_use_nm (EmpathyIdle *idle,
-                        gboolean     use_nm)
+/* This function returns %TRUE if EmpathyIdle considers the account
+ * @account as having just connected recently. Otherwise, it returns
+ * %FALSE. In doubt, %FALSE is returned. */
+gboolean
+empathy_idle_account_is_just_connected (EmpathyIdle *idle,
+                                       TpAccount *account)
 {
        EmpathyIdlePriv *priv = GET_PRIV (idle);
+       GTimeVal val;
+       gpointer ptr;
+       glong t;
 
-       if (!priv->nm_proxy || use_nm == priv->use_nm) {
-               return;
+       if (tp_account_get_connection_status (account, NULL)
+           != TP_CONNECTION_STATUS_CONNECTED) {
+               return FALSE;
        }
 
-       priv->use_nm = use_nm;
+       ptr = g_hash_table_lookup (priv->connect_times, account);
 
-       if (use_nm) {
-               guint   nm_status;
-               GError *error = NULL;
+       if (ptr == NULL) {
+               return FALSE;
+       }
 
-               dbus_g_proxy_call (priv->nm_proxy, "state",
-                                  &error,
-                                  G_TYPE_INVALID,
-                                  G_TYPE_UINT, &nm_status,
-                                  G_TYPE_INVALID);
+       t = GPOINTER_TO_INT (ptr);
 
-               if (error) {
-                       DEBUG ("Couldn't get NM state: %s", error->message);
-                       g_clear_error (&error);
-                       nm_status = NM_STATE_ASLEEP;
-               }
-               
-               idle_nm_state_change_cb (priv->nm_proxy, nm_status, idle);
-       } else {
-               priv->nm_connected = TRUE;
-               if (priv->nm_saved_state != MC_PRESENCE_UNSET) {
-                       empathy_idle_set_state (idle, priv->nm_saved_state);
-               }
-               priv->nm_saved_state = MC_PRESENCE_UNSET;
-       }
+       g_get_current_time (&val);
 
-       g_object_notify (G_OBJECT (idle), "use-nm");
+       return (val.tv_sec - t) < ACCOUNT_IS_JUST_CONNECTED_SECONDS;
 }
-