Index: .gitignore
===================================================================
--- .gitignore	(revision 10e0ab8394c3e55f5629d8cfaf8557366f76eac0)
+++ .gitignore	(revision ee0574ce7974a45c8080d1215db912b8f3e1444c)
@@ -1,2 +1,25 @@
 *~
+*.a
+autom4te.cache
+barnowl
+blib
+config.cache
+config.h
+config.log
+config.status
+configure
+core
+jabber.log
 libfaim/rxhandlers.c.orig
+Makefile
+META.yml
+*.o
+owl_prototypes.h
+owl_prototypes.h.new
+*.par
+perlglue.c
+perlwrap.c
+pm_to_blib
+TAGS
+tester
+varstubs.c
Index: ChangeLog
===================================================================
--- ChangeLog	(revision d7a3188828e158c5556573d6f9230747505a1c8b)
+++ ChangeLog	(revision 43a306cdd965ba39eebeb9f3ccf426f700e34876)
@@ -1,3 +1,33 @@
-$Id$
+1.0.3
+ * Moved BarnOwl source control to git on github.
+ * Only call the zsig proc when we actually send a message. -asedeno
+ * Strip out BOMs from Jabber messages. -asedeno
+ * Fix logging of personal jabbers from JIDs containing / -nelhage
+ * Fix Jabber breakage under reload-modules. -asedeno
+ * Make reload-moduled correctly re-run startup hooks. -asedeno
+ * Squelch Jabbers with no bodies, such as typing notifications. -asedeno
+ * Various small spelling and grammar fixes. -geofft
+ * Fix a segfault when sending short zcrypted messages. -asedeno
+
+1.0.2.1
+ * Fix :reload-module's interactions with PAR modules
+
+1.0.2
+ * Fix a segfault on retrieving zephyr subs when the user doesn't
+   have any or has expired tickets. -asedeno
+ * Don't complain about non-existant ~/.owl/startup when starting. -asedeno
+ * Fix narrowing to personals in IRC. -alexmv
+ * Don't segfault retrieving subscriptions without valid tickets. -asedeno
+ * Load modules even if .owlconf doesn't run successfully. -nelhage
+ * Update the manpage for barnowl. -nelhage
+ * Better support for irc-names, irc-topic, and irc-whois. -geofft
+ * Display /quit messages in IRC -geofft.
+ * Add a new perl hook for all new messages. -geofft
+ * Fix a bug causing corrupted input in the editwin on end-of-line. -nelhage
+ * Add better support for adding hooks in perl that behave correctly
+       on module reload. -nelhage
+ * Added a :reload-module command to reload a single module. -nelhage
+ * Fixed quoting issues replying to jabber users or MUCs containing
+        whitespace or quites. -nelhage
 
 1.0.1
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 8363d50a74e2799d0b49cb9691754129c1d66a54)
+++ Makefile.in	(revision 7e78e493b4fdb2a8be4960ed71a570ad9ce7645c)
@@ -11,5 +11,5 @@
 CC=@CC@
 LIBS=@LIBS@ -L./libfaim -lfaim
-CFLAGS=@CFLAGS@ -I. -I./libfaim -DDATADIR=\"${datadir}\" -DOWL_SVN_REVNO=$(shell ./svkversion)
+CFLAGS=@CFLAGS@ -I./libfaim -DDATADIR=\"${datadir}\"
 LDFLAGS=@LDFLAGS@
 XSUBPPDIR=@XSUBPPDIR@
@@ -129,5 +129,5 @@
 install: all installdirs
 	${INSTALL_PROGRAM} $(EXE) ${DESTDIR}${bindir}/$(EXE)
-	${INSTALL_DATA} doc/owl.1 ${DESTDIR}${mandir}/man1/barnowl.1
+	${INSTALL_DATA} doc/barnowl.1 ${DESTDIR}${mandir}/man1/barnowl.1
 	${INSTALL} -d ${DESTDIR}${datadir}/lib
 	${INSTALL} -d ${DESTDIR}${datadir}/modules
Index: cmd.c
===================================================================
--- cmd.c	(revision 34509d514dfa9ee441febffc6d61e108962d1507)
+++ cmd.c	(revision c4ba74dbb881fe02a8e19d2936144c033c7bb68f)
@@ -67,4 +67,17 @@
 }
 
+char *_owl_cmddict_execute(owl_cmddict *cd, owl_context *ctx, char **argv, int argc, char *buff) {
+  char *retval = NULL;
+  owl_cmd *cmd;
+
+  if (!strcmp(argv[0], "")) {
+  } else if (NULL != (cmd = (owl_cmd*)owl_dict_find_element(cd, argv[0]))) {
+    retval = owl_cmd_execute(cmd, cd, ctx, argc, argv, buff);
+  } else {
+    owl_function_makemsg("Unknown command '%s'.", buff);
+  }
+  return retval;
+}
+
 char *owl_cmddict_execute(owl_cmddict *cd, owl_context *ctx, char *cmdbuff) {
   char **argv;
@@ -72,5 +85,4 @@
   char *tmpbuff;
   char *retval = NULL;
-  owl_cmd *cmd;
 
   tmpbuff=owl_strdup(cmdbuff);
@@ -85,13 +97,33 @@
   if (argc < 1) return(NULL);
 
-  if (!strcmp(argv[0], "")) {
-  } else if (NULL != (cmd = (owl_cmd*)owl_dict_find_element(cd, argv[0]))) {
-    retval = owl_cmd_execute(cmd, cd, ctx, argc, argv, cmdbuff);
-  } else {
-    owl_function_makemsg("Unknown command '%s'.", cmdbuff);
-  }
+  retval = _owl_cmddict_execute(cd, ctx, argv, argc, cmdbuff);
+
   owl_parsefree(argv, argc);
   owl_free(tmpbuff);
   sepbar(NULL);
+  return retval;
+}
+
+char *owl_cmddict_execute_argv(owl_cmddict *cd, owl_context *ctx, char **argv, int argc) {
+  char *buff, *ptr;
+  int len = 0, i;
+  char *retval = NULL;
+
+  for(i = 0; i < argc; i++) {
+    len += strlen(argv[i]) + 1;
+  }
+
+  ptr = buff = owl_malloc(len);
+
+  for(i = 0; i < argc; i++) {
+    strcpy(ptr, argv[i]);
+    ptr += strlen(argv[i]);
+    *(ptr++) = ' ';
+  }
+  *(ptr - 1) = 0;
+
+  retval = _owl_cmddict_execute(cd, ctx, argv, argc, buff);
+
+  owl_free(buff);
   return retval;
 }
Index: commands.c
===================================================================
--- commands.c	(revision 864ed359c1c6fbc341ca8d3a273cb7c2ae4e0875)
+++ commands.c	(revision 451db9e0515b2671c88e0858f712b53a7fcc5b76)
@@ -51,5 +51,5 @@
 	      "when owl is started and a logout notification is sent when owl\n"
 	      "is exited.  This behavior can be changed with the 'startuplogin'\n"
-	      "and 'shudownlogout' variables.  If a tty is specified for zlog in\n"
+	      "and 'shutdownlogout' variables.  If a tty is specified for zlog in\n"
 	      "then the owl variable 'tty' will be set to that string, causing\n"
 	      "it to be used as the zephyr location tty.\n"),
@@ -193,22 +193,24 @@
   OWLCMD_ARGS("subscribe", owl_command_subscribe, OWL_CTX_ANY,
 	      "subscribe to a zephyr class, instance, recipient",
-	      "subscribe [-t] <class> <instance> [recipient]",
-	      "Subscribe the specified class and instance.  If the recipient\n"
-	      "is not listed on the command line it defaults\n"
-	      "to * (the wildcard recipient).  If the -t option is present\n"
-	      "the subscription will only be temporary, i.e., it will not\n"
-	      "be written to the subscription file and will therefore not\n"
-	      "be present the next time owl is started.\n"),
+	      "subscribe [-t] <class> [instance [recipient]]",
+	      "Subscribe to the specified class and instance.  If the\n"
+	      "instance or recipient is not listed on the command\n"
+	      "line they default to * (the wildcard recipient).\n"
+	      "If the -t option is present the subscription will\n"
+	      "only be temporary, i.e., it will not be written to\n"
+	      "the subscription file and will therefore not be\n"
+	      "present the next time owl is started.\n"),
   OWLCMD_ALIAS("sub", "subscribe"),
 
   OWLCMD_ARGS("unsubscribe", owl_command_unsubscribe, OWL_CTX_ANY,
 	      "unsubscribe from a zephyr class, instance, recipient",
-	      "unsubscribe [-t] <class> <instance> [recipient]",
+	      "unsubscribe [-t] <class> [instance [recipient]]",
 	      "Unsubscribe from the specified class and instance.  If the\n"
-	      "recipient is not listed on the command line it defaults\n"
-	      "to * (the wildcard recipient).  If the -t option is present\n"
-	      "the unsubscription will only be temporary, i.e., it will not\n"
-	      "be updated in the subscription file and will therefore not\n"
-	      "be in effect the next time owl is started.\n"),
+	      "instance or recipient is not listed on the command\n"
+	      "line they default to * (the wildcard recipient).\n"
+	      "If the -t option is present the unsubscription will\n"
+	      "only be temporary, i.e., it will not be updated in\n"
+	      "the subscription file and will therefore not be\n"
+	      "in effect the next time owl is started.\n"),
   OWLCMD_ALIAS("unsub", "unsubscribe"),
 
@@ -245,5 +247,5 @@
 	      "delete a buddy from a buddylist",
 	      "delbuddy <protocol> <screenname>",
-	      "Delete the named buddy to your buddylist.  <protocol< can be aim or zephyr\n"),
+	      "Delete the named buddy from your buddylist.  <protocol> can be aim or zephyr\n"),
 
   OWLCMD_ARGS("join", owl_command_join, OWL_CTX_INTERACTIVE,
@@ -263,5 +265,5 @@
 	      "zpunt <instance>",
 	      "The zpunt command will supress message to the specified\n"
-	      "zephyr triplet.  In the second usage messages as supressed\n"
+	      "zephyr triplet.  In the second usage messages are suppressed\n"
 	      "for class MESSAGE and the named instance.\n\n"
 	      "SEE ALSO:  zunpunt, show zpunts\n"),
@@ -271,5 +273,5 @@
 	      "zunpunt <class> <instance> [recipient]\n"
 	      "zunpunt <instance>",
-	      "The zunpunt command will allow messages that were previosly\n"
+	      "The zunpunt command will allow messages that were previously\n"
 	      "suppressed to be received again.\n\n"
 	      "SEE ALSO:  zpunt, show zpunts\n"),
@@ -545,5 +547,5 @@
 	      "    true\n"
 	      "    false\n"
-	      "Spaces must be present before and after parenthesis.  If the\n"
+	      "Spaces must be present before and after parentheses.  If the\n"
 	      "optional color arguments are used they specifies the colors that\n"
 	      "messages matching this filter should be displayed in.\n\n"
@@ -592,10 +594,10 @@
 	      "If the curmsg is a personal message narrow\n"
 	      "   to the conversation with that user.\n"
-	      "If the curmsg is a class message, instance foo, recip *\n"
-	      "   message, narrow to the class, inst.\n"
-	      "If the curmsg is a class message then narrow\n"
+	      "If the curmsg is a <MESSAGE, foo, *>\n"
+	      "   message, narrow to the instance.\n"
+	      "If the curmsg is a class message, narrow\n"
 	      "    to the class.\n"
-	      "If the curmsg is a class message and '-i' is specied\n"
-	      "    then narrow to the class, instance\n"),
+	      "If the curmsg is a class message and '-i' is specified\n"
+	      "    then narrow to the class and instance.\n"),
 
   OWLCMD_ARGS("smartfilter", owl_command_smartfilter, OWL_CTX_INTERACTIVE,
@@ -604,9 +606,9 @@
 	      "If the curmsg is a personal message, the filter is\n"
 	      "   the conversation with that user.\n"
-	      "If the curmsg is a class message, instance foo, recip *\n"
-	      "   message, the filter is the class, inst.\n"
+	      "If the curmsg is a <MESSAGE, foo, *>\n"
+	      "   message, the filter is to that instance.\n"
 	      "If the curmsg is a class message, the filter is that class.\n"
 	      "If the curmsg is a class message and '-i' is specied\n"
-	      "    the filter is that <class,instance> pair\n"),
+	      "    the filter is to that class and instance.\n"),
 
   OWLCMD_ARGS("viewclass", owl_command_viewclass, OWL_CTX_INTERACTIVE,
@@ -674,5 +676,5 @@
 	      "If no message id is specified the current message is marked\n"
 	      "for deletion.  Otherwise the message with the given message\n"
-	      "id is marked for deltion.\n"
+	      "id is marked for deletion.\n"
 	      "If '--no-move' is specified, don't move after deletion.\n"
 	      "If 'trash' is specified, deletes all trash/auto messages\n"
@@ -688,5 +690,5 @@
 	      "If no message id is specified the current message is\n"
 	      "unmarked for deletion.  Otherwise the message with the\n"
-	      "given message id is marked for undeltion.\n"
+	      "given message id is unmarked for deletion.\n"
 	      "If '--no-move' is specified, don't move after deletion.\n"
 	      "If 'view' is specified, undeletes all messages\n"
@@ -713,4 +715,8 @@
 	      "getvar <varname>", ""),
 
+  OWLCMD_ARGS("getfilter", owl_command_getfilter, OWL_CTX_INTERACTIVE,
+	      "returns the definition of a filter",
+	      "getfilter <filtername>", ""),
+
   OWLCMD_ARGS("getstyle", owl_command_getstyle, OWL_CTX_INTERACTIVE,
 	      "returns the name of the style for the current view",
@@ -723,5 +729,5 @@
 	      "specified string and move the cursor there.  If no string\n"
 	      "argument is supplied then the previous one is used.  By\n"
-	      "default searches are done fowards, if -r is used the search\n"
+	      "default searches are done forwards; if -r is used the search\n"
 	      "is performed backwards"),
 
@@ -732,5 +738,5 @@
           "argument and makes it the default argument for future\n"
           "search commands, but does not move the cursor.  With\n"
-          "no argument, it makes search inactive."),
+          "no argument, it makes search highlighting inactive."),
 
   OWLCMD_ARGS("aimlogin", owl_command_aimlogin, OWL_CTX_ANY,
@@ -750,5 +756,5 @@
 
   OWLCMD_ARGS("message", owl_command_message, OWL_CTX_ANY,
-              "Display an informatative message",
+              "Display an informative message",
               "message <message>",
               ""),
@@ -1739,9 +1745,9 @@
 char *owl_command_subscribe(int argc, char **argv, char *buff)
 {
-  char *recip="";
+  char *class, *instance, *recip="";
   int temp=0;
   int ret=0;
-  
-  if (argc<3) {
+
+  if (argc < 2) {
     owl_function_makemsg("Not enough arguments to the subscribe command");
     return(NULL);
@@ -1755,15 +1761,23 @@
     argv++;
   }
-  if (argc<2) {
+  if (argc < 1) {
     owl_function_makemsg("Not enough arguments to the subscribe command");
     return(NULL);
   }
 
-  if (argc>3) {
+  if (argc > 3) {
     owl_function_makemsg("Too many arguments to the subscribe command");
     return(NULL);
   }
 
-  if (argc==2) {
+  class = argv[0];
+
+  if (argc == 1) {
+    instance = "*";
+  } else {
+    instance = argv[1];
+  }
+
+  if (argc <= 2) {
     recip="";
   } else if (argc==3) {
@@ -1771,7 +1785,7 @@
   }
 
-  ret = owl_function_subscribe(argv[0], argv[1], recip);
+  ret = owl_function_subscribe(class, instance, recip);
   if (!temp && !ret) {
-    owl_zephyr_addsub(NULL, argv[0], argv[1], recip);
+    owl_zephyr_addsub(NULL, class, instance, recip);
   }
   return(NULL);
@@ -1781,8 +1795,8 @@
 char *owl_command_unsubscribe(int argc, char **argv, char *buff)
 {
-  char *recip="";
+  char *class, *instance, *recip="";
   int temp=0;
 
-  if (argc<3) {
+  if (argc < 2) {
     owl_function_makemsg("Not enough arguments to the unsubscribe command");
     return(NULL);
@@ -1796,15 +1810,23 @@
     argv++;
   }
-  if (argc<2) {
-    owl_function_makemsg("Not enough arguments to the subscribe command");
-    return(NULL);
-  }
-
-  if (argc>3) {
+  if (argc < 1) {
+    owl_function_makemsg("Not enough arguments to the unsubscribe command");
+    return(NULL);
+  }
+
+  if (argc > 3) {
     owl_function_makemsg("Too many arguments to the unsubscribe command");
     return(NULL);
   }
 
-  if (argc==2) {
+  class = argv[0];
+
+  if (argc == 1) {
+    instance = "*";
+  } else {
+    instance = argv[1];
+  }
+
+  if (argc <= 2) {
     recip="";
   } else if (argc==3) {
@@ -1812,7 +1834,7 @@
   }
 
-  owl_function_unsubscribe(argv[0], argv[1], recip);
+  owl_function_unsubscribe(class, instance, recip);
   if (!temp) {
-    owl_zephyr_delsub(NULL, argv[0], argv[1], recip);
+    owl_zephyr_delsub(NULL, class, instance, recip);
   }
   return(NULL);
@@ -2461,4 +2483,18 @@
 }
 
+char *owl_command_getfilter(int argc, char **argv, char *buf)
+{
+  owl_filter *f;
+  if (argc != 2) {
+    owl_function_makemsg("Wrong number of arguments for %s", argv[0]);
+    return NULL;
+  }
+  f = owl_global_get_filter(&g, argv[1]);
+  if (!f) {
+    return NULL;
+  }
+  return owl_filter_print(f);
+}
+
 char *owl_command_search(int argc, char **argv, char *buff)
 {
@@ -2580,5 +2616,5 @@
   cmd = owl_message_get_attribute_value(m, "yescommand");
   if(!cmd) {
-    owl_function_error("No yes command!");
+    owl_function_error("No 'yes' command!");
     return;
   }
@@ -2614,5 +2650,5 @@
   cmd = owl_message_get_attribute_value(m, "nocommand");
   if(!cmd) {
-    owl_function_error("No no command!");
+    owl_function_error("No 'no' command!");
     return;
   }
Index: doc/barnowl.1
===================================================================
--- doc/barnowl.1	(revision fa1b15b6aa7075915078e2657f066dd24929b772)
+++ doc/barnowl.1	(revision fa1b15b6aa7075915078e2657f066dd24929b772)
@@ -0,0 +1,92 @@
+.TH barnowl 1 "23 Jun 2008"
+.SH NAME
+barnowl \- tty based zephyr client
+.SH SYNOPSIS
+.B barnowl
+[ \-n
+]
+[ \-d
+]
+[ \-D
+]
+[ \-v
+]
+[ \-h
+]
+[ \-c
+.I configfile
+]
+[ \-t
+.I tty
+]
+[ \-s
+.I configdir
+]
+.br
+.SH DESCRIPTION
+.B BarnOwl
+is a fully integrated tty based instant messaging client.  Currently
+it supports AOL Instant Messenger, MIT Zephyr, and Jabber.  It is
+curses-based, allows for emacs-style editing of outgoing messages and
+uses perl as an extension and configuration language.  BarnOwl will
+also run happily without a configuration file.
+
+Once BarnOwl is started, typing 'h' will display a help screen.
+Typing \':\' enters command mode, allowing the user to type a barnowl
+command line.
+
+.PP
+.SH USE
+The following command line options are avilable when running barnowl:
+
+.B \-n
+.IP
+Do not subscribe to zephyr messages on startup.  By default BarnOwl
+subscribes to the default subscriptions and to anything found in
+~/.zephyr.subs.  When this option is used no subscriptions are loaded.
+.LP
+
+.B \-c \fIconfigfile\fP
+.IP
+Specifiy an alternate config file for BarnOwl to use.  By default,
+barnowl uses ~/.barnowlconf if it exists, and ~/.owlconf otherwise.
+.LP
+
+.B \-s \fIconfigdir\fP
+.IP
+Specify an alternate configuration directory. By default, BarnOwl uses
+~/.owl/.
+.LP
+
+.B \-t \fItty\fP
+.IP
+Specifiy the tty name to use for the zephyr location.
+.LP
+
+.B \-v
+.IP
+Print the version number of barnowl and exit.
+.LP
+
+.B \-d
+.IP
+Enable debugging.  By default debugging information is placed in
+/var/tmp/owldebug.
+.LP
+
+.B \-D
+.IP
+Enable debugging, but first delete any existing debugging file.
+.LP
+
+.B \-h
+.IP
+Print command line option help.
+.LP
+
+.SH AUTHOR
+Written by Nelson Elhage and Alejandro Sedeno at the Massachusetts
+Institute of Technology. Based on Owl by James Kretchmar.
+
+Comments, questions, and bug reports may be mailed to
+\fBbug-barnowl@mit.edu\fP.
Index: c/owl.1
===================================================================
--- doc/owl.1	(revision 1d1244a2005ee75a7bcfda43e2df9bdf38552b40)
+++ 	(revision )
@@ -1,83 +1,0 @@
-.TH owl 1 "10 Apr 2004"
-.SH NAME
-owl \- tty based zephyr client
-.SH SYNOPSIS
-.B owl
-[ \-n
-]
-[ \-d
-]
-[ \-D
-]
-[ \-v
-]
-[ \-h
-]
-[ \-c
-.I configfile
-]
-[ \-t
-.I tty
-]
-
-.br
-.SH DESCRIPTION
-.B Owl
-is a fully integrated tty based instant messaging client.  Currently
-it supports AOL Instant Messenger and MIT Zephyr.  It is curses-based,
-allows for emacs style editing of outgoing messages and uses a perl
-configuration language for setting options and customizing message
-formatting.  Owl will also run happily without a configuration file.
-
-Once Owl is started, typing 'h' will display a help screen.  Typing
-\':\' enters command mode, allowing the user to type an owl command
-line.
-
-.PP
-.SH USE
-The following command line options are avilable when running owl:
-
-.B \-n
-.IP
-Do not subscribe to zephyr messages on startup.  By default Owl
-subscribes to the default subscriptions and to anything found in
-~/.zephyr.subs.  When this option is used no subscriptions are loaded.
-.LP
-
-.B \-c \fIconfigfile\fP
-.IP
-Specifiy an alternate config file for Owl to use.  The default
-configuration file is ~/.owlconf
-.LP
-
-.B \-t \fItty\fP
-.IP
-Specifiy the tty name to use for the zephyr location.
-.LP
-
-.B \-v
-.IP
-Print the version number of owl and exit.
-.LP
-
-.B \-d
-.IP
-Enable debugging.  By default debugging information is placed in
-/var/tmp/owldebug.
-.LP
-
-.B \-D
-.IP
-Enable debugging, but first delete any existing debugging file.
-.LP
-
-.B \-h
-.IP
-Print command line option help.
-.LP
-
-.SH AUTHOR
-Written by James Kretchmar at the Massachusetts Institute of
-Technology.
-Comments, questions, and bug reports may be mailed to
-\fBbug-owl@ktools.org\fP.
Index: editwin.c
===================================================================
--- editwin.c	(revision 2d4ff1445f467cca0bcef79cbbe5e6332e4b1cf6)
+++ editwin.c	(revision e9bb404064914673e4c9588dccf789ce2c5d2fbc)
@@ -330,16 +330,20 @@
 {
   int i, z;
-  
+
   if ((e->bufflen + n) > (e->allocated - 5)) {
     _owl_editwin_addspace(e);
   }
 
+  z = _owl_editwin_get_index_from_xy(e);
+
+  if(z != e->bufflen) {
+    for (i = e->bufflen + n - 1; i > z; i--) {
+      e->buff[i] = e->buff[i - n];
+    }
+  }
+
   e->bufflen += n;
   e->buff[e->bufflen] = '\0';
-  
-  z = _owl_editwin_get_index_from_xy(e);
-  for (i = e->bufflen - 1; i > z; i--) {
-    e->buff[i] = e->buff[i - n];
-  }
+
 }
 
@@ -426,7 +430,5 @@
 
   /* shift all the other characters right */
-  if (z != e->bufflen) {
-    _owl_editwin_insert_bytes(e, len);
-  }
+  _owl_editwin_insert_bytes(e, len);
 
   /* insert the new character */
@@ -435,8 +437,4 @@
   }
 
-  /* housekeeping */
-  e->bufflen += len;
-  e->buff[e->bufflen] = '\0';
-  
   /* advance the cursor */
   z += len;
Index: filter.c
===================================================================
--- filter.c	(revision af1920fd98d8d860245a197dee998e0e5c337285)
+++ filter.c	(revision cdc6ff1af792c6ba025214d1b7f310e652c420d7)
@@ -29,5 +29,5 @@
   while ( argc>=2 && ( !strcmp(argv[0], "-c") ||
 		       !strcmp(argv[0], "-b") ) ) {
-    if (owl_util_string_to_color(argv[1])==-1) {
+    if (owl_util_string_to_color(argv[1])==OWL_COLOR_INVALID) {
       owl_function_error("The color '%s' is not available, using default.", argv[1]);
     } else {
@@ -212,36 +212,34 @@
 
 
-void owl_filter_print(owl_filter *f, char *out)
-{
-  strcpy(out, owl_filter_get_name(f));
-  strcat(out, ": ");
+char* owl_filter_print(owl_filter *f)
+{
+  GString *out = g_string_new("");
 
   if (f->fgcolor!=OWL_COLOR_DEFAULT) {
-    strcat(out, "-c ");
+    g_string_append(out, "-c ");
     if (f->fgcolor < 8) {
-      strcat(out, owl_util_color_to_string(f->fgcolor));
+      g_string_append(out, owl_util_color_to_string(f->fgcolor));
     }
     else {
-      char* c = owl_sprintf("%i",f->fgcolor);
-      strcat(out, c);
-      owl_free(c);
-    }
-    strcat(out, " ");
+      g_string_append_printf(out, "%i",f->fgcolor);
+    }
+    g_string_append(out, " ");
   }
   if (f->bgcolor!=OWL_COLOR_DEFAULT) {
-    strcat(out, "-b ");
+    g_string_append(out, "-b ");
     if (f->bgcolor < 8) {
-      strcat(out, owl_util_color_to_string(f->bgcolor));
+      g_string_append(out, owl_util_color_to_string(f->bgcolor));
     }
     else {
-      char* c = owl_sprintf("%i",f->bgcolor);
-      strcat(out, c);
-      owl_free(c);
-    }
-    strcat(out, " ");
-  }
-  if(!f->root) return;
-  owl_filterelement_print(f->root, out);
-  strcat(out, "\n");
+      g_string_append_printf(out, "%i",f->fgcolor);
+    }
+    g_string_append(out, " ");
+  }
+  if(f->root) {
+    owl_filterelement_print(f->root, out);
+    g_string_append(out, "\n");
+  }
+
+  return g_string_free(out, 0);
 }
 
@@ -249,11 +247,18 @@
 int owl_filter_equiv(owl_filter *a, owl_filter *b)
 {
-  char buff[LINE], buff2[LINE];
-
-  owl_filter_print(a, buff);
-  owl_filter_print(b, buff2);
-
-  if (!strcmp(buff, buff2)) return(1);
-  return(0);
+  char *buffa, *buffb;
+  int ret;
+
+  buffa = owl_filter_print(a);
+  buffb = owl_filter_print(b);
+
+  ret = !strcmp(buffa, buffb);
+  ret = ret && !strcmp(owl_filter_get_name(a),
+                       owl_filter_get_name(b));
+
+  owl_free(buffa);
+  owl_free(buffb);
+
+  return ret;
 }
 
Index: filterelement.c
===================================================================
--- filterelement.c	(revision 81655f8c44b634198f4f03d1fd96fbbd6f8a6717)
+++ filterelement.c	(revision 0504f6318cdf8fe825d6783bd0909a68afded8bb)
@@ -126,63 +126,63 @@
 /* Print methods */
 
-static void owl_filterelement_print_true(owl_filterelement *fe, char *buf)
-{
-  strcat(buf, "true");
-}
-
-static void owl_filterelement_print_false(owl_filterelement *fe, char *buf)
-{
-  strcat(buf, "false");
-}
-
-static void owl_filterelement_print_re(owl_filterelement *fe, char *buf)
+static void owl_filterelement_print_true(owl_filterelement *fe, GString *buf)
+{
+  g_string_append(buf, "true");
+}
+
+static void owl_filterelement_print_false(owl_filterelement *fe, GString *buf)
+{
+  g_string_append(buf, "false");
+}
+
+static void owl_filterelement_print_re(owl_filterelement *fe, GString *buf)
 {
   char *re, *q;
-  strcat(buf, fe->field);
-  strcat(buf, " ");
+  g_string_append(buf, fe->field);
+  g_string_append(buf, " ");
 
   re = owl_regex_get_string(&(fe->re));
   q = owl_getquoting(re);
-  strcat(buf, q);
-  strcat(buf, re); 
-  strcat(buf, q);
-}
-
-static void owl_filterelement_print_filter(owl_filterelement *fe, char *buf)
-{
-  strcat(buf, "filter ");
-  strcat(buf, fe->field);
-}
-
-static void owl_filterelement_print_perl(owl_filterelement *fe, char *buf)
-{
-  strcat(buf, "perl ");
-  strcat(buf, fe->field);
-}
-
-static void owl_filterelement_print_group(owl_filterelement *fe, char *buf)
-{
-  strcat(buf, "( ");
+  g_string_append(buf, q);
+  g_string_append(buf, re);
+  g_string_append(buf, q);
+}
+
+static void owl_filterelement_print_filter(owl_filterelement *fe, GString *buf)
+{
+  g_string_append(buf, "filter ");
+  g_string_append(buf, fe->field);
+}
+
+static void owl_filterelement_print_perl(owl_filterelement *fe, GString *buf)
+{
+  g_string_append(buf, "perl ");
+  g_string_append(buf, fe->field);
+}
+
+static void owl_filterelement_print_group(owl_filterelement *fe, GString *buf)
+{
+  g_string_append(buf, "( ");
   owl_filterelement_print(fe->left, buf) ;
-  strcat(buf, " )");
-}
-
-static void owl_filterelement_print_or(owl_filterelement *fe, char *buf)
+  g_string_append(buf, " )");
+}
+
+static void owl_filterelement_print_or(owl_filterelement *fe, GString *buf)
 {
   owl_filterelement_print(fe->left, buf);
-  strcat(buf, " or ");
+  g_string_append(buf, " or ");
   owl_filterelement_print(fe->right, buf);
 }
 
-static void owl_filterelement_print_and(owl_filterelement *fe, char *buf)
+static void owl_filterelement_print_and(owl_filterelement *fe, GString *buf)
 {
   owl_filterelement_print(fe->left, buf);
-  strcat(buf, " and ");
+  g_string_append(buf, " and ");
   owl_filterelement_print(fe->right, buf);
 }
 
-static void owl_filterelement_print_not(owl_filterelement *fe, char *buf)
-{
-  strcat(buf, " not ");
+static void owl_filterelement_print_not(owl_filterelement *fe, GString *buf)
+{
+  g_string_append(buf, " not ");
   owl_filterelement_print(fe->left, buf);
 }
@@ -321,5 +321,5 @@
 }
 
-void owl_filterelement_print(owl_filterelement *fe, char *buf)
+void owl_filterelement_print(owl_filterelement *fe, GString *buf)
 {
   if(!fe || !fe->print_elt) return;
Index: functions.c
===================================================================
--- functions.c	(revision 4367915fa4d8affc71c32cafad2d3bac876a22bd)
+++ functions.c	(revision 3f3ee611e4b4ff9de1453aa609918c0099936019)
@@ -25,4 +25,11 @@
   return owl_cmddict_execute(owl_global_get_cmddict(&g), 
 			     owl_global_get_context(&g), cmdbuff);
+}
+
+char *owl_function_command_argv(char **argv, int argc)
+{
+  return owl_cmddict_execute_argv(owl_global_get_cmddict(&g),
+                                  owl_global_get_context(&g),
+                                  argv, argc);
 }
 
@@ -283,5 +290,5 @@
   owl_editwin_set_dotsend(e);
   strcpy(buff, "----> ");
-  strcat(buff, line);
+  strncat(buff, line, 1016);
   strcat(buff, "\n");
   owl_editwin_set_locktext(e, buff);
@@ -371,4 +378,5 @@
   /* create the zwrite and send the message */
   owl_zwrite_create_from_line(&z, line);
+  owl_zwrite_populate_zsig(&z);
   if (msg) {
     owl_zwrite_set_message(&z, msg);
@@ -409,4 +417,5 @@
   /* create the zwrite and send the message */
   owl_zwrite_create_from_line(&z, line);
+  owl_zwrite_populate_zsig(&z);
   if (msg) {
     owl_zwrite_set_message(&z, msg);
@@ -415,5 +424,13 @@
   mymsg=owl_zwrite_get_message(&z);
 #ifdef OWL_ENABLE_ZCRYPT
-  cryptmsg=owl_malloc(strlen(mymsg)*4);
+  /* Allocate enough space for the crypted message. For each byte of
+   * the message, the encoded cyphertext will have two bytes. Block
+   * size is 8 bytes of input, or 16 bytes of output, so make sure we
+   * have at least one block worth of space allocated. If the message
+   * is empty, no blocks are sent, but we still allocate one
+   * block. The additional 16 bytes also provide space for the null
+   * terminator, as we will never use all of it for cyphertext.
+   */
+  cryptmsg=owl_malloc((strlen(mymsg)*2)+16);
   ret=owl_zcrypt_encrypt(cryptmsg, mymsg, owl_zwrite_get_class(&z), owl_zwrite_get_instance(&z));
   if (ret) {
@@ -421,4 +438,5 @@
     owl_function_beep();
     owl_free(cryptmsg);
+    owl_zwrite_free(&z);
     return;
   }
@@ -1633,8 +1651,4 @@
   }
 
-  if (owl_message_is_type_aim(m)) {
-    owl_fmtext_append_bold(&fm, "\nAIM Specific Information:\n");
-  }
-
   owl_fmtext_append_bold(&fm, "\nOwl Message Attributes:\n");
   owl_message_attributes_tofmtext(m, &attrfm);
@@ -1965,12 +1979,4 @@
   
 
-  owl_fmtext_append_normal(&fm, "\nMemory Usage:\n");
-  owl_fmtext_append_normal(&fm, "  Not currently available.\n");
-  /*
-  sprintf(buff, "%sMemory Malloced: %i\n", buff, owl_global_get_malloced(&g));
-  sprintf(buff, "%sMemory Freed: %i\n", buff, owl_global_get_freed(&g));
-  sprintf(buff, "%sMemory In Use: %i\n", buff, owl_global_get_meminuse(&g));
-  */
-
   owl_fmtext_append_normal(&fm, "\nAIM Status:\n");
   owl_fmtext_append_normal(&fm, "  Logged in: ");
@@ -2025,5 +2031,5 @@
 void owl_function_reply(int type, int enter)
 {
-  char *buff=NULL, *oldbuff;
+  char *buff=NULL;
   owl_message *m;
   owl_filter *f;
@@ -2032,5 +2038,4 @@
     owl_function_error("No message selected");
   } else {
-    char *class, *inst, *to, *cc=NULL;
     
     m=owl_view_get_element(owl_global_get_current_view(&g), owl_global_get_curmsg(&g));
@@ -2049,100 +2054,10 @@
     }
 
-    /* loopback */
-    if (owl_message_is_type_loopback(m)) {
-      owl_function_loopwrite_setup();
-      return;
-    }
-
-    /* zephyr */
-    if (owl_message_is_type_zephyr(m)) {
-      /* if it's a zephyr we sent, send it out the same way again */
-      if (owl_message_is_direction_out(m)) {
-          buff = owl_strdup(owl_message_get_zwriteline(m));
-      } else {
-
-        /* Special case a personal reply to a webzephyr user on a class */
-        if ((type==1) && !strcasecmp(owl_message_get_opcode(m), OWL_WEBZEPHYR_OPCODE)) {
-          class=OWL_WEBZEPHYR_CLASS;
-          inst=owl_message_get_sender(m);
-          to=OWL_WEBZEPHYR_PRINCIPAL;
-        } else if (!strcasecmp(owl_message_get_class(m), OWL_WEBZEPHYR_CLASS) && owl_message_is_loginout(m)) {
-          /* Special case LOGIN/LOGOUT notifications on class "webzephyr" */
-          class=OWL_WEBZEPHYR_CLASS;
-          inst=owl_message_get_instance(m);
-          to=OWL_WEBZEPHYR_PRINCIPAL;
-        } else if (owl_message_is_loginout(m)) {
-          /* Normal LOGIN/LOGOUT messages */
-          class="MESSAGE";
-          inst="PERSONAL";
-          to=owl_message_get_sender(m);
-        } else if (type==1) {
-          /* Personal reply */
-          class="MESSAGE";
-          inst="PERSONAL";
-          to=owl_message_get_sender(m);
-        } else {
-          /* General reply */
-          class=owl_message_get_class(m);
-          inst=owl_message_get_instance(m);
-          to=owl_message_get_recipient(m);
-          cc=owl_message_get_cc_without_recipient(m);
-          if (!strcmp(to, "") || !strcmp(to, "*")) {
-            to="";
-          } else if (to[0]=='@') {
-            /* leave it, to get the realm */
-          } else {
-            to=owl_message_get_sender(m);
-          }
-        }
-
-        /* create the command line */
-        if (!strcasecmp(owl_message_get_opcode(m), "CRYPT")) {
-          buff=owl_strdup("zcrypt");
-        } else {
-          buff = owl_strdup("zwrite");
-        }
-        if (strcasecmp(class, "message")) {
-          buff = owl_sprintf("%s -c %s%s%s", oldbuff=buff, owl_getquoting(class), class, owl_getquoting(class));
-          owl_free(oldbuff);
-        }
-        if (strcasecmp(inst, "personal")) {
-          buff = owl_sprintf("%s -i %s%s%s", oldbuff=buff, owl_getquoting(inst), inst, owl_getquoting(inst));
-          owl_free(oldbuff);
-        }
-        if (*to != '\0') {
-          char *tmp, *oldtmp, *tmp2;
-          tmp=short_zuser(to);
-          if (cc) {
-            tmp = owl_util_uniq(oldtmp=tmp, cc, "-");
-            owl_free(oldtmp);
-            buff = owl_sprintf("%s -C %s", oldbuff=buff, tmp);
-            owl_free(oldbuff);
-          } else {
-            if (owl_global_is_smartstrip(&g)) {
-              tmp2=tmp;
-              tmp=owl_zephyr_smartstripped_user(tmp2);
-              owl_free(tmp2);
-            }
-            buff = owl_sprintf("%s %s", oldbuff=buff, tmp);
-            owl_free(oldbuff);
-          }
-          owl_free(tmp);
-        }
-        if (cc) owl_free(cc);
-      }
-    } else if (owl_message_is_type_aim(m)) {
-      /* aim */
-      if (owl_message_is_direction_out(m)) {
-	buff=owl_sprintf("aimwrite %s", owl_message_get_recipient(m));
-      } else {
-	buff=owl_sprintf("aimwrite %s", owl_message_get_sender(m));
-      }
-    } else {
-      char *cmd;
-      if((type==0 && (cmd=owl_message_get_attribute_value(m, "replycmd")))
-         || (type==1 && (cmd=owl_message_get_attribute_value(m, "replysendercmd")))) {
-        buff = owl_strdup(cmd);
-      }
+    char *cmd;
+    if((type == 0 &&
+        (cmd=owl_perlconfig_message_call_method(m, "replycmd", 0, NULL))) ||
+       (type == 1 &&
+        (cmd=owl_perlconfig_message_call_method(m, "replysendercmd", 0, NULL)))) {
+      buff = cmd;
     }
 
@@ -2151,5 +2066,5 @@
         return;
     }
-    
+
     if (enter) {
       owl_history *hist = owl_global_get_cmd_history(&g);
@@ -2404,5 +2319,5 @@
       return;
     }
-    if (owl_util_string_to_color(argv[3])==-1) {
+    if (owl_util_string_to_color(argv[3])==OWL_COLOR_INVALID) {
       owl_function_error("The color '%s' is not available.", argv[3]);
       return;
@@ -2419,5 +2334,5 @@
       return;
     }
-    if (owl_util_string_to_color(argv[3])==-1) {
+    if (owl_util_string_to_color(argv[3])==OWL_COLOR_INVALID) {
       owl_function_error("The color '%s' is not available.", argv[3]);
       return;
@@ -2527,5 +2442,5 @@
 {
   owl_filter *f;
-  char buff[5000];
+  char *buff, *tmp;
 
   f=owl_global_get_filter(&g, name);
@@ -2534,6 +2449,9 @@
     return;
   }
-  owl_filter_print(f, buff);
+  tmp = owl_filter_print(f);
+  buff = owl_sprintf("%s: %s", owl_filter_get_name(f), tmp);
   owl_function_popless_text(buff);
+  owl_free(buff);
+  owl_free(tmp);
 }
 
@@ -2543,4 +2461,5 @@
   owl_list *fl;
   char buff[5000];
+  char *tmp;
   owl_fmtext fm;
   int i, j;
@@ -2556,5 +2475,7 @@
     snprintf(buff, sizeof(buff), "[% 2d] ", i+1);
     owl_fmtext_append_normal(&fm, buff);
-    owl_filter_print(f, buff);
+    tmp = owl_filter_print(f);
+    owl_fmtext_append_normal(&fm, tmp);
+    owl_free(tmp);
     owl_fmtext_append_normal(&fm, buff);
   }
@@ -2953,5 +2874,5 @@
   }
 
-  if (owl_util_string_to_color(fgcolor)==-1) {
+  if (owl_util_string_to_color(fgcolor)==OWL_COLOR_INVALID) {
     owl_function_error("No color named '%s' avilable.", fgcolor);
     return(-1);
@@ -2960,5 +2881,5 @@
 
   if (bgcolor != NULL) {
-    if (owl_util_string_to_color(bgcolor)==-1) {
+    if (owl_util_string_to_color(bgcolor)==OWL_COLOR_INVALID) {
       owl_function_error("No color named '%s' avilable.", bgcolor);
       return(-1);
@@ -3512,13 +3433,15 @@
   FILE *file;
   char buff[LINE];
+  int fail_silent = 0;
 
   if (!filename) {
+    fail_silent = 1;
     filename=owl_global_get_startupfile(&g);
-    file=fopen(filename, "r");
-  } else {
-    file=fopen(filename, "r");
-  }
+  }
+  file=fopen(filename, "r");
   if (!file) {
-    owl_function_error("Error opening file: %s", filename);
+    if (!fail_silent) {
+      owl_function_error("Error opening file: %s", filename);
+    }
     return;
   }
Index: glib_compat.c
===================================================================
--- glib_compat.c	(revision c60ade251647a4ea5fe6675372c30ea5a7772244)
+++ glib_compat.c	(revision 731dd1eae56c676c26e76bfa6f93f649afb529ab)
@@ -1,3 +1,3 @@
-#include <owl.h>
+#include "owl.h"
 
 #if (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 14)
Index: global.c
===================================================================
--- global.c	(revision 9f4e3f8e63d2376fd3e83432be7691fb45f4ffc3)
+++ global.c	(revision da466e09b1d178435cf117a103dee8a511df94f2)
@@ -310,8 +310,16 @@
 
 void owl_global_set_typwin_active(owl_global *g) {
+  int d = owl_global_get_typewindelta(g);
+  if (d > 0)
+      owl_function_resize_typwin(owl_global_get_typwin_lines(g) + d);
+
   g->typwinactive=1;
 }
 
 void owl_global_set_typwin_inactive(owl_global *g) {
+  int d = owl_global_get_typewindelta(g);
+  if (d > 0)
+      owl_function_resize_typwin(owl_global_get_typwin_lines(g) - d);
+
   g->typwinactive=0;
 }
Index: help.c
===================================================================
--- help.c	(revision ec53338446a35cf944c72d60bbcf932e633c3020)
+++ help.c	(revision 0398d55781db08fc6d990621fb6a488b6ce1eb49)
@@ -57,4 +57,5 @@
      "    M-n           View zephyrs in selected conversation\n"
      "    M-N           View zephyrs in selected converstaion of instance\n"
+     "    M-p           View only personal zephyrs\n"
      "    V             Change to back to home view ('all' by default)\n"
      "    v             Start a view command\n"
Index: logging.c
===================================================================
--- logging.c	(revision af1920fd98d8d860245a197dee998e0e5c337285)
+++ logging.c	(revision d8671a139b04d17e8b6303452daae01425a318ec)
@@ -51,7 +51,4 @@
   if (!owl_global_is_loglogins(&g) && owl_message_is_loginout(m)) return(0);
       
-  /* check for nolog */
-  if (!strcasecmp(owl_message_get_opcode(m), "nolog") || !strcasecmp(owl_message_get_instance(m), "nolog")) return(0);
-
   /* check direction */
   if ((owl_global_get_loggingdirection(&g)==OWL_LOGGING_DIRECTION_IN) && owl_message_is_direction_out(m)) {
@@ -154,4 +151,5 @@
   } else if (owl_message_is_type_jabber(m)) {
     to = owl_sprintf("jabber:%s", owl_message_get_recipient(m));
+    owl_text_tr(to, '/', '_');
   } else if (owl_message_is_type_aim(m)) {
     char *temp2;
Index: message.c
===================================================================
--- message.c	(revision 18108b1ebf65a6a18509f966ce68618ad5aae46d)
+++ message.c	(revision 147d88077919720ae7689914594bbda67e87d83b)
@@ -42,5 +42,4 @@
   owl_message_set_direction_none(m);
   m->delete=0;
-  m->zwriteline=NULL;
 
   owl_message_set_hostname(m, "");
@@ -485,13 +484,12 @@
 char *owl_message_get_zwriteline(owl_message *m)
 {
-  if(!m->zwriteline)
-    return "";
-  return(m->zwriteline);
+  char *z = owl_message_get_attribute_value(m, "zwriteline");
+  if (!z) return "";
+  return z;
 }
 
 void owl_message_set_zwriteline(owl_message *m, char *line)
 {
-  if(m->zwriteline) owl_free(m->zwriteline);
-  m->zwriteline=owl_strdup(line);
+  owl_message_set_attribute(m, "zwriteline", line);
 }
 
@@ -615,28 +613,4 @@
       return(0);
     }
-  }
-  return(0);
-}
-
-int owl_message_is_burningears(owl_message *m)
-{
-  /* we should add a global to cache the short zsender */
-  char sender[LINE], *ptr;
-
-  /* if the message is from us or to us, it doesn't count */
-  if (owl_message_is_from_me(m) || owl_message_is_private(m)) return(0);
-
-  if (owl_message_is_type_zephyr(m)) {
-    strcpy(sender, owl_zephyr_get_sender());
-    ptr=strchr(sender, '@');
-    if (ptr) *ptr='\0';
-  } else if (owl_message_is_type_aim(m)) {
-    strcpy(sender, owl_global_get_aim_screenname(&g));
-  } else {
-    return(0);
-  }
-
-  if (stristr(owl_message_get_body(m), sender)) {
-    return(1);
   }
   return(0);
@@ -884,6 +858,4 @@
   }
 
-  m->zwriteline=owl_strdup("");
-
   /* save the hostname */
   owl_function_debugmsg("About to do gethostbyaddr");
@@ -966,6 +938,4 @@
   }
 
-  m->zwriteline=owl_strdup("");
-
   owl_message_set_body(m, "<uninitialized>");
 
@@ -999,5 +969,5 @@
   owl_message_set_opcode(m, owl_zwrite_get_opcode(&z));
   owl_message_set_realm(m, owl_zwrite_get_realm(&z)); /* also a hack, but not here */
-  m->zwriteline=owl_strdup(line);
+  owl_message_set_zwriteline(m, line);
   owl_message_set_body(m, body);
   owl_message_set_zsig(m, zsig);
@@ -1040,5 +1010,4 @@
 #endif
   if (m->timestr) owl_free(m->timestr);
-  if (m->zwriteline) owl_free(m->zwriteline);
 
   /* free all the attributes */
Index: owl.c
===================================================================
--- owl.c	(revision 628c89797a5013f6d399ada2746c0155595472eb)
+++ owl.c	(revision 7ba9ead95bdf4c9a8c760468d3ab6ea6bc1da412)
@@ -120,5 +120,5 @@
       exit(0);
     } else {
-      fprintf(stderr, "Uknown argument\n");
+      fprintf(stderr, "Unknown argument\n");
       usage();	      
       exit(1);
@@ -603,16 +603,8 @@
       }
     }
-
-    /* check for burning ears message */
-    /* this is an unsupported feature */
-    if (owl_global_is_burningears(&g) && owl_message_is_burningears(m)) {
-      char *buff;
-      buff = owl_sprintf("@i(Burning ears message on class %s)", owl_message_get_class(m));
-      owl_function_adminmsg(buff, "");
-      owl_free(buff);
-      owl_function_beep();
-    }
-  }
-
+  }
+
+  /* let perl know about it */
+  owl_perlconfig_newmsg(m, NULL);
   /* log the message if we need to */
   owl_log_message(m);
Index: owl.h
===================================================================
--- owl.h	(revision d7a3188828e158c5556573d6f9230747505a1c8b)
+++ owl.h	(revision 43a306cdd965ba39eebeb9f3ccf426f700e34876)
@@ -20,5 +20,5 @@
 #include <signal.h>
 #include <termios.h>
-#include <libfaim/aim.h>
+#include "libfaim/aim.h"
 #include <wchar.h>
 #include "config.h"
@@ -51,10 +51,6 @@
 #define _STRINGIFY(x) #x
 
-#ifndef OWL_SVN_REVNO
-#define OWL_SVN_REVNO ????
-#endif
-
 #ifndef OWL_VERSION_STRING
-#define OWL_VERSION_STRING "1.0.1"
+#define OWL_VERSION_STRING "1.0.3"
 #endif
 
@@ -100,4 +96,5 @@
 #define OWL_COLOR_WHITE     7
 #define OWL_COLOR_DEFAULT   -1
+#define OWL_COLOR_INVALID   -2
 
 #define OWL_EDITWIN_STYLE_MULTILINE 0
@@ -341,5 +338,4 @@
   char *timestr;
   time_t time;
-  char *zwriteline;
 } owl_message;
 
@@ -405,5 +401,5 @@
   int (*match_message)(struct _owl_filterelement *fe, owl_message *m);
   /* Append a string representation of the filterelement onto buf*/
-  void (*print_elt)(struct _owl_filterelement *fe, char * buf);
+  void (*print_elt)(struct _owl_filterelement *fe, GString *buf);
   /* Operands for and,or,not*/
   struct _owl_filterelement *left, *right;
Index: perl/lib/BarnOwl/ModuleLoader.pm
===================================================================
--- perl/lib/BarnOwl/ModuleLoader.pm	(revision 965e14de7fdd8473abb3847fe7f44be48833964e)
+++ perl/lib/BarnOwl/ModuleLoader.pm	(revision 41bbb8a6ca458a8596f859362016a37fe22946e2)
@@ -8,10 +8,26 @@
 use PAR (BarnOwl::get_config_dir() . "/modules/*.par");
 
+our %modules;
+
 sub load_all {
+    my $class = shift;
+    $class->rescan_modules;
     PAR::reload_libs();
+
+    for my $mod (keys %modules) {
+        if(!defined eval "use BarnOwl::Module::$mod") {
+            BarnOwl::error("Unable to load module $mod: \n$@\n") if $@;
+        }
+    }
+
+    $BarnOwl::Hooks::startup->add(\&register_keybindings);
+}
+
+sub rescan_modules {
     PAR->import(BarnOwl::get_data_dir() . "/modules/*.par");
     PAR->import(BarnOwl::get_config_dir() . "/modules/*.par");
-    my %modules;
     my @modules;
+
+    %modules = ();
 
     my @moddirs = ();
@@ -37,12 +53,42 @@
         }
     }
-    for my $class (keys %modules) {
-        if(!defined eval "use BarnOwl::Module::$class") {
-            # BarnOwl::error("Unable to load module $class: $!") if $!;
-            BarnOwl::error("Unable to load module $class: \n$@\n") if $@;
+}
+
+sub reload_module {
+    my $class = shift;
+    my $module = shift;
+
+    $class->rescan_modules();
+
+    for my $m (keys %INC) {
+        delete $INC{$m} if $m =~ m{^BarnOwl/Module/$module};
+    }
+
+    my $parfile;
+    for my $p (@PAR::PAR_INC) {
+        if($p =~ m/\Q$module\E[.]par$/) {
+            $parfile = $p;
+            last;
         }
     }
 
-    $BarnOwl::Hooks::startup->add(\&register_keybindings);
+    local $SIG{__WARN__} = \&squelch_redefine;
+
+    if(defined $parfile) {
+        PAR::reload_libs($parfile);
+        $class->run_startup_hooks();
+    } elsif(!defined eval "use BarnOwl::Module::$module") {
+        BarnOwl::error("Unable to load module $module: \n$@\n") if $@;
+    }
+}
+
+sub reload_module_cmd {
+    my $class = shift;
+    shift; # Command
+    my $module = shift;
+    unless(defined($module)) {
+        die("Usage: reload-module [MODULE]");
+    };
+    $class->reload_module($module);
 }
 
@@ -52,4 +98,9 @@
                            usage   => 'reload-modules',
                            description => q{Reloads all modules located in ~/.owl/modules and the system modules directory}
+                          });
+    BarnOwl::new_command('reload-module', sub {BarnOwl::ModuleLoader->reload_module_cmd(@_)}, {
+                           summary => 'Reload one module',
+                           usage   => 'reload-module [MODULE]',
+                           description => q{Reloads a single module located in ~/.owl/modules or the system modules directory}
                           });
 }
@@ -63,10 +114,9 @@
     $INC{$_} = 1 for (qw(BarnOwl.pm BarnOwl/Hooks.pm
                          BarnOwl/Message.pm BarnOwl/Style.pm));
+    $class->run_startup_hooks();
+}
 
-    $BarnOwl::Hooks::startup->clear;
-    $BarnOwl::Hooks::getBuddyList->clear;
-    $BarnOwl::Hooks::mainLoop->clear;
-    $BarnOwl::Hooks::shutdown->clear;
-    $BarnOwl::Hooks::receiveMessage->clear;
+sub run_startup_hooks {
+    my $class = shift;
     local $SIG{__WARN__} = \&squelch_redefine;
     $class->load_all;
Index: perl/modules/IRC/lib/BarnOwl/Message/IRC.pm
===================================================================
--- perl/modules/IRC/lib/BarnOwl/Message/IRC.pm	(revision 8df6cbb1bc0d6c05e05f74189a40c220f77d9263)
+++ perl/modules/IRC/lib/BarnOwl/Message/IRC.pm	(revision 38a7f226a2a038aae5b96d2b47874fa30b6b0ed8)
@@ -20,5 +20,6 @@
     my $inst = shift;
 
-    my ($filter, $ftext);
+    my $filter;
+    my @filter;
 
     if($self->is_private) {
@@ -30,8 +31,10 @@
         }
         $filter = "irc-user-$who";
-        my $ftext  =
-             qq{type ^irc\$ and ( ( direction ^in\$ and sender ^$who\$ ) }
-           . qq{or ( direction ^out\$ and recipient ^$who\$ ) ) };
-        BarnOwl::filter("$filter $ftext");
+        @filter  =
+             (qw{( type ^irc$ and filter personal and },
+              qw{( ( direction ^in$ and sender}, "^$who\$",
+              qw{ ) or ( direction ^out$ and recipient}, "^$who\$",
+              qw{) ) ) });
+        BarnOwl::command("filter", "$filter", @filter);
         return $filter;
     } else {
@@ -43,10 +46,15 @@
         if ($inst && $self->body =~ /^(\S+):/) {
             $filter = "irc-$network-channel-$channel-$sender-$1";
-            $ftext = qq{type ^irc\$ and network ^$network\$ and channel ^$channel\$ and ( sender ^$sender\$ or sender ^$1\$ )};
+            @filter =
+                 (qw{type ^irc$ and network}, "^$network\$",
+                  qw{and channel}, "^$channel\$",
+                  qw{and ( sender}, "^$sender\$",
+                  qw{or sender}, "^$1\$",qq{)});
         } else {
             $filter = "irc-$network-channel-$channel";
-            $ftext = qq{type ^irc\$ and network ^$network\$ and channel ^$channel\$};
+            @filter = (qw{type ^irc$ and network}, "^$network\$",
+                       qw{and channel}, "^$channel\$");
         }
-        BarnOwl::filter("$filter $ftext");
+        BarnOwl::command("filter", "$filter", @filter);
         return $filter;
     }
@@ -56,4 +64,6 @@
 sub network {shift->{network}}
 sub channel {shift->{channel}}
+sub action {shift->{action}}
+sub reason {shift->{reason}}
 
 # display
@@ -65,9 +75,15 @@
 sub login_type {
     my $self = shift;
-    return " (" . ($self->is_login ? "JOIN" : "PART") . ")";
+    return " (" . uc $self->action . ")";
 }
 
-sub login_extra { shift->channel; }
-
+sub login_extra { 
+    my $self = shift;
+    if ($self->action eq "quit") {
+        return $self->reason;
+    } else {
+        return $self->channel;
+    }
+}
 
 1;
Index: perl/modules/IRC/lib/BarnOwl/Module/IRC.pm
===================================================================
--- perl/modules/IRC/lib/BarnOwl/Module/IRC.pm	(revision f094fc4697d7866213adaaf1ff356d1a396814b2)
+++ perl/modules/IRC/lib/BarnOwl/Module/IRC.pm	(revision 167044bea49b17d131f1846e1e5528ef58e1c159)
@@ -117,9 +117,9 @@
     BarnOwl::new_command('irc-who'        => \&cmd_who);
     BarnOwl::new_command('irc-stats'      => \&cmd_stats);
-}
-
-$BarnOwl::Hooks::startup->add(\&startup);
-$BarnOwl::Hooks::shutdown->add(\&shutdown);
-#$BarnOwl::Hooks::mainLoop->add(\&mainloop_hook);
+    BarnOwl::new_command('irc-topic'      => \&cmd_topic);
+}
+
+$BarnOwl::Hooks::startup->add('BarnOwl::Module::IRC::startup');
+$BarnOwl::Hooks::shutdown->add('BarnOwl::Module::IRC::shutdown');
 
 ################################################################################
@@ -262,4 +262,5 @@
     my $conn = get_connection(\@_);
     my $chan = get_channel(\@_) || die("Usage: $cmd <channel>\n");
+    $conn->names_tmp([]);
     $conn->conn->names($chan);
 }
@@ -299,4 +300,10 @@
     my $type = shift || die("Usage: $cmd <chiklmouy> [server] \n");
     $conn->conn->stats($type, @_);
+}
+
+sub cmd_topic {
+    my $cmd = shift;
+    my $conn = get_connection(\@_);
+    $conn->conn->topic(@_);
 }
 
Index: perl/modules/IRC/lib/BarnOwl/Module/IRC/Connection.pm
===================================================================
--- perl/modules/IRC/lib/BarnOwl/Module/IRC/Connection.pm	(revision 8faab0c804c9d8367f230dba7c79efa9c7b62cd6)
+++ perl/modules/IRC/lib/BarnOwl/Module/IRC/Connection.pm	(revision 4789b17987d2032fcf895ce27b81ac613343e169)
@@ -18,5 +18,5 @@
 
 use base qw(Class::Accessor Exporter);
-__PACKAGE__->mk_accessors(qw(conn alias channels connected motd));
+__PACKAGE__->mk_accessors(qw(conn alias channels connected motd names_tmp whois_tmp));
 our @EXPORT_OK = qw(&is_private);
 
@@ -45,4 +45,6 @@
     $self->motd("");
     $self->connected(0);
+    $self->names_tmp(0);
+    $self->whois_tmp("");
 
     $self->conn->add_handler(376 => sub { shift; $self->on_connect(@_) });
@@ -62,7 +64,13 @@
     $self->conn->add_handler(join      => sub { shift; $self->on_join(@_) });
     $self->conn->add_handler(part      => sub { shift; $self->on_part(@_) });
+    $self->conn->add_handler(quit      => sub { shift; $self->on_quit(@_) });
     $self->conn->add_handler(disconnect => sub { shift; $self->on_disconnect(@_) });
     $self->conn->add_handler(nicknameinuse => sub { shift; $self->on_nickinuse(@_) });
     $self->conn->add_handler(cping     => sub { shift; $self->on_ping(@_) });
+    $self->conn->add_handler(topic     => sub { shift; $self->on_topic(@_) });
+    $self->conn->add_handler(topicinfo => sub { shift; $self->on_topicinfo(@_) });
+    $self->conn->add_handler(namreply  => sub { shift; $self->on_namreply(@_) });
+    $self->conn->add_handler(endofnames=> sub { shift; $self->on_endofnames(@_) });
+    $self->conn->add_handler(endofwhois=> sub { shift; $self->on_endofwhois(@_) });
 
     return $self;
@@ -126,5 +134,5 @@
             BarnOwl::Style::boldify('IRC ' . $evt->type . ' message from '
                 . $self->alias) . "\n"
-            . strip_irc_formatting(join '\n', $evt->args));
+            . strip_irc_formatting(join ' ', cdr($evt->args)));
 }
 
@@ -157,6 +165,7 @@
     my $msg = $self->new_message($evt,
         loginout   => 'login',
+        action     => 'join',
         channel    => $evt->to,
-        replycmd => 'irc-msg -a ' . $self->alias . ' ' . $evt->nick,
+        replycmd => 'irc-msg -a ' . $self->alias . ' ' . join(' ', $evt->to),
         replysendercmd => 'irc-msg -a ' . $self->alias . ' ' . $evt->nick
         );
@@ -168,5 +177,19 @@
     my $msg = $self->new_message($evt,
         loginout   => 'logout',
+        action     => 'part',
         channel    => $evt->to,
+        replycmd => 'irc-msg -a ' . $self->alias . ' ' . join(' ', $evt->to),
+        replysendercmd => 'irc-msg -a ' . $self->alias . ' ' . $evt->nick
+        );
+    BarnOwl::queue_message($msg);
+}
+
+sub on_quit {
+    my ($self, $evt) = @_;
+    my $msg = $self->new_message($evt,
+        loginout   => 'logout',
+        action     => 'quit',
+        from       => $evt->to,
+        reason     => [$evt->args]->[0],
         replycmd => 'irc-msg -a ' . $self->alias . ' ' . $evt->nick,
         replysendercmd => 'irc-msg -a ' . $self->alias . ' ' . $evt->nick
@@ -193,6 +216,64 @@
 }
 
+sub on_topic {
+    my ($self, $evt) = @_;
+    my @args = $evt->args;
+    if (scalar @args > 1) {
+        BarnOwl::admin_message("IRC",
+                "Topic for $args[1] on " . $self->alias . " is $args[2]");
+    } else {
+        BarnOwl::admin_message("IRC",
+                "Topic changed to $args[0]");
+    }
+}
+
+sub on_topicinfo {
+    my ($self, $evt) = @_;
+    my @args = $evt->args;
+    BarnOwl::admin_message("IRC",
+        "Topic for $args[1] set by $args[2] at " . localtime($args[3]));
+}
+
+# IRC gives us a bunch of namreply messages, followed by an endofnames.
+# We need to collect them from the namreply and wait for the endofnames message.
+# After this happens, the names_tmp variable is cleared.
+
+sub on_namreply {
+    my ($self, $evt) = @_;
+    return unless $self->names_tmp;
+    $self->names_tmp([@{$self->names_tmp}, split(' ', [$evt->args]->[3])]);
+}
+
+sub on_endofnames {
+    my ($self, $evt) = @_;
+    return unless $self->names_tmp;
+    my $names = BarnOwl::Style::boldify("Members of " . [$evt->args]->[1] . ":\n");
+    for my $name (@{$self->names_tmp}) {
+        $names .= "  $name\n";
+    }
+    BarnOwl::popless_ztext($names);
+    $self->names_tmp(0);
+}
+
+sub on_whois {
+    my ($self, $evt) = @_;
+    $self->whois_tmp(
+      $self->whois_tmp . "\n" . $evt->type . ":\n  " .
+      join("\n  ", cdr(cdr($evt->args))) . "\n"
+    );
+}
+
+sub on_endofwhois {
+    my ($self, $evt) = @_;
+    BarnOwl::popless_ztext(
+        BarnOwl::Style::boldify("/whois for " . [$evt->args]->[1] . ":\n") .
+        $self->whois_tmp
+    );
+    $self->whois_tmp([]);
+}
+
 sub on_event {
     my ($self, $evt) = @_;
+    return on_whois(@_) if ($evt->type =~ /^whois/);
     BarnOwl::admin_message("IRC",
             "[" . $self->alias . "] Unhandled IRC event of type " . $evt->type . ":\n"
@@ -200,5 +281,4 @@
         if BarnOwl::getvar('irc:spew') eq 'on';
 }
-
 
 ################################################################################
@@ -214,5 +294,5 @@
     
     my @pieces = split /\cB/, $body;
-     my $out;
+    my $out = '';
     while(@pieces) {
         $out .= shift @pieces;
Index: perl/modules/Jabber/lib/BarnOwl/Message/Jabber.pm
===================================================================
--- perl/modules/Jabber/lib/BarnOwl/Message/Jabber.pm	(revision 693c8f2650535ea7992cd1ddb15aaeb33513b383)
+++ perl/modules/Jabber/lib/BarnOwl/Message/Jabber.pm	(revision 96134cb4aa5cfc151dbc860357af5a7156025c86)
@@ -22,4 +22,10 @@
 sub subject { shift->{subject} };
 sub status { shift->{status} }
+
+sub login_type {
+    my $self = shift;
+    my $type = $self->jtype;
+    return " ($type)" if $type;
+}
 
 sub login_extra {
@@ -50,5 +56,5 @@
     my $inst = shift;
 
-    my ($filter, $ftext);
+    my $filter;
 
     if($self->jtype eq 'chat') {
@@ -63,6 +69,6 @@
         my $room = $self->room;
         $filter = "jabber-room-$room";
-        $ftext = qq{type ^jabber\$ and room ^$room\$};
-        BarnOwl::filter("$filter $ftext");
+        BarnOwl::command(qw[filter], $filter,
+                         qw[type ^jabber$ and room], "^$room\$");
         return $filter;
     } elsif ($self->login ne 'none') {
@@ -77,12 +83,66 @@
     $user   = Net::Jabber::JID->new($user)->GetJID( $inst ? 'full' : 'base' );
     my $filter = "jabber-user-$user";
-    my $ftext  =
-        qq{type ^jabber\$ and ( ( direction ^in\$ and from ^$user ) }
-      . qq{or ( direction ^out\$ and to ^$user ) ) };
-    BarnOwl::filter("$filter $ftext");
+    BarnOwl::command(qw[filter], $filter, qw[type ^jabber$],
+                     qw[and ( ( direction ^in$ and from], "^$user",
+                     qw[) or ( direction ^out$ and to ], "^$user",
+                     qw[ ) ) ]);
     return $filter;
 
 }
 
+sub replycmd {
+    my $self = shift;
+    my ($recip, $account, $subject);
+    if ($self->is_loginout) {
+        $recip   = $self->sender;
+        $account = $self->recipient;
+    } elsif ($self->jtype eq 'chat') {
+        return $self->replysendercmd;
+    } elsif ($self->jtype eq 'groupchat') {
+        $recip = $self->room;
+        if ($self->is_incoming) {
+            $account = $self->to;
+        } else {
+            $account = $self->from;
+        }
+        $subject = $self->subject;
+    } else {
+        # Unknown type
+        return;
+    }
+    return jwrite_cmd($recip, $account, $subject);
+}
+
+sub replysendercmd {
+    my $self = shift;
+    if($self->jtype eq 'groupchat'
+       || $self->jtype eq 'chat') {
+        my ($recip, $account);
+        if ($self->is_incoming) {
+            $recip   = $self->from;
+            $account = $self->to;
+        } else {
+            $recip   = $self->to;
+            $account = $self->from;
+        }
+        return jwrite_cmd($recip, $account);
+    }
+    return $self->replycmd;
+}
+
+sub jwrite_cmd {
+    my ($recip, $account, $subject) = @_;
+    if (defined $recip) {
+        $recip   = BarnOwl::quote($recip);
+        $account = BarnOwl::quote($account);
+        my $cmd = "jwrite $recip -a $account";
+        if (defined $subject) {
+            $cmd .= " -s " . BarnOwl::quote($subject);
+        }
+        return $cmd;
+    } else {
+        return undef;
+    }
+}
 
 =head1 SEE ALSO
Index: perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm
===================================================================
--- perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm	(revision 8af89a7438d5bebf0467f52df54fea035107dedb)
+++ perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm	(revision e979da9926f59c32e4a380c936551b11683cfe94)
@@ -68,10 +68,13 @@
         register_keybindings();
         register_filters();
-        $BarnOwl::Hooks::mainLoop->add(\&onMainLoop);
-        $BarnOwl::Hooks::getBuddyList->add(\&onGetBuddyList);
+        $BarnOwl::Hooks::mainLoop->add("BarnOwl::Module::Jabber::onMainLoop");
+        $BarnOwl::Hooks::getBuddyList->add("BarnOwl::Module::Jabber::onGetBuddyList");
         $vars{show} = '';
 	BarnOwl::new_variable_bool("jabber:show_offline_buddies",
 				   { default => 1,
 				     summary => 'Show offline or pending buddies.'});
+	BarnOwl::new_variable_bool("jabber:show_logins",
+				   { default => 0,
+				     summary => 'Show login/logout messages.'});
 	BarnOwl::new_variable_bool("jabber:spew",
 				   { default => 0,
@@ -85,4 +88,10 @@
 				    summary => 'After minutes idle, auto extended away.'
 				});
+        # Force these. Reload can screw them up.
+        # Taken from Net::Jabber::Protocol.
+        $Net::XMPP::Protocol::NEWOBJECT{'iq'}       = "Net::Jabber::IQ";
+        $Net::XMPP::Protocol::NEWOBJECT{'message'}  = "Net::Jabber::Message";
+        $Net::XMPP::Protocol::NEWOBJECT{'presence'} = "Net::Jabber::Presence";
+        $Net::XMPP::Protocol::NEWOBJECT{'jid'}      = "Net::Jabber::JID";
     } else {
         # Our owl doesn't support queue_message. Unfortunately, this
@@ -92,5 +101,5 @@
 }
 
-$BarnOwl::Hooks::startup->add(\&onStart);
+$BarnOwl::Hooks::startup->add("BarnOwl::Module::Jabber::onStart");
 
 sub onMainLoop {
@@ -232,4 +241,11 @@
             summary => "Send a Jabber Message",
             usage   => "jwrite JID [-t thread] [-s subject]"
+        }
+    );
+    BarnOwl::new_command(
+        jaway => \&cmd_jaway,
+        {
+            summary => "Set Jabber away / presence information",
+            usage   => "jaway [-s online|dnd|...] [<message>]"
         }
     );
@@ -757,4 +773,31 @@
 }
 
+sub cmd_jaway {
+    my $cmd = shift;
+    local @ARGV = @_;
+    my $getopt = Getopt::Long::Parser->new;
+    my ($jid, $show);
+    my $p = new Net::Jabber::Presence;
+
+    $getopt->configure('pass_through', 'no_getopt_compat');
+    $getopt->getoptions(
+        'account=s' => \$jid,
+        'show=s'    => \$show
+    );
+    $jid ||= defaultJID();
+    if ($jid) {
+        $jid = resolveConnectedJID($jid);
+        return unless $jid;
+    }
+    else {
+        BarnOwl::error('You must specify an account with -a {jid}');
+    }
+
+    $p->SetShow($show eq "online" ? "" : $show) if $show;
+    $p->SetStatus(join(' ', @ARGV)) if @ARGV;
+    $conn->getConnectionFromJID($jid)->Send($p);
+}
+
+
 sub jroster_sub {
     my $jid = shift;
@@ -933,6 +976,8 @@
 sub process_incoming_chat_message {
     my ( $sid, $j ) = @_;
-    BarnOwl::queue_message( j2o( $j, { direction => 'in',
-                                   sid => $sid } ) );
+    if ($j->DefinedBody()) {
+        BarnOwl::queue_message( j2o( $j, { direction => 'in',
+                                           sid => $sid } ) );
+    }
 }
 
@@ -989,11 +1034,12 @@
 
 sub process_presence_available {
+    return unless (BarnOwl::getvar('jabber:show_logins') eq 'on');
     my ( $sid, $p ) = @_;
-    my $from = $p->GetFrom();
+    my $from = $p->GetFrom('jid')->GetJID('base');
     my $to = $p->GetTo();
     my $type = $p->GetType();
     my %props = (
         to => $to,
-        from => $from,
+        from => $p->GetFrom(),
         recipient => $to,
         sender => $from,
@@ -1013,8 +1059,5 @@
         $props{loginout} = 'logout';
     }
-    $props{replysendercmd} = $props{replycmd} = "jwrite $from -i $sid";
-    if(BarnOwl::getvar('debug') eq 'on') {
-        BarnOwl::queue_message(BarnOwl::Message->new(%props));
-    }
+    BarnOwl::queue_message(BarnOwl::Message->new(%props));
 }
 
@@ -1099,13 +1142,9 @@
 sub j2hash {
     my $j   = shift;
-    my %initProps = %{ shift() };
-
-    my $dir = 'none';
-    my %props = ( type => 'jabber' );
-
-    foreach my $k (keys %initProps) {
-        $dir = $initProps{$k} if ($k eq 'direction');
-        $props{$k} = $initProps{$k};
-    }
+    my %props = (type => 'jabber',
+                 dir  => 'none',
+                 %{$_[0]});
+
+    my $dir = $props{direction};
 
     my $jtype = $props{jtype} = $j->GetType();
@@ -1120,5 +1159,8 @@
     $props{subject}    = $j->GetSubject() if ( $j->DefinedSubject() );
     $props{thread}     = $j->GetThread() if ( $j->DefinedThread() );
-    $props{body}       = $j->GetBody() if ( $j->DefinedBody() );
+    if ( $j->DefinedBody() ) {
+        $props{body}   = $j->GetBody();
+        $props{body}  =~ s/\xEF\xBB\xBF//g; # Strip stray Byte-Order-Marks.
+    }
     $props{error}      = $j->GetError() if ( $j->DefinedError() );
     $props{error_code} = $j->GetErrorCode() if ( $j->DefinedErrorCode() );
@@ -1126,8 +1168,4 @@
 
     if ( $jtype eq 'chat' ) {
-        $props{replycmd} =
-          "jwrite " . ( ( $dir eq 'in' ) ? $props{from} : $props{to} );
-        $props{replycmd} .=
-          " -a " . ( ( $dir eq 'out' ) ? $props{from} : $props{to} );
         $props{private} = 1;
 
@@ -1152,17 +1190,4 @@
         my $nick = $props{nick} = $from->GetResource();
         my $room = $props{room} = $from->GetJID('base');
-        $props{replycmd} = "jwrite $room";
-        $props{replycmd} .=
-          " -a " . ( ( $dir eq 'out' ) ? $props{from} : $props{to} );
-	if ($props{subject}) {
-	  $props{replycmd} .= " -s " . $props{subject}
-	}
-
-        if ($dir eq 'out') {
-            $props{replysendercmd} = "jwrite ".$props{to}." -a ".$props{from};
-        }
-        else {
-            $props{replysendercmd} = "jwrite ".$props{from}." -a ".$props{to};
-        }
 
         $props{sender} = $nick || $room;
@@ -1175,12 +1200,9 @@
     }
     elsif ( $jtype eq 'normal' ) {
-        $props{replycmd}  = "";
         $props{private} = 1;
     }
     elsif ( $jtype eq 'headline' ) {
-        $props{replycmd} = "";
     }
     elsif ( $jtype eq 'error' ) {
-        $props{replycmd} = "";
         $props{body}     = "Error "
           . $props{error_code}
@@ -1190,5 +1212,4 @@
     }
 
-    $props{replysendercmd} = $props{replycmd} unless $props{replysendercmd};
     return %props;
 }
Index: perlconfig.c
===================================================================
--- perlconfig.c	(revision b67ab6b90002b0f2ff52289b0318415bd73cace9)
+++ perlconfig.c	(revision c4ba74dbb881fe02a8e19d2936144c033c7bb68f)
@@ -181,5 +181,6 @@
 {
   dSP ;
-  int count, len;
+  int count;
+  unsigned int len;
   SV *msgref, *srv;
   char *out, *preout;
@@ -421,4 +422,15 @@
 }
 
+/* Called on all new messages; receivemsg is only called on incoming ones */
+void owl_perlconfig_newmsg(owl_message *m, char *subname)
+{
+  char *ptr = NULL;
+  if (owl_perlconfig_is_function("BarnOwl::Hooks::_new_msg")) {
+    ptr = owl_perlconfig_call_with_message(subname?subname
+                                           :"BarnOwl::Hooks::_new_msg", m);
+  }
+  if (ptr) owl_free(ptr);
+}
+
 char *owl_perlconfig_perlcmd(owl_cmd *cmd, int argc, char **argv)
 {
@@ -446,5 +458,5 @@
   if(SvTRUE(ERRSV)) {
     owl_function_error("%s", SvPV(ERRSV, n_a));
-    POPs;
+    (void)POPs;
   } else {
     if(count != 1)
Index: perlglue.xs
===================================================================
--- perlglue.xs	(revision b67ab6b90002b0f2ff52289b0318415bd73cace9)
+++ perlglue.xs	(revision 740d5f76770d93df8236a59996511e8ce2d1c0c5)
@@ -17,5 +17,5 @@
 	 *************************************************************
 	 * These functions, when they are intended to be user-visible,
-	 * are document in perlwrap.pm. If you add functions to this
+	 * are documented in perlwrap.pm. If you add functions to this
 	 * file, add the appropriate documentation there!
 	 *
@@ -33,11 +33,25 @@
 
 char *
-command(cmd)
+command(cmd, ...)
 	char *cmd
 	PREINIT:
 		char *rv = NULL;
-	CODE:
-		rv = owl_function_command(cmd);
-		RETVAL = rv;	
+		char **argv;
+		int i;
+	CODE:
+	{
+		if (items == 1) {
+			rv = owl_function_command(cmd);
+		} else {
+			argv = owl_malloc((items + 1) * sizeof *argv);
+			argv[0] = cmd;
+			for(i = 1; i < items; i++) {
+				argv[i] = SvPV_nolen(ST(i));
+			}
+			rv = owl_function_command_argv(argv, items);
+			owl_free(argv);
+		}
+		RETVAL = rv;
+	}
 	OUTPUT:
 		RETVAL
@@ -98,4 +112,31 @@
 		RETVAL
 	CLEANUP:
+		if (rv) owl_free(rv);
+
+char *
+zephyr_smartstrip_user(in)
+	char *in
+	PREINIT:
+		char *rv = NULL;
+	CODE:
+	{
+		rv = owl_zephyr_smartstripped_user(in);
+		RETVAL = rv;
+	}
+	OUTPUT:
+		RETVAL
+	CLEANUP:
+		owl_free(rv);
+
+char *
+zephyr_getsubs()
+	PREINIT:
+		char *rv = NULL;
+	CODE:
+		rv = owl_zephyr_getsubs();
+		RETVAL = rv;
+    OUTPUT:
+		RETVAL
+    CLEANUP:
 		if (rv) owl_free(rv);
 
Index: perlwrap.pm
===================================================================
--- perlwrap.pm	(revision b441079ad2e92e73174512bd98faa87e08dcdb38)
+++ perlwrap.pm	(revision 740d5f76770d93df8236a59996511e8ce2d1c0c5)
@@ -67,4 +67,9 @@
 
 Strips zephyr formatting from a string and returns the result
+
+=head2 zephyr_getsubs
+
+Returns the list of subscription triples <class,instance,recipient>,
+separated by newlines.
 
 =head2 queue_message MESSAGE
@@ -295,4 +300,24 @@
         %{$args});
     $func->($name, $args{default}, $args{summary}, $args{description});
+}
+
+=head2 quote STRING
+
+Return a version of STRING fully quoted to survive processing by
+BarnOwl's command parser.
+
+=cut
+
+sub quote {
+    my $str = shift;
+    return "''" if $str eq '';
+    if ($str !~ /['" ]/) {
+        return "$str";
+    }
+    if ($str !~ /'/) {
+        return "'$str'";
+    }
+    $str =~ s/"/"'"'"/g;
+    return '"' . $str . '"';
 }
 
@@ -356,4 +381,10 @@
 sub login_host  { return undef; }
 sub login_tty   { return undef; }
+
+# This is for back-compat with old messages that set these properties
+# New protocol implementations are encourages to user override these
+# methods.
+sub replycmd         { return shift->{replycmd}};
+sub replysendercmd   { return shift->{replysendercmd}};
 
 sub pretty_sender    { return shift->sender; }
@@ -463,4 +494,7 @@
 }
 
+sub replycmd {return 'loopwrite';}
+sub replysendercmd {return 'loopwrite';}
+
 #####################################################################
 #####################################################################
@@ -475,4 +509,17 @@
 }
 
+sub replycmd {
+    my $self = shift;
+    if ($self->is_incoming) {
+        return "aimwrite " . BarnOwl::quote($self->sender);
+    } else {
+        return "aimwrite " . BarnOwl::quote($self->recipient);
+    }
+}
+
+sub replysendercmd {
+    return shift->replycmd;
+}
+
 #####################################################################
 #####################################################################
@@ -480,5 +527,16 @@
 package BarnOwl::Message::Zephyr;
 
+use constant WEBZEPHYR_PRINCIPAL => "daemon.webzephyr";
+use constant WEBZEPHYR_CLASS     => "webzephyr";
+use constant WEBZEPHYR_OPCODE    => "webzephyr";
+
 use base qw( BarnOwl::Message );
+
+sub strip_realm {
+    my $sender = shift;
+    my $realm = BarnOwl::zephyr_getrealm();
+    $sender =~ s/\@$realm$//;
+    return $sender;
+}
 
 sub login_type {
@@ -537,16 +595,10 @@
 sub pretty_sender {
     my ($m) = @_;
-    my $sender = $m->sender;
-    my $realm = BarnOwl::zephyr_getrealm();
-    $sender =~ s/\@$realm$//;
-    return $sender;
+    return strip_realm($m->sender);
 }
 
 sub pretty_recipient {
     my ($m) = @_;
-    my $recip = $m->recipient;
-    my $realm = BarnOwl::zephyr_getrealm();
-    $recip =~ s/\@$realm$//;
-    return $recip;
+    return strip_realm($m->recipient);
 }
 
@@ -563,7 +615,83 @@
 sub zsig        { return shift->{"zsig"}; }
 
-#####################################################################
-#####################################################################
-################################################################################
+sub zephyr_cc {
+    my $self = shift;
+    return $1 if $self->body =~ /^\s*cc:\s+([^\n]+)/i;
+    return undef;
+}
+
+sub replycmd {
+    my $self = shift;
+    my $sender = shift;
+    $sender = 0 unless defined $sender;
+    my ($class, $instance, $to, $cc);
+    if($self->is_outgoing) {
+        return $self->{zwriteline};
+    }
+
+    if($sender && $self->opcode eq WEBZEPHYR_OPCODE) {
+        $class = WEBZEPHYR_CLASS;
+        $instance = $self->sender;
+        $to = WEBZEPHYR_PRINCIPAL;
+    } elsif($self->class eq WEBZEPHYR_CLASS
+            && $self->is_loginout) {
+        $class = WEBZEPHYR_CLASS;
+        $instance = $self->instance;
+        $to = WEBZEPHYR_PRINCIPAL;
+    } elsif($self->is_loginout || $sender) {
+        $class = 'MESSAGE';
+        $instance = 'PERSONAL';
+        $to = $self->sender;
+    } else {
+        $class = $self->class;
+        $instance = $self->instance;
+        $to = $self->recipient;
+        $cc = $self->zephyr_cc();
+        if($to eq '*' || $to eq '') {
+            $to = '';
+        } elsif($to !~ /^@/) {
+            $to = $self->sender;
+        }
+    }
+
+    my $cmd;
+    if(lc $self->opcode eq 'crypt') {
+        $cmd = 'zcrypt';
+    } else {
+        $cmd = 'zwrite';
+    }
+
+    if (lc $class ne 'message') {
+        $cmd .= " -c " . BarnOwl::quote($self->class);
+    }
+    if (lc $instance ne 'personal') {
+        $cmd .= " -i " . BarnOwl::quote($self->instance);
+    }
+    if ($to ne '') {
+        $to = strip_realm($to);
+        if (defined $cc) {
+            my @cc = grep /^[^-]/, ($to, split /\s+/, $cc);
+            my %cc = map {$_ => 1} @cc;
+            delete $cc{strip_realm(BarnOwl::zephyr_getsender())};
+            @cc = keys %cc;
+            $cmd .= " -C " . join(" ", @cc);
+        } else {
+            if(BarnOwl::getvar('smartstrip') eq 'on') {
+                $to = BarnOwl::zephyr_smartstrip_user($to);
+            }
+            $cmd .= " $to";
+        }
+    }
+    return $cmd;
+}
+
+sub replysendercmd {
+    my $self = shift;
+    return $self->replycmd(1);
+}
+
+#####################################################################
+#####################################################################
+#####################################################################
 
 package BarnOwl::Hook;
@@ -598,5 +726,13 @@
     my $self = shift;
     my @args = @_;
-    return map {$_->(@args)} @$self;
+    return map {$self->_run($_,@args)} @$self;
+}
+
+sub _run {
+    my $self = shift;
+    my $fn = shift;
+    my @args = @_;
+    no strict 'refs';
+    return $fn->(@args);
 }
 
@@ -610,5 +746,6 @@
     my $self = shift;
     my $func = shift;
-    die("Not a coderef!") unless ref($func) eq 'CODE';
+    die("Not a coderef!") unless ref($func) eq 'CODE' || !ref($func);
+    return if grep {$_ eq $func} @$self;
     push @$self, $func;
 }
@@ -680,6 +817,6 @@
 
 our @EXPORT_OK = qw($startup $shutdown
-                    $receiveMessage $mainLoop
-                    $getBuddyList);
+                    $receiveMessage $newMessage
+                    $mainLoop $getBuddyList);
 
 our %EXPORT_TAGS = (all => [@EXPORT_OK]);
@@ -688,4 +825,5 @@
 our $shutdown = BarnOwl::Hook->new;
 our $receiveMessage = BarnOwl::Hook->new;
+our $newMessage = BarnOwl::Hook->new;
 our $mainLoop = BarnOwl::Hook->new;
 our $getBuddyList = BarnOwl::Hook->new;
@@ -713,5 +851,8 @@
         package main;
         do $BarnOwl::configfile;
-        die $@ if $@;
+        if($@) {
+            BarnOwl::error("In startup: $@\n");
+            return;
+        }
         package BarnOwl;
         if(*BarnOwl::format_msg{CODE}) {
@@ -761,4 +902,12 @@
     
     BarnOwl::receive_msg($m) if *BarnOwl::receive_msg{CODE};
+}
+
+sub _new_msg {
+    my $m = shift;
+
+    $newMessage->run($m);
+    
+    BarnOwl::new_msg($m) if *BarnOwl::new_msg{CODE};
 }
 
Index: kversion
===================================================================
--- svkversion	(revision 51f45d1f78677b5a52249457f10ef0021ee46220)
+++ 	(revision )
@@ -1,40 +1,0 @@
-#!/usr/bin/perl
-
-use strict;
-use warnings;
-
-if (-e ".svn") {
-    exec("svnversion",@ARGV);
-}
-
-use Getopt::Long;
-my $no_newline = 0;
-GetOptions("no-newline|n!" => \$no_newline);
-my $newline = $no_newline ? "" : "\n";
-my $p = shift @ARGV;
-$p ||= ".";
-
-my @lines = `svk info $p 2>&1`;
-if($! || $lines[0] =~ "not a checkout path") {
-    print "exported$newline";
-    exit;
-}
-my @merged = grep {/^Merged From: /} @lines;
-
-unless (@merged) {
-    @merged = grep {/^Revision: /} @lines;
-    my ($version) = $merged[0] =~ /^Revision: (\d+)/;
-    print "$version$newline";
-    exit;
-}
-
-my ($path, $rev) = $merged[0] =~ /^Merged From: (\S+), Rev. (\d+)/;
-
-my @log = `svk log -l1 -r$rev /$path`;
-@log = grep {/\(orig r\d+\)/} @log;
-
-if (@log and $log[0] =~ /\(orig r(\d+)\)/) {
-    print "$1$newline";
-} else {
-    print "$rev$newline";
-}
Index: util.c
===================================================================
--- util.c	(revision af1920fd98d8d860245a197dee998e0e5c337285)
+++ util.c	(revision 601733df0126729fcd095240a5ef18b057830617)
@@ -498,5 +498,5 @@
     return(c);
   }
-  return(-1);
+  return(OWL_COLOR_INVALID);
 }
 
Index: variable.c
===================================================================
--- variable.c	(revision 52f8dd6f954e971462a0a3fedc3550d1d0060e91)
+++ variable.c	(revision 451db9e0515b2671c88e0858f712b53a7fcc5b76)
@@ -84,5 +84,5 @@
 
   OWLVAR_BOOL( "sepbar_disable" /* %OwlVarStub */, 0,
-	       "disable printing information in the seperator bar", "" ),
+	       "disable printing information in the separator bar", "" ),
 
   OWLVAR_BOOL( "smartstrip" /* %OwlVarStub */, 1,
@@ -142,5 +142,5 @@
 		    "location of users in your .anyone file.  If a user is present\n"
 		    "but sent no login message, or a user is not present that sent no\n"
-		    "logout message a pseudo login or logout message wil be created\n",
+		    "logout message, a pseudo login or logout message wil be created\n",
 		    NULL, owl_variable_pseudologins_set, NULL),
 
@@ -177,10 +177,4 @@
 		    "off,middle,on",
 		    NULL, owl_variable_disable_ctrl_d_set, NULL),
-
-  OWLVAR_BOOL( "_burningears" /* %OwlVarStub:burningears */, 0,
-	       "[NOT YET IMPLEMENTED] beep on messages matching patterns", "" ),
-
-  OWLVAR_BOOL( "_summarymode" /* %OwlVarStub:summarymode */, 0,
-	       "[NOT YET IMPLEMENTED]", "" ),
 
   OWLVAR_PATH( "logpath" /* %OwlVarStub */, "~/zlog/people",
@@ -318,4 +312,14 @@
 		   NULL /* use default for get */
 		   ),
+
+  OWLVAR_INT( "typewindelta" /* %OwlVarStub */, 0,
+		  "number of lines to add to the typing window when in use",
+		   "On small screens you may want the typing window to\n"
+		   "auto-hide when not entering a command or message.\n"
+		   "This variable is the number of lines to add to the\n"
+           "typing window when it is in use; you can then set\n"
+           "typewinsize to 1.\n\n"
+           "This works a lot better with a non-default scrollmode;\n"
+           "try :set scrollmode pagedcenter.\n"),
 
   OWLVAR_ENUM( "scrollmode" /* %OwlVarStub */, OWL_SCROLLMODE_NORMAL,
Index: zephyr.c
===================================================================
--- zephyr.c	(revision 02f55dc6289d95812ed9f7661858d5533a0a251d)
+++ zephyr.c	(revision 451db9e0515b2671c88e0858f712b53a7fcc5b76)
@@ -806,5 +806,5 @@
   if (numlocs==0) {
     myuser=short_zuser(user);
-    sprintf(out, "%s: Hidden or not logged-in\n", myuser);
+    sprintf(out, "%s: Hidden or not logged in\n", myuser);
     owl_free(myuser);
     return;
@@ -1008,6 +1008,7 @@
 #ifdef HAVE_LIBZEPHYR
   int ret, num, i, one;
+  int buffsize;
   ZSubscription_t sub;
-  char *out, *tmpbuff;
+  char *out;
   one=1;
 
@@ -1015,25 +1016,40 @@
   if (ret==ZERR_TOOMANYSUBS) {
     return(owl_strdup("Zephyr: too many subscriptions\n"));
-  } else if (ret) {
+  } else if (ret || (num <= 0)) {
     return(owl_strdup("Zephyr: error retriving subscriptions\n"));
   }
 
-  out=owl_malloc(num*500);
-  tmpbuff=owl_malloc(num*500);
+  buffsize = (num + 1) * 50;
+  out=owl_malloc(buffsize);
   strcpy(out, "");
   for (i=0; i<num; i++) {
     if ((ret = ZGetSubscriptions(&sub, &one)) != ZERR_NONE) {
       owl_free(out);
-      owl_free(tmpbuff);
       ZFlushSubscriptions();
       out=owl_strdup("Error while getting subscriptions\n");
       return(out);
     } else {
-      sprintf(tmpbuff, "<%s,%s,%s>\n%s", sub.zsub_class, sub.zsub_classinst, sub.zsub_recipient, out);
+      int tmpbufflen;
+      char *tmpbuff;
+      tmpbuff = owl_sprintf("<%s,%s,%s>\n%s", sub.zsub_class, sub.zsub_classinst, sub.zsub_recipient, out);
+      tmpbufflen = strlen(tmpbuff) + 1;
+      if (tmpbufflen > buffsize) {
+        char *out2;
+        buffsize = tmpbufflen * 2;
+        out2 = owl_realloc(out, buffsize);
+        if (out2 == NULL) {
+          owl_free(out);
+          owl_free(tmpbuff);
+          ZFlushSubscriptions();
+          out=owl_strdup("Realloc error while getting subscriptions\n");
+          return(out);    
+        }
+        out = out2;
+      }
       strcpy(out, tmpbuff);
-    }
-  }
-
-  owl_free(tmpbuff);
+      owl_free(tmpbuff);
+    }
+  }
+
   ZFlushSubscriptions();
   return(out);
Index: zwrite.c
===================================================================
--- zwrite.c	(revision 7b1d048f7f97c017e859a6805cd148da213a3bc3)
+++ zwrite.c	(revision 3f3ee611e4b4ff9de1453aa609918c0099936019)
@@ -11,6 +11,4 @@
   int argc, badargs, myargc;
   char **argv, **myargv;
-  char *zsigproc, *zsigowlvar, *zsigzvar, *ptr;
-  struct passwd *pw;
 
   badargs=0;
@@ -139,4 +137,12 @@
   /* z->message is allowed to stay NULL */
   
+  return(0);
+}
+
+void owl_zwrite_populate_zsig(owl_zwrite *z)
+{
+  char *zsigproc, *zsigowlvar, *zsigzvar, *ptr;
+  struct passwd *pw;
+
   /* get a zsig, if not given */
   if (z->zsig==NULL) {
@@ -184,6 +190,4 @@
     }
   }
-
-  return(0);
 }
 
@@ -285,4 +289,5 @@
     owl_zwrite_set_message(&z, msg);
   }
+  owl_zwrite_populate_zsig(&z);
   owl_zwrite_send_message(&z);
   owl_zwrite_free(&z);
@@ -358,5 +363,5 @@
   return(0);
 }
-  
+
 void owl_zwrite_free(owl_zwrite *z)
 {
