Index: Makefile.in
===================================================================
--- Makefile.in	(revision 7e78e493b4fdb2a8be4960ed71a570ad9ce7645c)
+++ Makefile.in	(revision df7f3647dd2b00527dde45b84c564c64525f695c)
@@ -5,4 +5,5 @@
 prefix = @prefix@
 exec_prefix = @exec_prefix@
+datarootdir = @datarootdir@
 datadir = @datadir@/barnowl
 bindir = @bindir@
@@ -25,6 +26,6 @@
      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 \
-     zbuddylist.c muxevents.c popexec.c obarray.c select.c wcwidth.c \
+     aim.c buddy.c buddylist.c style.c errqueue.c \
+     zbuddylist.c popexec.c obarray.c select.c wcwidth.c \
      glib_compat.c
 OWL_SRC = owl.c
@@ -53,5 +54,5 @@
 	$(ATHSTATIC) $(CC) -o $(EXE) owl.o $(OBJS) $(LDFLAGS) $(LIBS)
 
-tester: $(AUTOGEN) $(OBJS) tester.o
+tester: $(AUTOGEN) $(OBJS) tester.o libfaim
 	$(ATHSTATIC) $(CC) -o tester tester.o $(OBJS) $(LDFLAGS) $(LIBS)
 
Index: aim.c
===================================================================
--- aim.c	(revision e3e6cff9f72f2e4f2c72c2a48f95e45db859298d)
+++ aim.c	(revision c675b3959f4b4476da37b65a66b27fa38163c845)
@@ -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, 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, 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);
 }
 
@@ -239,5 +253,5 @@
 {
   if (message) {
-    owl_function_error(message);
+    owl_function_error("%s", message);
   } else {
     owl_function_error("Authentication error on login");
@@ -246,4 +260,5 @@
   owl_global_set_aimnologgedin(&g);
   owl_global_set_no_doaimevents(&g);
+  owl_select_remove_timer(g.aim_nop_timer);
 }
 
@@ -252,5 +267,5 @@
   int ret;
 
-  ret=aim_im_sendch1(owl_global_get_aimsess(&g), to, NULL, msg);
+  ret=aim_im_sendch1(owl_global_get_aimsess(&g), to, 0, msg);
     
   /* I don't know how to check for an error yet */
@@ -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) {
@@ -1698,5 +1708,5 @@
   
   /* printf("snac threw error (reason 0x%04x: %s)\n", reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
-  if (reason<msgerrreasonslen) owl_function_error(msgerrreasons[reason]);
+  if (reason<msgerrreasonslen) owl_function_error("%s", msgerrreasons[reason]);
   
   return 1;
@@ -1715,5 +1725,5 @@
   
   /* printf("message to %s bounced (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
-  if (reason<msgerrreasonslen) owl_function_error(msgerrreasons[reason]);
+  if (reason<msgerrreasonslen) owl_function_error("%s", msgerrreasons[reason]);
 
   if (reason==4) {
@@ -1736,5 +1746,5 @@
   
   /* printf("user information for %s unavailable (reason 0x%04x: %s)\n", destsn, reason, (reason<msgerrreasonslen)?msgerrreasons[reason]:"unknown"); */
-  if (reason<msgerrreasonslen) owl_function_error(msgerrreasons[reason]);
+  if (reason<msgerrreasonslen) owl_function_error("%s", msgerrreasons[reason]);
   
   return 1;
@@ -2309,4 +2319,11 @@
   aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
   return;	
+}
+
+void owl_process_aim()
+{
+  if (owl_global_is_doaimevents(&g)) {
+    owl_aim_process_events();
+  }
 }
 
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: commands.c
===================================================================
--- commands.c	(revision 451db9e0515b2671c88e0858f712b53a7fcc5b76)
+++ commands.c	(revision f34dd65b3adbc2eedc045a674dd89b7e20257680)
@@ -453,11 +453,4 @@
   OWLCMD_VOID("pop-message", owl_command_pop_message, OWL_CTX_RECWIN,
 	      "pops up a message in a window", "", ""),
-
-  OWLCMD_VOID("openurl", owl_command_openurl, OWL_CTX_INTERACTIVE,
-	      "opens up a URL from the current message",
-	      "", 
-	      "Uses the 'webbrowser' variable to determine\n"
-	      "which browser to use.  Currently, 'netscape'\n"
-	      "and 'galeon' are supported.\n"),
 
   OWLCMD_ARGS("zaway", owl_command_zaway, OWL_CTX_INTERACTIVE,
@@ -641,4 +634,5 @@
 	      "show keymap <keymap>\n"
 	      "show license\n"
+	      "show quickstart\n"
 	      "show startup\n"
 	      "show status\n"
@@ -1046,8 +1040,5 @@
 void owl_command_version()
 {
-  char buff[1024];
-
-  sprintf(buff, "Owl version %s", OWL_VERSION_STRING);
-  owl_function_makemsg(buff);
+  owl_function_makemsg("BarnOwl version %s", OWL_VERSION_STRING);
 }
 
@@ -1461,5 +1452,5 @@
     owl_function_aaway_on();
     owl_function_zaway_on();
-    owl_function_makemsg("Away messages set.", owl_global_get_aaway_msg_default(&g));
+    owl_function_makemsg("Away messages set.");
     return NULL;
   }
@@ -1691,5 +1682,5 @@
   }
 
-  owl_function_debugmsg(argv[1]);
+  owl_function_debugmsg("%s", argv[1]);
   return(NULL);
 }
@@ -1735,11 +1726,4 @@
   return(NULL);
 }
-
-
-void owl_command_zlog_out(void)
-{
-  owl_zephyr_zlog_out();
-}
-
 
 char *owl_command_subscribe(int argc, char **argv, char *buff)
@@ -2207,4 +2191,6 @@
   } else if (!strcmp(argv[1], "license")) {
     owl_function_show_license();
+  } else if (!strcmp(argv[1], "quickstart")) {
+    owl_function_show_quickstart();
   } else if (!strcmp(argv[1], "startup")) {
     char *filename;
@@ -2251,9 +2237,4 @@
 {
   owl_function_curmsg_to_popwin();
-}
-
-void owl_command_openurl(void)
-{
-  owl_function_openurl();
 }
 
@@ -2580,5 +2561,5 @@
 {
     buff = skiptokens(buff, 1);
-    owl_function_error(buff);
+    owl_function_error("%s", buff);
     return NULL;
 }
@@ -2587,5 +2568,5 @@
 {
     buff = skiptokens(buff, 1);
-    owl_function_makemsg(buff);
+    owl_function_makemsg("%s", buff);
     return NULL;
 }
Index: configure.ac
===================================================================
--- configure.ac	(revision d9337637b38624a9f8d064c1a45062f7762f7b72)
+++ configure.ac	(revision d54035d6066afecc509f9a5d444f39a5c0b6725c)
@@ -46,5 +46,5 @@
 fi
 
-AC_CHECK_LIB(ncursesw, initscr,, AC_MSG_ERROR(No curses library found.))
+AC_CHECK_LIB(ncursesw, initscr,, AC_MSG_ERROR(No libncursesw found.))
 AC_CHECK_LIB(com_err, com_err)
 AC_CHECK_LIB(nsl, gethostbyname)
Index: editwin.c
===================================================================
--- editwin.c	(revision e9bb404064914673e4c9588dccf789ce2c5d2fbc)
+++ editwin.c	(revision 50e671ca58bb9d2a3f7ca0cac269bc966a246a95)
@@ -1042,4 +1042,9 @@
     if (e->buff[i] == '\n' && e->buff[i+1] == '\n') break;
 
+    /* bail if we hit a trailing dot on the buffer */
+    if (e->buff[i] == '\n' && e->buff[i+1] == '.'
+        && ((i+2) >= e->bufflen || e->buff[i+2] == '\0'))
+      break;
+
     /* if we've travelled too far, linewrap */
     if ((e->buffx) >= e->fillcol) {
Index: examples/owlconf.erik
===================================================================
--- examples/owlconf.erik	(revision 5d9c664a3ac870215d4deea22ef3d0be2978f94a)
+++ examples/owlconf.erik	(revision 4f15e8e9ceada0d4b2cc969ebf43b0a1fb3709ea)
@@ -147,7 +147,4 @@
     owl::command("set -q rxping on");
     owl::command("set -q typewinsize 5");
-    if ($ENV{"DISPLAY"} eq ":0.0") {
-      owl::command("set -q webbrowser galeon");	
-    }
     owl::command("filter me recipient %me% or ( sender %me% and class message and instance personal ) or class mail or type aim");
     owl::command("filter owl instance ^owl.*");
Index: examples/owlconf.simple
===================================================================
--- examples/owlconf.simple	(revision 2b14303f3f167f4a8fb4ed6f1141d62cdf13e433)
+++ examples/owlconf.simple	(revision 4f15e8e9ceada0d4b2cc969ebf43b0a1fb3709ea)
@@ -93,9 +93,4 @@
     # owl::command('set -q view_home all');
 
-
-    ## Which webbrowser to use to launch URLs with the 'w' key.
-    # owl::command('set -q webbrowser netscape');
-    # owl::command('set -q webbrowser galeon');
-    # owl::command('set -q webbrowser none');
 
     ## Default message to send when zaway is on (toggle with 'A')
Index: filter.c
===================================================================
--- filter.c	(revision cdc6ff1af792c6ba025214d1b7f310e652c420d7)
+++ filter.c	(revision f34dd65b3adbc2eedc045a674dd89b7e20257680)
@@ -3,6 +3,4 @@
 
 static const char fileIdent[] = "$Id$";
-
-#define OWL_FILTER_MAXRECURSE 20
 
 int owl_filter_init_fromstring(owl_filter *f, char *name, char *string)
@@ -20,5 +18,4 @@
 {
   f->name=owl_strdup(name);
-  f->polarity=0;
   f->fgcolor=OWL_COLOR_DEFAULT;
   f->bgcolor=OWL_COLOR_DEFAULT;
@@ -50,5 +47,5 @@
   /* Now check for recursion. */
   if (owl_filter_is_toodeep(f)) {
-    owl_function_error("Filter loop or exceeds recursion depth");
+    owl_function_error("Filter loop!");
     owl_filter_free(f);
     return(-1);
@@ -159,14 +156,4 @@
 }
 
-void owl_filter_set_polarity_match(owl_filter *f)
-{
-  f->polarity=0;
-}
-
-void owl_filter_set_polarity_unmatch(owl_filter *f)
-{
-  f->polarity=1;
-}
-
 void owl_filter_set_fgcolor(owl_filter *f, int color)
 {
@@ -207,5 +194,4 @@
   if(!f->root) return 0;
   ret = owl_filterelement_match(f->root, m);
-  if(f->polarity) ret = !ret;
   return ret;
 }
@@ -313,5 +299,5 @@
   int numfailed=0;
   owl_message m;
-  owl_filter f1, f2, f3, f4;
+  owl_filter f1, f2, f3, f4, f5;
 
   owl_list_create(&(g.filterlist));
@@ -365,4 +351,7 @@
   FAIL_UNLESS("mutual recursion",   owl_filter_init_fromstring(&f4, "f4", "filter f3"));
 
+  /* support referencing a filter several times */
+  FAIL_UNLESS("DAG", !owl_filter_init_fromstring(&f5, "dag", "filter f1 or filter f1"));
+
   return 0;
 }
Index: filterelement.c
===================================================================
--- filterelement.c	(revision 0504f6318cdf8fe825d6783bd0909a68afded8bb)
+++ filterelement.c	(revision f4464544a8d8ed67998d75c5715219161f0bae5f)
@@ -279,30 +279,43 @@
 }
 
+static int fe_visiting = 0;
+static int fe_visited  = 1;
+
 int owl_filterelement_is_toodeep(owl_filter *f, owl_filterelement *fe)
 {
-  int one = 1;
-  owl_list nodes;
+  int rv;
   owl_dict filters;
-  owl_list_create(&nodes);
   owl_dict_create(&filters);
-  
-  owl_list_append_element(&nodes, fe);
-  owl_dict_insert_element(&filters, f->name, &one, NULL);
-  while(owl_list_get_size(&nodes)) {
-    fe = owl_list_get_element(&nodes, 0);
-    owl_list_remove_element(&nodes, 0);
-    if(fe->left) owl_list_append_element(&nodes, fe->left);
-    if(fe->right) owl_list_append_element(&nodes, fe->right);
-    if(fe->match_message == owl_filterelement_match_filter) {
-      if(owl_dict_find_element(&filters, fe->field)) return 1;
-      owl_dict_insert_element(&filters, fe->field, &one, NULL);
+
+  owl_dict_insert_element(&filters, f->name, &fe_visiting, owl_dict_noop_free);
+
+  rv = _owl_filterelement_is_toodeep(fe, &filters);
+
+  owl_dict_free_simple(&filters);
+  return rv;
+}
+
+int _owl_filterelement_is_toodeep(owl_filterelement *fe, owl_dict *seen)
+{
+  int rv = 0;
+  owl_filter *f;
+
+  if(fe->match_message == owl_filterelement_match_filter) {
+    int *nval = owl_dict_find_element(seen, fe->field);
+    if(nval == &fe_visiting) {
+      return 1;
+    } else if (nval == NULL) {
       f = owl_global_get_filter(&g, fe->field);
-      if(f) owl_list_append_element(&nodes, f->root);
+      owl_dict_insert_element(seen, fe->field, &fe_visiting, owl_dict_noop_free);
+      if(f) rv = _owl_filterelement_is_toodeep(f->root, seen);
+      owl_dict_insert_element(seen, fe->field, &fe_visited, owl_dict_noop_free);
     }
-  }
-
-  owl_list_free_simple(&nodes);
-  owl_dict_free_simple(&filters);
-  return 0;
+  } else {
+    if(fe->left)
+      rv = rv || _owl_filterelement_is_toodeep(fe->left, seen);
+    if(fe->right)
+      rv = rv || _owl_filterelement_is_toodeep(fe->right, seen);
+  }
+  return rv;
 }
 
Index: fmtext.c
===================================================================
--- fmtext.c	(revision 6f6330b75dc25a4ca924840a42b64e3ae965435e)
+++ fmtext.c	(revision 14903270d4a34ee12357613525f0870544bc6915)
@@ -90,4 +90,18 @@
 }
 
+/* Append normal, uncolored text specified by format string to 'f' */
+void owl_fmtext_appendf_normal(owl_fmtext *f, char *fmt, ...)
+{
+  va_list ap;
+  char *buff;
+
+  va_start(ap, fmt);
+  buff = g_strdup_vprintf(fmt, ap);
+  va_end(ap);
+  if (!buff)
+    return;
+  owl_fmtext_append_attr(f, buff, OWL_FMTEXT_ATTR_NONE, OWL_COLOR_DEFAULT, OWL_COLOR_DEFAULT);
+}
+
 /* Append normal text 'text' to 'f' with color 'color' */
 void owl_fmtext_append_normal_color(owl_fmtext *f, char *text, int fgcolor, int bgcolor)
@@ -169,5 +183,6 @@
 
 /* Internal function.  Append text from 'in' between index 'start' and
- * 'stop' to the end of 'f'
+ * 'stop', inclusive, to the end of 'f'. This function works with
+ * bytes.
  */
 void _owl_fmtext_append_fmtext(owl_fmtext *f, owl_fmtext *in, int start, int stop) /*noproto*/
@@ -474,14 +489,15 @@
 	_owl_fmtext_append_fmtext(out, in, ptr_s - in->textbuff, ptr_c - in->textbuff);
       }
+      else if (chwidth > 1) {
+        /* Last char is wide, truncate. */
+        _owl_fmtext_append_fmtext(out, in, ptr_s - in->textbuff, ptr_c - in->textbuff - 1);
+        owl_fmtext_append_normal(out, "\n");
+      }
       else {
-	if (chwidth > 1) {
-	  /* Last char is wide, truncate. */
-	  _owl_fmtext_append_fmtext(out, in, ptr_s - in->textbuff, ptr_c - in->textbuff - 1);
-	  owl_fmtext_append_normal(out, "\n");
-	}
-	else {
-	  /* Last char fits perfectly, leave alone.*/
-	  _owl_fmtext_append_fmtext(out, in, ptr_s - in->textbuff, ptr_c - in->textbuff);
-	}
+        /* Last char fits perfectly, We skip to the next char and back
+         * up a byte to make sure we get it all.
+         */
+        ptr_c = g_utf8_next_char(ptr_c);
+        _owl_fmtext_append_fmtext(out, in, ptr_s - in->textbuff, ptr_c - in->textbuff - 1);
       }
     }
@@ -763,8 +779,8 @@
  * If format_fn is specified, passes it the list element value
  * and it will return a string which this needs to free. */
-void owl_fmtext_append_list(owl_fmtext *f, owl_list *l, char *join_with, char *(format_fn)(void*))
+void owl_fmtext_append_list(owl_fmtext *f, owl_list *l, char *join_with, char *(format_fn)(char *))
 {
   int i, size;
-  void *elem;
+  char *elem;
   char *text;
 
Index: functions.c
===================================================================
--- functions.c	(revision 3f3ee611e4b4ff9de1453aa609918c0099936019)
+++ functions.c	(revision b4c270c6f471826e40ad97087ba3c912dcfad7fc)
@@ -15,9 +15,4 @@
 static const char fileIdent[] = "$Id$";
 
-void owl_function_noop(void)
-{
-  return;
-}
-
 char *owl_function_command(char *cmdbuff)
 {
@@ -99,5 +94,5 @@
 }
 
-char *owl_function_style_describe(void *name) {
+char *owl_function_style_describe(char *name) {
   char *desc, *s;
   owl_style *style;
@@ -114,5 +109,5 @@
 }
 
-char *owl_function_cmd_describe(void *name)
+char *owl_function_cmd_describe(char *name)
 {
   owl_cmd *cmd = owl_cmddict_find(owl_global_get_cmddict(&g), name);
@@ -172,4 +167,34 @@
 }
 
+void owl_function_show_quickstart()
+{
+    char *message =
+    "Move between messages with the arrow keys, and press 'r' to reply.\n"
+    "For more info, press 'h' or visit http://barnowl.mit.edu/\n\n"
+#ifdef HAVE_LIBZEPHYR
+    "@b(Zephyr:)\n"
+    "To send a message to a user, type ':zwrite @b(username)'. You can also\n"
+    "press 'z' and then type the username. To subscribe to a class, type\n"
+    "':sub @b(class)', and then type ':zwrite -c @b(class)' to send.\n\n"
+#endif
+    "@b(AIM:)\n"
+    "Log in to AIM with ':aimlogin @b(screenname)'. Use ':aimwrite @b(screenname)',\n"
+    "or 'a' and then the screen name, to send someone a message.\n\n"
+    ;
+
+    if (owl_perlconfig_is_function("BarnOwl::Hooks::_get_quickstart")) {
+        char *perlquickstart = owl_perlconfig_execute("BarnOwl::Hooks::_get_quickstart()");
+        if (perlquickstart) {
+            char *result = owl_sprintf("%s%s", message, perlquickstart);
+            owl_function_adminmsg("BarnOwl Quickstart", result);
+            owl_free(result);
+            owl_free(perlquickstart);
+            return;
+        }
+    }
+    owl_function_adminmsg("BarnOwl Quickstart", message);
+}
+
+
 /* Create an admin message, append it to the global list of messages
  * and redisplay if necessary.
@@ -602,7 +627,9 @@
 
   if (!found) {
-    owl_function_makemsg("already at last%s message%s%s",
+    owl_function_makemsg("already at last%s message%s%s%s",
 			 skip_deleted?" non-deleted":"",
-			 filter?" in ":"", filter?filter:"");
+			 filter?" in ":"", filter?filter:"",
+			 owl_mainwin_is_curmsg_truncated(owl_global_get_mainwin(&g)) ?
+			 ", press Enter to scroll" : "");
     /* if (!skip_deleted) owl_function_beep(); */
   }
@@ -684,15 +711,4 @@
   owl_function_prevmsg_full(NULL, 1, 1);
 }
-
-void owl_function_nextmsg_personal()
-{
-  owl_function_nextmsg_full("personal", 0, 0);
-}
-
-void owl_function_prevmsg_personal()
-{
-  owl_function_prevmsg_full("personal", 0, 0);
-}
-
 
 /* if move_after is 1, moves after the delete */
@@ -1019,102 +1035,4 @@
   owl_function_debugmsg("Quitting Owl");
   exit(0);
-}
-
-void owl_function_openurl()
-{
-  /* visit the first url in the current message */
-  owl_message *m;
-  owl_view *v;
-  char *ptr1, *ptr2, *text, url[LINE], tmpbuff[LINE];
-  int webbrowser;
-
-  webbrowser = owl_global_get_webbrowser(&g);
-
-  if (webbrowser < 0 || webbrowser == OWL_WEBBROWSER_NONE) {
-    owl_function_error("No browser selected");
-    return;
-  }
-
-  v=owl_global_get_current_view(&g);
-  
-  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
-
-  if (!m || owl_view_get_size(v)==0) {
-    owl_function_error("No current message selected");
-    return;
-  }
-
-  text=owl_message_get_text(m);
-
-  /* First look for a good URL */  
-  if ((ptr1=strstr(text, "http://"))!=NULL) {
-    ptr2=strpbrk(ptr1, " \n\t");
-    if (ptr2) {
-      strncpy(url, ptr1, ptr2-ptr1+1);
-      url[ptr2-ptr1+1]='\0';
-    } else {
-      strcpy(url, ptr1);
-    }
-
-    /* if we had <http strip a trailing > */
-    if (ptr1>text && ptr1[-1]=='<') {
-      if (url[strlen(url)-1]=='>') {
-	url[strlen(url)-1]='\0';
-      }
-    }
-  } else if ((ptr1=strstr(text, "https://"))!=NULL) {
-    /* Look for an https URL */  
-    ptr2=strpbrk(ptr1, " \n\t");
-    if (ptr2) {
-      strncpy(url, ptr1, ptr2-ptr1+1);
-      url[ptr2-ptr1+1]='\0';
-    } else {
-      strcpy(url, ptr1);
-    }
-    
-    /* if we had <http strip a trailing > */
-    if (ptr1>text && ptr1[-1]=='<') {
-      if (url[strlen(url)-1]=='>') {
-	url[strlen(url)-1]='\0';
-      }
-    }
-  } else if ((ptr1=strstr(text, "www."))!=NULL) {
-    /* if we can't find a real url look for www.something */
-    ptr2=strpbrk(ptr1, " \n\t");
-    if (ptr2) {
-      strncpy(url, ptr1, ptr2-ptr1+1);
-      url[ptr2-ptr1+1]='\0';
-    } else {
-      strcpy(url, ptr1);
-    }
-  } else {
-    owl_function_beep();
-    owl_function_error("Could not find URL to open.");
-    return;
-  }
-
-  /* Make sure there aren't any quotes or \'s in the url */
-  for (ptr1 = url; *ptr1; ptr1++) {
-    if (*ptr1 == '"' || *ptr1 == '\\') {
-      owl_function_beep();
-      owl_function_error("URL contains invalid characters.");
-      return;
-    }
-  }
-  
-  /* NOTE: There are potentially serious security issues here... */
-
-  /* open the page */
-  owl_function_makemsg("Opening %s", url);
-  if (webbrowser == OWL_WEBBROWSER_NETSCAPE) {
-    snprintf(tmpbuff, LINE, "netscape -remote \"openURL(%s)\" > /dev/null 2> /dev/null", url);
-    system(tmpbuff); 
-  } else if (webbrowser == OWL_WEBBROWSER_GALEON) {
-    snprintf(tmpbuff, LINE, "galeon \"%s\" > /dev/null 2> /dev/null &", url);
-    system(tmpbuff); 
-  } else if (webbrowser == OWL_WEBBROWSER_OPERA) {
-    snprintf(tmpbuff, LINE, "opera \"%s\" > /dev/null 2> /dev/null &", url);
-    system(tmpbuff); 
-  }
 }
 
@@ -1344,9 +1262,4 @@
 }
 
-void owl_function_refresh()
-{
-  owl_function_resize();
-}
-
 void owl_function_beep()
 {
@@ -1471,27 +1384,26 @@
 void owl_function_about()
 {
-  char buff[5000];
-
-  sprintf(buff, "This is barnowl version %s\n\n", OWL_VERSION_STRING);
-  strcat(buff, "barnowl is a fork of the Owl zephyr client, written and\n");
-  strcat(buff, "maintained by Alejandro Sedeno and Nelson Elhage at the\n");
-  strcat(buff, "Massachusetts Institute of Technology. \n");
-  strcat(buff, "\n");
-  strcat(buff, "Owl was written by James Kretchmar. The first version, 0.5, was\n");
-  strcat(buff, "released in March 2002.\n");
-  strcat(buff, "\n");
-  strcat(buff, "The name 'owl' was chosen in reference to the owls in the\n");
-  strcat(buff, "Harry Potter novels, who are tasked with carrying messages\n");
-  strcat(buff, "between Witches and Wizards. The name 'barnowl' was chosen\n");
-  strcat(buff, "because we feel our owls should live closer to our ponies.\n");
-  strcat(buff, "\n");
-  strcat(buff, "Copyright (c) 2006-2008 The BarnOwl Developers. All rights reserved.\n");
-  strcat(buff, "Copyright (c) 2004 James Kretchmar. All rights reserved.\n");
-  strcat(buff, "Copyright 2002 Massachusetts Institute of Technology\n");
-  strcat(buff, "\n");
-  strcat(buff, "This program is free software. You can redistribute it and/or\n");
-  strcat(buff,  "modify under the terms of the Sleepycat License. Use the \n");
-  strcat(buff,  "':show license' command to display the full license\n");
-  owl_function_popless_text(buff);
+  owl_function_popless_text(
+    "This is barnowl version " OWL_VERSION_STRING ".\n\n"
+    "barnowl is a fork of the Owl zephyr client, written and\n"
+    "maintained by Alejandro Sedeno and Nelson Elhage at the\n"
+    "Massachusetts Institute of Technology. \n"
+    "\n"
+    "Owl was written by James Kretchmar. The first version, 0.5, was\n"
+    "released in March 2002.\n"
+    "\n"
+    "The name 'owl' was chosen in reference to the owls in the\n"
+    "Harry Potter novels, who are tasked with carrying messages\n"
+    "between Witches and Wizards. The name 'barnowl' was chosen\n"
+    "because we feel our owls should live closer to our ponies.\n"
+    "\n"
+    "Copyright (c) 2006-2008 The BarnOwl Developers. All rights reserved.\n"
+    "Copyright (c) 2004 James Kretchmar. All rights reserved.\n"
+    "Copyright 2002 Massachusetts Institute of Technology\n"
+    "\n"
+    "This program is free software. You can redistribute it and/or\n"
+    "modify under the terms of the Sleepycat License. Use the \n"
+    "':show license' command to display the full license\n"
+  );
 }
 
@@ -1500,5 +1412,4 @@
   owl_message *m;
   owl_fmtext fm, attrfm;
-  char buff[10000];
   owl_view *v;
 #ifdef HAVE_LIBZEPHYR
@@ -1516,8 +1427,5 @@
 
   owl_fmtext_append_bold(&fm, "General Information:\n");
-  owl_fmtext_append_normal(&fm, "  Msg Id    : ");
-  sprintf(buff, "%i", owl_message_get_id(m));
-  owl_fmtext_append_normal(&fm, buff);
-  owl_fmtext_append_normal(&fm, "\n");
+  owl_fmtext_appendf_normal(&fm, "  Msg Id    : %i\n", owl_message_get_id(m));
 
   owl_fmtext_append_normal(&fm, "  Type      : ");
@@ -1535,34 +1443,17 @@
   }
 
-  owl_fmtext_append_normal(&fm, "  Time      : ");
-  owl_fmtext_append_normal(&fm, owl_message_get_timestr(m));
-  owl_fmtext_append_normal(&fm, "\n");
+  owl_fmtext_appendf_normal(&fm, "  Time      : %s\n", owl_message_get_timestr(m));
 
   if (!owl_message_is_type_admin(m)) {
-    owl_fmtext_append_normal(&fm, "  Sender    : ");
-    owl_fmtext_append_normal(&fm, owl_message_get_sender(m));
-    owl_fmtext_append_normal(&fm, "\n");
-    
-    owl_fmtext_append_normal(&fm, "  Recipient : ");
-    owl_fmtext_append_normal(&fm, owl_message_get_recipient(m));
-    owl_fmtext_append_normal(&fm, "\n");
-  }
-    
+    owl_fmtext_appendf_normal(&fm, "  Sender    : %s\n", owl_message_get_sender(m));
+    owl_fmtext_appendf_normal(&fm, "  Recipient : %s\n", owl_message_get_recipient(m));
+  }
+
   if (owl_message_is_type_zephyr(m)) {
     owl_fmtext_append_bold(&fm, "\nZephyr Specific Information:\n");
     
-    owl_fmtext_append_normal(&fm, "  Class     : ");
-    owl_fmtext_append_normal(&fm, owl_message_get_class(m));
-    owl_fmtext_append_normal(&fm, "\n");
-    owl_fmtext_append_normal(&fm, "  Instance  : ");
-    owl_fmtext_append_normal(&fm, owl_message_get_instance(m));
-    owl_fmtext_append_normal(&fm, "\n");
-    owl_fmtext_append_normal(&fm, "  Opcode    : ");
-    owl_fmtext_append_normal(&fm, owl_message_get_opcode(m));
-    owl_fmtext_append_normal(&fm, "\n");
-    
-    owl_fmtext_append_normal(&fm, "  Time      : ");
-    owl_fmtext_append_normal(&fm, owl_message_get_timestr(m));
-    owl_fmtext_append_normal(&fm, "\n");
+    owl_fmtext_appendf_normal(&fm, "  Class     : %s\n", owl_message_get_class(m));
+    owl_fmtext_appendf_normal(&fm, "  Instance  : %s\n", owl_message_get_instance(m));
+    owl_fmtext_appendf_normal(&fm, "  Opcode    : %s\n", owl_message_get_opcode(m));
 #ifdef HAVE_LIBZEPHYR
     if (owl_message_is_direction_in(m)) {
@@ -1596,30 +1487,21 @@
 	}
       }
-      owl_fmtext_append_normal(&fm, "  Host      : ");
-      owl_fmtext_append_normal(&fm, owl_message_get_hostname(m));
+      owl_fmtext_appendf_normal(&fm, "  Host      : %s\n", owl_message_get_hostname(m));
 
       if (!owl_message_is_pseudo(m)) {
 	owl_fmtext_append_normal(&fm, "\n");
-	sprintf(buff, "  Port      : %i\n", ntohs(n->z_port));
-	owl_fmtext_append_normal(&fm, buff);
-
-	owl_fmtext_append_normal(&fm,    "  Auth      : ");
-	owl_fmtext_append_normal(&fm, owl_zephyr_get_authstr(n));
-	owl_fmtext_append_normal(&fm, "\n");
-	
-	/* fix this */
-	sprintf(buff, "  Checkd Ath: %i\n", n->z_checked_auth);
-	sprintf(buff, "%s  Multi notc: %s\n", buff, n->z_multinotice);
-	sprintf(buff, "%s  Num other : %i\n", buff, n->z_num_other_fields);
-	sprintf(buff, "%s  Msg Len   : %i\n", buff, n->z_message_len);
-	owl_fmtext_append_normal(&fm, buff);
-	
-	sprintf(buff, "  Fields    : %i\n", owl_zephyr_get_num_fields(n));
-	owl_fmtext_append_normal(&fm, buff);
-	
+	owl_fmtext_appendf_normal(&fm, "  Port      : %i\n", ntohs(n->z_port));
+	owl_fmtext_appendf_normal(&fm, "  Auth      : %s\n", owl_zephyr_get_authstr(n));
+
+	/* FIXME make these more descriptive */
+	owl_fmtext_appendf_normal(&fm, "  Checkd Ath: %i\n", n->z_checked_auth);
+	owl_fmtext_appendf_normal(&fm, "  Multi notc: %s\n", n->z_multinotice);
+	owl_fmtext_appendf_normal(&fm, "  Num other : %i\n", n->z_num_other_fields);
+	owl_fmtext_appendf_normal(&fm, "  Msg Len   : %i\n", n->z_message_len);
+
 	fields=owl_zephyr_get_num_fields(n);
+	owl_fmtext_appendf_normal(&fm, "  Fields    : %i\n", fields);
+
 	for (i=0; i<fields; i++) {
-	  sprintf(buff, "  Field %i   : ", i+1);
-	  
 	  ptr=owl_zephyr_get_field_as_utf8(n, i+1);
 	  len=strlen(ptr);
@@ -1633,20 +1515,17 @@
 	  }
 	  owl_free(ptr);
-	  
+
 	  for (j=0; j<strlen(tmpbuff); j++) {
 	    if (tmpbuff[j]=='\n') tmpbuff[j]='~';
 	    if (tmpbuff[j]=='\r') tmpbuff[j]='!';
 	  }
-	  
-	  strcat(buff, tmpbuff);
-	  strcat(buff, "\n");
-	  owl_fmtext_append_normal(&fm, buff);
+
+	  owl_fmtext_appendf_normal(&fm, "  Field %i   : %s\n", i+1, tmpbuff);
 	}
-	owl_fmtext_append_normal(&fm, "  Default Fm:");
-	owl_fmtext_append_normal(&fm, n->z_default_format);
+	owl_fmtext_appendf_normal(&fm, "  Default Fm: %s\n", n->z_default_format);
       }
-      
-    }
-#endif    
+
+    }
+#endif
   }
 
@@ -1749,22 +1628,4 @@
 }
 
-void owl_function_typwin_grow()
-{
-  int i;
-
-  i=owl_global_get_typwin_lines(&g);
-  owl_function_resize_typwin(i+1);
-}
-
-void owl_function_typwin_shrink()
-{
-  int i;
-
-  i=owl_global_get_typwin_lines(&g);
-  if (i>2) {
-    owl_function_resize_typwin(i-1);
-  }
-}
-
 void owl_function_mainwin_pagedown()
 {
@@ -1803,32 +1664,29 @@
 }
 
-#define PABUFLEN 5000
 void owl_function_printallvars()
 {
-  char buff[PABUFLEN], *pos, *name;
+  char *name;
+  char var[LINE];
   owl_list varnames;
-  int i, numvarnames, rem;
-
-  pos = buff;
-  pos += sprintf(pos, "%-20s = %s\n", "VARIABLE", "VALUE");
-  pos += sprintf(pos, "%-20s   %s\n",  "--------", "-----");
+  int i, numvarnames;
+  GString *str   = g_string_new("");
+
+  g_string_append_printf(str, "%-20s = %s\n", "VARIABLE", "VALUE");
+  g_string_append_printf(str, "%-20s   %s\n",  "--------", "-----");
   owl_variable_dict_get_names(owl_global_get_vardict(&g), &varnames);
-  rem = (buff+PABUFLEN)-pos-1;
   numvarnames = owl_list_get_size(&varnames);
   for (i=0; i<numvarnames; i++) {
     name = owl_list_get_element(&varnames, i);
     if (name && name[0]!='_') {
-      rem = (buff+PABUFLEN)-pos-1;    
-      pos += snprintf(pos, rem, "\n%-20s = ", name);
-      rem = (buff+PABUFLEN)-pos-1;    
-      owl_variable_get_tostring(owl_global_get_vardict(&g), name, pos, rem);
-      pos = buff+strlen(buff);
-    }
-  }
-  rem = (buff+PABUFLEN)-pos-1;    
-  snprintf(pos, rem, "\n");
+      g_string_append_printf(str, "\n%-20s = ", name);
+      owl_variable_get_tostring(owl_global_get_vardict(&g), name, var, LINE);
+      g_string_append(str, var);
+    }
+  }
+  g_string_append(str, "\n");
   owl_variable_dict_namelist_free(&varnames);
-  
-  owl_function_popless_text(buff);
+
+  owl_function_popless_text(str->str);
+  g_string_free(str, TRUE);
 }
 
@@ -1922,5 +1780,5 @@
 void owl_function_status()
 {
-  char buff[5000];
+  char buff[MAXPATHLEN+1];
   time_t start;
   int up, days, hours, minutes;
@@ -1942,10 +1800,12 @@
 
   owl_fmtext_append_normal(&fm, "  Current Directory: ");
-  (void) getcwd(buff, MAXPATHLEN);
-  owl_fmtext_append_normal(&fm, buff);
+  if(getcwd(buff, MAXPATHLEN) == NULL) {
+    owl_fmtext_append_normal(&fm, "<Error in getcwd>");
+  } else {
+    owl_fmtext_append_normal(&fm, buff);
+  }
   owl_fmtext_append_normal(&fm, "\n");
 
-  sprintf(buff, "  Startup Time: %s", ctime(&start));
-  owl_fmtext_append_normal(&fm, buff);
+  owl_fmtext_appendf_normal(&fm, "  Startup Time: %s", ctime(&start));
 
   up=owl_global_get_runtime(&g);
@@ -1956,6 +1816,5 @@
   minutes=up/60;
   up-=minutes*60;
-  sprintf(buff, "  Run Time: %i days %2.2i:%2.2i:%2.2i\n", days, hours, minutes, up);
-  owl_fmtext_append_normal(&fm, buff);
+  owl_fmtext_appendf_normal(&fm, "  Run Time: %i days %2.2i:%2.2i:%2.2i\n", days, hours, minutes, up);
 
   owl_fmtext_append_normal(&fm, "\nProtocol Options:\n");
@@ -2002,18 +1861,14 @@
 {
   owl_fmtext fm;
-  char buff[LINE];
 
   owl_fmtext_init_null(&fm);
-  sprintf(buff, "Terminal Lines: %i\nTerminal Columns: %i\n",
+  owl_fmtext_appendf_normal(&fm, "Terminal Lines: %i\nTerminal Columns: %i\n",
 	  owl_global_get_lines(&g),
 	  owl_global_get_cols(&g));
-  owl_fmtext_append_normal(&fm, buff);
 
   if (owl_global_get_hascolors(&g)) {
     owl_fmtext_append_normal(&fm, "Color: Yes\n");
-    sprintf(buff, "Number of color pairs: %i\n", owl_global_get_colorpairs(&g));
-    owl_fmtext_append_normal(&fm, buff);
-    sprintf(buff, "Can change colors: %s\n", can_change_color() ? "yes" : "no");
-    owl_fmtext_append_normal(&fm, buff);
+    owl_fmtext_appendf_normal(&fm, "Number of color pairs: %i\n", owl_global_get_colorpairs(&g));
+    owl_fmtext_appendf_normal(&fm, "Can change colors: %s\n", can_change_color() ? "yes" : "no");
   } else {
     owl_fmtext_append_normal(&fm, "Color: No\n");
@@ -2052,4 +1907,10 @@
 	return;
       }
+    }
+
+    /* then check if it's a question and just bring up the command prompt */
+    if (owl_message_is_question(m)) {
+      owl_function_start_command("");
+      return;
     }
 
@@ -2495,5 +2356,4 @@
   char *tmpclass, *tmpinstance = NULL;
   char *class, *instance = NULL;
-  int len;
 
   class = owl_util_baseclass(c);
@@ -2505,11 +2365,8 @@
 
   /* name for the filter */
-  len=strlen(class)+30;
-  if (instance) len+=strlen(instance);
-  filtname=owl_malloc(len);
   if (!instance) {
-    sprintf(filtname, "class-%s", class);
-  } else {
-    sprintf(filtname, "class-%s-instance-%s", class, instance);
+    filtname = owl_sprintf("class-%s", class);
+  } else {
+    filtname = owl_sprintf("class-%s-instance-%s", class, instance);
   }
   /* downcase it */
@@ -2542,11 +2399,10 @@
     owl_text_tr(tmpinstance, '"', '.');
   }
-  len = strlen(tmpclass);
-  if(tmpinstance) len += strlen(tmpinstance);
-  len += 60;
-  argbuff = owl_malloc(len);
-  sprintf(argbuff, "class ^(un)*%s(\\.d)*$", tmpclass);
+
+  argbuff = owl_sprintf("class ^(un)*%s(\\.d)*$", tmpclass);
   if (tmpinstance) {
-    sprintf(argbuff, "%s and ( instance ^(un)*%s(\\.d)*$ )", argbuff, tmpinstance);
+    char *tmp = argbuff;
+    argbuff = owl_sprintf("%s and ( instance ^(un)*%s(\\.d)*$ )", tmp, tmpinstance);
+    owl_free(tmp);
   }
   owl_free(tmpclass);
@@ -2577,5 +2433,5 @@
 {
   owl_filter *f;
-  char *argbuff, *longuser, *shortuser, *filtname;
+  char *argbuff, *longuser, *esclonguser, *shortuser, *filtname;
 
   /* stick the local realm on if it's not there */
@@ -2584,6 +2440,5 @@
 
   /* name for the filter */
-  filtname=owl_malloc(strlen(shortuser)+20);
-  sprintf(filtname, "user-%s", shortuser);
+  filtname=owl_sprintf("user-%s", shortuser);
 
   /* if it already exists then go with it.  This lets users override */
@@ -2595,8 +2450,10 @@
   f=owl_malloc(sizeof(owl_filter));
 
-  argbuff=owl_malloc(strlen(longuser)+1000);
-  sprintf(argbuff, "( type ^zephyr$ and filter personal and ");
-  sprintf(argbuff, "%s ( ( direction ^in$ and sender ^%s$ ) or ( direction ^out$ and recipient ^%s$ ) ) )", argbuff, longuser, longuser);
-  sprintf(argbuff, "%s or ( ( class ^login$ ) and ( sender ^%s$ ) )", argbuff, longuser);
+  esclonguser = owl_text_quote(longuser, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
+
+  argbuff=owl_sprintf("( type ^zephyr$ and filter personal and "
+      "( ( direction ^in$ and sender ^%1$s$ ) or ( direction ^out$ and "
+      "recipient ^%1$s$ ) ) ) or ( ( class ^login$ ) and ( sender ^%1$s$ ) )",
+      esclonguser);
 
   owl_filter_init_fromstring(f, filtname, argbuff);
@@ -2608,4 +2465,5 @@
   owl_free(argbuff);
   owl_free(longuser);
+  owl_free(esclonguser);
   owl_free(shortuser);
 
@@ -2626,6 +2484,5 @@
 
   /* name for the filter */
-  filtname=owl_malloc(strlen(user)+40);
-  sprintf(filtname, "aimuser-%s", user);
+  filtname=owl_sprintf("aimuser-%s", user);
 
   /* if it already exists then go with it.  This lets users override */
@@ -2639,9 +2496,8 @@
   escuser = owl_text_quote(user, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
 
-  argbuff=owl_malloc(1000);
-  sprintf(argbuff,
-          "( type ^aim$ and ( ( sender ^%s$ and recipient ^%s$ ) or ( sender ^%s$ and recipient ^%s$ ) ) )",
-          escuser, owl_global_get_aim_screenname_for_filters(&g),
-          owl_global_get_aim_screenname_for_filters(&g), escuser);
+  argbuff = owl_sprintf(
+      "( type ^aim$ and ( ( sender ^%1$s$ and recipient ^%2$s$ ) or "
+      "( sender ^%2$s$ and recipient ^%1$s$ ) ) )",
+      escuser, owl_global_get_aim_screenname_for_filters(&g));
 
   owl_filter_init_fromstring(f, filtname, argbuff);
@@ -2660,5 +2516,5 @@
 {
   owl_filter *f;
-  char *argbuff, *filtname;
+  char *argbuff, *filtname, *esctype;
 
   /* name for the filter */
@@ -2673,5 +2529,7 @@
   f=owl_malloc(sizeof(owl_filter));
 
-  argbuff = owl_sprintf("type ^%s$", type);
+  esctype = owl_text_quote(type, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
+
+  argbuff = owl_sprintf("type ^%s$", esctype);
 
   owl_filter_init_fromstring(f, filtname, argbuff);
@@ -2682,4 +2540,5 @@
   /* free stuff */
   owl_free(argbuff);
+  owl_free(esctype);
 
   return filtname;
@@ -2943,11 +2802,9 @@
 void owl_function_zpunt(char *class, char *inst, char *recip, int direction)
 {
-  char *buff;
+  char *puntexpr, *classexpr, *instexpr, *recipexpr;
   char *quoted;
 
-  buff=owl_malloc(strlen(class)+strlen(inst)+strlen(recip)+100);
-  strcpy(buff, "class");
   if (!strcmp(class, "*")) {
-    strcat(buff, " .*");
+    classexpr = owl_sprintf("class .*");
   } else {
     quoted=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
@@ -2955,9 +2812,9 @@
     owl_text_tr(quoted, '\'', '.');
     owl_text_tr(quoted, '"', '.');
-    sprintf(buff, "%s ^(un)*%s(\\.d)*$", buff, quoted);
+    classexpr = owl_sprintf("class ^(un)*%s(\\.d)*$", quoted);
     owl_free(quoted);
   }
   if (!strcmp(inst, "*")) {
-    strcat(buff, " and instance .*");
+    instexpr = owl_sprintf(" and instance .*");
   } else {
     quoted=owl_text_quote(inst, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
@@ -2965,18 +2822,24 @@
     owl_text_tr(quoted, '\'', '.');
     owl_text_tr(quoted, '"', '.');
-    sprintf(buff, "%s and instance ^(un)*%s(\\.d)*$", buff, quoted);
+    instexpr = owl_sprintf(" and instance ^(un)*%s(\\.d)*$", quoted);
     owl_free(quoted);
   }
-  if (strcmp(recip, "*")) {
+  if (!strcmp(recip, "*")) {
+    recipexpr = owl_sprintf("");
+  } else {
     quoted=owl_text_quote(recip, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
     owl_text_tr(quoted, ' ', '.');
     owl_text_tr(quoted, '\'', '.');
     owl_text_tr(quoted, '"', '.');
-    sprintf(buff, "%s and recipient ^%s$", buff, quoted);
+    recipexpr = owl_sprintf(" and recipient ^%s$", quoted);
     owl_free(quoted);
   }
 
-  owl_function_punt(buff, direction);
-  owl_free(buff);
+  puntexpr = owl_sprintf("%s %s %s", classexpr, instexpr, recipexpr);
+  owl_function_punt(puntexpr, direction);
+  owl_free(puntexpr);
+  owl_free(classexpr);
+  owl_free(instexpr);
+  owl_free(recipexpr);
 }
 
@@ -3065,5 +2928,5 @@
 }
 
-char *owl_function_keymap_summary(void *name)
+char *owl_function_keymap_summary(char *name)
 {
   owl_keymap *km 
@@ -3195,7 +3058,7 @@
   owl_buddy *b;
   owl_list anyone;
-  char *foo, *timestr;
+  char *timestr;
 #ifdef HAVE_LIBZEPHYR
-  char *tmp, *user, *line;
+  char *tmp, *user;
   ZLocations_t location[200];
   int numlocs, ret;
@@ -3219,8 +3082,6 @@
 	timestr=owl_strdup("");
       }
-      foo=owl_sprintf("  %-20.20s %-12.12s\n", owl_buddy_get_name(b), timestr);
-      owl_fmtext_append_normal(&fm, foo);
+      owl_fmtext_appendf_normal(&fm, "  %-20.20s %-12.12s\n", owl_buddy_get_name(b), timestr);
       owl_free(timestr);
-      owl_free(foo);
     }
   }
@@ -3250,14 +3111,11 @@
           if (ret==0) {
             for (x=0; x<numlocs; x++) {
-              line=owl_malloc(strlen(location[x].host)+strlen(location[x].time)+strlen(location[x].tty)+100);
               tmp=short_zuser(user);
-              sprintf(line, "  %-10.10s %-24.24s %-12.12s  %20.20s\n",
-                      tmp,
-                      location[x].host,
-                      location[x].tty,
-                      location[x].time);
-              owl_fmtext_append_normal(&fm, line);
+              owl_fmtext_appendf_normal(&fm, "  %-10.10s %-24.24s %-12.12s  %20.20s\n",
+                                        tmp,
+                                        location[x].host,
+                                        location[x].tty,
+                                        location[x].time);
               owl_free(tmp);
-              owl_free(line);
             }
             if (numlocs>=200) {
@@ -3491,5 +3349,6 @@
 {
   va_list ap;
-  char buff[2048], buff2[2048];
+  char *buff, *buff2;
+  char *nl;
   char *date;
   time_t now;
@@ -3501,16 +3360,19 @@
   va_start(ap, fmt);
 
-  vsnprintf(buff, 2048, fmt, ap);
-  sprintf(buff2, "%s %s", date, buff);
+  buff = g_strdup_vprintf(fmt, ap);
+  buff2 = owl_sprintf("%s %s", date, buff);
   owl_function_debugmsg("ERROR: %s", buff);
-  if (owl_global_get_curs_msgwin(&g)) {
-    werase(owl_global_get_curs_msgwin(&g));
-    waddstr(owl_global_get_curs_msgwin(&g), buff);  
-    wnoutrefresh(owl_global_get_curs_msgwin(&g));
-    owl_global_set_needrefresh(&g);
+  nl = strchr(buff, '\n');
+  if(nl && *(nl + 1)) {
+    /* Multiline error */
+    owl_function_adminmsg("ERROR", buff);
+  } else {
+    owl_function_makemsg("[Error] %s", buff);
   }
   owl_errqueue_append_err(owl_global_get_errqueue(&g), buff2);
   va_end(ap);
   owl_free(date);
+  owl_free(buff);
+  owl_free(buff2);
 }
 
Index: global.c
===================================================================
--- global.c	(revision da466e09b1d178435cf117a103dee8a511df94f2)
+++ global.c	(revision f34dd65b3adbc2eedc045a674dd89b7e20257680)
@@ -51,5 +51,4 @@
   owl_keys_setup_keymaps(&g->kh);
 
-  owl_list_create(&(g->muxevents));
   owl_list_create(&(g->filterlist));
   owl_list_create(&(g->puntlist));
@@ -100,11 +99,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 +110,4 @@
 
   owl_zbuddylist_create(&(g->zbuddies));
-  owl_timer_create_countdown(&(g->zephyr_buddycheck_timer), 60*3);
 
   owl_obarray_init(&(g->obarray));
@@ -119,4 +115,5 @@
   owl_message_init_fmtext_cache();
   owl_list_create(&(g->dispatchlist));
+  g->timerlist = NULL;
 }
 
@@ -139,5 +136,5 @@
   g->recwin=newwin(g->recwinlines, cols, 0, 0);
   if (g->recwin==NULL) {
-    owl_function_debugmsg("_owl_global_setup_windows: newwin returned NULL\n", g->recwinlines, cols);
+    owl_function_debugmsg("_owl_global_setup_windows: newwin returned NULL\n");
     endwin();
     exit(50);
@@ -570,5 +567,5 @@
   strcpy(g->startupargs, "");
   for (i=0; i<argc; i++) {
-    sprintf(g->startupargs, "%s%s ", g->startupargs, argv[i]);
+    sprintf(g->startupargs + strlen(g->startupargs), "%s ", argv[i]);
   }
   g->startupargs[strlen(g->startupargs)-1]='\0';
@@ -588,10 +585,4 @@
 owl_history *owl_global_get_cmd_history(owl_global *g) {
   return(&(g->cmdhist));
-}
-
-/* muxevents */
-
-owl_muxevents *owl_global_get_muxevents(owl_global *g) {
-  return(&(g->muxevents));
 }
 
@@ -719,24 +710,4 @@
 int owl_global_get_newmsgproc_pid(owl_global *g) {
   return(g->newmsgproc_pid);
-}
-
-void owl_global_add_to_malloced(owl_global *g, int i) {
-  g->malloced+=i;
-}
-
-void owl_global_add_to_freed(owl_global *g, int i) {
-  g->freed+=1;
-}
-
-int owl_global_get_malloced(owl_global *g) {
-  return(g->malloced);
-}
-
-int owl_global_get_freed(owl_global *g) {
-  return(g->freed);
-}
-
-int owl_global_get_meminuse(owl_global *g) {
-  return(g->malloced-g->freed);
 }
 
@@ -812,20 +783,4 @@
 {
   g->bosconn=*conn;
-}
-
-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));
 }
 
@@ -902,4 +857,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 +881,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 +909,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 +929,7 @@
   return &(g->dispatchlist);
 }
+
+GList **owl_global_get_timerlist(owl_global *g)
+{
+  return &(g->timerlist);
+}
Index: help.c
===================================================================
--- help.c	(revision 0398d55781db08fc6d990621fb6a488b6ce1eb49)
+++ help.c	(revision 799b60ea3145bfa2ad773b09544d31a3e30e77ff)
@@ -18,4 +18,6 @@
   owl_fmtext_append_normal
     (&fm, 
+     "  If you're new to BarnOwl, the first thing you should type is\n\n"
+     "    :show quickstart\n\n"
      "  For help on a specific command use 'help <command>'\n"
      "  For information on advanced keys, use 'show keymaps'.\n"
Index: keys.c
===================================================================
--- keys.c	(revision 3004c9f7ea88e3888e2d6a71cbf552f9f9f84afb)
+++ keys.c	(revision ce561499ae34e2491909f1b4059182b7381b9f04)
@@ -50,6 +50,8 @@
 
   BIND_CMD("LEFT",        "edit:move-left", "");
+  BIND_CMD("M-[ D",       "edit:move-left", "");
   BIND_CMD("C-b",         "edit:move-left", "");
   BIND_CMD("RIGHT",       "edit:move-right", "");
+  BIND_CMD("M-[ C",       "edit:move-right", "");
   BIND_CMD("C-f",         "edit:move-right", "");
 
@@ -65,10 +67,12 @@
   BIND_CMD("M-DELETE",    "edit:delete-prev-word", "");
   BIND_CMD("M-d",         "edit:delete-next-word", "");
+  BIND_CMD("M-DC",        "edit:delete-next-word", "");
   BIND_CMD("M-[ 3 ; 3 ~", "edit:delete-next-word", "");
 
   BIND_CMD("C-h",         "edit:delete-prev-char", "");
   BIND_CMD("BACKSPACE",   "edit:delete-prev-char", "");
-  BIND_CMD("DC",          "edit:delete-prev-char", "");
   BIND_CMD("DELETE",      "edit:delete-prev-char", "");
+  BIND_CMD("C-d",         "edit:delete-next-char", "");
+  BIND_CMD("DC",          "edit:delete-next-char", "");
 
   BIND_CMD("C-k",         "edit:delete-to-line-end", "");
@@ -79,6 +83,4 @@
 
   BIND_CMD("C-l",         "( edit:recenter ; redisplay )", "");
-
-  BIND_CMD("C-d",     "edit:delete-next-char", "");
 
 
@@ -93,6 +95,8 @@
 
   BIND_CMD("UP",      "editmulti:move-up-line", "");
+  BIND_CMD("M-[ A",   "editmulti:move-up-line", "");
   BIND_CMD("C-p",     "editmulti:move-up-line", "");
   BIND_CMD("DOWN",    "editmulti:move-down-line", "");
+  BIND_CMD("M-[ B",   "editmulti:move-down-line", "");
   BIND_CMD("C-n",     "editmulti:move-down-line", "");
 
@@ -120,8 +124,10 @@
 
   BIND_CMD("UP",          "edit:history-prev", "");
+  BIND_CMD("M-[ A",       "edit:history-prev", "");
   BIND_CMD("C-p",         "edit:history-prev", "");
   BIND_CMD("M-p",         "edit:history-prev", "");
 
   BIND_CMD("DOWN",        "edit:history-next", "");
+  BIND_CMD("M-[ B",       "edit:history-next", "");
   BIND_CMD("C-n",         "edit:history-next", "");
   BIND_CMD("M-n",         "edit:history-next", "");
@@ -166,7 +172,9 @@
   BIND_CMD("LF",          "popless:scroll-down-line", "");
   BIND_CMD("DOWN",        "popless:scroll-down-line", "");
+  BIND_CMD("M-[ B",       "popless:scroll-down-line", "");
   BIND_CMD("C-n",         "popless:scroll-down-line", "");
 
   BIND_CMD("UP",          "popless:scroll-up-line", "");
+  BIND_CMD("M-[ A",       "popless:scroll-up-line", "");
   BIND_CMD("C-h",         "popless:scroll-up-line", "");
   BIND_CMD("C-p",         "popless:scroll-up-line", "");
@@ -176,5 +184,7 @@
 
   BIND_CMD("RIGHT",       "popless:scroll-right 10", "scrolls right");
+  BIND_CMD("M-[ C",       "popless:scroll-right 10", "scrolls right");
   BIND_CMD("LEFT",        "popless:scroll-left  10", "scrolls left");
+  BIND_CMD("M-[ D",       "popless:scroll-left  10", "scrolls left");
 
   BIND_CMD("HOME",        "popless:scroll-to-top", "");
@@ -232,5 +242,5 @@
   BIND_CMD("M-[ D",  "recv:shiftleft", "");
   BIND_CMD("RIGHT",  "recv:shiftright","");
-  BIND_CMD("M-[ C",  "recv:shiftleft", "");
+  BIND_CMD("M-[ C",  "recv:shiftright","");
   BIND_CMD("DOWN",   "recv:next",      "");
   BIND_CMD("C-n",    "recv:next",      "");
@@ -282,6 +292,4 @@
   BIND_CMD("M-r", "reply -e",         "reply to the current message, but allow editing of recipient");
   BIND_CMD("M-R", "reply -e sender",  "reply to sender of the current message, but allow editing of recipient");
-		  
-  BIND_CMD("w",   "openurl",          "open a URL using a webbrowser");
 
   BIND_CMD("W",   "start-command webzephyr ", "start a webzephyr command");
Index: list.c
===================================================================
--- list.c	(revision 50622a59357b6958f78b136d6d25ce31540f7c59)
+++ list.c	(revision f34dd65b3adbc2eedc045a674dd89b7e20257680)
@@ -78,13 +78,4 @@
 }
 
-/* todo: might leak memory */
-int owl_list_replace_element(owl_list *l, int n, void *element)
-{
-  if (n>l->size-1) return(-1);
-
-  l->list[n]=element;
-  return(0);
-}
-
 void owl_list_free_all(owl_list *l, void (*elefree)(void *))
 {
Index: message.c
===================================================================
--- message.c	(revision 147d88077919720ae7689914594bbda67e87d83b)
+++ message.c	(revision f34dd65b3adbc2eedc045a674dd89b7e20257680)
@@ -338,16 +338,4 @@
 }
 
-/* caller must free the return */
-char *owl_message_get_shorttimestr(owl_message *m)
-{
-  struct tm *tmstruct;
-  char *out;
-
-  tmstruct=localtime(&(m->time));
-  out=owl_sprintf("%2.2i:%2.2i", tmstruct->tm_hour, tmstruct->tm_min);
-  if (out) return(out);
-  return("??:??");
-}
-
 void owl_message_set_type_admin(owl_message *m)
 {
@@ -384,10 +372,4 @@
 {
   return owl_message_is_type(m, "admin");
-}
-
-int owl_message_is_type_generic(owl_message *m)
-{
-  char * t = owl_message_get_attribute_value(m, "type");
-  return (t == NULL);
 }
 
@@ -573,40 +555,8 @@
 }
 
-int owl_message_is_from_me(owl_message *m)
-{
-  if (owl_message_is_type_zephyr(m)) {
-    if (!strcasecmp(owl_message_get_sender(m), owl_zephyr_get_sender())) {
-      return(1);
-    } else {
-      return(0);
-    }
-  } else if (owl_message_is_type_aim(m)) {
-    if (!strcasecmp(owl_message_get_sender(m), owl_global_get_aim_screenname(&g))) {
-      return(1);
-    } else {
-      return(0);
-    }
-  } else if (owl_message_is_type_admin(m)) {
-    return(0);
-  }
-  return(0);
-}
-
 int owl_message_is_mail(owl_message *m)
 {
   if (owl_message_is_type_zephyr(m)) {
     if (!strcasecmp(owl_message_get_class(m), "mail") && owl_message_is_private(m)) {
-      return(1);
-    } else {
-      return(0);
-    }
-  }
-  return(0);
-}
-
-int owl_message_is_ping(owl_message *m)
-{
-  if (owl_message_is_type_zephyr(m)) {
-    if (!strcasecmp(owl_message_get_opcode(m), "ping")) {
       return(1);
     } else {
@@ -964,6 +914,8 @@
   owl_message_set_instance(m, owl_zwrite_get_instance(&z));
   if (owl_zwrite_get_numrecips(&z)>0) {
+    char *longzuser = long_zuser(owl_zwrite_get_recip_n(&z, 0));
     owl_message_set_recipient(m,
-			      long_zuser(owl_zwrite_get_recip_n(&z, 0))); /* only gets the first user, must fix */
+			      longzuser); /* only gets the first user, must fix */
+    owl_free(longzuser);
   }
   owl_message_set_opcode(m, owl_zwrite_get_opcode(&z));
@@ -990,14 +942,4 @@
 }
 
-void owl_message_pretty_zsig(owl_message *m, char *buff)
-{
-  /* stick a one line version of the zsig in buff */
-  char *ptr;
-
-  strcpy(buff, owl_message_get_zsig(m));
-  ptr=strchr(buff, '\n');
-  if (ptr) ptr[0]='\0';
-}
-
 void owl_message_free(owl_message *m)
 {
Index: xevents.c
===================================================================
--- muxevents.c	(revision 948b94240edb7210e2db1029e279718ea7fe3aac)
+++ 	(revision )
@@ -1,129 +1,0 @@
-#include <sys/poll.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include "owl.h"
-
-static const char fileIdent[] = "$Id $";
-
-#define OWL_MUX_MAX_FD (FD_SETSIZE-1)
-
-static int owl_mux_nexthandle = 5000; /* next handle to hand out */
-static int owl_mux_needgc = 0;	/* number of muxevents needing to be gc'd */
-
-/* returns a handle id or 0 on failure */
-int owl_muxevents_add(owl_muxevents *muxevents, int fd, int eventmask, void (*handler_fn)(int handle, int fd, int eventmask, void *data), void *data)
-{
-  owl_mux *mux;
-  
-  mux = owl_malloc(sizeof(owl_mux));
-  if (!mux) return 0;
-  if (fd > OWL_MUX_MAX_FD) {
-    owl_function_error("owl_muxevents_add: fd %d too large", fd);
-    return 0;
-  }
-  mux->handle = owl_mux_nexthandle++;
-  mux->fd = fd;
-  mux->active = 1;
-  mux->eventmask = eventmask;
-  mux->data = data;
-  mux->handler_fn = handler_fn;
-  if (0!=owl_list_append_element(muxevents, mux)) {
-    owl_free(mux);
-    return(0);
-  }
-  return mux->handle;
-}
-
-/* deactivates a muxevent entry with the given handle */
-void owl_muxevents_remove(owl_muxevents *muxevents, int handle)
-{
-  int max, i;
-  owl_mux *m;
-
-  max = owl_list_get_size(muxevents);
-  for (i=0; i<max; i++) {
-    m = (owl_mux*)owl_list_get_element(muxevents, i);
-    if (m->handle == handle) {
-      m->active=0;
-      owl_mux_needgc++;
-    }
-  }
-}
-
-/* cleans up a muxevents list at a safe time (ie, when it is
-   not being traversed). */
-void owl_muxevents_gc(owl_muxevents *muxevents)
-{
-  int max, i, done=0;
-  owl_mux *m;
-
-  if (!owl_mux_needgc) return;
-  while (!done) {
-    max = owl_list_get_size(muxevents);
-    for (i=0; i<max; i++) {
-      m = (owl_mux*)owl_list_get_element(muxevents, i);
-      if (!m->active) {
-	owl_list_remove_element(muxevents, i);
-	owl_free(m);
-	owl_mux_needgc--;
-	break;
-      }
-    }  
-    if (i==max) done=1;
-  }
-}
-
-/* dispatches out events */
-void owl_muxevents_dispatch(owl_muxevents *muxevents, int timeout_usec)
-{
-  int nevents, i, rv, emask;
-  owl_mux *m;
-  fd_set rfds, wfds, efds;
-  int maxfd=0;
-  struct timeval tv;
-
-  FD_ZERO(&rfds);
-  FD_ZERO(&wfds);
-  FD_ZERO(&efds);
-  nevents = owl_list_get_size(muxevents);
-  for (i=0; i<nevents; i++) {
-      m = (owl_mux*)owl_list_get_element(muxevents, i);
-      if (m->eventmask & OWL_MUX_READ)   FD_SET(m->fd, &rfds);
-      if (m->eventmask & OWL_MUX_WRITE)  FD_SET(m->fd, &wfds);
-      if (m->eventmask & OWL_MUX_EXCEPT) FD_SET(m->fd, &efds);
-      if (m->fd > maxfd) maxfd = m->fd;
-  }
-  tv.tv_sec = 0;
-  tv.tv_usec = timeout_usec;
-  rv = select(maxfd+1, &rfds, &wfds, &efds, &tv);
-  if (rv == 0) return;
-  
-  for (i=0; i<nevents; i++) {
-      m = (owl_mux*)owl_list_get_element(muxevents, i);
-      if (!m->active) continue;
-      emask = 0;
-      if (m->eventmask & OWL_MUX_READ && FD_ISSET(m->fd, &rfds)) {
-	emask |= OWL_MUX_READ;
-      }
-      if (m->eventmask & OWL_MUX_WRITE && FD_ISSET(m->fd, &wfds)) {
-	emask |= OWL_MUX_WRITE;
-      }
-      if (m->eventmask & OWL_MUX_EXCEPT && FD_ISSET(m->fd, &efds)) {
-	emask |= OWL_MUX_EXCEPT;
-      }
-      owl_function_debugmsg("muxevents: dispatching %s%s%s to %d\n",
-			    emask&OWL_MUX_READ?"[read]":"",
-			    emask&OWL_MUX_WRITE?"[write]":"",
-			    emask&OWL_MUX_EXCEPT?"[except]":"",
-			    m->fd);
-      if (emask) {
-	m->handler_fn(m->handle, m->fd, emask, m->data);
-      }
-  }
-
-  owl_function_debugmsg("muxevents: finishing dispatch\n");
-  /* we need to do this here so that the size of muxevents
-  * doesn't change while we're traversing it... */
-  owl_muxevents_gc(muxevents);
-}
Index: owl.c
===================================================================
--- owl.c	(revision c1d2e6c253c25bace704f5d9d9171396524ae595)
+++ owl.c	(revision 28fa23c1162940f75a7e835c9c19de7eac3e33b5)
@@ -46,5 +46,5 @@
   int newmsgs, nexttimediff;
   struct sigaction sigact;
-  char *configfile, *tty, *perlout, *perlerr, **argvsave, buff[LINE], startupmsg[LINE];
+  char *configfile, *tty, *perlout, *perlerr, **argvsave;
   char *confdir;
   owl_filter *f;
@@ -55,8 +55,5 @@
   struct termios tio;
   owl_message *m;
-#if OWL_STDERR_REDIR
-  int newstderr;
-#endif
-  
+
   if (!GLIB_CHECK_VERSION (2, 12, 0))
     g_error ("GLib version 2.12.0 or above is needed.");
@@ -191,5 +188,5 @@
     d->fd = STDIN;
     d->cfunc = &owl_process_input;
-    d->pfunc = NULL;
+    d->destroy = NULL;
     owl_select_add_dispatch(d);
   }
@@ -202,5 +199,5 @@
     d->fd = ZGetFD();
     d->cfunc = &owl_zephyr_process_events;
-    d->pfunc = NULL;
+    d->destroy = NULL;
     owl_select_add_dispatch(d);
     owl_global_set_havezephyr(&g);
@@ -211,9 +208,13 @@
 #if OWL_STDERR_REDIR
   /* Do this only after we've started curses up... */
-  owl_function_debugmsg("startup: doing stderr redirection");
-  newstderr = stderr_replace();
-  owl_muxevents_add(owl_global_get_muxevents(&g), newstderr, OWL_MUX_READ,
-		    stderr_redirect_handler, NULL);
-#endif   
+  {
+    owl_dispatch *d = owl_malloc(sizeof(owl_dispatch));
+    owl_function_debugmsg("startup: doing stderr redirection");
+    d->fd = stderr_replace();
+    d->cfunc = stderr_redirect_handler;
+    d->destroy = NULL;
+    owl_select_add_dispatch(d);
+  }
+#endif
 
   /* create the owl directory, in case it does not exist */
@@ -320,15 +321,15 @@
   /* welcome message */
   owl_function_debugmsg("startup: creating splash message");
-  strcpy(startupmsg, "-----------------------------------------------------------------------\n");
-  sprintf(buff,      "Welcome to barnowl version %s.  Press 'h' for on-line help.            \n", OWL_VERSION_STRING);
-  strcat(startupmsg, buff);
-  strcat(startupmsg, "                                                                       \n");
-  strcat(startupmsg, "BarnOwl is free software. Type ':show license' for more                \n");
-  strcat(startupmsg, "information.                                                           \n");
-  strcat(startupmsg, "                                                                 ^ ^   \n");
-  strcat(startupmsg, "                                                                 OvO   \n");
-  strcat(startupmsg, "Please report any bugs or suggestions to bug-barnowl@mit.edu    (   )  \n");
-  strcat(startupmsg, "-----------------------------------------------------------------m-m---\n");
-  owl_function_adminmsg("", startupmsg);
+  owl_function_adminmsg("",
+    "-----------------------------------------------------------------------\n"
+    "Welcome to barnowl version " OWL_VERSION_STRING ".  Press 'h' for on-line help.\n"
+    "To see a quick introduction, type ':show quickstart'.                  \n"
+    "                                                                       \n"
+    "BarnOwl is free software. Type ':show license' for more                \n"
+    "information.                                                     ^ ^   \n"
+    "                                                                 OvO   \n"
+    "Please report any bugs or suggestions to bug-barnowl@mit.edu    (   )  \n"
+    "-----------------------------------------------------------------m-m---\n"
+  );
   sepbar(NULL);
 
@@ -395,9 +396,11 @@
   nexttime=time(NULL);
 
-#ifdef HAVE_LIBZEPHYR
-  /* Check for any zephyrs that have come in while we've done init. */
-  owl_zephyr_process_events();
-#endif
-  
+
+  owl_select_add_timer(180, 180, owl_zephyr_buddycheck_timer, NULL, NULL);
+
+  /* If we ever deprecate the mainloop hook, remove this. */
+  owl_select_add_timer(0, 1, owl_perlconfig_mainloop, NULL, NULL);
+
+
   owl_function_debugmsg("startup: entering main loop");
   /* main loop */
@@ -414,6 +417,4 @@
 
     followlast=owl_global_should_followlast(&g);
-    
-    owl_perlconfig_mainloop();
 
     /* little hack */
@@ -442,16 +443,4 @@
     }
 
-    /* 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));
-      }
-    }
-
-    /* dispatch any muxevents */
-    owl_muxevents_dispatch(owl_global_get_muxevents(&g), 0);
-
     /* follow the last message if we're supposed to */
     if (newmsgs && followlast) {
@@ -511,5 +500,5 @@
       int signum;
       if ((signum = owl_global_get_errsignal_and_clear(&g, &si)) > 0) {
-	owl_function_error("Got unexpected signal: %d %s  (code: %d band: %d  errno: %d)", 
+	owl_function_error("Got unexpected signal: %d %s  (code: %d band: %ld  errno: %d)",
 			   signum, signum==SIGPIPE?"SIGPIPE":"SIG????",
 			   si.si_code, si.si_band, si.si_errno);
@@ -614,19 +603,5 @@
 }
 
-void owl_process_aim()
-{
-  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));
-      }
-    }
-  }
-}
-
-void owl_process_input()
+void owl_process_input(owl_dispatch *d)
 {
   int ret;
@@ -773,9 +748,9 @@
 
 /* Sends stderr (read from rfd) messages to the error console */
-void stderr_redirect_handler(int handle, int rfd, int eventmask, void *data) 
+void stderr_redirect_handler(owl_dispatch *d)
 {
   int navail, bread;
-  char *buf;
-  /*owl_function_debugmsg("stderr_redirect: called with rfd=%d\n", rfd);*/
+  char buf[4096];
+  int rfd = d->fd;
   if (rfd<0) return;
   if (-1 == ioctl(rfd, FIONREAD, (void*)&navail)) {
@@ -783,14 +758,22 @@
   }
   /*owl_function_debugmsg("stderr_redirect: navail = %d\n", navail);*/
-  if (navail<=0) return;
-  if (navail>256) { navail = 256; }
-  buf = owl_malloc(navail+1);
+  if (navail <= 0) return;
+  if (navail > sizeof(buf)-1) {
+    navail = sizeof(buf)-1;
+  }
   bread = read(rfd, buf, navail);
   if (buf[navail-1] != '\0') {
     buf[navail] = '\0';
   }
-  owl_function_error("Err: %s", buf);
-  owl_free(buf);
+  owl_function_error("[stderr]\n%s", buf);
 }
 
 #endif /* OWL_STDERR_REDIR */
+
+void owl_zephyr_buddycheck_timer(owl_timer *t, void *data)
+{
+  if (owl_global_is_pseudologins(&g)) {
+    owl_function_debugmsg("Doing zephyr buddy check");
+    owl_function_zephyr_buddy_check(1);
+  }
+}
Index: owl.h
===================================================================
--- owl.h	(revision 43a306cdd965ba39eebeb9f3ccf426f700e34876)
+++ owl.h	(revision f34dd65b3adbc2eedc045a674dd89b7e20257680)
@@ -320,6 +320,6 @@
 
 typedef struct _owl_pair {
-  void *key;
-  void *value;
+  char *key;
+  char *value;
 } owl_pair;
 
@@ -377,14 +377,5 @@
   int active;
   int needsfirstrefresh;
-  void (*handler) (int ch);
 } owl_popwin;
-
-typedef struct _owl_popexec {
-  int refcount;
-  owl_viewwin *vwin;
-  int winactive;
-  int pid;			/* or 0 if it has terminated */
-  int rfd;  
-} owl_popexec;
 
 typedef struct _owl_messagelist {
@@ -412,5 +403,4 @@
 typedef struct _owl_filter {
   char *name;
-  int polarity;
   owl_filterelement * root;
   int fgcolor;
@@ -453,14 +443,4 @@
 } owl_editwin;
 
-typedef struct _owl_mux {
-  int handle;			/* for referencing this */
-  int active;			/* has this been deleted? */
-  int fd;		       
-  int eventmask;		/* bitmask of OWL_MUX_* */
-  void (*handler_fn)(int handle, int fd, int eventmask, void *data);
-  void *data;			/* data reference to pass to callback */
-} owl_mux;
-typedef owl_list owl_muxevents;
-
 typedef struct _owl_keybinding {
   int  *j;			/* keypress stack (0-terminated) */  
@@ -505,7 +485,9 @@
 
 typedef struct _owl_timer {
-  int direction;
-  time_t starttime;
-  int start;
+  time_t time;
+  int interval;
+  void (*callback)(struct _owl_timer *, void *);
+  void (*destroy)(struct _owl_timer *);
+  void *data;
 } owl_timer;
 
@@ -524,8 +506,18 @@
 
 typedef struct _owl_dispatch {
-  int fd;           /* FD to watch for dispatch. */
-  void (*cfunc)();  /* C function to dispatch to. */
-  SV *pfunc;        /* Perl function to dispatch to. */
+  int fd;                                 /* FD to watch for dispatch. */
+  int needs_gc;
+  void (*cfunc)(struct _owl_dispatch*);   /* C function to dispatch to. */
+  void (*destroy)(struct _owl_dispatch*); /* Destructor */
+  void *data;
 } owl_dispatch;
+
+typedef struct _owl_popexec {
+  int refcount;
+  owl_viewwin *vwin;
+  int winactive;
+  int pid;			/* or 0 if it has terminated */
+  owl_dispatch dispatch;
+} owl_popexec;
 
 typedef struct _owl_global {
@@ -537,5 +529,4 @@
   owl_list filterlist;
   owl_list puntlist;
-  owl_muxevents muxevents;	/* fds to dispatch on */
   owl_vardict vars;
   owl_cmddict cmds;
@@ -583,5 +574,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 +584,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 +592,6 @@
   owl_obarray obarray;
   owl_list dispatchlist;
+  GList *timerlist;
+  owl_timer *aim_nop_timer;
 } owl_global;
 
Index: pair.c
===================================================================
--- pair.c	(revision 160ea47d4619a2f544022ad89e83dbc934674d61)
+++ pair.c	(revision de1c8a59c19d33ab73607ff6539f55d51088ec6b)
@@ -1,22 +1,22 @@
 #include "owl.h"
 
-void owl_pair_create(owl_pair *p, void *key, void *value) {
+void owl_pair_create(owl_pair *p, char *key, char *value) {
   p->key=key;
   p->value=value;
 }
 
-void owl_pair_set_key(owl_pair *p, void *key) {
+void owl_pair_set_key(owl_pair *p, char *key) {
   p->key=key;
 }
 
-void owl_pair_set_value(owl_pair *p, void *value) {
+void owl_pair_set_value(owl_pair *p, char *value) {
   p->value=value;
 }
 
-void *owl_pair_get_key(owl_pair *p) {
+char *owl_pair_get_key(owl_pair *p) {
   return(p->key);
 }
 
-void *owl_pair_get_value(owl_pair *p) {
+char *owl_pair_get_value(owl_pair *p) {
   return(p->value);
 }
Index: perl/modules/IRC/lib/BarnOwl/Message/IRC.pm
===================================================================
--- perl/modules/IRC/lib/BarnOwl/Message/IRC.pm	(revision 38a7f226a2a038aae5b96d2b47874fa30b6b0ed8)
+++ perl/modules/IRC/lib/BarnOwl/Message/IRC.pm	(revision f79d6a2ccedcc7110b1391f385fb739e324562bd)
@@ -33,6 +33,6 @@
         @filter  =
              (qw{( type ^irc$ and filter personal and },
-              qw{( ( direction ^in$ and sender}, "^$who\$",
-              qw{ ) or ( direction ^out$ and recipient}, "^$who\$",
+              qw{( ( direction ^in$ and sender}, "^\Q$who\E\$",
+              qw{ ) or ( direction ^out$ and recipient}, "^\Q$who\E\$",
               qw{) ) ) });
         BarnOwl::command("filter", "$filter", @filter);
@@ -47,12 +47,12 @@
             $filter = "irc-$network-channel-$channel-$sender-$1";
             @filter =
-                 (qw{type ^irc$ and network}, "^$network\$",
-                  qw{and channel}, "^$channel\$",
-                  qw{and ( sender}, "^$sender\$",
-                  qw{or sender}, "^$1\$",qq{)});
+                 (qw{type ^irc$ and network}, "^\Q$network\E\$",
+                  qw{and channel}, "^\Q$channel\E\$",
+                  qw{and ( sender}, "^\Q$sender\E\$",
+                  qw{or sender}, "^\Q$1\E\$",qq{)});
         } else {
             $filter = "irc-$network-channel-$channel";
-            @filter = (qw{type ^irc$ and network}, "^$network\$",
-                       qw{and channel}, "^$channel\$");
+            @filter = (qw{type ^irc$ and network}, "^\Q$network\E\$",
+                       qw{and channel}, "^\Q$channel\E\$");
         }
         BarnOwl::command("filter", "$filter", @filter);
Index: perl/modules/IRC/lib/BarnOwl/Module/IRC.pm
===================================================================
--- perl/modules/IRC/lib/BarnOwl/Module/IRC.pm	(revision 167044bea49b17d131f1846e1e5528ef58e1c159)
+++ perl/modules/IRC/lib/BarnOwl/Module/IRC.pm	(revision 56d018933b753ce1293b3f7b8f96e664cc9e06b3)
@@ -214,5 +214,5 @@
     if ($body =~ /^\/me (.*)/) {
         $conn->conn->me($to, $1);
-        $body = BarnOwl::Style::boldify($conn->nick.' '.$1);
+        $body = '* '.$conn->nick.' '.$1;
     } else {
         $conn->conn->privmsg($to, $body);
Index: perl/modules/IRC/lib/BarnOwl/Module/IRC/Connection.pm
===================================================================
--- perl/modules/IRC/lib/BarnOwl/Module/IRC/Connection.pm	(revision 4789b17987d2032fcf895ce27b81ac613343e169)
+++ perl/modules/IRC/lib/BarnOwl/Module/IRC/Connection.pm	(revision 3048f1f1ca1c5d195114af9c9dcdc8dc80da65a8)
@@ -107,5 +107,5 @@
     my $nick = $self->nick;
     BarnOwl::beep() if $body =~ /\b\Q$nick\E\b/;
-    $body = BarnOwl::Style::boldify($evt->nick.' '.$body) if $evt->type eq 'caction';
+    $body = '* '.$evt->nick.' '.$body if $evt->type eq 'caction';
     my $msg = $self->new_message($evt,
         direction   => 'in',
Index: perl/modules/Jabber/lib/BarnOwl/Message/Jabber.pm
===================================================================
--- perl/modules/Jabber/lib/BarnOwl/Message/Jabber.pm	(revision 96134cb4aa5cfc151dbc860357af5a7156025c86)
+++ perl/modules/Jabber/lib/BarnOwl/Message/Jabber.pm	(revision 9375f8c6437069cd5e17a476685a9e7b280aa9a5)
@@ -70,5 +70,5 @@
         $filter = "jabber-room-$room";
         BarnOwl::command(qw[filter], $filter,
-                         qw[type ^jabber$ and room], "^$room\$");
+                         qw[type ^jabber$ and room], "^\Q$room\E\$");
         return $filter;
     } elsif ($self->login ne 'none') {
@@ -84,6 +84,6 @@
     my $filter = "jabber-user-$user";
     BarnOwl::command(qw[filter], $filter, qw[type ^jabber$],
-                     qw[and ( ( direction ^in$ and from], "^$user",
-                     qw[) or ( direction ^out$ and to ], "^$user",
+                     qw[and ( ( direction ^in$ and from], "^\Q$user\E(/.*)?\$",
+                     qw[) or ( direction ^out$ and to ], "^\Q$user\E(/.*)?\$",
                      qw[ ) ) ]);
     return $filter;
Index: perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm
===================================================================
--- perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm	(revision e979da9926f59c32e4a380c936551b11683cfe94)
+++ perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm	(revision b73ce70657f6a0da0aab9573fc0844ed89527136)
@@ -70,4 +70,5 @@
         $BarnOwl::Hooks::mainLoop->add("BarnOwl::Module::Jabber::onMainLoop");
         $BarnOwl::Hooks::getBuddyList->add("BarnOwl::Module::Jabber::onGetBuddyList");
+        $BarnOwl::Hooks::getQuickstart->add("BarnOwl::Module::Jabber::onGetQuickstart");
         $vars{show} = '';
 	BarnOwl::new_variable_bool("jabber:show_offline_buddies",
@@ -222,4 +223,14 @@
 }
 
+sub onGetQuickstart {
+    return <<'EOF'
+@b(Jabber:)
+Type ':jabberlogin @b(username@mit.edu)' to log in to Jabber. The command
+':jroster sub @b(somebody@gmail.com)' will request that they let you message
+them. Once you get a message saying you are subscribed, you can message
+them by typing ':jwrite @b(somebody@gmail.com)' or just 'j @b(somebody)'.
+EOF
+}
+
 ################################################################################
 ### Owl Commands
@@ -435,4 +446,5 @@
 
 sub cmd_logout {
+    return "You are not logged into jabber." unless ($conn->connected() > 0);
     # Logged into multiple accounts
     if ( $conn->connected() > 1 ) {
@@ -1112,5 +1124,5 @@
 sub process_presence_subscribed {
     my ( $sid, $p ) = @_;
-    queue_admin_msg("ignoring:".$p->GetXML());
+    queue_admin_msg("ignoring:".$p->GetXML()) if BarnOwl::getvar('jabber:spew') eq 'on';
     # RFC 3921 says we should respond to this with a "subscribe"
     # but this causes a flood of sub/sub'd presence packets with
@@ -1122,5 +1134,5 @@
 sub process_presence_unsubscribed {
     my ( $sid, $p ) = @_;
-    queue_admin_msg("ignoring:".$p->GetXML());
+    queue_admin_msg("ignoring:".$p->GetXML()) if BarnOwl::getvar('jabber:spew') eq 'on';
     # RFC 3921 says we should respond to this with a "subscribe"
     # but this causes a flood of unsub/unsub'd presence packets with
Index: perlconfig.c
===================================================================
--- perlconfig.c	(revision c1d2e6c253c25bace704f5d9d9171396524ae595)
+++ perlconfig.c	(revision e8c6d8f81a793b9ebcbd5898fa4b2ebd2b7c1c51)
@@ -44,6 +44,6 @@
   h = newHV();
 
-#define MSG2H(h,field) hv_store(h, #field, strlen(#field), \
-			      newSVpv(owl_message_get_##field(m),0), 0)
+#define MSG2H(h,field) (void)hv_store(h, #field, strlen(#field),        \
+                                      newSVpv(owl_message_get_##field(m),0), 0)
 
   if (owl_message_is_type_zephyr(m)
@@ -59,8 +59,8 @@
       owl_free(ptr);
     }
-    hv_store(h, "fields", strlen("fields"), newRV_noinc((SV*)av_zfields), 0);
-
-    hv_store(h, "auth", strlen("auth"), 
-	     newSVpv(owl_zephyr_get_authstr(owl_message_get_notice(m)),0),0);
+    (void)hv_store(h, "fields", strlen("fields"), newRV_noinc((SV*)av_zfields), 0);
+
+    (void)hv_store(h, "auth", strlen("auth"), 
+                   newSVpv(owl_zephyr_get_authstr(owl_message_get_notice(m)),0),0);
   }
 
@@ -68,6 +68,6 @@
   for(i=0; i<j; i++) {
     pair=owl_list_get_element(&(m->attributes), i);
-    hv_store(h, owl_pair_get_key(pair), strlen(owl_pair_get_key(pair)),
-	     newSVpv(owl_pair_get_value(pair),0),0);
+    (void)hv_store(h, owl_pair_get_key(pair), strlen(owl_pair_get_key(pair)),
+                   newSVpv(owl_pair_get_value(pair),0),0);
   }
   
@@ -88,11 +88,11 @@
     MSG2H(h, header); 
   }
-  hv_store(h, "time", strlen("time"), newSVpv(owl_message_get_timestr(m),0),0);
-  hv_store(h, "id", strlen("id"), newSViv(owl_message_get_id(m)),0);
-  hv_store(h, "deleted", strlen("deleted"), newSViv(owl_message_is_delete(m)),0);
-  hv_store(h, "private", strlen("private"), newSViv(owl_message_is_private(m)),0);
-  hv_store(h, "should_wordwrap",
-	   strlen("should_wordwrap"), newSViv(
-					      owl_filter_message_match(wrap, m)),0);
+  (void)hv_store(h, "time", strlen("time"), newSVpv(owl_message_get_timestr(m),0),0);
+  (void)hv_store(h, "id", strlen("id"), newSViv(owl_message_get_id(m)),0);
+  (void)hv_store(h, "deleted", strlen("deleted"), newSViv(owl_message_is_delete(m)),0);
+  (void)hv_store(h, "private", strlen("private"), newSViv(owl_message_is_private(m)),0);
+  (void)hv_store(h, "should_wordwrap",
+                 strlen("should_wordwrap"), newSViv(
+                                                    owl_filter_message_match(wrap, m)),0);
 
   type = owl_message_get_type(m);
@@ -102,5 +102,5 @@
   blessas = owl_sprintf("BarnOwl::Message::%s", type);
 
-  hr = sv_2mortal(newRV_noinc((SV*)h));
+  hr = newRV_noinc((SV*)h);
   stash =  gv_stashpv(blessas,0);
   if(!stash) {
@@ -182,7 +182,6 @@
   dSP ;
   int count;
-  unsigned int len;
   SV *msgref, *srv;
-  char *out, *preout;
+  char *out;
   
   ENTER ;
@@ -191,5 +190,5 @@
   PUSHMARK(SP) ;
   msgref = owl_perlconfig_message2hashref(m);
-  XPUSHs(msgref);
+  XPUSHs(sv_2mortal(msgref));
   PUTBACK ;
   
@@ -199,6 +198,5 @@
 
   if (SvTRUE(ERRSV)) {
-    STRLEN n_a;
-    owl_function_error("Perl Error: '%s'", SvPV(ERRSV, n_a));
+    owl_function_error("Perl Error: '%s'", SvPV_nolen(ERRSV));
     /* and clear the error */
     sv_setsv (ERRSV, &PL_sv_undef);
@@ -213,8 +211,5 @@
 
   if (srv) {
-    preout=SvPV(srv, len);
-    out = owl_malloc(strlen(preout)+1);
-    strncpy(out, preout, len);
-    out[len] = '\0';
+    out = owl_strdup(SvPV_nolen(srv));
   } else {
     out = NULL;
@@ -235,7 +230,7 @@
 {
   dSP;
-  unsigned int count, len, i;
+  unsigned int count, i;
   SV *msgref, *srv;
-  char *out, *preout;
+  char *out;
 
   msgref = owl_perlconfig_message2hashref(m);
@@ -245,5 +240,5 @@
 
   PUSHMARK(SP);
-  XPUSHs(msgref);
+  XPUSHs(sv_2mortal(msgref));
   for(i=0;i<argc;i++) {
     XPUSHs(sv_2mortal(newSVpv(argv[i], 0)));
@@ -261,6 +256,5 @@
 
   if (SvTRUE(ERRSV)) {
-    STRLEN n_a;
-    owl_function_error("Error: '%s'", SvPV(ERRSV, n_a));
+    owl_function_error("Error: '%s'", SvPV_nolen(ERRSV));
     /* and clear the error */
     sv_setsv (ERRSV, &PL_sv_undef);
@@ -270,8 +264,5 @@
 
   if (srv) {
-    preout=SvPV(srv, len);
-    out = owl_malloc(strlen(preout)+1);
-    strncpy(out, preout, len);
-    out[len] = '\0';
+    out = owl_strdup(SvPV_nolen(srv));
   } else {
     out = NULL;
@@ -301,9 +292,7 @@
   owl_global_set_no_have_config(&g);
 
-
   ret=perl_parse(p, owl_perl_xs_init, 2, args, NULL);
   if (ret || SvTRUE(ERRSV)) {
-    STRLEN n_a;
-    err=owl_strdup(SvPV(ERRSV, n_a));
+    err=owl_strdup(SvPV_nolen(ERRSV));
     sv_setsv(ERRSV, &PL_sv_undef);     /* and clear the error */
     return(err);
@@ -312,6 +301,5 @@
   ret=perl_run(p);
   if (ret || SvTRUE(ERRSV)) {
-    STRLEN n_a;
-    err=owl_strdup(SvPV(ERRSV, n_a));
+    err=owl_strdup(SvPV_nolen(ERRSV));
     sv_setsv(ERRSV, &PL_sv_undef);     /* and clear the error */
     return(err);
@@ -321,16 +309,16 @@
 
   /* create legacy variables */
-  perl_get_sv("BarnOwl::id", TRUE);
-  perl_get_sv("BarnOwl::class", TRUE);
-  perl_get_sv("BarnOwl::instance", TRUE);
-  perl_get_sv("BarnOwl::recipient", TRUE);
-  perl_get_sv("BarnOwl::sender", TRUE);
-  perl_get_sv("BarnOwl::realm", TRUE);
-  perl_get_sv("BarnOwl::opcode", TRUE);
-  perl_get_sv("BarnOwl::zsig", TRUE);
-  perl_get_sv("BarnOwl::msg", TRUE);
-  perl_get_sv("BarnOwl::time", TRUE);
-  perl_get_sv("BarnOwl::host", TRUE);
-  perl_get_av("BarnOwl::fields", TRUE);
+  get_sv("BarnOwl::id", TRUE);
+  get_sv("BarnOwl::class", TRUE);
+  get_sv("BarnOwl::instance", TRUE);
+  get_sv("BarnOwl::recipient", TRUE);
+  get_sv("BarnOwl::sender", TRUE);
+  get_sv("BarnOwl::realm", TRUE);
+  get_sv("BarnOwl::opcode", TRUE);
+  get_sv("BarnOwl::zsig", TRUE);
+  get_sv("BarnOwl::msg", TRUE);
+  get_sv("BarnOwl::time", TRUE);
+  get_sv("BarnOwl::host", TRUE);
+  get_av("BarnOwl::fields", TRUE);
 
   if(file) {
@@ -339,9 +327,8 @@
   }
 
-  perl_eval_pv(owl_perlwrap_codebuff, FALSE);
+  eval_pv(owl_perlwrap_codebuff, FALSE);
 
   if (SvTRUE(ERRSV)) {
-    STRLEN n_a;
-    err=owl_strdup(SvPV(ERRSV, n_a));
+    err=owl_strdup(SvPV_nolen(ERRSV));
     sv_setsv (ERRSV, &PL_sv_undef);     /* and clear the error */
     return(err);
@@ -358,27 +345,6 @@
 /* returns whether or not a function exists */
 int owl_perlconfig_is_function(char *fn) {
-  if (perl_get_cv(fn, FALSE)) return(1);
+  if (get_cv(fn, FALSE)) return(1);
   else return(0);
-}
-
-/* returns 0 on success */
-int owl_perlconfig_get_hashkeys(char *hashname, owl_list *l)
-{
-  HV *hv;
-  HE *he;
-  char *key;
-  I32 i;
-
-  if (owl_list_create(l)) return(-1);
-  hv = get_hv(hashname, FALSE);
-  if (!hv) return(-1);
-  i = hv_iterinit(hv);
-  while ((he = hv_iternext(hv))) {
-    key = hv_iterkey(he, &i);
-    if (key) {
-      owl_list_append_element(l, owl_strdup(key));
-    }
-  }
-  return(0);
 }
 
@@ -392,21 +358,21 @@
   if (!owl_global_have_config(&g)) return NULL;
 
+  ENTER;
+  SAVETMPS;
   /* execute the subroutine */
-  response = perl_eval_pv(line, FALSE);
+  response = eval_pv(line, FALSE);
 
   if (SvTRUE(ERRSV)) {
-    STRLEN n_a;
-    owl_function_error("Perl Error: '%s'", SvPV(ERRSV, n_a));
+    owl_function_error("Perl Error: '%s'", SvPV_nolen(ERRSV));
     sv_setsv (ERRSV, &PL_sv_undef);     /* and clear the error */
   }
 
   preout=SvPV(response, len);
-  /* leave enough space in case we have to add a newline */
-  out = owl_malloc(strlen(preout)+2);
-  strncpy(out, preout, len);
-  out[len] = '\0';
-  if (!strlen(out) || out[strlen(out)-1]!='\n') {
-    strcat(out, "\n");
-  }
+  if (len == 0 || preout[len - 1] != '\n')
+    out = owl_sprintf("%s\n", preout);
+  else
+    out = owl_strdup(preout);
+  FREETMPS;
+  LEAVE;
 
   return(out);
@@ -439,5 +405,4 @@
   char * ret = NULL;
   SV *rv;
-  STRLEN n_a;
   dSP;
 
@@ -458,5 +423,5 @@
 
   if(SvTRUE(ERRSV)) {
-    owl_function_error("%s", SvPV(ERRSV, n_a));
+    owl_function_error("%s", SvPV_nolen(ERRSV));
     (void)POPs;
   } else {
@@ -465,5 +430,5 @@
     rv = POPs;
     if(SvTRUE(rv)) {
-      ret = owl_strdup(SvPV(rv, n_a));
+      ret = owl_strdup(SvPV_nolen(rv));
     }
   }
@@ -482,5 +447,6 @@
 void owl_perlconfig_dispatch_free(owl_dispatch *d)
 {
-  SvREFCNT_dec(d->pfunc);
+  SvREFCNT_dec(d->data);
+  owl_free(d);
 }
 
@@ -489,5 +455,4 @@
   SV *cb = (SV*)(e->cbdata);
   SV *text;
-  unsigned int n_a;
   dSP;
 
@@ -508,5 +473,5 @@
 
   if(SvTRUE(ERRSV)) {
-    owl_function_error("%s", SvPV(ERRSV, n_a));
+    owl_function_error("%s", SvPV_nolen(ERRSV));
   }
 
@@ -526,17 +491,16 @@
   call_pv("BarnOwl::Hooks::_mainloop_hook", G_DISCARD|G_EVAL);
   if(SvTRUE(ERRSV)) {
-    STRLEN n_a;
-    owl_function_error("%s", SvPV(ERRSV, n_a));
+    owl_function_error("%s", SvPV_nolen(ERRSV));
   }
   return;
 }
 
-void owl_perlconfig_do_dispatch(owl_dispatch *d)
-{
-  SV *cb = d->pfunc;
-  unsigned int n_a;
+void owl_perlconfig_dispatch(owl_dispatch *d)
+{
+  SV *cb = d->data;
   dSP;
   if(cb == NULL) {
     owl_function_error("Perl callback is NULL!");
+    return;
   }
 
@@ -550,5 +514,5 @@
 
   if(SvTRUE(ERRSV)) {
-    owl_function_error("%s", SvPV(ERRSV, n_a));
+    owl_function_error("%s", SvPV_nolen(ERRSV));
   }
 
@@ -556,2 +520,39 @@
   LEAVE;
 }
+
+void owl_perlconfig_perl_timer(owl_timer *t, void *data)
+{
+  SV *obj = data;
+
+  if(!SvROK(obj)) {
+    return;
+  }
+
+  dSP;
+  ENTER;
+  SAVETMPS;
+
+  PUSHMARK(SP);
+  XPUSHs(obj);
+  PUTBACK;
+
+  call_method("do_callback", G_DISCARD|G_KEEPERR|G_EVAL);
+
+  SPAGAIN;
+
+  if (SvTRUE(ERRSV)) {
+    owl_function_error("Error in calback: '%s'", SvPV_nolen(ERRSV));
+    sv_setsv (ERRSV, &PL_sv_undef);
+  }
+
+  PUTBACK;
+  FREETMPS;
+  LEAVE;
+}
+
+void owl_perlconfig_perl_timer_destroy(owl_timer *t)
+{
+  if(SvOK((SV*)t->data)) {
+    SvREFCNT_dec((SV*)t->data);
+  }
+}
Index: perlglue.xs
===================================================================
--- perlglue.xs	(revision 740d5f76770d93df8236a59996511e8ce2d1c0c5)
+++ perlglue.xs	(revision 16318254b6ef4667cccff7ba22cf480c35e23b0c)
@@ -24,8 +24,8 @@
 	 * complex argument processing or something, we define a
 	 * simple version here that takes arguments in as flat a
-	 * manner as possible, to simplify the XS code, with a name
-	 * with a trailing `_internal', and write a perl wrapper in
-	 * perlwrap.pm that munges the arguments as appropriate and
-	 * calls the internal version.
+	 * manner as possible, to simplify the XS code, put it in
+	 * BarnOwl::Intenal::, and write a perl wrapper in perlwrap.pm
+	 * that munges the arguments as appropriate and calls the
+	 * internal version.
 	 */
 
@@ -62,5 +62,7 @@
 getcurmsg()
 	CODE:
-		ST(0) = owl_perlconfig_curmessage2hashref();
+		RETVAL = owl_perlconfig_curmessage2hashref();
+	OUTPUT:
+		RETVAL
 
 int
@@ -141,6 +143,193 @@
 		if (rv) owl_free(rv);
 
-void
-new_command_internal(name, func, summary, usage, description)
+void queue_message(msg) 
+	SV *msg
+	PREINIT:
+		owl_message *m;
+	CODE:
+	{
+		if(!SvROK(msg) || SvTYPE(SvRV(msg)) != SVt_PVHV) {
+			croak("Usage: BarnOwl::queue_message($message)");
+		}
+
+		m = owl_perlconfig_hashref2message(msg);
+
+		owl_global_messagequeue_addmsg(&g, m);
+	}
+
+void admin_message(header, body) 
+	char *header
+	char *body
+	CODE:
+	{
+		owl_function_adminmsg(header, body);		
+	}
+
+void start_question(line, callback)
+	char *line
+	SV *callback
+	PREINIT:
+	CODE:
+	{
+		if(!SV_IS_CODEREF(callback))
+			croak("Callback must be a subref");
+
+		owl_function_start_question(line);
+
+		SvREFCNT_inc(callback);
+		owl_editwin_set_cbdata(owl_global_get_typwin(&g), callback);
+		owl_editwin_set_callback(owl_global_get_typwin(&g), owl_perlconfig_edit_callback);
+	}
+
+void start_password(line, callback)
+	char *line
+	SV *callback
+	PREINIT:
+	CODE:
+	{
+		if(!SV_IS_CODEREF(callback))
+			croak("Callback must be a subref");
+
+		owl_function_start_password(line);
+
+		SvREFCNT_inc(callback);
+		owl_editwin_set_cbdata(owl_global_get_typwin(&g), callback);
+		owl_editwin_set_callback(owl_global_get_typwin(&g), owl_perlconfig_edit_callback);
+	}
+
+void start_edit_win(line, callback)
+	char *line
+	SV *callback
+	PREINIT:
+		owl_editwin * e;
+		char buff[1024];
+	CODE:
+	{
+		if(!SV_IS_CODEREF(callback))
+			croak("Callback must be a subref");
+
+		e = owl_global_get_typwin(&g);
+		owl_editwin_new_style(e, OWL_EDITWIN_STYLE_MULTILINE,
+				      owl_global_get_msg_history(&g));
+		owl_editwin_clear(e);
+		owl_editwin_set_dotsend(e);
+		snprintf(buff, 1023, "----> %s\n", line);
+		owl_editwin_set_locktext(e, buff);
+
+		owl_global_set_typwin_active(&g);
+
+		SvREFCNT_inc(callback);
+		owl_editwin_set_cbdata(owl_global_get_typwin(&g), callback);
+		owl_editwin_set_callback(owl_global_get_typwin(&g), owl_perlconfig_edit_callback);
+	}
+
+
+char * 
+get_data_dir ()
+	CODE:
+		RETVAL = (char *) owl_get_datadir();
+	OUTPUT:
+	RETVAL
+
+char * 
+get_config_dir ()
+	CODE:
+		RETVAL = (char *) owl_global_get_confdir(&g);
+	OUTPUT:
+	RETVAL	
+
+void
+popless_text(text) 
+	char *text
+	CODE:
+	{
+		owl_function_popless_text(text);
+	}
+
+void
+popless_ztext(text) 
+	char *text
+	CODE:
+	{
+		owl_fmtext fm;
+		owl_fmtext_init_null(&fm);
+		owl_fmtext_append_ztext(&fm, text);
+		owl_function_popless_fmtext(&fm);
+		owl_fmtext_free(&fm);
+	}
+
+void
+error(text) 
+	char *text
+	CODE:
+	{
+		owl_function_error("%s", text);
+	}
+
+void
+create_style(name, object)
+     char *name
+     SV  *object
+     PREINIT:
+		owl_style *s;
+     CODE:
+	{
+		s = owl_malloc(sizeof(owl_style));
+		owl_style_create_perl(s, name, object);
+		owl_global_add_style(&g, s);
+	}
+
+int
+getnumcolors()
+	CODE:
+		RETVAL = owl_function_get_color_count();
+	OUTPUT:
+		RETVAL
+
+void
+_remove_filter(filterName)
+	char *filterName
+	CODE:
+	{
+		/* Don't delete the current view, or the 'all' filter */
+		if (strcmp(filterName, owl_view_get_filtname(owl_global_get_current_view(&g)))
+		    && strcmp(filterName, "all")) {
+			owl_global_remove_filter(&g,filterName);
+		}
+	}
+
+char *
+wordwrap(in, cols)
+	char *in
+	int cols
+	PREINIT:
+		char *rv = NULL;
+	CODE:
+		rv = owl_text_wordwrap(in, cols);
+		RETVAL = rv;	
+	OUTPUT:
+		RETVAL
+	CLEANUP:
+		if (rv) owl_free(rv);
+
+void
+add_dispatch(fd, cb)
+	int fd
+	SV * cb
+	CODE:
+        SvREFCNT_inc(cb);
+	owl_select_add_perl_dispatch(fd, cb);
+
+void
+remove_dispatch(fd)
+	int fd
+	CODE:
+	owl_select_remove_perl_dispatch(fd);
+
+MODULE = BarnOwl		PACKAGE = BarnOwl::Internal
+
+
+void
+new_command(name, func, summary, usage, description)
 	char *name
 	SV *func
@@ -172,176 +361,6 @@
 	   }
 
-void queue_message(msg) 
-	SV *msg
-	PREINIT:
-		owl_message *m;
-	CODE:
-	{
-		if(!SvROK(msg) || SvTYPE(SvRV(msg)) != SVt_PVHV) {
-			croak("Usage: BarnOwl::queue_message($message)");
-		}
-
-		m = owl_perlconfig_hashref2message(msg);
-
-		owl_global_messagequeue_addmsg(&g, m);
-	}
-
-void admin_message(header, body) 
-	char *header
-	char *body
-	CODE:
-	{
-		owl_function_adminmsg(header, body);		
-	}
-
-void start_question(line, callback)
-	char *line
-	SV *callback
-	PREINIT:
-	CODE:
-	{
-		if(!SV_IS_CODEREF(callback))
-			croak("Callback must be a subref");
-
-		owl_function_start_question(line);
-
-		SvREFCNT_inc(callback);
-		owl_editwin_set_cbdata(owl_global_get_typwin(&g), callback);
-		owl_editwin_set_callback(owl_global_get_typwin(&g), owl_perlconfig_edit_callback);
-	}
-
-void start_password(line, callback)
-	char *line
-	SV *callback
-	PREINIT:
-	CODE:
-	{
-		if(!SV_IS_CODEREF(callback))
-			croak("Callback must be a subref");
-
-		owl_function_start_password(line);
-
-		SvREFCNT_inc(callback);
-		owl_editwin_set_cbdata(owl_global_get_typwin(&g), callback);
-		owl_editwin_set_callback(owl_global_get_typwin(&g), owl_perlconfig_edit_callback);
-	}
-
-void start_edit_win(line, callback)
-	char *line
-	SV *callback
-	PREINIT:
-		owl_editwin * e;
-		char buff[1024];
-	CODE:
-	{
-		if(!SV_IS_CODEREF(callback))
-			croak("Callback must be a subref");
-
-		e = owl_global_get_typwin(&g);
-		owl_editwin_new_style(e, OWL_EDITWIN_STYLE_MULTILINE,
-				      owl_global_get_msg_history(&g));
-		owl_editwin_clear(e);
-		owl_editwin_set_dotsend(e);
-		snprintf(buff, 1023, "----> %s\n", line);
-		owl_editwin_set_locktext(e, buff);
-
-		owl_global_set_typwin_active(&g);
-
-		SvREFCNT_inc(callback);
-		owl_editwin_set_cbdata(owl_global_get_typwin(&g), callback);
-		owl_editwin_set_callback(owl_global_get_typwin(&g), owl_perlconfig_edit_callback);
-	}
-
-
-char * 
-get_data_dir ()
-	CODE:
-		RETVAL = (char *) owl_get_datadir();
-	OUTPUT:
-	RETVAL
-
-char * 
-get_config_dir ()
-	CODE:
-		RETVAL = (char *) owl_global_get_confdir(&g);
-	OUTPUT:
-	RETVAL	
-
-void
-popless_text(text) 
-	char *text
-	CODE:
-	{
-		owl_function_popless_text(text);
-	}
-
-void
-popless_ztext(text) 
-	char *text
-	CODE:
-	{
-		owl_fmtext fm;
-		owl_fmtext_init_null(&fm);
-		owl_fmtext_append_ztext(&fm, text);
-		owl_function_popless_fmtext(&fm);
-		owl_fmtext_free(&fm);
-	}
-
-void
-error(text) 
-	char *text
-	CODE:
-	{
-		owl_function_error("%s", text);
-	}
-
-void
-create_style(name, object)
-     char *name
-     SV  *object
-     PREINIT:
-		owl_style *s;
-     CODE:
-	{
-		s = owl_malloc(sizeof(owl_style));
-		owl_style_create_perl(s, name, object);
-		owl_global_add_style(&g, s);
-	}
-
-int
-getnumcolors()
-	CODE:
-		RETVAL = owl_function_get_color_count();
-	OUTPUT:
-		RETVAL
-
-void
-_remove_filter(filterName)
-	char *filterName
-	CODE:
-	{
-		/* Don't delete the current view, or the 'all' filter */
-		if (strcmp(filterName, owl_view_get_filtname(owl_global_get_current_view(&g)))
-		    && strcmp(filterName, "all")) {
-			owl_global_remove_filter(&g,filterName);
-		}
-	}
-
-char *
-wordwrap(in, cols)
-	char *in
-	int cols
-	PREINIT:
-		char *rv = NULL;
-	CODE:
-		rv = owl_text_wordwrap(in, cols);
-		RETVAL = rv;	
-	OUTPUT:
-		RETVAL
-	CLEANUP:
-		if (rv) owl_free(rv);
-
-void
-new_variable_string_internal(name, ival, summ, desc)
+void
+new_variable_string(name, ival, summ, desc)
 	char * name
 	char * ival
@@ -356,5 +375,5 @@
 
 void
-new_variable_int_internal(name, ival, summ, desc)
+new_variable_int(name, ival, summ, desc)
 	char * name
 	int ival
@@ -369,5 +388,5 @@
 
 void
-new_variable_bool_internal(name, ival, summ, desc)
+new_variable_bool(name, ival, summ, desc)
 	char * name
 	int ival
@@ -381,15 +400,31 @@
 				      ival);
 
-void
-add_dispatch(fd, cb)
-	int fd
-	SV * cb
-	CODE:
-        SvREFCNT_inc(cb);
-	owl_select_add_perl_dispatch(fd, cb);
-
-void
-remove_dispatch(fd)
-	int fd
-	CODE:
-	owl_select_remove_perl_dispatch(fd);
+IV
+add_timer(after, interval, cb)
+	int after
+	int interval
+	SV *cb
+	PREINIT:
+		SV *ref;
+		owl_timer *t;
+	CODE:
+		ref = sv_rvweaken(newSVsv(cb));
+		t = owl_select_add_timer(after,
+					 interval,
+					 owl_perlconfig_perl_timer,
+					 owl_perlconfig_perl_timer_destroy,
+					 ref);
+	owl_function_debugmsg("Created timer %p", t);
+	RETVAL = (IV)t;
+	OUTPUT:
+		RETVAL
+
+void
+remove_timer(timer)
+	IV timer
+	PREINIT:
+		owl_timer *t;
+	CODE:
+		t = (owl_timer*)timer;
+		owl_function_debugmsg("Freeing timer %p", t);
+				owl_select_remove_timer(t);
Index: perlwrap.pm
===================================================================
--- perlwrap.pm	(revision 740d5f76770d93df8236a59996511e8ce2d1c0c5)
+++ perlwrap.pm	(revision e9708d2252864359eae00b0d49981f5659a555f5)
@@ -242,5 +242,5 @@
     );
 
-    BarnOwl::new_command_internal($name, $func, $args{summary}, $args{usage}, $args{description});
+    BarnOwl::Internal::new_command($name, $func, $args{summary}, $args{usage}, $args{description});
 }
 
@@ -275,15 +275,15 @@
 
 sub new_variable_int {
-    unshift @_, \&BarnOwl::new_variable_int_internal, 0;
+    unshift @_, \&BarnOwl::Internal::new_variable_int, 0;
     goto \&_new_variable;
 }
 
 sub new_variable_bool {
-    unshift @_, \&BarnOwl::new_variable_bool_internal, 0;
+    unshift @_, \&BarnOwl::Internal::new_variable_bool, 0;
     goto \&_new_variable;
 }
 
 sub new_variable_string {
-    unshift @_, \&BarnOwl::new_variable_string_internal, "";
+    unshift @_, \&BarnOwl::Internal::new_variable_string, "";
     goto \&_new_variable;
 }
@@ -795,6 +795,11 @@
 =item $receiveMessage
 
-Called with a C<BarnOwl::Message> object every time BarnOwl appends a
-new message to its message list
+Called with a C<BarnOwl::Message> object every time BarnOwl receives a
+new incoming message.
+
+=item $newMessage
+
+Called with a C<BarnOwl::Message> object every time BarnOwl appends
+I<any> new message to the message list.
 
 =item $mainLoop
@@ -810,4 +815,12 @@
 displayed in a popup window, with zephyr formatting parsed.
 
+=item $getQuickstart
+
+Called by :show quickstart to display 2-5 lines of help on how to
+start using the protocol. The result from every function registered
+with this hook will be appended and displayed in an admin message,
+with zephyr formatting parsed. The format should be
+"@b(Protocol:)\nSome text.\nMore text.\n"
+
 =back
 
@@ -818,5 +831,6 @@
 our @EXPORT_OK = qw($startup $shutdown
                     $receiveMessage $newMessage
-                    $mainLoop $getBuddyList);
+                    $mainLoop $getBuddyList
+                    $getQuickstart);
 
 our %EXPORT_TAGS = (all => [@EXPORT_OK]);
@@ -828,4 +842,5 @@
 our $mainLoop = BarnOwl::Hook->new;
 our $getBuddyList = BarnOwl::Hook->new;
+our $getQuickstart = BarnOwl::Hook->new;
 
 # Internal startup/shutdown routines called by the C code
@@ -921,4 +936,8 @@
 }
 
+sub _get_quickstart {
+    return join("\n", $getQuickstart->run);
+}
+
 ################################################################################
 # Built-in perl styles
@@ -1214,4 +1233,35 @@
 }
 
+package BarnOwl::Timer;
+
+sub new {
+    my $class = shift;
+    my $args = shift;
+
+    my $cb = $args->{cb};
+    die("Invalid callback pased to BarnOwl::Timer\n") unless ref($cb) eq 'CODE';
+
+    my $self = {cb => $cb};
+
+    bless($self, $class);
+
+    $self->{timer} = BarnOwl::Internal::add_timer($args->{after} || 0,
+                                                  $args->{interval} || 0,
+                                                  $self);
+    return $self;
+}
+
+sub do_callback {
+    my $self = shift;
+    $self->{cb}->($self);
+}
+
+sub DESTROY {
+    my $self = shift;
+    if(defined($self->{timer})) {
+        BarnOwl::Internal::remove_timer($self->{timer});
+    }
+}
+
 
 # switch to package main when we're done
Index: popexec.c
===================================================================
--- popexec.c	(revision 1971b59613b1999b306139b8c2119beeb060b84c)
+++ popexec.c	(revision 40c665796431e6bd112feb7e36e6520b696396c4)
@@ -51,13 +51,13 @@
     return NULL;
   } else if (pid != 0) {
+    close(child_write_fd);
     /* still in owl */
-    int muxhandle;
     pe->pid=pid;
     pe->winactive=1;
-    pe->rfd = parent_read_fd;
-    close(child_write_fd);
-    muxhandle = owl_muxevents_add(owl_global_get_muxevents(&g),
-    				  parent_read_fd, OWL_MUX_READ|OWL_MUX_EXCEPT,
-    				  owl_popexec_inputhandler, (void*)pe);
+    pe->dispatch.fd = parent_read_fd;
+    pe->dispatch.cfunc = owl_popexec_inputhandler;
+    pe->dispatch.destroy = owl_popexec_free_dispatch;
+    pe->dispatch.data = pe;
+    owl_select_add_dispatch(&pe->dispatch);
     pe->refcount++;
   } else {
@@ -73,9 +73,4 @@
     dup2(child_write_fd, 2 /*stderr*/);
     close(child_write_fd);
-    
-    while(0) {
-      write(child_write_fd, "meep\n", 5);
-      sleep(1);
-    }
 
     argv[0] = "sh";
@@ -90,7 +85,7 @@
 }
 
-void owl_popexec_inputhandler(int handle, int fd, int eventmask, void *data)
+void owl_popexec_inputhandler(owl_dispatch *d)
 {
-  owl_popexec *pe = (owl_popexec*)data;
+  owl_popexec *pe = d->data;
   int navail, bread, rv_navail;
   char *buf;
@@ -101,5 +96,5 @@
   /* If pe->winactive is 0 then the vwin has closed. 
    * If pe->pid is 0 then the child has already been reaped.
-   * if pe->rfd is -1 then the fd has been closed out.
+   * if d->fd is -1 then the fd has been closed out.
    * Under these cases we want to get to a state where:
    *   - data read until end if child running
@@ -110,12 +105,10 @@
 
   /* the viewwin has closed */
-  if (pe->rfd<0 && !pe->pid && !pe->winactive) {
-    owl_muxevents_remove(owl_global_get_muxevents(&g), handle);
-    owl_function_debugmsg("unref of %p from input handler at A", pe);
-    owl_popexec_unref(pe);
+  if (!pe->pid && !pe->winactive) {
+    owl_select_remove_dispatch(d->fd);
     return;
   }
 
-  if (0 != (rv_navail = ioctl(fd, FIONREAD, (void*)&navail))) {
+  if (0 != (rv_navail = ioctl(d->fd, FIONREAD, (void*)&navail))) {
     owl_function_debugmsg("ioctl error");
   }
@@ -130,15 +123,9 @@
       owl_viewwin_redisplay(pe->vwin, 1);
     }
-    if (pe->rfd>0) {
-      close(pe->rfd);
-      pe->rfd = -1;
-    }
-    owl_muxevents_remove(owl_global_get_muxevents(&g), handle);
-    owl_function_debugmsg("unref of %p from input handler at B", pe);
-    owl_popexec_unref(pe);
+    owl_select_remove_dispatch(d->fd);
     return;
   }
 
-  if (pe->rfd<0 || !pe->pid || !pe->winactive || rv_navail) {
+  if (d->fd<0 || !pe->pid || !pe->winactive || rv_navail) {
     owl_function_error("popexec should not have reached this point");
     return;
@@ -148,6 +135,6 @@
   if (navail>1024) { navail = 1024; }
   buf = owl_malloc(navail+1);
-  owl_function_debugmsg("about to read %d\n", navail);
-  bread = read(fd, buf, navail);
+  owl_function_debugmsg("about to read %d", navail);
+  bread = read(d->fd, buf, navail);
   if (bread<0) {
     perror("read");
@@ -157,5 +144,5 @@
     buf[navail] = '\0';
   }
-  owl_function_debugmsg("got data:  <%s>\n", buf);
+  owl_function_debugmsg("got data:  <%s>", buf);
   if (pe->winactive) {
     owl_viewwin_append_text(pe->vwin, buf);
@@ -166,4 +153,11 @@
 }
 
+void owl_popexec_free_dispatch(owl_dispatch *d)
+{
+  owl_popexec *pe = d->data;
+  close(d->fd);
+  owl_popexec_unref(pe);
+}
+
 void owl_popexec_viewwin_onclose(owl_viewwin *vwin, void *data)
 {
@@ -172,7 +166,6 @@
 
   pe->winactive = 0;
-  if (pe->rfd>0) {
-    close(pe->rfd);
-    pe->rfd = -1;
+  if (pe->dispatch.fd>0) {
+    owl_select_remove_dispatch(pe->dispatch.fd);
   }
   if (pe->pid) {
Index: popwin.c
===================================================================
--- popwin.c	(revision 818a07348f30d7fbee5ff8c98ceca4886c9a710f)
+++ popwin.c	(revision f34dd65b3adbc2eedc045a674dd89b7e20257680)
@@ -57,14 +57,4 @@
 }
 
-int owl_popwin_display_text(owl_popwin *pw, char *text)
-{
-  waddstr(pw->popwin, text);
-  wnoutrefresh(pw->popwin);
-  touchwin(pw->borderwin);
-  wnoutrefresh(pw->borderwin);
-  owl_global_set_needrefresh(&g);
-  return(0);
-}	      
-
 int owl_popwin_close(owl_popwin *pw)
 {
@@ -96,14 +86,4 @@
 }
 
-void owl_popwin_set_handler(owl_popwin *pw, void (*func)(int ch))
-{
-  pw->handler=func;
-}
-
-void owl_popwin_unset_handler(owl_popwin *pw)
-{
-  pw->handler=NULL;
-}
-
 WINDOW *owl_popwin_get_curswin(owl_popwin *pw)
 {
Index: regex.c
===================================================================
--- regex.c	(revision 8b7466b709fc7f9b93872e1191dfa060187cf2d4)
+++ regex.c	(revision 554a2b836ba40cb8a9fbbc1b1b8aeb195a334e78)
@@ -13,5 +13,5 @@
 {
   int ret;
-  char buff1[LINE], buff2[LINE];
+  char buff1[LINE];
   char *ptr;
   
@@ -29,6 +29,5 @@
   if (ret) {
     regerror(ret, NULL, buff1, LINE);
-    sprintf(buff2, "Error in regular expression: %s", buff1);
-    owl_function_makemsg(buff2);
+    owl_function_makemsg("Error in regular expression: %s", buff1);
     owl_free(re->string);
     re->string=NULL;
Index: select.c
===================================================================
--- select.c	(revision 2f690811f743b0ec04fdd98ce530c5a296c031df)
+++ select.c	(revision 1895c292a4af5f8fb2b9305e3ea30bebe2ec9b4e)
@@ -2,4 +2,83 @@
 
 static const char fileIdent[] = "$Id: select.c 894 2008-01-17 07:13:44Z asedeno $";
+
+static int dispatch_active = 0;
+
+int _owl_select_timer_cmp(owl_timer *t1, owl_timer *t2) {
+  return t1->time - t2->time;
+}
+
+int _owl_select_timer_eq(owl_timer *t1, owl_timer *t2) {
+  return t1 == t2;
+}
+
+owl_timer *owl_select_add_timer(int after, int interval, void (*cb)(owl_timer *, void *), void (*destroy)(owl_timer*), void *data)
+{
+  owl_timer *t = owl_malloc(sizeof(owl_timer));
+  GList **timers = owl_global_get_timerlist(&g);
+
+  t->time = time(NULL) + after;
+  t->interval = interval;
+  t->callback = cb;
+  t->destroy = destroy;
+  t->data = data;
+
+  *timers = g_list_insert_sorted(*timers, t,
+                                 (GCompareFunc)_owl_select_timer_cmp);
+  return t;
+}
+
+void owl_select_remove_timer(owl_timer *t)
+{
+  GList **timers = owl_global_get_timerlist(&g);
+  if (t && g_list_find(*timers, t)) {
+    *timers = g_list_remove(*timers, t);
+    if(t->destroy) {
+      t->destroy(t);
+    }
+    owl_free(t);
+  }
+}
+
+void owl_select_process_timers(struct timeval *timeout)
+{
+  time_t now = time(NULL);
+  GList **timers = owl_global_get_timerlist(&g);
+
+  while(*timers) {
+    owl_timer *t = (*timers)->data;
+    int remove = 0;
+
+    if(t->time > now)
+      break;
+
+    /* Reschedule if appropriate */
+    if(t->interval > 0) {
+      t->time = now + t->interval;
+      *timers = g_list_remove(*timers, t);
+      *timers = g_list_insert_sorted(*timers, t,
+                                     (GCompareFunc)_owl_select_timer_cmp);
+    } else {
+      remove = 1;
+    }
+
+    /* Do the callback */
+    t->callback(t, t->data);
+    if(remove) {
+      owl_select_remove_timer(t);
+    }
+  }
+
+  if(*timers) {
+    owl_timer *t = (*timers)->data;
+    timeout->tv_sec = t->time - now;
+    if (timeout->tv_sec > 60)
+      timeout->tv_sec = 60;
+  } else {
+    timeout->tv_sec = 60;
+  }
+
+  timeout->tv_usec = 0;
+}
 
 /* Returns the index of the dispatch for the file descriptor. */
@@ -19,4 +98,17 @@
 }
 
+void owl_select_remove_dispatch_at(int elt) /* noproto */
+{
+  owl_list *dl;
+  owl_dispatch *d;
+
+  dl = owl_global_get_dispatchlist(&g);
+  d = (owl_dispatch*)owl_list_get_element(dl, elt);
+  owl_list_remove_element(dl, elt);
+  if (d->destroy) {
+    d->destroy(d);
+  }
+}
+
 /* Adds a new owl_dispatch to the list, replacing existing ones if needed. */
 void owl_select_add_dispatch(owl_dispatch *d)
@@ -24,4 +116,6 @@
   int elt;
   owl_list *dl;
+
+  d->needs_gc = 0;
 
   elt = owl_select_find_dispatch(d->fd);
@@ -34,11 +128,8 @@
        replace the old dispatch. */
     if (d_old != d) {
-      owl_list_replace_element(dl, elt, d);
-      owl_free(d_old);
-    }
-  }
-  else {
-    owl_list_append_element(dl, d);
-  }
+      owl_select_remove_dispatch_at(elt);
+    }
+  }
+  owl_list_append_element(dl, d);
 }
 
@@ -48,16 +139,16 @@
   int elt;
   owl_list *dl;
+  owl_dispatch *d;
 
   elt = owl_select_find_dispatch(fd);
-  dl = owl_global_get_dispatchlist(&g);
-  
-  if (elt != -1) {
-    owl_dispatch *d;
+  if(elt == -1) {
+    return;
+  } else if(dispatch_active) {
+    /* Defer the removal until dispatch is done walking the list */
+    dl = owl_global_get_dispatchlist(&g);
     d = (owl_dispatch*)owl_list_get_element(dl, elt);
-    owl_list_remove_element(dl, elt);
-    if (d->pfunc) {
-      owl_perlconfig_dispatch_free(d);
-    }
-    owl_free(d);
+    d->needs_gc = 1;
+  } else {
+    owl_select_remove_dispatch_at(elt);
   }
 }
@@ -75,5 +166,5 @@
   if (elt != -1) {
     d = (owl_dispatch*)owl_list_get_element(owl_global_get_dispatchlist(&g), elt);
-    if (d->pfunc == NULL) {
+    if (d->cfunc != owl_perlconfig_dispatch) {
       /* don't mess with non-perl dispatch functions from here. */
       return 1;
@@ -83,6 +174,7 @@
   d = malloc(sizeof(owl_dispatch));
   d->fd = fd;
-  d->cfunc = NULL;
-  d->pfunc = cb;
+  d->cfunc = owl_perlconfig_dispatch;
+  d->destroy = owl_perlconfig_dispatch_free;
+  d->data = cb;
   owl_select_add_dispatch(d);
   return 0;
@@ -97,6 +189,6 @@
   if (elt != -1) {
     d = (owl_dispatch*)owl_list_get_element(owl_global_get_dispatchlist(&g), elt);
-    if (d->pfunc != NULL) {
-      owl_select_remove_dispatch(fd);
+    if (d->cfunc == owl_perlconfig_dispatch) {
+      owl_select_remove_dispatch_at(elt);
       return 0;
     }
@@ -125,4 +217,22 @@
 }
 
+void owl_select_gc()
+{
+  int i;
+  owl_list *dl;
+
+  dl = owl_global_get_dispatchlist(&g);
+  /*
+   * Count down so we aren't set off by removing items from the list
+   * during the iteration.
+   */
+  for(i = owl_list_get_size(dl) - 1; i >= 0; i--) {
+    owl_dispatch *d = owl_list_get_element(dl, i);
+    if(d->needs_gc) {
+      owl_select_remove_dispatch_at(i);
+    }
+  }
+}
+
 void owl_select_dispatch(fd_set *fds, int max_fd)
 {
@@ -133,17 +243,20 @@
   dl = owl_global_get_dispatchlist(&g);
   len = owl_select_dispatch_count();
+
+  dispatch_active = 1;
+
   for(i = 0; i < len; i++) {
     d = (owl_dispatch*)owl_list_get_element(dl, i);
     /* While d shouldn't normally be null, the list may be altered by
      * functions we dispatch to. */
-    if (d != NULL && FD_ISSET(d->fd, fds)) {
+    if (d != NULL && !d->needs_gc && FD_ISSET(d->fd, fds)) {
       if (d->cfunc != NULL) {
-        (d->cfunc)();
+        d->cfunc(d);
       }
-      else if (d->pfunc != NULL) {
-        owl_perlconfig_do_dispatch(d);
-      }
-    }
-  }
+    }
+  }
+
+  dispatch_active = 0;
+  owl_select_gc();
 }
 
@@ -182,6 +295,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: tester.c
===================================================================
--- tester.c	(revision 1cf3f8d3cf08ed3fb38d1c83459a1db140cb0d17)
+++ tester.c	(revision 33813991523c10b91982179dd48f55b4dc3ce7b8)
@@ -6,140 +6,4 @@
 
 owl_global g;
-
-void screeninit()
-{
-  char buff[1024];
-  
-  sprintf(buff, "TERMINFO=%s", TERMINFO);
-  putenv(buff);
-
-  initscr();
-  start_color();
-  /* cbreak(); */
-  raw();
-  noecho();
-  intrflush(stdscr,FALSE);
-  keypad(stdscr,TRUE);
-  nodelay(stdscr,1);
-  clear();
-  refresh();
-  meta(stdscr, TRUE);
-}
-
-void test1()
-{
-  int j;
-  owl_editwin e;
-
-  screeninit();
-
-  owl_editwin_init(&e, stdscr, LINES, COLS, OWL_EDITWIN_STYLE_MULTILINE, NULL);
-  /* owl_editwin_set_locktext(&e, "Here is some locktext:\n");*/
-  doupdate();
-  while (1) {
-    usleep(50);
-
-    j=getch();
-
-    if (j==ERR) continue;
-
-    if (j==3) break;
-
-    if (j==27) {
-      j=getch();
-      if (j==ERR) continue;
-      owl_editwin_process_char(&e, j);
-      doupdate();
-    } else {
-      owl_editwin_process_char(&e, j);
-      doupdate();
-    }
-  }
-  endwin();
-  printf("Had:\n%s", owl_editwin_get_text(&e));
-}
-
-void test2(char *in)
-{
-  owl_fmtext t;
-
-  screeninit();
-
-  owl_fmtext_init_null(&t);
-  owl_fmtext_append_ztext(&t, in);
-  owl_fmtext_curs_waddstr(&t, stdscr);
-  wrefresh(stdscr);
-  sleep(5000);
-  endwin();
-}
-
-void test3()
-{
-  ZNotice_t *n;
-
-  printf("%i\n", sizeof(n->z_uid.zuid_addr));
-  /* gethostbyaddr((char *) &(n->z_uid.zuid_addr), sizeof(n->z_uid.zuid_addr), AF_INET); */
-}
-
-void colorinfo()
-{
-  char buff[1024];
-  
-  screeninit();
-  sprintf(buff, "Have %i COLOR_PAIRS\n", COLOR_PAIRS);
-  addstr(buff);
-  refresh();
-  sleep(10);
-  endwin();  
-}
-
-void test4()
-{
-  int j;
-  char buff[1024];
-
-  screeninit();
-  
-  while (1) {
-    usleep(100);
-
-    j=getch();
-
-    if (j==ERR) continue;
-
-    if (j==3) break;
-    sprintf(buff, "%o\n", j);
-    addstr(buff);
-  }
-  endwin();
-}
-
-void test_keypress()
-{
-  int j, rev;
-  char buff[1024], buff2[64];
-
-  screeninit();
-  
-  while (1) {
-    usleep(100);
-
-    j=wgetch(stdscr);
-
-    if (j==ERR) continue;
-
-    if (j==3) break;
-    if (0 == owl_keypress_tostring(j, 0, buff2, 1000)) {
-      rev = owl_keypress_fromstring(buff2);
-      sprintf(buff, "%s : 0x%x 0%o %d %d %s\n", buff2, j, j, j, rev,
-	      (j==rev?"matches":"*** WARNING: Does Not Reverse"));
-    } else {
-      sprintf(buff, "UNKNOWN : 0x%x 0%o %d\n", j, j, j);
-    }
-      addstr(buff);
-  }
-  endwin();
-}
-
 
 #define OWL_DICT_NTESTS  20
@@ -155,27 +19,14 @@
 
   int numfailures=0;
-  if (argc==1 || (argc==2 && 0==strcmp(argv[1],"reg"))) {
-    printf("1..%d\n", OWL_UTIL_NTESTS+OWL_DICT_NTESTS+OWL_VARIABLE_NTESTS
-           +OWL_FILTER_NTESTS+OWL_OBARRAY_NTESTS);
-    numfailures += owl_util_regtest();
-    numfailures += owl_dict_regtest();
-    numfailures += owl_variable_regtest();
-    numfailures += owl_filter_regtest();
-    numfailures += owl_obarray_regtest();
-    if (numfailures) {
+  printf("1..%d\n", OWL_UTIL_NTESTS+OWL_DICT_NTESTS+OWL_VARIABLE_NTESTS
+         +OWL_FILTER_NTESTS+OWL_OBARRAY_NTESTS);
+  numfailures += owl_util_regtest();
+  numfailures += owl_dict_regtest();
+  numfailures += owl_variable_regtest();
+  numfailures += owl_filter_regtest();
+  numfailures += owl_obarray_regtest();
+  if (numfailures) {
       fprintf(stderr, "# *** WARNING: %d failures total\n", numfailures);
-    }
-    return(numfailures);
-  } else if (argc==2 && 0==strcmp(argv[1],"test1")) {
-    test1();
-  } else if (argc==2 && 0==strcmp(argv[1],"colorinfo")) {
-    colorinfo();
-  } else if (argc==2 && 0==strcmp(argv[1],"test4")) {
-    test4();
-  } else if (argc==2 && 0==strcmp(argv[1],"keypress")) {
-    test_keypress();
-  } else {
-    fprintf(stderr, "No test specified.  Current options are: reg test1\n");
   }
-  return(0);
+  return(numfailures);
 }
Index: text.c
===================================================================
--- text.c	(revision 3bcf12527e47f730a032a807fd38018ae8b13c7e)
+++ text.c	(revision f34dd65b3adbc2eedc045a674dd89b7e20257680)
@@ -6,115 +6,4 @@
 
 static const char fileIdent[] = "$Id$";
-
-/* start with line aline (where the first line is 1) and print 'lines'
- *  lines
- */
-int owl_text_truncate_lines(char *out, char *in, int aline, int lines)
-{
-  char *ptr1, *ptr2;
-  int i;
-
-  strcpy(out, "");
-  
-  if (aline==0) aline=1; /* really illegal use */
-
-  /* find the starting line */
-  ptr1=in;
-  if (aline!=1) {
-     for (i=0; i<aline-1; i++) {
-      ptr1=strchr(ptr1, '\n');
-      if (!ptr1) return(-1);
-      ptr1++;
-    }
-  }
-  /* ptr1 now holds the starting point */
-
-  /* copy in the next 'lines' lines */
-  if (lines<1) return(-1);
-  
-  for (i=0; i<lines; i++) {
-    ptr2=strchr(ptr1, '\n');
-    if (!ptr2) {
-      strcat(out, ptr1);
-      return(-1);
-    }
-    strncat(out, ptr1, ptr2-ptr1+1);
-    ptr1=ptr2+1;
-  }
-  return(0);
-}
-
-  
-/* the first column is column 0.  The message is expected to end in a
- * new line for now */
-void owl_text_truncate_cols(char *out, char *in, int acol, int bcol)
-{
-  char *ptr_s, *ptr_e, *ptr_c, *tmpbuff, *last;
-  int col, cnt, padding;
-  
-  tmpbuff=owl_malloc(strlen(in)+20);
-
-  strcpy(tmpbuff, "");
-  last=in+strlen(in)-1;
-  ptr_s=in;
-  while (ptr_s<last) {
-    ptr_e=strchr(ptr_s, '\n');
-    if (!ptr_e) {
-      /* but this shouldn't happen if we end in a \n */
-      break;
-    }
-    
-    if (ptr_e==ptr_s) {
-      strcat(tmpbuff, "\n");
-      ptr_s++;
-      continue;
-    }
-
-    col = 0;
-    cnt = 0;
-    padding = 0;
-    ptr_c = ptr_s;
-    while(col < bcol && ptr_c < ptr_e) {
-      gunichar c = g_utf8_get_char(ptr_c);
-      if (col + mk_wcwidth(c) > bcol) break;
-      col += mk_wcwidth(c);
-      ptr_c = g_utf8_next_char(ptr_c);
-      if (col >= acol) {
-	if (cnt == 0) {
-	  ptr_s = ptr_c;
-	  padding = col - acol;
-	}
-	++cnt;
-      }
-    }
-    if (cnt) {
-      while(padding-- > 0) {
-	strcat(tmpbuff, " ");
-      }
-      strncat(tmpbuff, ptr_s, ptr_c - ptr_s - 1);
-    }
-    strcat(tmpbuff, "\n");
-    ptr_s = ptr_e + 1;
-#if 0
-    /* we need to check that we won't run over here */
-    if ( (ptr_e-ptr_s) < (bcol-acol) ) {
-      len=ptr_e-(ptr_s+acol);
-    } else {
-      len=bcol-acol;
-    }
-    if ((ptr_s+len)>=last) {
-      len-=last-(ptr_s+len);
-    }
-
-    strncat(tmpbuff, ptr_s+acol, len);
-    strcat(tmpbuff, "\n");
-
-    ptr_s=ptr_e+1;
-#endif
-  }
-  strcpy(out, tmpbuff);
-  owl_free(tmpbuff);
-}
-
 
 void owl_text_indent(char *out, char *in, int n)
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);
-}
Index: util.c
===================================================================
--- util.c	(revision 601733df0126729fcd095240a5ef18b057830617)
+++ util.c	(revision f34dd65b3adbc2eedc045a674dd89b7e20257680)
@@ -125,12 +125,4 @@
   wattroff(sepwin, A_REVERSE);
   wnoutrefresh(sepwin);
-}
-
-
-void pophandler_quit(int ch)
-{
-  if (ch=='q') {
-    owl_popwin_close(owl_global_get_popwin(&g));
-  }
 }
 
@@ -373,62 +365,9 @@
 
   if (days>0) {
-    out=owl_sprintf("%i d %2.2i:%2.2i", days, hours, run);
+    out=owl_sprintf("%i d %2.2i:%2.2li", days, hours, run);
   } else {
-    out=owl_sprintf("    %2.2i:%2.2i", hours, run);
+    out=owl_sprintf("    %2.2i:%2.2li", hours, run);
   }
   return(out);
-}
-
-/* return the index of the last char before a change from the first one */
-int owl_util_find_trans(char *in, int len)
-{
-  int i;
-  for (i=1; i<len; i++) {
-    if (in[i] != in[0]) return(i-1);
-  }
-  return(i);
-}
-
-int owl_util_find_trans_short(short *in, int len)
-{
-  int i;
-  for (i=1; i<len; i++) {
-    if (in[i] != in[0]) return(i-1);
-  }
-  return(i);
-}
-
-/* Caller must free response. 
- * Takes in strings which are space-separated lists of tokens
- * and returns a single string containing no token more than once.
- * If prohibit is non-null, no token may start with a character
- * in prohibit.
- */
-char *owl_util_uniq(char *A, char *B, char *prohibit)
-{
-  
-  char *cat, **tok;
-  int toklen, i, j, first=1;
-  cat = owl_malloc(strlen(A)+strlen(B)+3);
-  strcpy(cat, A);
-  strcat(cat, " ");
-  strcat(cat, B);
-  tok = atokenize(cat, " ", &toklen);
-  strcpy(cat, "");
-  for (i=0; i<toklen; i++) {
-    int dup=0;
-    for (j=0; j<i; j++) {
-      if (!strcmp(tok[i], tok[j])) dup=1;
-    }
-    if (!dup && (!prohibit || !strchr(prohibit, tok[i][0]))) {
-      if (!first) {
-	strcat(cat, " ");
-      }
-      first=0;
-      strcat(cat, tok[i]);
-    }
-  }
-  atokenize_free(tok, toklen);
-  return(cat);
 }
 
@@ -641,7 +580,7 @@
       owl_function_error("Error opening file %s for writing", backupfilename);
       owl_free(backupfilename);
+      fclose(file);
       return;
     }
-    owl_free(backupfilename);
   }
 
@@ -682,38 +621,12 @@
     owl_function_error("WARNING: Error opening %s for writing.  Use %s to restore.", filename, backupfilename);
     owl_function_beep();
-    owl_free(line);
-    return;
-  }
-
-  fputs(text, file);
-  fclose(file);
-}
-
-/* add the string 'str' to the list 'list' of strings, only if it
- * is not already present
- */
-void owl_util_list_add_unique_string(owl_list *list, char *str)
-{
-  int i, j;
-
-  j=owl_list_get_size(list);
-  for (i=0; i<j; i++) {
-    if (!strcmp(str, owl_list_get_element(list, i))) return;
-  }
-  owl_list_append_element(list, owl_strdup(str));
-}
-
-int owl_util_common_strings_in_lists(owl_list *a, owl_list *b)
-{
-  int i, j, x, y;
-
-  j=owl_list_get_size(a);
-  for (i=0; i<j; i++) {
-    y=owl_list_get_size(b);
-    for (x=0; x<y; x++) {
-      if (!strcmp(owl_list_get_element(a, i), owl_list_get_element(b, x))) return(1);
-    }
-  }
-  return(0);
+  } else {
+    fputs(text, file);
+    fclose(file);
+  }
+
+  if (backup)
+    owl_free(backupfilename);
+  owl_free(text);
 }
 
@@ -881,11 +794,4 @@
 	      !strcmp("meep", skiptokens("foo 'bar quux' meep", 2)));
 
-  FAIL_UNLESS("owl_util_uniq 1", 
-	      !strcmp("foo bar x", owl_util_uniq("foo", "bar x", "-")));
-  FAIL_UNLESS("owl_util_uniq 2", 
-	      !strcmp("foo bar x", owl_util_uniq("foo", "bar -y x", "-")));
-  FAIL_UNLESS("owl_util_uniq 3", 
-	      !strcmp("meep foo bar", owl_util_uniq("meep foo", "bar foo meep", "-")));
-
   /* if (numfailed) printf("*** WARNING: failures encountered with owl_util\n"); */
   printf("# END testing owl_util (%d failures)\n", numfailed);
Index: variable.c
===================================================================
--- variable.c	(revision 451db9e0515b2671c88e0858f712b53a7fcc5b76)
+++ variable.c	(revision 4f15e8e9ceada0d4b2cc969ebf43b0a1fb3709ea)
@@ -351,10 +351,4 @@
 	       "                 the cursor will be near the center.\n",
 	       "normal,top,neartop,center,paged,pagedcenter" ),
-
-  OWLVAR_ENUM( "webbrowser" /* %OwlVarStub */, OWL_WEBBROWSER_NETSCAPE,
-	       "web browser to use to launch URLs",
-	       "When the 'w' key is pressed, this browser is used\n"
-	       "to display the requested URL.\n",
-	       "none,netscape,galeon,opera" ),
 
 
@@ -1056,21 +1050,4 @@
   FAIL_UNLESS("get int 7", 9==owl_variable_get_int(&vd,"typewinsize"));
 
-  FAIL_UNLESS("get enum", OWL_WEBBROWSER_NETSCAPE==owl_variable_get_int(&vd,"webbrowser"));
-  FAIL_UNLESS("get enum as string 1", 0==owl_variable_get_tostring(&vd,"webbrowser", buf, 1024));
-  FAIL_UNLESS("get enum as string 2", 0==strcmp(buf,"netscape"));
-  FAIL_UNLESS("set enum 1", 0==owl_variable_set_int(&vd,"webbrowser",OWL_WEBBROWSER_GALEON));
-  FAIL_UNLESS("get enum 2", OWL_WEBBROWSER_GALEON==owl_variable_get_int(&vd,"webbrowser"));
-  FAIL_UNLESS("set enum 1b", -1==owl_variable_set_int(&vd,"webbrowser",-3));
-  FAIL_UNLESS("set enum 1b", -1==owl_variable_set_int(&vd,"webbrowser",209));
-  FAIL_UNLESS("get enum 2b", OWL_WEBBROWSER_GALEON==owl_variable_get_int(&vd,"webbrowser"));
-  FAIL_UNLESS("set enum 3", 0==owl_variable_set_fromstring(&vd,"webbrowser","none",0,0));
-  FAIL_UNLESS("get enum 4", OWL_WEBBROWSER_NONE==owl_variable_get_int(&vd,"webbrowser"));
-  FAIL_UNLESS("set enum 5", 0==owl_variable_set_fromstring(&vd,"webbrowser","netscape",0,0));
-  FAIL_UNLESS("get enum 6", OWL_WEBBROWSER_NETSCAPE==owl_variable_get_int(&vd,"webbrowser"));
-  FAIL_UNLESS("set enum 7", -1==owl_variable_set_fromstring(&vd,"webbrowser","xxx",0,0));
-  FAIL_UNLESS("set enum 8", -1==owl_variable_set_fromstring(&vd,"webbrowser","",0,0));
-  FAIL_UNLESS("set enum 9", -1==owl_variable_set_fromstring(&vd,"webbrowser","netscapey",0,0));
-  FAIL_UNLESS("get enum 10", OWL_WEBBROWSER_NETSCAPE==owl_variable_get_int(&vd,"webbrowser"));
-
   owl_variable_dict_newvar_string(&vd, "stringvar", "", "", "testval");
   FAIL_UNLESS("get new string var", NULL != (v = owl_variable_get(&vd, "stringvar", OWL_VARIABLE_STRING)));
Index: wcwidth.c
===================================================================
--- wcwidth.c	(revision 47519e1bcab60a6026c4192bf5b20290f37f4737)
+++ wcwidth.c	(revision 49a8434e3707923940236017e5739cdc2c4d2b7a)
@@ -62,5 +62,5 @@
 #include <wchar.h>
 
-static struct interval {
+struct interval {               /* noproto */
   int first;
   int last;
Index: zcrypt.c
===================================================================
--- zcrypt.c	(revision 34509d514dfa9ee441febffc6d61e108962d1507)
+++ zcrypt.c	(revision f34dd65b3adbc2eedc045a674dd89b7e20257680)
@@ -66,204 +66,4 @@
 #define M_RANDOMIZE       4
 #define M_SETKEY          5
-
-int zcrypt(int argc, char *argv[]) {
-  char *fname = NULL;
-  int error = FALSE;
-  int zephyr = FALSE;
-  char *class = NULL, *instance = NULL;
-  int mode = M_NONE;
-
-  extern int optind, opterr;
-  extern char *optarg;
-  char c;
-
-  int messageflag = FALSE;
-  ZWRITEOPTIONS zoptions;
-  zoptions.flags = 0;
-
-  while ((c = getopt(argc, argv, "ZDERSF:c:i:advqtluons:f:m")) != (char)EOF) {
-    switch(c) {
-      case 'Z':
-        /* Zephyr encrypt */
-        mode = M_ZEPHYR_ENCRYPT;
-	break;
-      case 'D':
-        /* Decrypt */
-	mode = M_DECRYPT;
-	break;
-      case 'E':
-	/* Encrypt */
-	mode = M_ENCRYPT;
-	break;
-      case 'R':
-	/* Randomize the keyfile */
-	mode = M_RANDOMIZE;
-	break;
-      case 'S':
-	/* Set a new key value from stdin */
-	mode = M_SETKEY;
-	break;
-      case 'F':
-	/* Specify the keyfile explicitly */
-	if (fname != NULL) error = TRUE;
-	fname = optarg;
-	break;
-      case 'c':
-	/* Zwrite/zcrypt: class name */
-	if (class != NULL) error = TRUE;
-	class = optarg;
-	break;
-      case 'i':
-	/* Zwrite/zcrypt: instance name */
-	if (instance != NULL) error = TRUE;
-	instance = optarg;
-	break;
-      case 'a':
-	/* Zwrite: authenticate (default) */
-	zoptions.flags &= ~ZWRITE_OPT_NOAUTH;
-	break;
-      case 'd':
-	/* Zwrite: do not authenticate */
-	zoptions.flags |= ZWRITE_OPT_NOAUTH;
-	break;
-      case 'v':
-	/* Zwrite: verbose */
-	zoptions.flags |= ZWRITE_OPT_VERBOSE;
-	break;
-      case 'q':
-	/* Zwrite: quiet */
-	zoptions.flags |= ZWRITE_OPT_QUIET;
-	break;
-      case 't':
-	/* Zwrite: no expand tabs (ignored) */
-	break;
-      case 'l':
-	/* Zwrite: ignore '.' on a line by itself (ignored) */
-	zoptions.flags |= ZCRYPT_OPT_IGNOREDOT;
-	break;
-      case 'u':
-	/* Zwrite: urgent message */
-	instance = "URGENT";
-	break;
-      case 'o':
-	/* Zwrite: ignore zephyr variables zwrite-class, zwrite-inst, */
-	/*         zwrite-opcode */
-	zoptions.flags |= ZWRITE_OPT_IGNOREVARS;
-	break;
-      case 'n':
-	/* Zwrite: prevent PING message (always used) */
-	break;
-      case 's':
-	/* Zwrite: signature */
-	zoptions.flags |= ZWRITE_OPT_SIGNATURE;
-	zoptions.signature = optarg;
-	break;
-      case 'f':
-	/* Zwrite: file system specification (ignored) */
-	break;
-      case 'm':
-	/* Message on rest of line */
-	messageflag = TRUE;
-	break;
-      case '?':
-	error = TRUE;
-	break;
-    }
-    if (error || messageflag) break;
-  }
-
-  if (class != NULL || instance != NULL) {
-    zephyr = TRUE;
-  }
-
-  if (messageflag) {
-    zoptions.flags |= ZCRYPT_OPT_MESSAGE;
-    zoptions.message = BuildArgString(argv, optind, argc);
-    if (!zoptions.message)
-    {
-      printf("Memory allocation error.\n");
-      error = TRUE;
-    }
-  } else if (optind < argc) {
-    error = TRUE;
-  }
-
-  if (mode == M_NONE) mode = (zephyr?M_ZEPHYR_ENCRYPT:M_ENCRYPT);
-
-  if (mode == M_ZEPHYR_ENCRYPT && !zephyr) error = TRUE;
-
-  if (!error && fname == NULL && (class != NULL || instance != NULL)) {
-    fname = GetZephyrVarKeyFile(argv[0], class, instance);
-  }
-
-  
-  if (error || fname == NULL) {
-    printf("Usage: %s [-Z|-D|-E|-R|-S] [-F Keyfile] [-c class] [-i instance]\n", argv[0]);
-    printf("       [-advqtluon] [-s signature] [-f arg] [-m message]\n");
-    printf("  One or more of class, instance, and keyfile must be specified.\n");
-  } else {
-    if (mode == M_RANDOMIZE) {
-      /* Choose a new, random key */
-/*
-      FILE *fkey = fopen(fname, "w");
-      if (!fkey)
-	printf("Could not open key file for writing: %s\n", fname);
-      else
-      {
-	char string[100];
-	fputs(fkey, string);
-	fclose(fkey);
-	}
- */
-      printf("Feature not yet implemented.\n");
-    } else if (mode == M_SETKEY) {
-      /* Set a new, user-entered key */
-      char newkey[MAX_KEY];
-      FILE *fkey;
-      
-      if (isatty(0)) {
-	printf("Enter new key: ");
-	/* Really should read without echo!!! */
-	fgets(newkey, MAX_KEY - 1, stdin);
-      } else {
-	fgets(newkey, MAX_KEY - 1, stdin);
-      }
-
-      fkey = fopen(fname, "w");
-      if (!fkey) {
-	printf("Could not open key file for writing: %s\n", fname);
-      } else {
-	if (fputs(newkey, fkey) != strlen(newkey) || putc('\n', fkey) != '\n') {
-	  printf("Error writing to key file.\n");
-	  fclose(fkey);
-	} else {
-	  fclose(fkey);
-	  printf("Key update complete.\n");
-	}
-      }
-    } else {
-      /* Encrypt/decrypt */
-      FILE *fkey = fopen(fname, "r");
-      if (!fkey) {
-	printf("Could not open key file: %s\n", fname);
-      } else {
-	char keystring[MAX_KEY];
-	fgets(keystring, MAX_KEY-1, fkey);
-	if (mode == M_ZEPHYR_ENCRYPT || mode == M_ENCRYPT) {
-	  do_encrypt(keystring, (mode == M_ZEPHYR_ENCRYPT), class, instance,
-		     &zoptions, fname);
-	} else {
-	  do_decrypt(keystring);
-	}
-	fclose(fkey);
-      }
-    }
-  }
-
-  /* Always print the **END** message if -D is specified. */
-  if (mode == M_DECRYPT) printf("**END**\n");
-
-  exit(0);
-}
 
 /* The 'owl_zcrypt_decrypt' function was written by kretch for Owl.
@@ -375,6 +175,6 @@
 
     for (i = 0; i < 8; i++) {
-      sprintf(out, "%s%c", out, ((output[i] & 0xf0) >> 4) + BASE_CODE);
-      sprintf(out, "%s%c", out, (output[i] & 0x0f)        + BASE_CODE);
+      sprintf(out + strlen(out), "%c", ((output[i] & 0xf0) >> 4) + BASE_CODE);
+      sprintf(out + strlen(out), "%c", (output[i] & 0x0f)        + BASE_CODE);
     }
 
@@ -384,37 +184,4 @@
 }
 
-/* Build a space-separated string from argv from elements between start  *
- * and end - 1.  owl_malloc()'s the returned string. */
-char *BuildArgString(char **argv, int start, int end) {
-  int len = 1;
-  int i;
-  char *result;
-
-  /* Compute the length of the string.  (Plus 1 or 2) */
-  for (i = start; i < end; i++) {
-    len += strlen(argv[i]) + 1;
-  }
-
-  /* Allocate memory */
-  result = (char *)owl_malloc(len);
-  if (result) {
-    /* Build the string */
-    char *ptr = result;
-    /* Start with an empty string, in case nothing is copied. */
-    *ptr = '\0';
-    /* Copy the arguments */
-    for (i = start; i < end; i++) {
-      char *temp = argv[i];
-      /* Add a space, if not the first argument */
-      if (i != start) *ptr++ = ' ';
-      /* Copy argv[i], leaving ptr pointing to the '\0' copied from temp */
-      while ((*ptr = *temp++)!=0) {
-	ptr++;
-      }
-    }
-  }
-
-  return(result);
-}
 
 #define MAX_BUFF 258
@@ -423,20 +190,22 @@
 char *GetZephyrVarKeyFile(char *whoami, char *class, char *instance) {
   char *keyfile = NULL;
-  char varname[MAX_SEARCH][128];
+  char *varname[MAX_SEARCH];
   int length[MAX_SEARCH], i;
   char buffer[MAX_BUFF];
-  char filename[MAX_BUFF];
+  char *filename;
   char result[MAX_SEARCH][MAX_BUFF];
   int numsearch = 0;
   FILE *fsearch;
 
+  memset(varname, 0, sizeof(varname));
+
   /* Determine names to look for in .crypt-table */
   if (instance) {
-    sprintf(varname[numsearch++], "crypt-%s-%s:", (class?class:"message"), instance);
+    varname[numsearch++] = owl_sprintf("crypt-%s-%s:", (class?class:"message"), instance);
   }
   if (class) {
-    sprintf(varname[numsearch++], "crypt-%s:", class);
-  }
-  sprintf(varname[numsearch++], "crypt-default:");
+    varname[numsearch++] = owl_sprintf("crypt-%s:", class);
+  }
+  varname[numsearch++] = owl_strdup("crypt-default:");
 
   /* Setup the result array, and determine string lengths */
@@ -447,5 +216,5 @@
 
   /* Open~/.crypt-table */
-  sprintf(filename, "%s/.crypt-table", getenv("HOME"));
+  filename = owl_sprintf("%s/.crypt-table", getenv("HOME"));
   fsearch = fopen(filename, "r");
   if (fsearch) {
@@ -495,4 +264,10 @@
   }
 
+  for(i = 0; i < MAX_SEARCH; i++) {
+    owl_free(varname[i]);
+  }
+
+  owl_free(filename);
+
   return(keyfile);
 }
@@ -500,261 +275,3 @@
 static pid_t zephyrpipe_pid = 0;
 
-/* Open a pipe to zwrite */
-static FILE *GetZephyrPipe(char *class, char *instance, ZWRITEOPTIONS *zoptions) {
-  int fildes[2];
-  pid_t pid;
-  FILE *result;
-  char *argv[20];
-  int argc = 0;
-
-  if (pipe(fildes) < 0) return(NULL);
-  pid = fork();
-
-  if (pid < 0) {
-    /* Error: clean up */
-    close(fildes[0]);
-    close(fildes[1]);
-    result = NULL;
-  } else if (pid == 0) {
-    /* Setup child process */
-    argv[argc++] = "zwrite";
-    argv[argc++] = "-n";     /* Always send without ping */
-    if (class) {
-      argv[argc++] = "-c";
-      argv[argc++] = class;
-    }
-    if (instance) {
-      argv[argc++] = "-i";
-      argv[argc++] = instance;
-    }
-    if (zoptions->flags & ZWRITE_OPT_NOAUTH) argv[argc++] = "-d";
-    if (zoptions->flags & ZWRITE_OPT_QUIET) argv[argc++] = "-q";
-    if (zoptions->flags & ZWRITE_OPT_VERBOSE) argv[argc++] = "-v";
-    if (zoptions->flags & ZWRITE_OPT_SIGNATURE) {
-      argv[argc++] = "-s";
-      argv[argc++] = zoptions->signature;
-    }
-    argv[argc++] = "-O";
-    argv[argc++] = "crypt";
-    argv[argc] = NULL;
-    close(fildes[1]);
-    if (fildes[0] != STDIN_FILENO) {
-      if (dup2(fildes[0], STDIN_FILENO) != STDIN_FILENO) exit(0);
-      close(fildes[0]);
-    }
-    close(fildes[0]);
-    execvp(argv[0], argv);
-    printf("Exec error: could not run zwrite\n");
-    exit(0);
-  } else {
-    close(fildes[0]);
-    /* Create a FILE * for the zwrite pipe */
-    result = (FILE *)fdopen(fildes[1], "w");
-    zephyrpipe_pid = pid;
-  }
-
-  return(result);
-}
-
-/* Close the pipe to zwrite */
-void CloseZephyrPipe(FILE *pipe) {
-  fclose(pipe);
-  waitpid(zephyrpipe_pid, NULL, 0);
-  zephyrpipe_pid = 0;
-}
-
-#define MAX_RESULT 2048
-
-
-void block_to_ascii(char *output, FILE *outfile) {
-  int i;
-  for (i = 0; i < 8; i++) {
-    putc(((output[i] & 0xf0) >> 4) + BASE_CODE, outfile);
-    putc( (output[i] & 0x0f)       + BASE_CODE, outfile);
-  }
-}
-
-#define MAX_LINE 128
-
-/* Encrypt stdin, with prompt if isatty, and send to stdout, or to zwrite
-   if zephyr is set. */
-static int do_encrypt(char *keystring, int zephyr, char *class, char *instance, ZWRITEOPTIONS *zoptions, char* keyfile) {
-  des_cblock key;
-  des_key_schedule schedule;
-  char input[8], output[8];
-  int size;
-  FILE *outfile = stdout;
-  int error = FALSE;
-  char *inbuff = NULL, *inptr;
-  int freein = FALSE;
-  int use_buffer = FALSE;
-  int num_blocks=0, last_block_size=0;
-
-  des_string_to_key(keystring, key);
-  des_key_sched(key, schedule);
-
-  if (zephyr) {
-    if (zoptions->flags & ZCRYPT_OPT_MESSAGE) {
-      /* Use the -m message */
-      int length;
-      inbuff = zoptions->message;      
-      length = strlen(inbuff);
-      num_blocks = (length + 7) / 8;
-      last_block_size = ((length + 7) % 8) + 1;
-      use_buffer = TRUE;
-    } else if (isatty(0)) {
-      /* tty input, so show the "Type your message now..." message */
-      if (zoptions->flags & ZCRYPT_OPT_IGNOREDOT) {
-	printf("Type your message now.  End with the end-of-file character.\n");
-      } else {
-	printf("Type your message now.  End with control-D or a dot on a line by itself.\n");
-      }
-      use_buffer = TRUE;
-      if ((inptr = inbuff = (char *)owl_malloc(MAX_RESULT)) == NULL) {
-	printf("Memory allocation error\n");
-	return FALSE;
-      }
-      while (inptr - inbuff < MAX_RESULT - MAX_LINE - 20) {
-	fgets(inptr, MAX_LINE, stdin);
-	if (inptr[0]) {
-	  if (inptr[0] == '.' && inptr[1] == '\n' && 
-	      !(zoptions->flags & ZCRYPT_OPT_IGNOREDOT)) {
-	    inptr[0] = '\0';
-	    break;
-	  } else {
-	    inptr += strlen(inptr);
-	  }
-	} else {
-	  break;
-	}
-      }
-      num_blocks = (inptr - inbuff + 7) / 8;
-      last_block_size = ((inptr - inbuff + 7) % 8) + 1;
-      freein = TRUE;
-    }
-
-    /* if (zephyr) */
-    outfile = GetZephyrPipe(class, instance, zoptions);
-    if (!outfile) {
-      printf("Could not run zwrite\n");
-      if (freein && inbuff) {
-	owl_free(inbuff);
-      }
-      return(FALSE);
-    }
-  }
-
-  inptr = inbuff;
-
-  /* Encrypt the input (inbuff or stdin) and send it to outfile */
-  while (TRUE) {
-    if (use_buffer) {
-      /* Get 8 bytes from buffer */
-      if (num_blocks > 1) {
-	size = 8;
-	memcpy(input, inptr, size);
-	inptr += 8;
-	num_blocks--;
-      } else if (num_blocks == 1) {
-	size = last_block_size;
-	memcpy(input, inptr, size);
-	num_blocks--;
-      } else {
-	size = 0;
-      }
-    } else {
-      /* Get 8 bytes from stdin */
-      size = fread(input, 1, 8, stdin);
-    }
-
-    /* Check for EOF and pad the string to 8 chars, if needed */
-    if (size == 0) break;     /* END OF INPUT: BREAK FROM while LOOP! */
-      
-    if (size < 8) memset(input + size, 0, 8 - size);
-
-    /* Encrypt and output the block */
-    des_ecb_encrypt(input, output, schedule, TRUE);
-    block_to_ascii(output, outfile);
-
-    if (size < 8) break;
-  }
-
-  /* Close out the output */
-  if (!error) putc('\n', outfile);
-  if (zephyr) CloseZephyrPipe(outfile);
-
-  /* Free the input buffer, if necessary */
-  if (freein && inbuff) owl_free(inbuff);
-
-  return(!error);
-}
-
-/* Read a half-byte from stdin, skipping invalid characters.  Returns -1
-   if at EOF or file error */
-int read_ascii_nybble() {
-  char c;
-
-  while (TRUE) {
-    if (fread(&c, 1, 1, stdin) == 0) {
-      return(-1);
-    } else if (c >= BASE_CODE && c <= LAST_CODE) {
-      return(c - BASE_CODE);
-    }
-  }
-}
-
-/* Read both halves of the byte and return the single byte.  Returns -1
-   if at EOF or file error. */
-int read_ascii_byte() {
-  int c1, c2;
-  c1 = read_ascii_nybble();
-  if (c1 >= 0) {
-    c2 = read_ascii_nybble();
-    if (c2 >= 0) {
-      return c1 * 0x10 + c2;
-    }
-  }
-  return(-1);
-}
-
-/* Read an 8-byte DES block from stdin */
-int read_ascii_block(char *input) {
-  int c, i;
-
-  for (i = 0; i < 8; i++) {
-    c = read_ascii_byte();
-    if (c < 0) return(FALSE);
-    input[i] = c;
-  }
-
-  return(TRUE);
-}
-
-/* Decrypt stdin */
-int do_decrypt(char *keystring) {
-  des_cblock key;
-  des_key_schedule schedule;
-  char input[8], output[9];
-
-  output[0] = '\0';    /* In case no message at all                 */
-  output[8] = '\0';    /* NULL at end will limit string length to 8 */
-
-  des_string_to_key(keystring, key);
-  des_key_sched(key, schedule);
-
-  while (read_ascii_block(input)) {
-    des_ecb_encrypt(input, output, schedule, FALSE);
-    printf("%s", output);
-  }
-
-  if (output[0]) {
-    if (output[strlen(output)-1] != '\n') {
-      printf("\n");
-    }
-  } else {
-    printf("\n");
-  }
-  return(0);
-}
-
-#endif
+#endif
Index: zephyr.c
===================================================================
--- zephyr.c	(revision 451db9e0515b2671c88e0858f712b53a7fcc5b76)
+++ zephyr.c	(revision e2a620bfeaf812a985ea52e6f21f6893fcc7ee0b)
@@ -516,5 +516,6 @@
   }
   /* deal with MIT Discuss messages */
-  else if (!strcasecmp(n->z_default_format, "New transaction [$1] entered in $2\nFrom: $3 ($5)\nSubject: $4")) {
+  else if (!strcasecmp(n->z_default_format, "New transaction [$1] entered in $2\nFrom: $3 ($5)\nSubject: $4") ||
+           !strcasecmp(n->z_default_format, "New transaction [$1] entered in $2\nFrom: $3\nSubject: $4")) {
     char *msg, *field1, *field2, *field3, *field4, *field5;
     
@@ -814,5 +815,5 @@
     ZGetLocations(&locations,&one);
     myuser=short_zuser(user);
-    sprintf(out, "%s%s: %s\t%s\t%s\n", out, myuser,
+    sprintf(out + strlen(out), "%s: %s\t%s\t%s\n", myuser,
 	    locations.host ? locations.host : "?",
 	    locations.tty ? locations.tty : "?",
@@ -1203,5 +1204,5 @@
 
 #ifdef HAVE_LIBZEPHYR
-void owl_zephyr_process_events() {
+void owl_zephyr_process_events(owl_dispatch *d) {
   int zpendcount=0;
   ZNotice_t notice;
@@ -1235,6 +1236,6 @@
 
 #else
-void owl_zephyr_process_events() {
-  
-}
-#endif
+void owl_zephyr_process_events(owl_dispatch *d) {
+  
+}
+#endif
Index: zwrite.c
===================================================================
--- zwrite.c	(revision 3f3ee611e4b4ff9de1453aa609918c0099936019)
+++ zwrite.c	(revision 823671cd845781e426dcfdb50f582d386452c05e)
@@ -195,5 +195,5 @@
 {
   int i, j;
-  char to[LINE];
+  char *to;
 
   if (z->noping) return;
@@ -209,9 +209,10 @@
   for (i=0; i<j; i++) {
     if (strcmp(z->realm, "")) {
-      sprintf(to, "%s@%s", (char *) owl_list_get_element(&(z->recips), i), z->realm);
+      to = owl_sprintf("%s@%s", (char *) owl_list_get_element(&(z->recips), i), z->realm);
     } else {
-      strcpy(to, owl_list_get_element(&(z->recips), i));
+      to = owl_strdup(owl_list_get_element(&(z->recips), i));
     }
     send_ping(to);
+    owl_free(to);
   }
 
@@ -221,5 +222,5 @@
 {
   int i, j;
-  char toline[LINE];
+  char *toline = NULL;
   char *tmp = NULL;
 
@@ -228,14 +229,18 @@
   j=owl_list_get_size(&(z->recips));
   if (j>0 && z->cc) {
-    strcpy(toline, "CC: ");
+    toline = owl_strdup( "CC: ");
     for (i=0; i<j; i++) {
+      tmp = toline;
       if (strcmp(z->realm, "")) {
-	sprintf(toline, "%s%s@%s ", toline, (char *) owl_list_get_element(&(z->recips), i), z->realm);
+        toline = owl_sprintf( "%s%s@%s ", toline, (char *) owl_list_get_element(&(z->recips), i), z->realm);
       } else {
-	sprintf(toline, "%s%s ", toline, (char *) owl_list_get_element(&(z->recips), i));
-      }
+        toline = owl_sprintf( "%s%s ", toline, (char *) owl_list_get_element(&(z->recips), i));
+      }
+      owl_free(tmp);
+      tmp = NULL;
     }
     tmp = owl_get_iso_8859_1_if_possible(msg);
     z->message=owl_sprintf("%s\n%s", toline, tmp);
+    owl_free(toline);
   } else {
     z->message=owl_get_iso_8859_1_if_possible(msg);
@@ -259,5 +264,5 @@
 {
   int i, j;
-  char to[LINE];
+  char *to = NULL;
 
   if (z->message==NULL) return(-1);
@@ -267,14 +272,17 @@
     for (i=0; i<j; i++) {
       if (strcmp(z->realm, "")) {
-	sprintf(to, "%s@%s", (char *) owl_list_get_element(&(z->recips), i), z->realm);
+        to = owl_sprintf("%s@%s", (char *) owl_list_get_element(&(z->recips), i), z->realm);
       } else {
-	strcpy(to, owl_list_get_element(&(z->recips), i));
+        to = owl_strdup( owl_list_get_element(&(z->recips), i));
       }
       send_zephyr(z->opcode, z->zsig, z->class, z->inst, to, z->message);
+      owl_free(to);
+      to = NULL;
     }
   } else {
-    sprintf(to, "@%s", z->realm);
+    to = owl_sprintf( "@%s", z->realm);
     send_zephyr(z->opcode, z->zsig, z->class, z->inst, to, z->message);
   }
+  owl_free(to);
   return(0);
 }
