changeset 12272:3ef381cdc47e

[gaim-migrate @ 14574] This should fix idle time reporting for all accounts. Previously it would only work for one account because I'm dumb. We're also doing one idleness check every 5 seconds instead of checking for each account every 20 seconds. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Wed, 30 Nov 2005 06:03:49 +0000
parents 3c6675e1400e
children 9ed903d0c619
files plugins/idle.c src/Makefile.am src/Makefile.mingw src/connection.c src/connection.h src/core.c src/gtkconv.c src/gtkidle.c src/gtkidle.h src/gtkmain.c src/gtkprefs.c src/idle.c src/idle.h src/prefs.c src/server.c
diffstat 15 files changed, 423 insertions(+), 233 deletions(-) [+]
line wrap: on
line diff
--- a/plugins/idle.c	Wed Nov 30 06:02:38 2005 +0000
+++ b/plugins/idle.c	Wed Nov 30 06:03:49 2005 +0000
@@ -26,6 +26,7 @@
 
 #include "connection.h"
 #include "debug.h"
+#include "idle.h"
 #include "notify.h"
 #include "plugin.h"
 #include "request.h"
@@ -62,7 +63,7 @@
 			gaim_account_get_username(acct), mins_idle);
 
 	t = time(NULL) - (60 * mins_idle); /* subtract seconds idle from current time */
-	gc->last_sent_time = t;
+	gaim_idle_set(t);
 
 	gaim_presence_set_idle(presence, mins_idle ? TRUE : FALSE, t);
 }
--- a/src/Makefile.am	Wed Nov 30 06:02:38 2005 +0000
+++ b/src/Makefile.am	Wed Nov 30 06:03:49 2005 +0000
@@ -75,6 +75,7 @@
 	desktopitem.c \
 	eventloop.c \
 	ft.c \
+	idle.c \
 	imgstore.c \
 	log.c \
 	media.c \
@@ -122,6 +123,7 @@
 	desktopitem.h \
 	eventloop.h \
 	ft.h \
+	idle.h \
 	imgstore.h \
 	log.h \
 	media.h \
--- a/src/Makefile.mingw	Wed Nov 30 06:02:38 2005 +0000
+++ b/src/Makefile.mingw	Wed Nov 30 06:03:49 2005 +0000
@@ -127,6 +127,7 @@
 			gtkthemes.c \
 			gtkutils.c \
 			gtkwhiteboard.c \
+			idle.c \
 			imgstore.c \
 			log.c \
 			mime.c \
--- a/src/connection.c	Wed Nov 30 06:02:38 2005 +0000
+++ b/src/connection.c	Wed Nov 30 06:03:49 2005 +0000
@@ -304,7 +304,6 @@
 									 GAIM_CONV_ACCOUNT_ONLINE);
 		}
 #endif
-		time(&gc->last_sent_time); /* Start the idle count from here */
 		gaim_signal_emit(gaim_connections_get_handle(), "signed-on", gc);
 
 		serv_set_permit_deny(gc);
--- a/src/connection.h	Wed Nov 30 06:02:38 2005 +0000
+++ b/src/connection.h	Wed Nov 30 06:03:49 2005 +0000
@@ -88,8 +88,6 @@
 	char *display_name;          /**< The name displayed.                */
 	guint keepalive;             /**< Keep-alive.                        */
 
-	guint idle_timer;            /**< The idle timer.                    */
-	time_t last_sent_time;       /**< The time something was last sent.  */
 
 	gboolean is_auto_away;       /**< Whether or not it's auto-away.     */
 
--- a/src/core.c	Wed Nov 30 06:02:38 2005 +0000
+++ b/src/core.c	Wed Nov 30 06:03:49 2005 +0000
@@ -29,6 +29,7 @@
 #include "core.h"
 #include "debug.h"
 #include "ft.h"
+#include "idle.h"
 #include "network.h"
 #include "notify.h"
 #include "plugin.h"
@@ -128,6 +129,7 @@
 	gaim_ssl_init();
 	gaim_stun_init();
 	gaim_xfers_init();
+	gaim_idle_init();
 
 	if (ops != NULL && ops->ui_init != NULL)
 		ops->ui_init();
@@ -150,6 +152,7 @@
 	gaim_connections_disconnect_all();
 
 	/* Save .xml files, remove signals, etc. */
+	gaim_idle_uninit();
 	gaim_ssl_uninit();
 	gaim_pounces_uninit();
 	gaim_blist_uninit();
--- a/src/gtkconv.c	Wed Nov 30 06:02:38 2005 +0000
+++ b/src/gtkconv.c	Wed Nov 30 06:03:49 2005 +0000
@@ -42,6 +42,7 @@
 #include "account.h"
 #include "cmds.h"
 #include "debug.h"
+#include "idle.h"
 #include "imgstore.h"
 #include "log.h"
 #include "notify.h"
@@ -517,6 +518,8 @@
 		return;
 	}
 
+	gaim_idle_touch();
+
 	/* XXX: is there a better way to tell if the message has images? */
 	if (GTK_IMHTML(gtkconv->entry)->im_images != NULL)
 		flags |= GAIM_MESSAGE_IMAGES;
--- a/src/gtkidle.c	Wed Nov 30 06:02:38 2005 +0000
+++ b/src/gtkidle.c	Wed Nov 30 06:03:49 2005 +0000
@@ -33,34 +33,8 @@
 # endif
 #endif /* USE_SCREENSAVER */
 
-#include "connection.h"
-#include "debug.h"
-#include "log.h"
-#include "prefs.h"
-#include "savedstatuses.h"
-#include "signals.h"
-
-#define IDLEMARK 600 /* 10 minutes! */
-#define IDLE_CHECK_INTERVAL 20 /* 20 seconds */
+#include "idle.h"
 
-typedef enum
-{
-	GAIM_IDLE_NOT_AWAY = 0,
-	GAIM_IDLE_AUTO_AWAY,
-	GAIM_IDLE_AWAY_BUT_NOT_AUTO_AWAY
-
-} GaimAutoAwayState;
-
-/**
- * This is needed for the I'dle Mak'er plugin to work correctly.  We
- * use it to determine if we're the ones who set our accounts idle
- * or if someone else did it (the I'dle Mak'er plugin, for example).
- * If our accounts are marked as idle and have_set_idle is FALSE and
- * the user moves the mouse, then we will NOT unidle our accounts.
- */
-static gboolean have_set_idle = FALSE;
-
-#ifdef USE_SCREENSAVER
 /**
  * Get the number of seconds the user has been idle.  In Unix-world
  * this is based on the X Windows usage.  In MS Windows this is based
@@ -83,10 +57,12 @@
  *
  * @return The number of seconds the user has been idle.
  */
-static int
-get_idle_time_from_system()
+static time_t
+gaim_gtk_get_time_idle()
 {
-#ifndef _WIN32
+#ifdef USE_SCREENSAVER
+# ifndef _WIN32
+	/* Query xscreensaver */
 	static XScreenSaverInfo *mit_info = NULL;
 	int event_base, error_base;
 	if (XScreenSaverQueryExtension(GDK_DISPLAY(), &event_base, &error_base)) {
@@ -97,186 +73,20 @@
 		return (mit_info->idle) / 1000;
 	} else
 		return 0;
-#else
+# else
+	/* Query windows */
 	return (GetTickCount() - wgaim_get_lastactive()) / 1000;
-#endif
-}
-#endif /* USE_SCREENSAVER */
-
-/*
- * This function should be called when you think your idle state
- * may have changed.  Maybe you're over the 10-minute mark and
- * Gaim should start reporting idle time to the server.  Maybe
- * you've returned from being idle.  Maybe your auto-away message
- * should be set.
- *
- * There is no harm to calling this many many times, other than
- * it will be kinda slow.  This is called every 20 seconds by a
- * timer set when an account logs in.  It is also called when
- * you send an IM, a chat, etc.
- *
- * This function has 3 sections.
- * 1. Get your idle time.  It will query XScreenSaver or Windows
- *    or get the Gaim idle time.  Whatever.
- * 2. Set or unset your auto-away message.
- * 3. Report your current idle time to the IM server.
- */
-/*
- * TODO: Make this loop so it's only called once, and handles all accounts?
- */
-static gint
-gaim_gtk_idle_check(gpointer data)
-{
-	GaimConnection *gc = (GaimConnection *)data;
-	gboolean report_idle;
-	GaimAccount *account;
-	GaimPresence *presence;
-	GaimStatus *status;
-	time_t t;
-	int idle_time;
-
-	account = gaim_connection_get_account(gc);
-	presence = gaim_account_get_presence(account);
-	status = gaim_presence_get_active_status(presence);
-
-	gaim_signal_emit(gaim_blist_get_handle(), "update-idle");
-
-	time(&t);
-
-	report_idle = gaim_prefs_get_bool("/gaim/gtk/idle/report");
-
-#ifdef USE_SCREENSAVER
-	idle_time = get_idle_time_from_system();
-#else
-	/*
-	 * If Gaim wasn't built with xscreensaver support, then
-	 * fallback to calculating our idle time based on when
-	 * we last sent a message.
-	 */
-	idle_time = t - gc->last_sent_time;
+# endif /* _WIN32 */
 #endif /* USE_SCREENSAVER */
-
-	/* Begining of auto-away stuff */
-	if (gaim_prefs_get_bool("/core/away/away_when_idle") &&
-		(idle_time > (60 * gaim_prefs_get_int("/core/away/mins_before_away")))
-		&& (!gc->is_auto_away))
-	{
-		if (gaim_status_is_available(status))
-		{
-			GaimSavedStatus *saved_status;
-
-			gaim_debug_info("idle", "Making %s auto-away\n",
-							gaim_account_get_username(account));
-
-			/* Mark our accounts "away" using the idleaway status */
-			saved_status = gaim_savedstatus_get_idleaway();
-			gaim_savedstatus_activate_for_account(saved_status, account);
-
-			gc->is_auto_away = GAIM_IDLE_AUTO_AWAY;
-		} else {
-			gc->is_auto_away = GAIM_IDLE_AWAY_BUT_NOT_AUTO_AWAY;
-		}
-
-	} else if (gc->is_auto_away &&
-			idle_time < 60 * gaim_prefs_get_int("/core/away/mins_before_away"))
-	{
-		/* Return from being idle */
-		GaimSavedStatus *saved_status;
-
-		if (gc->is_auto_away == GAIM_IDLE_AWAY_BUT_NOT_AUTO_AWAY) {
-			gc->is_auto_away = GAIM_IDLE_NOT_AWAY;
-		} else {
-			gc->is_auto_away = GAIM_IDLE_NOT_AWAY;
-
-			gaim_debug_info("idle", "%s returning from auto-away\n",
-							gaim_account_get_username(account));
-
-			/* Return our account to its previous status */
-			saved_status = gaim_savedstatus_get_current();
-			gaim_savedstatus_activate_for_account(saved_status, account);
-		}
-	}
-	/* End of auto-away stuff */
-
-	/* Begining of idle reporting stuff */
-	if (report_idle && idle_time >= IDLEMARK && !have_set_idle && !gaim_presence_is_idle(presence))
-	{
-		gaim_debug_info("idle", "Setting %s idle %d seconds\n",
-				   gaim_account_get_username(account), idle_time);
-		gaim_presence_set_idle(presence, TRUE, time(NULL) - idle_time);
-		have_set_idle = TRUE;
-	} else if ((!report_idle || idle_time < IDLEMARK) && have_set_idle && gaim_presence_is_idle(presence))
-	{
-		gaim_debug_info("idle", "Setting %s unidle\n",
-				   gaim_account_get_username(account));
-		gaim_presence_set_idle(presence, FALSE, time(NULL));
-		have_set_idle = FALSE;
-	}
-	/* End of idle reporting stuff */
-
-	return TRUE;
 }
 
-static void
-im_msg_sent_cb(GaimAccount *account, const char *receiver,
-			   const char *message, void *data)
-{
-	GaimConnection	*gc = gaim_account_get_connection(account);
-
-	/* After an IM is sent, check our idle time */
-	gaim_gtk_idle_check(gc);
-}
-
-static void
-remove_idle_timer(GaimConnection *gc)
+static GaimIdleUiOps ui_ops =
 {
-	/* Remove any existing idle_timer */
-	if (gc->idle_timer > 0)
-		gaim_timeout_remove(gc->idle_timer);
-	gc->idle_timer = 0;
-}
-
-static void
-connection_disconnected_cb(GaimConnection *gc, gpointer user_data)
-{
-	remove_idle_timer(gc);
-}
-
-static void
-connection_connected_cb(GaimConnection *gc, gpointer user_data)
-{
-	/* Now that we are connected, check for idleness every 20 seconds */
-	remove_idle_timer(gc);
-	gc->idle_timer = gaim_timeout_add(IDLE_CHECK_INTERVAL * 1000, gaim_gtk_idle_check, gc);
+	gaim_gtk_get_time_idle
+};
 
-	/* Immediately update our idleness, in case we connected while idle */
-	gaim_gtk_idle_check(gc);
-}
-
-void *
-gaim_gtk_idle_get_handle()
-{
-	static int handle;
-
-	return &handle;
-}
-
-void
-gaim_gtk_idle_init()
+GaimIdleUiOps *
+gaim_gtk_idle_get_ui_ops()
 {
-	gaim_signal_connect(gaim_conversations_get_handle(), "sent-im-msg",
-						gaim_gtk_idle_get_handle(),
-						GAIM_CALLBACK(im_msg_sent_cb), NULL);
-	gaim_signal_connect(gaim_connections_get_handle(), "signed-on",
-						gaim_gtk_idle_get_handle(),
-						GAIM_CALLBACK(connection_connected_cb), NULL);
-	gaim_signal_connect(gaim_connections_get_handle(), "signed-off",
-						gaim_gtk_idle_get_handle(),
-						GAIM_CALLBACK(connection_disconnected_cb), NULL);
+	return &ui_ops;
 }
-
-void
-gaim_gtk_idle_uninit()
-{
-	gaim_signals_disconnect_by_handle(gaim_gtk_idle_get_handle());
-}
--- a/src/gtkidle.h	Wed Nov 30 06:02:38 2005 +0000
+++ b/src/gtkidle.h	Wed Nov 30 06:03:49 2005 +0000
@@ -25,21 +25,19 @@
 #ifndef _GAIM_GTK_IDLE_H_
 #define _GAIM_GTK_IDLE_H_
 
+#include "idle.h"
+
 /**************************************************************************/
 /** @name GTK+ Idle API                                                  */
 /**************************************************************************/
 /*@{*/
 
-
 /**
- * Initializes the GTK+ idle system.
+ * Returns the GTK+ idle UI ops.
+ *
+ * @return The UI operations structure.
  */
-void gaim_gtk_idle_init(void);
-
-/**
- * Uninitializes the GTK+ idle system.
- */
-void gaim_gtk_idle_uninit(void);
+GaimIdleUiOps *gaim_gtk_idle_get_ui_ops(void);
 
 /*@}*/
 
--- a/src/gtkmain.c	Wed Nov 30 06:02:38 2005 +0000
+++ b/src/gtkmain.c	Wed Nov 30 06:03:49 2005 +0000
@@ -259,6 +259,9 @@
 	gaim_sound_set_ui_ops(gaim_gtk_sound_get_ui_ops());
 	gaim_connections_set_ui_ops(gaim_gtk_connections_get_ui_ops());
 	gaim_whiteboard_set_ui_ops(gaim_gtk_whiteboard_get_ui_ops());
+#ifdef USE_SCREENSAVER
+	gaim_idle_set_ui_ops(gaim_gtk_idle_get_ui_ops());
+#endif
 
 	gaim_gtk_stock_init();
 	gaim_gtk_prefs_init();
@@ -273,7 +276,6 @@
 #ifdef HAVE_VV
 	gaim_gtk_media_init();
 #endif
-	gaim_gtk_idle_init();
 }
 
 static void
@@ -294,7 +296,6 @@
 	gaim_gtk_account_uninit();
 	gaim_gtk_xfers_uninit();
 	gaim_gtk_debug_uninit();
-	gaim_gtk_idle_uninit();
 
 	/* and end it all... */
 	gtk_main_quit();
--- a/src/gtkprefs.c	Wed Nov 30 06:02:38 2005 +0000
+++ b/src/gtkprefs.c	Wed Nov 30 06:03:49 2005 +0000
@@ -1668,7 +1668,7 @@
 		NULL);
 
 	button = gaim_gtk_prefs_checkbox(_("_Report idle time"),
-			"/gaim/gtk/idle/report", vbox);
+			"/core/away/report_idle", vbox);
 
 	vbox = gaim_gtk_make_frame (ret, _("Auto-away"));
 	button = gaim_gtk_prefs_checkbox(_("Change status when _idle"),
@@ -1867,10 +1867,6 @@
 	gaim_prefs_add_string("/gaim/gtk/browsers/browser", "mozilla");
 #endif
 
-	/* Idle */
-	gaim_prefs_add_none("/gaim/gtk/idle");
-	gaim_prefs_add_bool("/gaim/gtk/idle/report", TRUE);
-
 	/* Plugins */
 	gaim_prefs_add_none("/gaim/gtk/plugins");
 	gaim_prefs_add_string_list("/gaim/gtk/plugins/loaded", NULL);
@@ -1909,9 +1905,11 @@
 									 "/gaim/gtk/conversations/show_incoming_formatting");
 
 	/* this string pref turned into a boolean, try to be friendly */
-	tmp = gaim_prefs_get_string("/gaim/gtk/idle/reporting_method");
-	if (tmp != NULL && !strcmp(tmp, "none")) {
-		gaim_prefs_set_bool("/gaim/gtk/idle/report", FALSE);
+	if (gaim_prefs_exists("/gaim/gtk/idle/reporting_method"))
+	{
+		tmp = gaim_prefs_get_string("/gaim/gtk/idle/reporting_method");
+		if (tmp != NULL && !strcmp(tmp, "none"))
+			gaim_prefs_set_bool("/core/away/report_idle", FALSE);
 	}
 
 	/* Remove some no-longer-used prefs */
@@ -1944,6 +1942,7 @@
 	gaim_prefs_remove("/gaim/gtk/conversations/ignore_fonts");
 	gaim_prefs_remove("/gaim/gtk/conversations/ignore_font_sizes");
 	gaim_prefs_remove("/gaim/gtk/idle/reporting_method");
+	gaim_prefs_remove("/gaim/gtk/idle");
 	gaim_prefs_remove("/gaim/gtk/logging/individual_logs");
 	gaim_prefs_remove("/gaim/gtk/sound/signon");
 	gaim_prefs_remove("/gaim/gtk/sound/silent_signon");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/idle.c	Wed Nov 30 06:03:49 2005 +0000
@@ -0,0 +1,284 @@
+/*
+ * gaim
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include "internal.h"
+
+#include "connection.h"
+#include "debug.h"
+#include "idle.h"
+#include "log.h"
+#include "prefs.h"
+#include "savedstatuses.h"
+#include "signals.h"
+
+#define IDLEMARK 600 /* 10 minutes! */
+#define IDLE_CHECK_INTERVAL 5 /* 5 seconds */
+
+typedef enum
+{
+	GAIM_IDLE_NOT_AWAY = 0,
+	GAIM_IDLE_AUTO_AWAY,
+	GAIM_IDLE_AWAY_BUT_NOT_AUTO_AWAY
+
+} GaimAutoAwayState;
+
+static GaimIdleUiOps *idle_ui_ops = NULL;
+
+/**
+ * This is needed for the I'dle Mak'er plugin to work correctly.  We
+ * use it to determine if we're the ones who set our accounts idle
+ * or if someone else did it (the I'dle Mak'er plugin, for example).
+ * If our accounts are marked as idle and have_set_idle is FALSE and
+ * the user moves the mouse, then we will NOT unidle our accounts.
+ */
+static gboolean have_set_idle = FALSE;
+
+static guint idle_timer = 0;
+
+static time_t last_active_time = 0;
+
+static void
+set_account_autoaway(GaimConnection *gc)
+{
+	GaimAccount *account;
+	GaimPresence *presence;
+	GaimStatus *status;
+
+	if (gc->is_auto_away)
+		/* This account is already auto-away! */
+		return;
+
+	account = gaim_connection_get_account(gc);
+	presence = gaim_account_get_presence(account);
+	status = gaim_presence_get_active_status(presence);
+
+	if (gaim_status_is_available(status))
+	{
+		GaimSavedStatus *saved_status;
+
+		gaim_debug_info("idle", "Making %s auto-away\n",
+						gaim_account_get_username(account));
+
+		saved_status = gaim_savedstatus_get_idleaway();
+		gaim_savedstatus_activate_for_account(saved_status, account);
+
+		gc->is_auto_away = GAIM_IDLE_AUTO_AWAY;
+	} else {
+		gc->is_auto_away = GAIM_IDLE_AWAY_BUT_NOT_AUTO_AWAY;
+	}
+}
+
+static void
+unset_account_autoaway(GaimConnection *gc)
+{
+	GaimAccount *account;
+	GaimPresence *presence;
+	GaimStatus *status;
+	GaimSavedStatus *saved_status;
+
+	account = gaim_connection_get_account(gc);
+	presence = gaim_account_get_presence(account);
+	status = gaim_presence_get_active_status(presence);
+
+	if (!gc->is_auto_away)
+		/* This account is already not auto-away! */
+		return;
+
+	if (gc->is_auto_away == GAIM_IDLE_AWAY_BUT_NOT_AUTO_AWAY) {
+		gc->is_auto_away = GAIM_IDLE_NOT_AWAY;
+	} else {
+		gc->is_auto_away = GAIM_IDLE_NOT_AWAY;
+
+		gaim_debug_info("idle", "%s returning from auto-away\n",
+						gaim_account_get_username(account));
+
+		/* Return our account to its previous status */
+		saved_status = gaim_savedstatus_get_current();
+		gaim_savedstatus_activate_for_account(saved_status, account);
+	}
+}
+
+static void
+set_account_idle(GaimConnection *gc, int time_idle)
+{
+	GaimAccount *account;
+	GaimPresence *presence;
+
+	account = gaim_connection_get_account(gc);
+	presence = gaim_account_get_presence(account);
+
+	if (gaim_presence_is_idle(presence))
+		/* This account is already idle! */
+		return;
+
+	gaim_debug_info("idle", "Setting %s idle %d seconds\n",
+			   gaim_account_get_username(account), time_idle);
+	gaim_presence_set_idle(presence, TRUE, time(NULL) - time_idle);
+}
+
+static void
+set_account_unidle(GaimConnection *gc)
+{
+	GaimAccount *account;
+	GaimPresence *presence;
+
+	account = gaim_connection_get_account(gc);
+	presence = gaim_account_get_presence(account);
+
+	if (!gaim_presence_is_idle(presence))
+		/* This account is already unidle! */
+		return;
+
+	gaim_debug_info("idle", "Setting %s unidle\n",
+			   gaim_account_get_username(account));
+	gaim_presence_set_idle(presence, FALSE, time(NULL));
+}
+
+/*
+ * This function should be called when you think your idle state
+ * may have changed.  Maybe you're over the 10-minute mark and
+ * Gaim should start reporting idle time to the server.  Maybe
+ * you've returned from being idle.  Maybe your auto-away message
+ * should be set.
+ *
+ * There is no harm to calling this many many times, other than
+ * it will be kinda slow.  This is called every 5 seconds by a
+ * timer set when Gaim starts.  It is also called when
+ * you send an IM, a chat, etc.
+ *
+ * This function has 3 sections.
+ * 1. Get your idle time.  It will query XScreenSaver or Windows
+ *    or use the Gaim idle time.  Whatever.
+ * 2. Set or unset your auto-away message.
+ * 3. Report your current idle time to the IM server.
+ */
+static gint
+check_idleness()
+{
+	time_t time_idle;
+	gboolean auto_away;
+	gboolean report_idle;
+	GList *l;
+
+	gaim_signal_emit(gaim_blist_get_handle(), "update-idle");
+
+	if (idle_ui_ops != NULL && idle_ui_ops->get_time_idle != NULL)
+		time_idle = idle_ui_ops->get_time_idle();
+	else
+		/* Use 'Gaim idle' */
+		time_idle = time(NULL) - last_active_time;
+
+	/* Auto-away stuff */
+	auto_away = gaim_prefs_get_bool("/core/away/away_when_idle");
+	if (auto_away &&
+		(time_idle > (60 * gaim_prefs_get_int("/core/away/mins_before_away"))))
+	{
+		for (l = gaim_connections_get_all(); l != NULL; l = l->next)
+			set_account_autoaway(l->data);
+	}
+	else if (time_idle < 60 * gaim_prefs_get_int("/core/away/mins_before_away"))
+	{
+		for (l = gaim_connections_get_all(); l != NULL; l = l->next)
+			unset_account_autoaway(l->data);
+	}
+
+	/* Idle reporting stuff */
+	report_idle = gaim_prefs_get_bool("/core/away/report_idle");
+	if (report_idle && (time_idle >= IDLEMARK) && !have_set_idle)
+	{
+		for (l = gaim_connections_get_all(); l != NULL; l = l->next)
+			set_account_idle(l->data, time_idle);
+		have_set_idle = TRUE;
+	}
+	else if ((!report_idle || time_idle < IDLEMARK) && have_set_idle)
+	{
+		for (l = gaim_connections_get_all(); l != NULL; l = l->next)
+			set_account_unidle(l->data);
+		have_set_idle = FALSE;
+	}
+
+	return TRUE;
+}
+
+static void
+im_msg_sent_cb(GaimAccount *account, const char *receiver,
+			   const char *message, void *data)
+{
+	/* Check our idle time after an IM is sent */
+	check_idleness();
+}
+
+void
+gaim_idle_touch()
+{
+	time(&last_active_time);
+}
+
+void
+gaim_idle_set(time_t time)
+{
+	last_active_time = time;
+}
+
+void
+gaim_idle_set_ui_ops(GaimIdleUiOps *ops)
+{
+	idle_ui_ops = ops;
+}
+
+GaimIdleUiOps *
+gaim_idle_get_ui_ops(void)
+{
+	return idle_ui_ops;
+}
+
+void *
+gaim_idle_get_handle()
+{
+	static int handle;
+
+	return &handle;
+}
+
+void
+gaim_idle_init()
+{
+	/* Add the timer to check if we're idle */
+	idle_timer = gaim_timeout_add(IDLE_CHECK_INTERVAL * 1000, check_idleness, NULL);
+
+	gaim_signal_connect(gaim_conversations_get_handle(), "sent-im-msg",
+						gaim_idle_get_handle(),
+						GAIM_CALLBACK(im_msg_sent_cb), NULL);
+
+	gaim_idle_touch();
+}
+
+void
+gaim_idle_uninit()
+{
+	gaim_signals_disconnect_by_handle(gaim_idle_get_handle());
+
+	/* Remove the idle timer */
+	if (idle_timer > 0)
+		gaim_timeout_remove(idle_timer);
+	idle_timer = 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/idle.h	Wed Nov 30 06:03:49 2005 +0000
@@ -0,0 +1,96 @@
+/**
+ * @file idle.h Idle API
+ * @ingroup core
+ *
+ * gaim
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _GAIM_IDLE_H_
+#define _GAIM_IDLE_H_
+
+/**
+ * Idle UI operations.
+ */
+typedef struct
+{
+	time_t (*get_time_idle)(void);
+} GaimIdleUiOps;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**************************************************************************/
+/** @name Idle API                                                        */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Touch our idle tracker.  This signifies that the user is
+ * 'active'.  The conversation code calls this when the
+ * user sends an IM, for example.
+ */
+void gaim_idle_touch(void);
+
+/**
+ * Fake our idle time by setting the time at which our
+ * accounts purportedly became idle.  This is used by
+ * the I'dle Mak'er plugin.
+ */
+void gaim_idle_set(time_t time);
+
+/*@}*/
+
+/**************************************************************************/
+/** @name Idle Subsystem                                                  */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Sets the UI operations structure to be used for idle reporting.
+ *
+ * @param ops The UI operations structure.
+ */
+void gaim_idle_set_ui_ops(GaimIdleUiOps *ops);
+
+/**
+ * Returns the UI operations structure used for idle reporting.
+ *
+ * @return The UI operations structure in use.
+ */
+GaimIdleUiOps *gaim_idle_get_ui_ops(void);
+
+/**
+ * Initializes the idle system.
+ */
+void gaim_idle_init(void);
+
+/**
+ * Uninitializes the idle system.
+ */
+void gaim_idle_uninit(void);
+
+/*@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GAIM_IDLE_H_ */
--- a/src/prefs.c	Wed Nov 30 06:02:38 2005 +0000
+++ b/src/prefs.c	Wed Nov 30 06:03:49 2005 +0000
@@ -1097,6 +1097,7 @@
 
 	/* Away */
 	gaim_prefs_add_none("/core/away");
+	gaim_prefs_add_bool("/core/away/report_idle", TRUE);
 	gaim_prefs_add_bool("/core/away/away_when_idle", TRUE);
 	gaim_prefs_add_int("/core/away/mins_before_away", 5);
 
--- a/src/server.c	Wed Nov 30 06:02:38 2005 +0000
+++ b/src/server.c	Wed Nov 30 06:03:49 2005 +0000
@@ -133,10 +133,6 @@
 	if (prpl_info && prpl_info->send_im)
 		val = prpl_info->send_im(gc, name, message, flags);
 
-	/* Only update the last_sent_time if the user actually sent the message */
-	if (!(flags & GAIM_MESSAGE_AUTO_RESP))
-		time(&gc->last_sent_time);
-
 	/*
 	 * XXX - If "only auto-reply when away & idle" is set, then shouldn't
 	 * this only reset lar->sent if we're away AND idle?
@@ -411,8 +407,6 @@
 	if (prpl_info && prpl_info->chat_send)
 		val = prpl_info->chat_send(gc, id, message, flags);
 
-	time(&gc->last_sent_time);
-
 	return val;
 }