Index: Makefile.in
===================================================================
--- Makefile.in	(revision 0ff8fb572754799e77ac2cf2d386b7699f995257)
+++ Makefile.in	(revision aa5f725832e087e7a8c053b6d238f21fae14500b)
@@ -22,5 +22,6 @@
      readconfig.c keys.c functions.c zwrite.c viewwin.c help.c filter.c \
      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
+     keypress.c keymap.c keybinding.c cmd.c context.c zcrypt.c \
+     aim.c buddylist.c
 OWL_SRC = owl.c
 TESTER_SRC = tester.c
Index: aim.c
===================================================================
--- aim.c	(revision 651560fb0ba1ab37fb315a20ec96eb3c18929676)
+++ aim.c	(revision aa5f725832e087e7a8c053b6d238f21fae14500b)
@@ -367,40 +367,40 @@
   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNINITDONE, conninitdone_bos, 0);
 
-  aim_conn_addhandler(sess, bosconn, 0x0013, 0x0003, ssirights, 0);
-  aim_conn_addhandler(sess, bosconn, 0x0013, 0x0006, ssidata, 0);
-  aim_conn_addhandler(sess, bosconn, 0x0013, 0x000f, ssidatanochange, 0);
-  aim_conn_addhandler(sess, bosconn, 0x0008, 0x0002, handlepopup, 0);
-  aim_conn_addhandler(sess, bosconn, 0x0009, 0x0003, faimtest_bosrights, 0);
-  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT, faimtest_handleredirect, 0);
-  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL, faimtest_reportinterval, 0);
-  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO, faimtest_parse_buddyrights, 0);
-  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, faimtest_parse_motd, 0);
-  aim_conn_addhandler(sess, bosconn, 0x0004, 0x0005, faimtest_icbmparaminfo, 0);
-  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, faimtest_parse_connerr, 0);
-  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_RIGHTSINFO, faimtest_locrights, 0);
-  aim_conn_addhandler(sess, bosconn, 0x0001, 0x001f, faimtest_memrequest, 0);
-  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, faimtest_parse_oncoming, 0);
-  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, faimtest_parse_offgoing, 0);
-  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, faimtest_parse_incoming_im, 0);
-  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR, faimtest_parse_locerr, 0);
-  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL, faimtest_parse_misses, 0);
-  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE, faimtest_parse_ratechange, 0);
-  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL, faimtest_parse_evilnotify, 0);
-  aim_conn_addhandler(sess, bosconn, 0x000a, 0x0001, faimtest_parse_searcherror, 0);
-  aim_conn_addhandler(sess, bosconn, 0x000a, 0x0003, faimtest_parse_searchreply, 0);
-  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR, faimtest_parse_msgerr, 0);
-  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, faimtest_parse_userinfo, 0);
-  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK, faimtest_parse_msgack, 0);
-
-  aim_conn_addhandler(sess, bosconn, 0x0001, 0x0001, faimtest_parse_genericerr, 0);
-  aim_conn_addhandler(sess, bosconn, 0x0003, 0x0001, faimtest_parse_genericerr, 0);
-  aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, faimtest_parse_genericerr, 0);
-  aim_conn_addhandler(sess, bosconn, 0x0001, 0x000b, serverpause, 0);
-  aim_conn_addhandler(sess, bosconn, 0x0001, 0x0012, migrate, 0);
-  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG, offlinemsg, 0);
+  aim_conn_addhandler(sess, bosconn, 0x0013,         0x0003,                        ssirights, 0);
+  aim_conn_addhandler(sess, bosconn, 0x0013,         0x0006,                        ssidata, 0);
+  aim_conn_addhandler(sess, bosconn, 0x0013,         0x000f,                        ssidatanochange, 0);
+  aim_conn_addhandler(sess, bosconn, 0x0008,         0x0002,                        handlepopup, 0);
+  aim_conn_addhandler(sess, bosconn, 0x0009,         0x0003,                        faimtest_bosrights, 0);
+  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT,           faimtest_handleredirect, 0);
+  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL,  faimtest_reportinterval, 0);
+  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO,         faimtest_parse_buddyrights, 0);
+  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD,               faimtest_parse_motd, 0);
+  aim_conn_addhandler(sess, bosconn, 0x0004,         0x0005,                        faimtest_icbmparaminfo, 0);
+  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR,    faimtest_parse_connerr, 0);
+  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_RIGHTSINFO,         faimtest_locrights, 0);
+  aim_conn_addhandler(sess, bosconn, 0x0001,         0x001f,                        faimtest_memrequest, 0);
+  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING,           faimtest_parse_oncoming, 0);
+  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING,           faimtest_parse_offgoing, 0);
+  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING,           faimtest_parse_incoming_im, 0);
+  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR,              faimtest_parse_locerr, 0);
+  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL,         faimtest_parse_misses, 0);
+  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE,         faimtest_parse_ratechange, 0);
+  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL,               faimtest_parse_evilnotify, 0);
+  aim_conn_addhandler(sess, bosconn, 0x000a,         0x0001,                        faimtest_parse_searcherror, 0);
+  aim_conn_addhandler(sess, bosconn, 0x000a,         0x0003,                        faimtest_parse_searchreply, 0);
+  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR,              faimtest_parse_msgerr, 0);
+  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO,           faimtest_parse_userinfo, 0);
+  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK,                faimtest_parse_msgack, 0);
+
+  aim_conn_addhandler(sess, bosconn, 0x0001,         0x0001,                        faimtest_parse_genericerr, 0);
+  aim_conn_addhandler(sess, bosconn, 0x0003,         0x0001,                        faimtest_parse_genericerr, 0);
+  aim_conn_addhandler(sess, bosconn, 0x0009,         0x0001,                        faimtest_parse_genericerr, 0);
+  aim_conn_addhandler(sess, bosconn, 0x0001,         0x000b,                        serverpause, 0);
+  aim_conn_addhandler(sess, bosconn, 0x0001,         0x0012,                        migrate, 0);
+  aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG,         offlinemsg, 0);
   aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE, offlinemsgdone, 0);
 
   #ifdef MID_REWROTE_ALL_THE_CRAP
-  aim_conn_addhandler(sess, bosconn, 0xffff, 0xffff, faimtest_parse_unknown, 0);
+  aim_conn_addhandler(sess, bosconn, 0xffff,         0xffff,                        faimtest_parse_unknown, 0);
   #endif
 
@@ -421,5 +421,5 @@
 
   /*
-  snprintf(buddies, sizeof(buddies), "jagworks&jkretch76&");
+  snprintf(buddies, sizeof(buddies), "Buddy1&Buddy2&");
   snprintf(profile, sizeof(profile), "Hello.<br>This is a test");
   */
@@ -1387,9 +1387,12 @@
 {
   aim_userinfo_t *userinfo;
-  
+
   va_list ap;
   va_start(ap, fr);
   userinfo = va_arg(ap, aim_userinfo_t *);
   va_end(ap);
+
+  owl_buddylist_oncoming(owl_global_get_buddylist(&g), userinfo->sn);
+  
   /*
     printf("%ld  %s is now online (flags: %04x = %s%s%s%s%s%s%s%s) (caps = %s = 0x%08lx)\n",
@@ -1407,5 +1410,5 @@
     userinfo->capabilities);
   */
-  return 1;
+  return(1);
 }
 
@@ -1418,4 +1421,6 @@
   userinfo = va_arg(ap, aim_userinfo_t *);
   va_end(ap);
+
+  owl_buddylist_offgoing(owl_global_get_buddylist(&g), userinfo->sn);
 
   /*
@@ -2468,2 +2473,70 @@
   }
 }
+
+
+/****************************************/
+
+/*
+static int gaim_parse_oncoming(aim_session_t *sess, aim_frame_t *fr, ...) {
+        struct gaim_connection *gc = sess->aux_data;
+        struct oscar_data *od = gc->proto_data;
+        aim_userinfo_t *info;
+        time_t time_idle = 0, signon = 0;
+        int type = 0;
+        int caps = 0;
+        char *tmp;
+
+        va_list ap;
+        va_start(ap, fr);
+        info = va_arg(ap, aim_userinfo_t *);
+        va_end(ap);
+
+        if (info->present & AIM_USERINFO_PRESENT_CAPABILITIES)
+                caps = info->capabilities;
+        if (info->flags & AIM_FLAG_ACTIVEBUDDY)
+                type |= UC_AB;
+
+        if ((!od->icq) && (info->present & AIM_USERINFO_PRESENT_FLAGS)) {
+                        if (info->flags & AIM_FLAG_UNCONFIRMED)
+                                type |= UC_UNCONFIRMED;
+                        if (info->flags & AIM_FLAG_ADMINISTRATOR)
+                                type |= UC_ADMIN;
+                        if (info->flags & AIM_FLAG_AOL)
+                                type |= UC_AOL;
+                        if (info->flags & AIM_FLAG_FREE)
+                                type |= UC_NORMAL;
+                        if (info->flags & AIM_FLAG_AWAY)
+                                type |= UC_UNAVAILABLE;
+                        if (info->flags & AIM_FLAG_WIRELESS)
+                                type |= UC_WIRELESS;
+        }
+        if (info->present & AIM_USERINFO_PRESENT_ICQEXTSTATUS) {
+                type = (info->icqinfo.status << 16);
+                if (!(info->icqinfo.status & AIM_ICQ_STATE_CHAT) &&
+                      (info->icqinfo.status != AIM_ICQ_STATE_NORMAL)) {
+                        type |= UC_UNAVAILABLE;
+                }
+        }
+
+        if (caps & AIM_CAPS_ICQ)
+                caps ^= AIM_CAPS_ICQ;
+
+        if (info->present & AIM_USERINFO_PRESENT_IDLE) {
+                time(&time_idle);
+                time_idle -= info->idletime*60;
+        }
+
+        if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN)
+                signon = time(NULL) - info->sessionlen;
+
+        tmp = g_strdup(normalize(gc->username));
+        if (!strcmp(tmp, normalize(info->sn)))
+                g_snprintf(gc->displayname, sizeof(gc->displayname), "%s", info->sn);
+        g_free(tmp);
+
+        serv_got_update(gc, info->sn, 1, info->warnlevel/10, signon,
+                        time_idle, type, caps);
+
+        return 1;
+}
+*/
Index: buddylist.c
===================================================================
--- buddylist.c	(revision aa5f725832e087e7a8c053b6d238f21fae14500b)
+++ buddylist.c	(revision aa5f725832e087e7a8c053b6d238f21fae14500b)
@@ -0,0 +1,78 @@
+#include "owl.h"
+
+void owl_buddylist_init(owl_buddylist *b)
+{
+  owl_list_create(&(b->buddies));
+}
+
+/* Deal with an "oncoming" message.  This means recognizing the user
+ * has logged in, and sending a message if they were not already
+ * logged in.
+ */
+void owl_buddylist_oncoming(owl_buddylist *b, char *screenname)
+{
+  int i, j, found;
+  owl_message *m;
+
+  found=0;
+  j=owl_list_get_size(&(b->buddies));
+  for (i=0; i<j; i++) {
+    if (!strcasecmp(owl_list_get_element(&(b->buddies), i), screenname)) {
+      found=1;
+      break;
+    }
+  }
+
+  if (!found) {
+    owl_list_append_element(&(b->buddies), owl_strdup(screenname));
+
+    m=owl_malloc(sizeof(owl_message));
+    owl_message_create_aim_login(m, 0, screenname);
+    owl_global_messagequeue_addmsg(&g, m);
+  }
+}
+    
+
+
+/* Deal with an "offgoing" message.  This means recognizing the user
+ * has logged out, and sending a message if they were logged in.
+ */
+void owl_buddylist_offgoing(owl_buddylist *b, char *screenname)
+{
+  int i, j, found;
+  owl_message *m;
+
+  found=0;
+  j=owl_list_get_size(&(b->buddies));
+  for (i=0; i<j; i++) {
+    if (!strcasecmp(owl_list_get_element(&(b->buddies), i), screenname)) {
+      found=1;
+      owl_free(owl_list_get_element(&(b->buddies), i));
+      owl_list_remove_element(&(b->buddies), i);
+      break;
+    }
+  }
+
+  if (found) {
+    m=owl_malloc(sizeof(owl_message));
+    owl_message_create_aim_login(m, 1, screenname);
+    owl_global_messagequeue_addmsg(&g, m);
+  }
+}
+
+int owl_buddylist_get_size(owl_buddylist *b)
+{
+  return(owl_list_get_size(&(b->buddies)));
+}
+
+char *owl_buddylist_get_buddy(owl_buddylist *b, int n)
+{
+  return(owl_list_get_element(&(b->buddies), n));
+}
+
+void owl_buddylist_clear(owl_buddylist *b) {
+  int i, j;
+
+  owl_list_free_all(&(b->buddies), owl_free);
+  owl_list_create(&(b->buddies));
+}
Index: commands.c
===================================================================
--- commands.c	(revision 651560fb0ba1ab37fb315a20ec96eb3c18929676)
+++ commands.c	(revision aa5f725832e087e7a8c053b6d238f21fae14500b)
@@ -233,5 +233,15 @@
 	      "znol [-f file]",
 	      "Print a znol-style listing of users logged in"),
-  
+
+  OWLCMD_ARGS("alist", owl_command_alist, OWL_CTX_INTERACTIVE,
+	      "List AIM users logged in",
+	      "alist",
+	      "Print a listing of AIM users logged in"),
+
+  OWLCMD_ARGS("blist", owl_command_blist, OWL_CTX_INTERACTIVE,
+	      "List all buddies logged in",
+	      "alist",
+	      "Print a listing of buddies logged in, regardless of protocol."),
+
   OWLCMD_VOID("recv:shiftleft", owl_command_shift_left, OWL_CTX_INTERACTIVE,
 	      "scrolls receive window to the left", "", ""),
@@ -818,5 +828,15 @@
     }
   }
-  owl_function_zlist(file, elapsed, timesort);
+  owl_function_buddylist(0, 1, file);
+  return(NULL);
+}
+
+char *owl_command_alist() {
+  owl_function_buddylist(1, 0, NULL);
+  return(NULL);
+}
+
+char *owl_command_blist() {
+  owl_function_buddylist(1, 1, NULL);
   return(NULL);
 }
@@ -1378,13 +1398,19 @@
   char *tmpbuff;
 
+  if (!owl_global_is_aimloggedin(&g)) {
+    owl_function_makemsg("You are not logged in to AIM.");
+    return(NULL);
+  }
+
   if (argc < 2) {
     owl_function_makemsg("Not enough arguments to the aimwrite command.");
-  } else {
-    tmpbuff=owl_strdup(buff);
-    owl_function_aimwrite_setup(tmpbuff);
-    owl_global_set_buffercommand(&g, tmpbuff);
-    owl_free(tmpbuff);
-  }
-  return NULL;
+    return(NULL);
+  }
+
+  tmpbuff=owl_strdup(buff);
+  owl_function_aimwrite_setup(tmpbuff);
+  owl_global_set_buffercommand(&g, tmpbuff);
+  owl_free(tmpbuff);
+  return(NULL);
 }
 
@@ -1772,9 +1798,14 @@
 char *owl_command_aimlogin(int argc, char **argv, char *buff) {
   int ret;
-
+  
   if (argc!=3) {
     owl_function_makemsg("Wrong number of arguments to aimlogin command");
     return(NULL);
   }
+
+  /* clear the buddylist */
+  owl_buddylist_clear(owl_global_get_buddylist(&g));
+
+  /* try to login */
   ret=owl_aim_login(argv[1], argv[2]);
   if (!ret) {
@@ -1788,4 +1819,7 @@
 
 char *owl_command_aimlogout(int argc, char **argv, char *buff) {
+  /* clear the buddylist */
+  owl_buddylist_clear(owl_global_get_buddylist(&g));
+
   owl_aim_logout();
   return(NULL);
Index: functions.c
===================================================================
--- functions.c	(revision 3abf28bfbedff7d4c809523f93b98d6fd70d120e)
+++ functions.c	(revision aa5f725832e087e7a8c053b6d238f21fae14500b)
@@ -125,8 +125,13 @@
 }
 
-void owl_function_make_outgoing_aim(char *body, char *to)
+int owl_function_make_outgoing_aim(char *body, char *to)
 {
   owl_message *m;
   int followlast;
+
+
+  if (!owl_global_is_aimloggedin(&g)) {
+    return(-1);
+  }
   
   followlast=owl_global_should_followlast(&g);
@@ -149,4 +154,5 @@
   wnoutrefresh(owl_global_get_curs_recwin(&g));
   owl_global_set_needrefresh(&g);
+  return(0);
 }
 
@@ -2689,90 +2695,105 @@
 }
 
-/* popup a znol listing.  If file is NULL use the default .anyone */
-/* this doesn't obey 'elapsed' or 'timesort' yet */
-void owl_function_zlist(char *file, int elapsed, int timesort)
+/* Popup a buddylisting.  If file is NULL use the default .anyone */
+void owl_function_buddylist(int aim, int zephyr, char *file)
 {
   char *ourfile, *tmp, buff[LINE], *line;
   FILE *f;
-  int numlocs, ret, i;
+  int numlocs, ret, i, j;
   ZLocations_t location[200];
   owl_fmtext fm;
-
-  if (file==NULL) {
-    tmp=owl_global_get_homedir(&g);
-    if (!tmp) {
-      owl_function_makemsg("Could not determine home directory");
+  owl_buddylist *b;
+
+  owl_fmtext_init_null(&fm);
+
+  if (aim && owl_global_is_aimloggedin(&g)) {
+    b=owl_global_get_buddylist(&g);
+
+    owl_fmtext_append_bold(&fm, "AIM users logged in:\n");
+    j=owl_buddylist_get_size(b);
+    for (i=0; i<j; i++) {
+      owl_fmtext_append_normal(&fm, "  ");
+      owl_fmtext_append_normal(&fm, owl_buddylist_get_buddy(b, i));
+      owl_fmtext_append_normal(&fm, "\n");
+    }
+  }
+
+  if (zephyr) {
+    if (file==NULL) {
+      tmp=owl_global_get_homedir(&g);
+      if (!tmp) {
+	owl_function_makemsg("Could not determine home directory");
+	return;
+      }
+      ourfile=owl_malloc(strlen(tmp)+50);
+      sprintf(ourfile, "%s/.anyone", owl_global_get_homedir(&g));
+    } else {
+      ourfile=owl_strdup(file);
+    }
+    
+    f=fopen(ourfile, "r");
+    if (!f) {
+      owl_function_makemsg("Error opening file %s: %s",
+			   ourfile,
+			   strerror(errno) ? strerror(errno) : "");
       return;
     }
-    ourfile=owl_malloc(strlen(tmp)+50);
-    sprintf(ourfile, "%s/.anyone", owl_global_get_homedir(&g));
-  } else {
-    ourfile=owl_strdup(file);
-  }
-
-  f=fopen(ourfile, "r");
-  if (!f) {
-    owl_function_makemsg("Error opening file %s: %s",
-			 ourfile,
-			 strerror(errno) ? strerror(errno) : "");
-    return;
-  }
-
-  owl_fmtext_init_null(&fm);
     
-  while (fgets(buff, LINE, f)!=NULL) {
-    /* ignore comments, blank lines etc. */
-    if (buff[0]=='#') continue;
-    if (buff[0]=='\n') continue;
-    if (buff[0]=='\0') continue;
-
-    /* strip the \n */
-    buff[strlen(buff)-1]='\0';
-
-    /* ingore from # on */
-    tmp=strchr(buff, '#');
-    if (tmp) tmp[0]='\0';
-
-    /* ingore from SPC */
-    tmp=strchr(buff, ' ');
-    if (tmp) tmp[0]='\0';
-
-    /* stick on the local realm. */
-    if (!strchr(buff, '@')) {
-      strcat(buff, "@");
-      strcat(buff, ZGetRealm());
-    }
-
-    ret=ZLocateUser(buff, &numlocs, ZAUTH);
-    if (ret!=ZERR_NONE) {
-      owl_function_makemsg("Error getting location for %s", buff);
-      continue;
-    }
-
-    numlocs=200;
-    ret=ZGetLocations(location, &numlocs);
-    if (ret==0) {
-      for (i=0; i<numlocs; i++) {
-	line=malloc(strlen(location[i].host)+strlen(location[i].time)+strlen(location[i].tty)+100);
-	tmp=short_zuser(buff);
-	sprintf(line, "%-10.10s %-24.24s %-12.12s  %20.20s\n",
-		tmp,
-		location[i].host,
-		location[i].tty,
-		location[i].time);
-	owl_fmtext_append_normal(&fm, line);
-	owl_free(tmp);
+    owl_fmtext_append_bold(&fm, "Zephyr users logged in:\n");
+    
+    while (fgets(buff, LINE, f)!=NULL) {
+      /* ignore comments, blank lines etc. */
+      if (buff[0]=='#') continue;
+      if (buff[0]=='\n') continue;
+      if (buff[0]=='\0') continue;
+      
+      /* strip the \n */
+      buff[strlen(buff)-1]='\0';
+      
+      /* ingore from # on */
+      tmp=strchr(buff, '#');
+      if (tmp) tmp[0]='\0';
+      
+      /* ingore from SPC */
+      tmp=strchr(buff, ' ');
+      if (tmp) tmp[0]='\0';
+      
+      /* stick on the local realm. */
+      if (!strchr(buff, '@')) {
+	strcat(buff, "@");
+	strcat(buff, ZGetRealm());
       }
-      if (numlocs>=200) {
-	owl_fmtext_append_normal(&fm, "Too many locations found for this user, truncating.\n");
+      
+      ret=ZLocateUser(buff, &numlocs, ZAUTH);
+      if (ret!=ZERR_NONE) {
+	owl_function_makemsg("Error getting location for %s", buff);
+	continue;
       }
-    }
-  }
-  fclose(f);
-
+      
+      numlocs=200;
+      ret=ZGetLocations(location, &numlocs);
+      if (ret==0) {
+	for (i=0; i<numlocs; i++) {
+	  line=malloc(strlen(location[i].host)+strlen(location[i].time)+strlen(location[i].tty)+100);
+	  tmp=short_zuser(buff);
+	  sprintf(line, "  %-10.10s %-24.24s %-12.12s  %20.20s\n",
+		  tmp,
+		  location[i].host,
+		  location[i].tty,
+		  location[i].time);
+	  owl_fmtext_append_normal(&fm, line);
+	  owl_free(tmp);
+	}
+	if (numlocs>=200) {
+	  owl_fmtext_append_normal(&fm, "  Too many locations found for this user, truncating.\n");
+	}
+      }
+    }
+    fclose(f);
+    owl_free(ourfile);
+  }
+  
   owl_function_popless_fmtext(&fm);
   owl_fmtext_free(&fm);
-
-  owl_free(ourfile);
 }
 
Index: global.c
===================================================================
--- global.c	(revision d09e5a1609d038695dbc6bc34a8177935a9bf7ea)
+++ global.c	(revision aa5f725832e087e7a8c053b6d238f21fae14500b)
@@ -92,4 +92,6 @@
   g->aim_loggedin=0;
   g->aim_lastnop=0;
+
+  owl_buddylist_init(&(g->buddylist));
 }
 
@@ -717,2 +719,7 @@
   return(1);
 }
+
+owl_buddylist *owl_global_get_buddylist(owl_global *g) {
+  return(&(g->buddylist));
+}
+  
Index: keys.c
===================================================================
--- keys.c	(revision 440ce0128879af680216691261571cf7a278f993)
+++ keys.c	(revision aa5f725832e087e7a8c053b6d238f21fae14500b)
@@ -241,5 +241,5 @@
 
   BIND_CMD("i",   "info",             "");
-  BIND_CMD("l",   "zlist",            "");
+  BIND_CMD("l",   "blist",            "");
   BIND_CMD("M",   "pop-message",      "");
   BIND_CMD("T",   "delete trash",     "mark all 'trash' messages for deletion");
Index: message.c
===================================================================
--- message.c	(revision 3abf28bfbedff7d4c809523f93b98d6fd70d120e)
+++ message.c	(revision aa5f725832e087e7a8c053b6d238f21fae14500b)
@@ -579,4 +579,28 @@
   
   owl_free(indent);
+}
+
+/* For login direction == 0
+ * For logout direction == 1
+ */
+void owl_message_create_aim_login(owl_message *m, int direction, char *screenname)
+{
+  owl_message_init(m);
+  owl_message_set_body(m, "");
+  owl_message_set_sender(m, screenname);
+  owl_message_set_recipient(m, owl_global_get_aim_screenname(&g));
+  owl_message_set_type_aim(m);
+  owl_message_set_direction_in(m);
+
+  owl_fmtext_init_null(&(m->fmtext));
+  owl_fmtext_append_normal(&(m->fmtext), OWL_TABSTR);
+  if (direction==0) {
+    owl_fmtext_append_bold(&(m->fmtext), "AIM LOGIN");
+  } else if (direction==1) {
+    owl_fmtext_append_bold(&(m->fmtext), "AIM LOGOUT");
+  }
+  owl_fmtext_append_normal(&(m->fmtext), " for ");
+  owl_fmtext_append_normal(&(m->fmtext), screenname);
+  owl_fmtext_append_normal(&(m->fmtext), "\n");
 }
 
Index: owl.h
===================================================================
--- owl.h	(revision d09e5a1609d038695dbc6bc34a8177935a9bf7ea)
+++ owl.h	(revision aa5f725832e087e7a8c053b6d238f21fae14500b)
@@ -350,4 +350,9 @@
   int       kpstackpos;		/* location in stack (-1 = none) */
 } owl_keyhandler;
+
+typedef struct _owl_buddylist {
+  owl_list buddies;
+} owl_buddylist;
+
 
 typedef struct _owl_global {
@@ -403,4 +408,5 @@
   int aim_loggedin;
   char *aim_screenname;
+  owl_buddylist buddylist;
   owl_list messagequeue; /* for queueing up aim and other messages */
 } owl_global;
Index: owl_prototypes.h
===================================================================
--- owl_prototypes.h	(revision 651560fb0ba1ab37fb315a20ec96eb3c18929676)
+++ owl_prototypes.h	(revision aa5f725832e087e7a8c053b6d238f21fae14500b)
@@ -22,4 +22,12 @@
 extern void directim_requested(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args);
 
+/* -------------------------------- buddylist.c -------------------------------- */
+extern void owl_buddylist_init(owl_buddylist *b);
+extern void owl_buddylist_oncoming(owl_buddylist *b, char *screenname);
+extern void owl_buddylist_offgoing(owl_buddylist *b, char *screenname);
+extern int owl_buddylist_get_size(owl_buddylist *b);
+extern char *owl_buddylist_get_buddy(owl_buddylist *b, int n);
+extern void owl_buddylist_clear(owl_buddylist *b);
+
 /* -------------------------------- cmd.c -------------------------------- */
 extern int owl_cmddict_setup(owl_cmddict *cd);
@@ -45,4 +53,6 @@
 extern char *owl_command_help(int argc, char **argv, char *buff);
 extern char *owl_command_zlist(int argc, char **argv, char *buff);
+extern char *owl_command_alist();
+extern char *owl_command_blist();
 extern void owl_command_about();
 extern void owl_command_version();
@@ -280,5 +290,5 @@
 extern void owl_function_adminmsg(char *header, char *body);
 extern void owl_function_make_outgoing_zephyr(char *body, char *zwriteline, char *zsig);
-extern void owl_function_make_outgoing_aim(char *body, char *to);
+extern int owl_function_make_outgoing_aim(char *body, char *to);
 extern void owl_function_zwrite_setup(char *line);
 extern void owl_function_aimwrite_setup(char *line);
@@ -376,5 +386,5 @@
 extern void owl_function_search_helper(int mode, int direction);
 extern char *owl_function_ztext_stylestrip(char *zt);
-extern void owl_function_zlist(char *file, int elapsed, int timesort);
+extern void owl_function_buddylist(int aim, int zephyr, char *file);
 extern void owl_function_dump(char *filename);
 extern void owl_function_do_newmsgproc(void);
@@ -479,4 +489,5 @@
 extern owl_message *owl_global_messageuque_popmsg(owl_global *g);
 extern int owl_global_messagequeue_pending(owl_global *g);
+extern owl_buddylist *owl_global_get_buddylist(owl_global *g);
 
 /* -------------------------------- help.c -------------------------------- */
@@ -614,4 +625,5 @@
 extern void owl_message_create_incoming_aim(owl_message *m, char *sender, char *recipient, char *text);
 extern void owl_message_create_outgoing_aim(owl_message *m, char *sender, char *recipient, char *text);
+extern void owl_message_create_aim_login(owl_message *m, int direction, char *screenname);
 extern void owl_message_create_admin(owl_message *m, char *header, char *text);
 extern void owl_message_create_from_znotice(owl_message *m, ZNotice_t *n);
