Index: Makefile.in
===================================================================
--- Makefile.in	(revision 33813991523c10b91982179dd48f55b4dc3ce7b8)
+++ Makefile.in	(revision b7bb4545f69af6f073e4844a0cc06b07c8a11873)
@@ -25,5 +25,5 @@
      regex.c history.c view.c dict.c variable.c filterelement.c pair.c \
      keypress.c keymap.c keybinding.c cmd.c context.c zcrypt.c \
-     aim.c buddy.c buddylist.c timer.c style.c errqueue.c \
+     aim.c buddy.c buddylist.c style.c errqueue.c \
      zbuddylist.c muxevents.c popexec.c obarray.c select.c wcwidth.c \
      glib_compat.c
Index: aim.c
===================================================================
--- aim.c	(revision 554a2b836ba40cb8a9fbbc1b1b8aeb195a334e78)
+++ aim.c	(revision b7bb4545f69af6f073e4844a0cc06b07c8a11873)
@@ -130,4 +130,11 @@
 }
 
+void owl_aim_send_nop(owl_timer *t, void *data) {
+    if(owl_global_is_doaimevents(&g)) {
+        aim_session_t *sess = owl_global_get_aimsess(&g);
+        aim_flap_nop(sess, aim_getconn_type(sess, AIM_CONN_TYPE_BOS));
+    }
+}
+
 
 int owl_aim_login(char *screenname, char *password)
@@ -194,5 +201,11 @@
   owl_function_debugmsg("owl_aim_login: connecting");
 
+  g.aim_nop_timer = owl_select_add_timer(30, 30, owl_aim_send_nop, NULL);
+
   return(0);
+}
+
+void owl_aim_unset_ignorelogin(owl_timer *t, void *data) {      /* noproto */
+    owl_global_unset_ignore_aimlogin(&g);
 }
 
@@ -212,8 +225,8 @@
 
   /* start the ingorelogin timer */
-  owl_timer_reset_newstart(owl_global_get_aim_login_timer(&g),
-			   owl_global_get_aim_ignorelogin_timer(&g));
-
-  
+  owl_global_set_ignore_aimlogin(&g);
+  owl_select_add_timer(owl_global_get_aim_ignorelogin_timer(&g),
+                       0, owl_aim_unset_ignorelogin, NULL);
+
   /* aim_ssi_setpresence(owl_global_get_aimsess(&g), 0x00000400); */
   /* aim_bos_setidle(owl_global_get_aimsess(&g), owl_global_get_bosconn(&g), 5000); */
@@ -228,4 +241,5 @@
   owl_global_set_aimnologgedin(&g);
   owl_global_set_no_doaimevents(&g);
+  owl_select_remove_timer(g.aim_nop_timer);
 }
 
@@ -246,4 +260,5 @@
   owl_global_set_aimnologgedin(&g);
   owl_global_set_no_doaimevents(&g);
+  owl_select_remove_timer(g.aim_nop_timer);
 }
 
@@ -422,9 +437,4 @@
   tv.tv_usec = 0;
   waitingconn = aim_select(aimsess, &tv, &selstat);
-
-  if (owl_global_is_aimnop_time(&g)) {
-    aim_flap_nop(aimsess, aim_getconn_type(aimsess, AIM_CONN_TYPE_BOS));
-    owl_global_aimnop_sent(&g);
-  }
 
   if (selstat == -1) {
@@ -2315,11 +2325,4 @@
   if (owl_global_is_doaimevents(&g)) {
     owl_aim_process_events();
-
-    if (owl_global_is_aimloggedin(&g)) {
-      if (owl_timer_is_expired(owl_global_get_aim_buddyinfo_timer(&g))) {
-        /* owl_buddylist_request_idletimes(owl_global_get_buddylist(&g)); */
-        owl_timer_reset(owl_global_get_aim_buddyinfo_timer(&g));
-      }
-    }
   }
 }
Index: buddylist.c
===================================================================
--- buddylist.c	(revision 257a22f9949fe230526eb336a3d6c236f702da66)
+++ buddylist.c	(revision b7bb4545f69af6f073e4844a0cc06b07c8a11873)
@@ -51,5 +51,5 @@
 
     /* are we ingoring login messages for a while? */
-    if (!owl_timer_is_expired(owl_global_get_aim_login_timer(&g))) return;
+    if (owl_global_is_ignore_aimlogin(&g)) return;
 
     /* if not, create the login message */
Index: global.c
===================================================================
--- global.c	(revision 2b237308fb6a3f4831e639cbcc7f54ef74beed74)
+++ global.c	(revision b7bb4545f69af6f073e4844a0cc06b07c8a11873)
@@ -100,11 +100,9 @@
   g->aim_screenname_for_filters=NULL;
   g->aim_loggedin=0;
-  owl_timer_create_countdown(&(g->aim_noop_timer), 30);
-  owl_timer_create_countdown(&(g->aim_ignorelogin_timer), 0);
-  owl_timer_create_countdown(&(g->aim_buddyinfo_timer), 60);
   owl_buddylist_init(&(g->buddylist));
-    
+
   g->havezephyr=0;
   g->haveaim=0;
+  g->ignoreaimlogin=0;
   owl_global_set_no_doaimevents(g);
 
@@ -113,5 +111,4 @@
 
   owl_zbuddylist_create(&(g->zbuddies));
-  owl_timer_create_countdown(&(g->zephyr_buddycheck_timer), 60*3);
 
   owl_obarray_init(&(g->obarray));
@@ -119,4 +116,5 @@
   owl_message_init_fmtext_cache();
   owl_list_create(&(g->dispatchlist));
+  g->timerlist = g_sequence_new(NULL);
 }
 
@@ -814,20 +812,4 @@
 }
 
-int owl_global_is_aimnop_time(owl_global *g)
-{
-  if (owl_timer_is_expired(&(g->aim_noop_timer))) return(1);
-  return(0);
-}
-
-void owl_global_aimnop_sent(owl_global *g)
-{
-  owl_timer_reset(&(g->aim_noop_timer));
-}
-
-owl_timer *owl_global_get_aim_login_timer(owl_global *g)
-{
-  return(&(g->aim_ignorelogin_timer));
-}
-
 /* message queue */
 
@@ -902,4 +884,19 @@
 }
 
+void owl_global_set_ignore_aimlogin(owl_global *g)
+{
+    g->ignoreaimlogin = 1;
+}
+
+void owl_global_unset_ignore_aimlogin(owl_global *g)
+{
+    g->ignoreaimlogin = 0;
+}
+
+int owl_global_is_ignore_aimlogin(owl_global *g)
+{
+    return g->ignoreaimlogin;
+}
+
 void owl_global_set_havezephyr(owl_global *g)
 {
@@ -911,9 +908,4 @@
   if (g->havezephyr) return(1);
   return(0);
-}
-
-owl_timer *owl_global_get_aim_buddyinfo_timer(owl_global *g)
-{
-  return(&(g->aim_buddyinfo_timer));
 }
 
@@ -944,8 +936,4 @@
 }
 
-owl_timer *owl_global_get_zephyr_buddycheck_timer(owl_global *g)
-{
-  return(&(g->zephyr_buddycheck_timer));
-}
 
 owl_zbuddylist *owl_global_get_zephyr_buddylist(owl_global *g)
@@ -968,2 +956,7 @@
   return &(g->dispatchlist);
 }
+
+GSequence *owl_global_get_timerlist(owl_global *g)
+{
+    return g->timerlist;
+}
Index: owl.c
===================================================================
--- owl.c	(revision 6eaf35b1b74b142244bdde7df41bb5891454bbb7)
+++ owl.c	(revision b7bb4545f69af6f073e4844a0cc06b07c8a11873)
@@ -394,4 +394,11 @@
   nexttime=time(NULL);
 
+
+  owl_select_add_timer(180, 180, owl_zephyr_buddycheck_timer, NULL);
+
+  /* If we ever deprecate the mainloop hook, remove this. */
+  owl_select_add_timer(0, 1, owl_perlconfig_mainloop, NULL);
+
+
 #ifdef HAVE_LIBZEPHYR
   /* Check for any zephyrs that have come in while we've done init. */
@@ -413,6 +420,4 @@
 
     followlast=owl_global_should_followlast(&g);
-    
-    owl_perlconfig_mainloop();
 
     /* little hack */
@@ -439,13 +444,4 @@
       if(owl_process_message(m))
         newmsgs = 1;
-    }
-
-    /* is it time to check zbuddies? */
-    if (owl_global_is_pseudologins(&g)) {
-      if (owl_timer_is_expired(owl_global_get_zephyr_buddycheck_timer(&g))) {
-	owl_function_debugmsg("Doing zephyr buddy check");
-	owl_function_zephyr_buddy_check(1);
-	owl_timer_reset(owl_global_get_zephyr_buddycheck_timer(&g));
-      }
     }
 
@@ -780,2 +776,8 @@
 
 #endif /* OWL_STDERR_REDIR */
+
+void owl_zephyr_buddycheck_timer(owl_timer *t, void *data)
+{
+    owl_function_debugmsg("Doing zephyr buddy check");
+    owl_function_zephyr_buddy_check(1);
+}
Index: owl.h
===================================================================
--- owl.h	(revision de1c8a59c19d33ab73607ff6539f55d51088ec6b)
+++ owl.h	(revision b7bb4545f69af6f073e4844a0cc06b07c8a11873)
@@ -505,7 +505,8 @@
 
 typedef struct _owl_timer {
-  int direction;
-  time_t starttime;
-  int start;
+  time_t time;
+  int interval;
+  void (*callback)(struct _owl_timer *, void *);
+  void *data;
 } owl_timer;
 
@@ -583,5 +584,4 @@
   owl_timer aim_noop_timer;
   owl_timer aim_ignorelogin_timer;
-  owl_timer aim_buddyinfo_timer;
   int aim_loggedin;         /* true if currently logged into AIM */
   int aim_doprocessing;     /* true if we should process AIM events (like pending login) */
@@ -594,4 +594,5 @@
   int havezephyr;
   int haveaim;
+  int ignoreaimlogin;
   int got_err_signal;	    /* 1 if we got an unexpected signal */
   siginfo_t err_signal_info;
@@ -601,4 +602,6 @@
   owl_obarray obarray;
   owl_list dispatchlist;
+  GSequence *timerlist;
+  owl_timer *aim_nop_timer;
 } owl_global;
 
Index: select.c
===================================================================
--- select.c	(revision 2f690811f743b0ec04fdd98ce530c5a296c031df)
+++ select.c	(revision b7bb4545f69af6f073e4844a0cc06b07c8a11873)
@@ -2,4 +2,78 @@
 
 static const char fileIdent[] = "$Id: select.c 894 2008-01-17 07:13:44Z asedeno $";
+
+int _owl_select_timer_cmp(owl_timer *t1, owl_timer *t2, void *data) {
+    return t1->time - t2->time;
+}
+
+int _owl_select_timer_eq(owl_timer *t1, owl_timer *t2, void *data) {
+    return t1 == t2;
+}
+
+owl_timer *owl_select_add_timer(int after, int interval, void (*cb)(struct _owl_timer *, void *), void *data)
+{
+    owl_timer *t = owl_malloc(sizeof(owl_timer));
+    GSequence *timers = owl_global_get_timerlist(&g);
+
+    t->time = time(NULL) + after;
+    t->interval = interval;
+    t->callback = cb;
+    t->data = data;
+
+    g_sequence_insert_sorted(timers, t,
+                             (GCompareDataFunc)_owl_select_timer_cmp, NULL);
+    return t;
+}
+
+void owl_select_remove_timer(owl_timer *t)
+{
+    GSequenceIter *it = g_sequence_search(owl_global_get_timerlist(&g),
+                                          t, (GCompareDataFunc)_owl_select_timer_eq, NULL);
+    if(!g_sequence_iter_is_end(it) &&
+       g_sequence_get(it) == t) {
+        owl_free(t);
+        g_sequence_remove(it);
+    }
+}
+
+void owl_select_process_timers(struct timeval *timeout)
+{
+    time_t now = time(NULL);
+    GSequenceIter *it = g_sequence_get_begin_iter(owl_global_get_timerlist(&g));
+
+    while(!g_sequence_iter_is_end(it)) {
+        owl_timer *t = g_sequence_get(it);
+        int remove = 0;
+
+        if(t->time > now)
+            break;
+
+        /* Reschedule if appropriate */
+        if(t->interval > 0) {
+            t->time = now + t->interval;
+            g_sequence_sort_changed(it, (GCompareDataFunc)_owl_select_timer_cmp, NULL);
+        } else {
+            g_sequence_remove(it);
+            remove = 1;
+        }
+
+        /* Do the callback */
+        t->callback(t, t->data);
+
+        if (remove) {
+            owl_free(t);
+        }
+        it = g_sequence_get_begin_iter(owl_global_get_timerlist(&g));
+    }
+
+    if(g_sequence_iter_is_end(it)) {
+        timeout->tv_sec = 60;
+    } else {
+        owl_timer *t = g_sequence_get(it);
+        timeout->tv_sec = t->time - now;
+    }
+
+    timeout->tv_usec = 0;
+}
 
 /* Returns the index of the dispatch for the file descriptor. */
@@ -182,6 +256,5 @@
   struct timeval timeout;
 
-  timeout.tv_sec = 1;
-  timeout.tv_usec = 0;
+  owl_select_process_timers(&timeout);
 
   max_fd = owl_select_dispatch_prepare_fd_sets(&r, &e);
Index: mer.c
===================================================================
--- timer.c	(revision 6a415e91912b4795a141097f08a02c8a3229a908)
+++ 	(revision )
@@ -1,74 +1,0 @@
-#include "owl.h"
-
-#define OWL_TIMER_DIRECTION_COUNTUP    1
-#define OWL_TIMER_DIRECTION_COUNTDOWN  2
-
-
-/* Create a "counting up" timer.  The counter starts running as soon
- * as this is called.  Use owl_timer_reset() to reset it.
- */
-void owl_timer_create_countup(owl_timer *t)
-{
-  t->direction=OWL_TIMER_DIRECTION_COUNTUP;
-  t->starttime=time(NULL);
-}
-
-/* create a "counting down" timer, which counts down from 'start'
- * seconds.  The counter starts running as soon as this is called.
- * Use owl_timer_reset to reset it.
- */
-void owl_timer_create_countdown(owl_timer *t, int start)
-{
-  t->direction=OWL_TIMER_DIRECTION_COUNTDOWN;
-  t->start=start;
-  t->starttime=time(NULL);
-}
-
-/* Reset the timer.  For a "counting up" timer, it is reset to 0.  For
- * a "counting down" timer it is set to the value initially set with
- * owl_timer_create_countdown() or the last value set with
- * owl_timer_reset_newstart() */
-void owl_timer_reset(owl_timer *t)
-{
-  t->starttime=time(NULL);
-}
-
-/* Only for a countdown timer.  Rest the timer, but this time (and on
- * future resets) start with 'start' seconds.
- */
-void owl_timer_reset_newstart(owl_timer *t, int start)
-{
-  t->start=start;
-  t->starttime=time(NULL);
-}
-
-/* Return the number of seconds elapsed or remaining.  If using a
- * countdown timer, a negative value is never reported.  Once the
- * timer gets to 0 it stays at 0 */
-int owl_timer_get_time(owl_timer *t)
-{
-  time_t now;
-  int rem;
-
-  now=time(NULL);
-
-  if (t->direction==OWL_TIMER_DIRECTION_COUNTUP) {
-    return(now-t->starttime);
-  } else if (t->direction==OWL_TIMER_DIRECTION_COUNTDOWN) {
-    rem=t->start-(now-t->starttime);
-    if (rem<0) return(0);
-    return(rem);
-  }
-
-  /* never reached */
-  return(0);
-}
-
-/* Only for countdown timer.  Return true if time has run out (the
- * timer is at 0 seconds or less
- */
-int owl_timer_is_expired(owl_timer *t)
-{
-  if (owl_timer_get_time(t)==0) return(1);
-  return(0);
-}
