Index: ChangeLog
===================================================================
--- ChangeLog	(revision 43a306cdd965ba39eebeb9f3ccf426f700e34876)
+++ ChangeLog	(revision b940b91e7aa126759387aa2da6dd5b353accdd32)
@@ -1,2 +1,14 @@
+1.0.4
+ * Added a ':show quickstart' command. -geofft
+ * Allow filters that reference a sub filter more than once non-cyclically. -nelhage
+ * Make 'version' return 'BarnOwl' not 'Owl'
+ * Escape interpolated regexes in filters. -andersk
+ * Various code cleanups. -andersk
+ * Fix format string injection bugs. -andersk
+ * Clean up various code warnings. -nelhage
+ * Replace questionable sprintf(buf, "%s...", buf, ...) pattern. -andersk
+ * Show IRC /me messages with the conventional * instead of bold. -andersk
+ * Rip out the openurl function and webbrowser variable. -andersk
+
 1.0.3
  * Moved BarnOwl source control to git on github.
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 7e78e493b4fdb2a8be4960ed71a570ad9ce7645c)
+++ Makefile.in	(revision d4b6b23362b3a9b7e5b8ca836bfceba4383c11f7)
@@ -5,4 +5,5 @@
 prefix = @prefix@
 exec_prefix = @exec_prefix@
+datarootdir = @datarootdir@
 datadir = @datadir@/barnowl
 bindir = @bindir@
@@ -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 554a2b836ba40cb8a9fbbc1b1b8aeb195a334e78)
@@ -239,5 +239,5 @@
 {
   if (message) {
-    owl_function_error(message);
+    owl_function_error("%s", message);
   } else {
     owl_function_error("Authentication error on login");
@@ -252,5 +252,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 */
@@ -1698,5 +1698,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 +1715,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 +1736,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 +2309,18 @@
   aim_sendcookie(sess, tstconn, redir->cookielen, redir->cookie);
   return;	
+}
+
+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));
+      }
+    }
+  }
 }
 
Index: commands.c
===================================================================
--- commands.c	(revision 451db9e0515b2671c88e0858f712b53a7fcc5b76)
+++ commands.c	(revision 9b70dd4730dcdc958150fe126007d358cec3c713)
@@ -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);
 }
@@ -2207,4 +2198,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 +2244,4 @@
 {
   owl_function_curmsg_to_popwin();
-}
-
-void owl_command_openurl(void)
-{
-  owl_function_openurl();
 }
 
@@ -2580,5 +2568,5 @@
 {
     buff = skiptokens(buff, 1);
-    owl_function_error(buff);
+    owl_function_error("%s", buff);
     return NULL;
 }
@@ -2587,5 +2575,5 @@
 {
     buff = skiptokens(buff, 1);
-    owl_function_makemsg(buff);
+    owl_function_makemsg("%s", buff);
     return NULL;
 }
Index: examples/owlconf.erik
===================================================================
--- examples/owlconf.erik	(revision 5d9c664a3ac870215d4deea22ef3d0be2978f94a)
+++ examples/owlconf.erik	(revision 160d3f421ceb80ae77fe01b5158f58cba7f61960)
@@ -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 160d3f421ceb80ae77fe01b5158f58cba7f61960)
@@ -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 9711a6ed78d99195d08bc9f693d8d203fea0cc12)
@@ -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)
@@ -50,5 +48,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);
@@ -313,5 +311,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 +363,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 2aaca9484520a9cea0bdc795273de2fd34751c20)
@@ -763,8 +763,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 9b70dd4730dcdc958150fe126007d358cec3c713)
@@ -99,5 +99,5 @@
 }
 
-char *owl_function_style_describe(void *name) {
+char *owl_function_style_describe(char *name) {
   char *desc, *s;
   owl_style *style;
@@ -114,5 +114,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 +172,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 +632,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(); */
   }
@@ -1019,102 +1051,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); 
-  }
 }
 
@@ -1610,7 +1544,7 @@
 	/* 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);
+	sprintf(buff + strlen(buff), "  Multi notc: %s\n", n->z_multinotice);
+	sprintf(buff + strlen(buff), "  Num other : %i\n", n->z_num_other_fields);
+	sprintf(buff + strlen(buff), "  Msg Len   : %i\n", n->z_message_len);
 	owl_fmtext_append_normal(&fm, buff);
 	
@@ -1922,5 +1856,5 @@
 void owl_function_status()
 {
-  char buff[5000];
+  char buff[MAXPATHLEN+1];
   time_t start;
   int up, days, hours, minutes;
@@ -1942,6 +1876,9 @@
 
   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");
 
@@ -2052,4 +1989,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;
     }
 
@@ -2548,5 +2491,5 @@
   sprintf(argbuff, "class ^(un)*%s(\\.d)*$", tmpclass);
   if (tmpinstance) {
-    sprintf(argbuff, "%s and ( instance ^(un)*%s(\\.d)*$ )", argbuff, tmpinstance);
+    sprintf(argbuff + strlen(argbuff), " and ( instance ^(un)*%s(\\.d)*$ )", tmpinstance);
   }
   owl_free(tmpclass);
@@ -2577,5 +2520,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 +2527,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 +2537,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 +2552,5 @@
   owl_free(argbuff);
   owl_free(longuser);
+  owl_free(esclonguser);
   owl_free(shortuser);
 
@@ -2626,6 +2571,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 +2583,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 +2603,5 @@
 {
   owl_filter *f;
-  char *argbuff, *filtname;
+  char *argbuff, *filtname, *esctype;
 
   /* name for the filter */
@@ -2673,5 +2616,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 +2627,5 @@
   /* free stuff */
   owl_free(argbuff);
+  owl_free(esctype);
 
   return filtname;
@@ -2955,5 +2901,5 @@
     owl_text_tr(quoted, '\'', '.');
     owl_text_tr(quoted, '"', '.');
-    sprintf(buff, "%s ^(un)*%s(\\.d)*$", buff, quoted);
+    sprintf(buff + strlen(buff), " ^(un)*%s(\\.d)*$", quoted);
     owl_free(quoted);
   }
@@ -2965,5 +2911,5 @@
     owl_text_tr(quoted, '\'', '.');
     owl_text_tr(quoted, '"', '.');
-    sprintf(buff, "%s and instance ^(un)*%s(\\.d)*$", buff, quoted);
+    sprintf(buff + strlen(buff), " and instance ^(un)*%s(\\.d)*$", quoted);
     owl_free(quoted);
   }
@@ -2973,5 +2919,5 @@
     owl_text_tr(quoted, '\'', '.');
     owl_text_tr(quoted, '"', '.');
-    sprintf(buff, "%s and recipient ^%s$", buff, quoted);
+    sprintf(buff + strlen(buff), " and recipient ^%s$", quoted);
     owl_free(quoted);
   }
@@ -3065,5 +3011,5 @@
 }
 
-char *owl_function_keymap_summary(void *name)
+char *owl_function_keymap_summary(char *name)
 {
   owl_keymap *km 
Index: global.c
===================================================================
--- global.c	(revision da466e09b1d178435cf117a103dee8a511df94f2)
+++ global.c	(revision 5547211b2a49e2fe6b405d8b72af6474b2a7b1a6)
@@ -139,5 +139,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 +570,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';
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 9b70dd4730dcdc958150fe126007d358cec3c713)
@@ -282,6 +282,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: owl.c
===================================================================
--- owl.c	(revision 5b37c063d5a6a7a9fdfe3cde5a21e30d94beee7b)
+++ owl.c	(revision 5b37c063d5a6a7a9fdfe3cde5a21e30d94beee7b)
@@ -323,8 +323,8 @@
   sprintf(buff,      "Welcome to barnowl version %s.  Press 'h' for on-line help.            \n", OWL_VERSION_STRING);
   strcat(startupmsg, buff);
+  strcat(startupmsg, "To see a quick introduction, type ':show quickstart'.                  \n");
   strcat(startupmsg, "                                                                       \n");
   strcat(startupmsg, "BarnOwl is free software. Type ':show license' for more                \n");
-  strcat(startupmsg, "information.                                                           \n");
-  strcat(startupmsg, "                                                                 ^ ^   \n");
+  strcat(startupmsg, "information.                                                     ^ ^   \n");
   strcat(startupmsg, "                                                                 OvO   \n");
   strcat(startupmsg, "Please report any bugs or suggestions to bug-barnowl@mit.edu    (   )  \n");
@@ -511,5 +511,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);
@@ -612,18 +612,4 @@
 
   return 1;
-}
-
-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));
-      }
-    }
-  }
 }
 
Index: owl.h
===================================================================
--- owl.h	(revision 43a306cdd965ba39eebeb9f3ccf426f700e34876)
+++ owl.h	(revision b940b91e7aa126759387aa2da6dd5b353accdd32)
@@ -52,5 +52,5 @@
 
 #ifndef OWL_VERSION_STRING
-#define OWL_VERSION_STRING "1.0.3"
+#define OWL_VERSION_STRING "1.0.4.1"
 #endif
 
@@ -320,6 +320,6 @@
 
 typedef struct _owl_pair {
-  void *key;
-  void *value;
+  char *key;
+  char *value;
 } owl_pair;
 
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 1c014eece4610d0a5882362dc4eede679792364b)
@@ -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/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 799b60ea3145bfa2ad773b09544d31a3e30e77ff)
@@ -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
Index: perlconfig.c
===================================================================
--- perlconfig.c	(revision 5b37c063d5a6a7a9fdfe3cde5a21e30d94beee7b)
+++ perlconfig.c	(revision 5b37c063d5a6a7a9fdfe3cde5a21e30d94beee7b)
@@ -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;
@@ -304,6 +295,5 @@
   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 +302,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);
@@ -342,6 +331,5 @@
 
   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);
@@ -396,17 +384,13 @@
 
   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);
 
   return(out);
@@ -439,5 +423,4 @@
   char * ret = NULL;
   SV *rv;
-  STRLEN n_a;
   dSP;
 
@@ -458,5 +441,5 @@
 
   if(SvTRUE(ERRSV)) {
-    owl_function_error("%s", SvPV(ERRSV, n_a));
+    owl_function_error("%s", SvPV_nolen(ERRSV));
     (void)POPs;
   } else {
@@ -465,5 +448,5 @@
     rv = POPs;
     if(SvTRUE(rv)) {
-      ret = owl_strdup(SvPV(rv, n_a));
+      ret = owl_strdup(SvPV_nolen(rv));
     }
   }
@@ -489,5 +472,4 @@
   SV *cb = (SV*)(e->cbdata);
   SV *text;
-  unsigned int n_a;
   dSP;
 
@@ -508,5 +490,5 @@
 
   if(SvTRUE(ERRSV)) {
-    owl_function_error("%s", SvPV(ERRSV, n_a));
+    owl_function_error("%s", SvPV_nolen(ERRSV));
   }
 
@@ -526,6 +508,5 @@
   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;
@@ -535,5 +516,4 @@
 {
   SV *cb = d->pfunc;
-  unsigned int n_a;
   dSP;
   if(cb == NULL) {
@@ -550,5 +530,5 @@
 
   if(SvTRUE(ERRSV)) {
-    owl_function_error("%s", SvPV(ERRSV, n_a));
+    owl_function_error("%s", SvPV_nolen(ERRSV));
   }
 
Index: perlglue.xs
===================================================================
--- perlglue.xs	(revision 740d5f76770d93df8236a59996511e8ce2d1c0c5)
+++ perlglue.xs	(revision 5d2248c62dd7715238ac8948f05c0b8fd2963856)
@@ -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
@@ -380,16 +399,2 @@
 				      desc,
 				      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);
Index: perlwrap.pm
===================================================================
--- perlwrap.pm	(revision 740d5f76770d93df8236a59996511e8ce2d1c0c5)
+++ perlwrap.pm	(revision 5d2248c62dd7715238ac8948f05c0b8fd2963856)
@@ -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;
 }
@@ -810,4 +810,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 +826,6 @@
 our @EXPORT_OK = qw($startup $shutdown
                     $receiveMessage $newMessage
-                    $mainLoop $getBuddyList);
+                    $mainLoop $getBuddyList
+                    $getQuickstart);
 
 our %EXPORT_TAGS = (all => [@EXPORT_OK]);
@@ -828,4 +837,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 +931,8 @@
 }
 
+sub _get_quickstart {
+    return join("\n", $getQuickstart->run);
+}
+
 ################################################################################
 # Built-in perl styles
Index: popexec.c
===================================================================
--- popexec.c	(revision 1971b59613b1999b306139b8c2119beeb060b84c)
+++ popexec.c	(revision 44fc93be20484f09d5265df4bb55456979efd531)
@@ -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";
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: 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: util.c
===================================================================
--- util.c	(revision 601733df0126729fcd095240a5ef18b057830617)
+++ util.c	(revision 6eaf35b1b74b142244bdde7df41bb5891454bbb7)
@@ -373,7 +373,7 @@
 
   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);
Index: variable.c
===================================================================
--- variable.c	(revision 451db9e0515b2671c88e0858f712b53a7fcc5b76)
+++ variable.c	(revision 160d3f421ceb80ae77fe01b5158f58cba7f61960)
@@ -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 44fc93be20484f09d5265df4bb55456979efd531)
@@ -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 5547211b2a49e2fe6b405d8b72af6474b2a7b1a6)
@@ -375,6 +375,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);
     }
 
Index: zephyr.c
===================================================================
--- zephyr.c	(revision 451db9e0515b2671c88e0858f712b53a7fcc5b76)
+++ zephyr.c	(revision 5547211b2a49e2fe6b405d8b72af6474b2a7b1a6)
@@ -814,5 +814,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 : "?",
Index: zwrite.c
===================================================================
--- zwrite.c	(revision 3f3ee611e4b4ff9de1453aa609918c0099936019)
+++ zwrite.c	(revision 5547211b2a49e2fe6b405d8b72af6474b2a7b1a6)
@@ -231,7 +231,7 @@
     for (i=0; i<j; i++) {
       if (strcmp(z->realm, "")) {
-	sprintf(toline, "%s%s@%s ", toline, (char *) owl_list_get_element(&(z->recips), i), z->realm);
+	sprintf(toline + strlen(toline), "%s@%s ", (char *) owl_list_get_element(&(z->recips), i), z->realm);
       } else {
-	sprintf(toline, "%s%s ", toline, (char *) owl_list_get_element(&(z->recips), i));
+	sprintf(toline + strlen(toline), "%s ", (char *) owl_list_get_element(&(z->recips), i));
       }
     }
