Index: Makefile.am
===================================================================
--- Makefile.am	(revision ae333f0f83ce6468975a0f6261b21866eab1389a)
+++ Makefile.am	(revision c45e1eb9376a28e40375388e3b11847bf9ea6620)
@@ -1,3 +1,4 @@
 ACLOCAL_AMFLAGS = -I m4
+CFLAGS += $(EXTRA_CFLAGS)
 
 GIT_DESCRIPTION := $(if $(wildcard .git),$(shell git describe --match='barnowl-*' HEAD 2>/dev/null))
@@ -48,5 +49,5 @@
      keypress.c keymap.c keybinding.c cmd.c context.c \
      aim.c buddy.c buddylist.c style.c errqueue.c \
-     zbuddylist.c popexec.c obarray.c select.c wcwidth.c \
+     zbuddylist.c popexec.c select.c wcwidth.c \
      glib_compat.c filterproc.c
 
Index: commands.c
===================================================================
--- commands.c	(revision 8a5b5a12327c205b798d00f5cc5505f787e55331)
+++ commands.c	(revision d544237f77a88ded81cbe50b88544589a3e918f1)
@@ -92,6 +92,7 @@
 	      "Use 'show keymaps' to see the existing keymaps.\n"
 	      "Key sequences may be things like M-C-t or NPAGE.\n\n"
-	      "Ex.: bindkey recv C-b command zwrite -c barnowl"
-              "SEE ALSO: bindkey"),
+	      "Ex.: bindkey recv C-b command zwrite -c barnowl\n"
+              "Ex.: bindkey recv m command start-command zwrite -c my-class -i \n\n"
+              "SEE ALSO: unbindkey, start-command"),
 
   OWLCMD_ARGS("unbindkey", owl_command_unbindkey, OWL_CTX_ANY,
@@ -100,10 +101,10 @@
 	      "Removes a binding of a key sequence within a keymap.\n"
 	      "Use 'show keymaps' to see the existing keymaps.\n"
-	      "Ex.: unbindkey recv H"
+	      "Ex.: unbindkey recv H\n\n"
               "SEE ALSO: bindkey"),
 
   OWLCMD_ARGS("zwrite", owl_command_zwrite, OWL_CTX_INTERACTIVE,
 	      "send a zephyr",
-	      "zwrite [-n] [-C] [-c class] [-i instance] [-r realm] [-O opcde] [<user> ...] [-m <message...>]",
+	      "zwrite [-n] [-C] [-c class] [-i instance] [-r realm] [-O opcode] [<user> ...] [-m <message...>]",
 	      "Zwrite send a zephyr to the one or more users specified.\n\n"
 	      "The following options are available:\n\n"
@@ -137,5 +138,5 @@
   OWLCMD_ARGS("zcrypt", owl_command_zcrypt, OWL_CTX_INTERACTIVE,
 	      "send an encrypted zephyr",
-	      "zcrypt [-n] [-C] [-c class] [-i instance] [-r realm] [-O opcde] [-m <message...>]\n",
+	      "zcrypt [-n] [-C] [-c class] [-i instance] [-r realm] [-O opcode] [-m <message...>]\n",
 	      "Behaves like zwrite but uses encryption.  Not for use with\n"
 	      "personal messages\n"),
@@ -147,5 +148,5 @@
 	      "allow editing.\n\n"
 	      "If 'sender' is specified, reply to the sender.\n\n"
-	      "If 'all' or no args are specified, reply publically to the\n"
+	      "If 'all' or no args are specified, reply publicly to the\n"
 	      "same class/instance for non-personal messages and to the\n"
 	      "sender for personal messages.\n\n"
@@ -265,5 +266,5 @@
 	      "zpunt <class> <instance> [recipient]\n"
 	      "zpunt <instance>",
-	      "The zpunt command will supress message to the specified\n"
+	      "The zpunt command will suppress messages to the specified\n"
 	      "zephyr triplet.  In the second usage messages are suppressed\n"
 	      "for class MESSAGE and the named instance.\n\n"
@@ -282,5 +283,5 @@
 	      "punt <filter-text>",
 	      "punt <filter-text (multiple words)>\n"
-	      "The punt command will supress message to the specified\n"
+	      "The punt command will suppress messages to the specified\n"
 	      "filter\n\n"
 	      "SEE ALSO:  unpunt, zpunt, show zpunts\n"),
@@ -585,5 +586,5 @@
               "name style after the -s argument.\n"
 	      "\n"
-	      "The other usages listed above are abbreivated forms that simply set\n"
+	      "The other usages listed above are abbreviated forms that simply set\n"
 	      "the filter of the current view. The -d option allows you to write a\n"
               "filter expression that will be dynamically created by owl and then\n"
@@ -593,5 +594,5 @@
   OWLCMD_ARGS("smartnarrow", owl_command_smartnarrow, OWL_CTX_INTERACTIVE,
 	      "view only messages similar to the current message",
-	      "smartnarrow [-i | --instance]  [-r | --relatde]",
+	      "smartnarrow [-i | --instance]  [-r | --related]",
 	      "If the curmsg is a personal message narrow\n"
 	      "   to the conversation with that user.\n"
@@ -613,5 +614,5 @@
 	      "   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"
+	      "If the curmsg is a class message and '-i' is specified\n"
 	      "    the filter is to that class and instance.\n"),
 
@@ -633,4 +634,6 @@
 	      "SEE ALSO: filter, view, viewclass\n"),
   OWLCMD_ALIAS("vu", "viewuser"),
+  OWLCMD_ALIAS("viewperson", "viewuser"),
+  OWLCMD_ALIAS("vp", "viewuser"),
 
   OWLCMD_ARGS("show", owl_command_show, OWL_CTX_INTERACTIVE,
@@ -671,5 +674,5 @@
 	      "for formatting messages.\n\n"
 	      "Show variables will list the names of all variables.\n\n"
-	      "Show errors will show a list of errors ecountered by Owl.\n\n"
+	      "Show errors will show a list of errors encountered by Owl.\n\n"
 	      "SEE ALSO: filter, view, alias, bindkey, help\n"),
   
@@ -740,5 +743,5 @@
 	      "set the search highlight string without searching",
 	      "setsearch <string>",
-	      "The setsearch command highlights all occurences of its\n"
+	      "The setsearch command highlights all occurrences of its\n"
           "argument and makes it the default argument for future\n"
           "search commands, but does not move the cursor.  With\n"
@@ -1292,14 +1295,16 @@
   char opt;
   int instance = 0, related = 0, i;
-  char **tmp_argv = owl_malloc(sizeof(char *) * argc);
+  const char **tmp_argv = owl_malloc(sizeof(char *) * argc);
 
   for (i = 0; i < argc; i++)
-    tmp_argv[i] = owl_strdup(argv[i]);
-
-  static struct option options[] = {
+    tmp_argv[i] = argv[i];
+
+  static const struct option options[] = {
     {"instance", 0, 0, 'i'},
     {"related",  0, 0, 'r'},
     {NULL,       0, 0, 0}};
-  while ((opt = getopt_long(argc, tmp_argv, "ir", options, NULL)) != -1) {
+
+  optind = 0;
+  while ((opt = getopt_long(argc, (char **)tmp_argv, "ir", options, NULL)) != -1) {
     switch (opt) {
       case 'i':
@@ -1315,8 +1320,4 @@
   }
 
-  for (i = 0; i < argc; i++)
-    owl_free(tmp_argv[i]);
-  owl_free(tmp_argv);
-
   filtname = owl_function_smartfilter(instance, related);
 
@@ -1327,5 +1328,6 @@
 
 done:
-  optind = 0; /* reset getopt */
+  owl_free(tmp_argv);
+
   return NULL;
 }
@@ -1606,30 +1608,30 @@
 char *owl_command_exec(int argc, const char *const *argv, const char *buff)
 {
-  return owl_function_exec(argc, argv, buff, 0);
+  return owl_function_exec(argc, argv, buff, OWL_OUTPUT_RETURN);
 }
 
 char *owl_command_pexec(int argc, const char *const *argv, const char *buff)
 {
-  return owl_function_exec(argc, argv, buff, 1);
+  return owl_function_exec(argc, argv, buff, OWL_OUTPUT_POPUP);
 }
 
 char *owl_command_aexec(int argc, const char *const *argv, const char *buff)
 {
-  return owl_function_exec(argc, argv, buff, 2);
+  return owl_function_exec(argc, argv, buff, OWL_OUTPUT_ADMINMSG);
 }
 
 char *owl_command_perl(int argc, const char *const *argv, const char *buff)
 {
-  return owl_function_perl(argc, argv, buff, 0);
+  return owl_function_perl(argc, argv, buff, OWL_OUTPUT_RETURN);
 }
 
 char *owl_command_pperl(int argc, const char *const *argv, const char *buff)
 {
-  return owl_function_perl(argc, argv, buff, 1);
+  return owl_function_perl(argc, argv, buff, OWL_OUTPUT_POPUP);
 }
 
 char *owl_command_aperl(int argc, const char *const *argv, const char *buff)
 {
-  return owl_function_perl(argc, argv, buff, 2);
+  return owl_function_perl(argc, argv, buff, OWL_OUTPUT_ADMINMSG);
 }
 
Index: configure.ac
===================================================================
--- configure.ac	(revision 07f655b20b5524bbf5480ab80f4e08e69f6281ab)
+++ configure.ac	(revision 263320f0be9d4016164837d2de7310b687a6f076)
@@ -64,5 +64,6 @@
    ])])
 
-AC_CHECK_FUNCS([use_default_colors resizeterm])
+AC_CHECK_FUNCS([use_default_colors])
+AC_CHECK_FUNCS([resizeterm], [], [AC_MSG_ERROR([No resizeterm found])])
 AC_CHECK_FUNCS([des_string_to_key DES_string_to_key], [HAVE_DES_STRING_TO_KEY=1])
 AC_CHECK_FUNCS([des_ecb_encrypt DES_ecb_encrypt], [HAVE_DES_ECB_ENCRYPT=1])
Index: doc/releasing-barnowl.txt
===================================================================
--- doc/releasing-barnowl.txt	(revision 1ea0249f36575e3bee628ddba71ed6ebab247f03)
+++ doc/releasing-barnowl.txt	(revision 5f08dbedc485ad82e84f7efcf1575e67ba819c76)
@@ -1,79 +1,68 @@
-DOING A BARNOWL RELEASE
+-*- mode: org *-
+* DOING A BARNOWL RELEASE
+  - [ ] Send mail to barnowl-dev indicating that a release is
+        happening soon, and soliciting any improvements that
+        developers want included in the release.
+  - [ ] Wait a while (a week or so, or more if necessary) for any
+        pending patches to get in.
+  - [ ] Prepare the -rc commit
+   - [ ] Run ./scripts/add-changelog NEW-VERSION PREV-TAG..HEAD
+   - [ ] Edit ChangeLog to combine and filter entries
+   - [ ] Edit configure.ac to bump the version to 1.Nrc1
+  - [ ] Commit with message 'BarnOwl 1.Nrc1'; don't push until after
+        builds all succeed
+  - [ ] Run scripts/do-release with -f (so it won't complain about
+        missing changelog), makes a tarball
+  - [ ] Do a locker build (See DOING A LOCKER BUILD)
+  - [ ] Update configure.ac on master to bump the version to 1.(N+1)dev
+  - [ ] Push git git:
+   - [ ] The RC commit
+   - [ ] The configure.ac change on master
+   - [ ] A release-1.N branch pointing at the RC commit
+  - [ ] Copy tarball into /mit/barnowl/web_scripts/dist
+  - [ ] Send mail announcing the RC to barnowl-dev@mit.edu
+  - [ ] Wait 1-2 weeks, collect any bug reports
+  - [ ] Fix any reported bugs on master
+  - [ ] Cherry-pick/backport appropriate fixes from master onto
+        release-1.N
+  - [ ] If there have been many or large bugfixes, repeat the process
+        for barnowl 1.Nrc2
 
-[ ] Send mail to barnowl-dev indicating that a release is happening
-    soon, and soliciting any improvements that developers want
-    included in the release.
+* DOING THE ACTUAL RELEASE
+  - [ ] Update the changelog and configure.ac for barnowl 1.N
+  - [ ] run ./scripts/do-release
+  - [ ] Do the locker build
+  - [ ] Push the release tag
+  - [ ] Write up release notes
+        (I usually use the previous release's email as a template)
+  - [ ] Update the website
+   - [ ] Add the line that `do-release` printed to the changelog on the home page
+   - [ ] Add your release notes as /release-notes/1.N
+  - [ ] Send the release notes to barnowl-users@mit.edu
 
-[ ] Wait a while (a week or so, or more if necessary) for any pending
-    patches to get in.
+* DOING A LOCKER BUILD
+  - [ ] Copy the tarball to build@nelhage.com
+  - [ ] ssh to build@nelhage.com and kinit
+  - [ ] On build@nelhage.com, run barnowl-build-all TARBALL.
+        This script does builds for all Debathena platforms using chroots
+        on nelhage.com, and ssh's to Athena 9 machines to do the two
+        Athena 9 builds.
+  - [ ] Sanity-check the builds
+   - [ ] Do cursory testing on debathena platforms and both athena9s.
+   - [ ] chroots on nelhage.com also useful
+  - [ ] Update symlinks with locker-update script;
+        - locker-update [-b] [-n] VERSION
+        - e.g. locker-update -b -n barnowl-1.6rc1
+   - [ ] Use -b to update the barnowl-beta name
+   - [ ] Use -n first for dry-run
 
-[ ] Prepare the -rc commit
-
- [ ] Run ./scripts/add-changelog NEW-VERSION PREV-TAG..HEAD
-
- [ ] Edit ChangeLog to combine and filter entries
-
- [ ] Edit configure.ac to bump the version to 1.Nrc1
-
-[ ] Commit with message 'BarnOwl 1.Nrc1'; don't push until after
-    builds all succeed
-
-[ ] Run scripts/do-release with -f (so it won't complain about missing
-    changelog), makes a tarball
-
-[ ] Make all the builds
- 
- [ ] On build@nelhage.com, run barnowl-build-all TARBALL to build for
-     everything with chroots, doesn't do athena 9 builds. Builds into
-     locker parellel to all other versions.
-
- [ ] Do two athena9 builds: solaris and linux, usually use multics (or
-     sun.dialup) for the solaris build, oliver for linux athena9
-
-  [ ] Remember to add gnu; add barnowl
-
-  [ ] eval `barnowl-perl-config` to include the perl modules in the
-      barnowl locker
-
-  [ ] Run scripts/locker-build TARBALL (barnowl-build-all loops over
-      all of them in schroots). It overrides existing one.
-
-[ ] Sanity-check the builds
-
- [ ] Do cursory testing on debathena platforms and both athena9s.
-
- [ ] chroots on nelhage.com also useful
-
-[ ] Update symlinks with locker-update script;
-
-      locker-update [-b] [-n] VERSION
-
-    e.g. locker-update -b -n barnowl-1.6rc1
- 
- [ ] -b for the beta
-
- [ ] -n first for dry-run
-
-[ ] Push the RC commit
-
-[ ] Copy tarball into /mit/barnowl/web_scripts/dist
-
-[ ] Send mail (rcs to barnowl-dev@, release to barnowl-users@)
-
-[ ] Make an actual release about a week after the RC
-
-
-LOCKER LAYOUT
-
-* builds/barnowl-VERSION contains the arch-independent files by
-  version
-
-* arch/SYSNAME/bin/barnowl-VERSION is the actual binary
-
-* arch/SYSNAME/bin/barnowl is a symlink to ../../common/bin/barnowl
-  (wrapper script runs barnowl.real). .../barnowl.real is a symlink to
-  the latest version.
-
-* zcrypt is also installed with a versioned name, but currently
-  barnowl-N will not run zcrypt-N, so we can't change that interface
-  at all.
+* LOCKER LAYOUT
+  - builds/barnowl-VERSION contains the arch-independent files by
+    version
+  - arch/SYSNAME/bin/barnowl-VERSION is the actual binary
+  - arch/SYSNAME/bin/barnowl is a symlink to ../../common/bin/barnowl
+    (wrapper script runs barnowl.real). .../barnowl.real is a symlink
+    to the latest version.
+  - zcrypt is also installed with a versioned name, but currently
+    barnowl-N will not run zcrypt-N, so we can't change that interface
+    at all.
Index: editwin.c
===================================================================
--- editwin.c	(revision 6e58ff2a099509b2521982936764e24b43331f33)
+++ editwin.c	(revision 9d7a7205d6c9cbea0e8999e4c350440f8ef5fef8)
@@ -47,7 +47,7 @@
 static int oe_char_width(gunichar c, int column);
 static int oe_region_width(owl_editwin *e, int start, int end, int width);
-static int oe_find_display_line(owl_editwin *e, int *x, int index);
+static int oe_find_display_line(owl_editwin *e, int *x, int index, int *hard);
 static void oe_insert_char(owl_editwin *e, gunichar c);
-static int owl_editwin_limit_maxcols(int v, int maxv);
+static int owl_editwin_limit_maxcols(int width, int cols);
 static int owl_editwin_check_dotsend(owl_editwin *e);
 static int owl_editwin_is_char_in(owl_editwin *e, const char *set);
@@ -125,5 +125,4 @@
   e->topindex = 0;
   e->excursions = NULL;
-  owl_editwin_set_curswin(e, win, winlines, wincols);
   e->style=style;
   if ((style!=OWL_EDITWIN_STYLE_MULTILINE) &&
@@ -131,4 +130,5 @@
     e->style=OWL_EDITWIN_STYLE_MULTILINE;
   }
+  owl_editwin_set_curswin(e, win, winlines, wincols);
   e->lock=0;
   e->dotsend=0;
@@ -152,5 +152,8 @@
   e->wincols=wincols;
   e->fillcol=owl_editwin_limit_maxcols(wincols-7, owl_global_get_edit_maxfillcols(&g));
-  e->wrapcol=owl_editwin_limit_maxcols(wincols-7, owl_global_get_edit_maxwrapcols(&g));
+  if (e->style == OWL_EDITWIN_STYLE_MULTILINE)
+    e->wrapcol=owl_editwin_limit_maxcols(wincols-7, owl_global_get_edit_maxwrapcols(&g));
+  else
+    e->wrapcol = 0;
 }
 
@@ -218,12 +221,9 @@
 }
 
-static int owl_editwin_limit_maxcols(int v, int maxv)
-{
-  /* maxv > 5 ? MAX(v, vax) : v */
-  if (maxv > 5 && v > maxv) {
-    return(maxv);
-  } else {
-    return(v);
-  }
+static int owl_editwin_limit_maxcols(int width, int cols)
+{
+  if (cols == 0)
+    return width;
+  return cols;
 }
 
@@ -388,5 +388,5 @@
 }
 
-static int oe_find_display_line(owl_editwin *e, int *x, int index)
+static int oe_find_display_line(owl_editwin *e, int *x, int index, int *hard)
 {
   int width = 0, cw;
@@ -405,7 +405,8 @@
     cw = oe_char_width(c, width);
 
-    if (width + cw > e->wincols) {
+    if (width + cw > e->wincols - 1) {
       if (x != NULL && *x == width)
 	*x = -1;
+      if (hard != NULL) *hard = 0;
       break;
     }
@@ -415,4 +416,5 @@
       if (width < e->wincols)
 	++index; /* skip the newline */
+      if (hard != NULL) *hard = 1;
       break;
     }
@@ -423,4 +425,5 @@
       if (x != NULL && e->index > index)
 	*x = width + 1;
+      if (hard != NULL) *hard = 1;
       break;
     }
@@ -452,5 +455,5 @@
     last = e->index;
     for (n = 0, i = e->index; i < index; n++)
-      i = oe_find_display_line(e, NULL, i);
+      i = oe_find_display_line(e, NULL, i, NULL);
     count += n == 0 ? 1 : n;
     if (count < goal)
@@ -461,5 +464,5 @@
   /* if we overshot, backtrack */
   for (n = 0; n < (count - goal); n++)
-    e->topindex = oe_find_display_line(e, NULL, e->topindex);
+    e->topindex = oe_find_display_line(e, NULL, e->topindex, NULL);
 
   oe_restore_excursion(e, &x);
@@ -483,5 +486,5 @@
 void owl_editwin_redisplay(owl_editwin *e)
 {
-  int x = -1, y = -1, t;
+  int x = -1, y = -1, t, hard;
   int line, index, lineindex, times = 0;
 
@@ -497,5 +500,5 @@
       lineindex = index;
       t = -1;
-      index = oe_find_display_line(e, &t, lineindex);
+      index = oe_find_display_line(e, &t, lineindex, &hard);
       if (x == -1 && t != -1)
 	x = t, y = line;
@@ -516,6 +519,8 @@
 					oe_region_width(e, lineindex, e->lock, 0)));
 	  } else
-	    oe_mvaddnec(e, line, 0, oe_region_width(e, line, index, 0));
+	    oe_mvaddnec(e, line, 0, oe_region_width(e, lineindex, index, 0));
 	}
+        if (!hard)
+          waddch(e->curswin, '\\');
       }
       line++;
@@ -1096,4 +1101,8 @@
   int sentence;
 
+  if (e->fillcol < 0)
+    /* auto-fill disabled */
+    return;
+
   oe_save_excursion(e, &x);
 
@@ -1232,5 +1241,6 @@
     }
 
-    if (e->cursorx != -1 && e->cursorx + oe_char_width(c, e->cursorx) > e->wrapcol) {
+    if (e->wrapcol > 0 && e->cursorx != -1 &&
+        e->cursorx + oe_char_width(c, e->cursorx) > e->wrapcol) {
       /* XXX this is actually wrong:
        * + If the line has been been wrapped, we can be past the wrap column but
Index: functions.c
===================================================================
--- functions.c	(revision 1cfcab729ebc4dd79d260e510e75b35572c3c5c5)
+++ functions.c	(revision 2cfc6d7937fafd2aa67f247fa4de3ef41aba1783)
@@ -1264,11 +1264,8 @@
 void owl_function_full_redisplay(void)
 {
-  redrawwin(owl_global_get_curs_recwin(&g));
-  redrawwin(owl_global_get_curs_sepwin(&g));
-  /* Work around curses segfualts with windows off the screen */
-  if (g.lines >= owl_global_get_typwin_lines(&g)+2)
-      redrawwin(owl_global_get_curs_typwin(&g));
-  if (g.lines >= 2)
-      redrawwin(owl_global_get_curs_msgwin(&g));
+  touchwin(owl_global_get_curs_recwin(&g));
+  touchwin(owl_global_get_curs_sepwin(&g));
+  touchwin(owl_global_get_curs_typwin(&g));
+  touchwin(owl_global_get_curs_msgwin(&g));
 
   sepbar("");
@@ -1575,5 +1572,5 @@
 {
   owl_global_set_typwin_lines(&g, newsize);
-  owl_function_resize();
+  owl_global_set_relayout_pending(&g);
 }
 
@@ -1995,5 +1992,5 @@
   newbuff = owl_sprintf("%s%s", buff, redirect);
 
-  if (type == 1) {
+  if (type == OWL_OUTPUT_POPUP) {
     owl_popexec_new(newbuff);
   } else {
@@ -2002,13 +1999,9 @@
     pclose(p);
     
-    if (type==1) {
-      owl_function_popless_text(out);
-    } else if (type==0) {
+    if (type == OWL_OUTPUT_RETURN) {
       owl_free(newbuff);
       return out;
-    } else if (type==2) {
+    } else if (type == OWL_OUTPUT_ADMINMSG) {
       owl_function_adminmsg(buff, out);
-    } else {
-      owl_function_popless_text(out);
     }
     owl_free(out);
@@ -2037,12 +2030,10 @@
   perlout = owl_perlconfig_execute(buff);
   if (perlout) { 
-    if (type==1) {
+    if (type == OWL_OUTPUT_POPUP) {
       owl_function_popless_text(perlout);
-    } else if (type==2) {
+    } else if (type == OWL_OUTPUT_ADMINMSG) {
       owl_function_adminmsg(buff, perlout);
-    } else if (type==0) {
+    } else if (type == OWL_OUTPUT_RETURN) {
       return perlout;
-    } else {
-      owl_function_popless_text(perlout);
     }
     owl_free(perlout);
@@ -2334,5 +2325,5 @@
   /* if it already exists then go with it.  This lets users override */
   if (owl_global_get_filter(&g, filtname)) {
-    return(filtname);
+    goto done;
   }
 
@@ -2364,4 +2355,5 @@
 
   owl_free(argbuff);
+done:
   owl_free(class);
   if (instance) {
@@ -2392,5 +2384,5 @@
   /* if it already exists then go with it.  This lets users override */
   if (owl_global_get_filter(&g, filtname)) {
-    return(owl_strdup(filtname));
+    return filtname;
   }
 
@@ -2507,4 +2499,32 @@
 
   owl_mainwin_redisplay(owl_global_get_mainwin(&g));  
+}
+
+static char *owl_function_smartfilter_cc(const owl_message *m) {
+  const char *ccs;
+  char *filtname;
+  char *text;
+  owl_filter *f;
+
+  ccs = owl_message_get_attribute_value(m, "zephyr_ccs");
+
+  filtname = owl_sprintf("conversation-%s", ccs);
+  owl_text_tr(filtname, ' ', '-');
+
+  if (owl_global_get_filter(&g, filtname)) {
+    return filtname;
+  }
+
+  text = owl_sprintf("type ^zephyr$ and filter personal and "
+                     "zephyr_ccs ^%s%s%s$",
+                     owl_getquoting(ccs), ccs, owl_getquoting(ccs));
+
+  f = owl_filter_new_fromstring(filtname, text);
+
+  owl_global_add_filter(&g, f);
+
+  owl_free(text);
+
+  return filtname;
 }
 
@@ -2562,4 +2582,8 @@
   if (owl_message_is_type_zephyr(m)) {
     if (owl_message_is_personal(m) || owl_message_is_loginout(m)) {
+      if (owl_message_get_attribute_value(m, "zephyr_ccs") != NULL) {
+        return owl_function_smartfilter_cc(m);
+      }
+
       if (owl_message_is_direction_in(m)) {
         zperson=short_zuser(owl_message_get_sender(m));
Index: global.c
===================================================================
--- global.c	(revision 8479494366381666e80a4b5294b72de5af244cb1)
+++ global.c	(revision 20aced312921e75d69f84133af763117bac62675)
@@ -53,8 +53,9 @@
   g->filterlist = NULL;
   owl_list_create(&(g->puntlist));
-  owl_list_create(&(g->messagequeue));
+  g->messagequeue = g_queue_new();
   owl_dict_create(&(g->styledict));
   g->curmsg_vert_offset=0;
   g->resizepending=0;
+  g->relayoutpending = 0;
   g->direction=OWL_DIRECTION_DOWNWARDS;
   g->zaway=0;
@@ -112,6 +113,4 @@
   g->pseudologin_notify = 0;
 
-  owl_obarray_init(&(g->obarray));
-
   owl_message_init_fmtext_cache();
   owl_list_create(&(g->io_dispatch_list));
@@ -119,4 +118,10 @@
   g->timerlist = NULL;
   g->interrupted = FALSE;
+
+  /* set up a pad for input */
+  g->input_pad = newpad(1, 1);
+  nodelay(g->input_pad, 1);
+  keypad(g->input_pad, 1);
+  meta(g->input_pad, 1);
 }
 
@@ -137,5 +142,5 @@
 
   if (win == NULL) {
-    owl_function_debugmsg("_owl_panel_set_window: passed NULL win (failed to allocate?)\n");
+    owl_function_debugmsg("_owl_panel_set_window: passed NULL win (failed to allocate?)");
     endwin();
     exit(50);
@@ -164,6 +169,4 @@
   }
 
-  owl_function_debugmsg("_owl_global_setup_windows: about to call newwin(%i, %i, 0, 0)\n", g->recwinlines, cols);
-
   /* create the new windows */
   _owl_panel_set_window(&g->recpan, newwin(g->recwinlines, cols, 0, 0));
@@ -180,9 +183,5 @@
   idlok(owl_global_get_curs_msgwin(g), FALSE);
 
-  nodelay(owl_global_get_curs_typwin(g), 1);
-  keypad(owl_global_get_curs_typwin(g), TRUE);
   wmove(owl_global_get_curs_typwin(g), 0, 0);
-
-  meta(owl_global_get_curs_typwin(g), TRUE);
 }
 
@@ -394,4 +393,8 @@
 }
 
+void owl_global_set_relayout_pending(owl_global *g) {
+  g->relayoutpending = 1;
+}
+
 const char *owl_global_get_homedir(const owl_global *g) {
   if (g->homedir) return(g->homedir);
@@ -467,40 +470,52 @@
 }
 
+/*
+ * Compute the size of the terminal. Try a ioctl, fallback to other stuff on
+ * fail.
+ */
+static void _owl_global_get_size(int *lines, int *cols) {
+  struct winsize size;
+  /* get the new size */
+  ioctl(STDIN_FILENO, TIOCGWINSZ, &size);
+  if (size.ws_row) {
+    *lines = size.ws_row;
+  } else {
+    *lines = LINES;
+  }
+
+  if (size.ws_col) {
+    *cols = size.ws_col;
+  } else {
+    *cols = COLS;
+  }
+}
+
 void owl_global_resize(owl_global *g, int x, int y) {
   /* resize the screen.  If x or y is 0 use the terminal size */
-  struct winsize size;
-    
   if (!g->resizepending) return;
   g->resizepending = 0;
 
-  if (!isendwin()) {
-    endwin();
-  }
-
-  /* get the new size */
-  ioctl(STDIN_FILENO, TIOCGWINSZ, &size);
-  if (x==0) {
-    if (size.ws_row) {
-      g->lines=size.ws_row;
-    } else {
-      g->lines=LINES;
-    } 
-  } else {
-      g->lines=x;
-  }
-
-  if (y==0) {
-    if (size.ws_col) {
-      g->cols=size.ws_col;
-    } else {
-      g->cols=COLS;
-    } 
-  } else {
-    g->cols=y;
-  }
-
-#ifdef HAVE_RESIZETERM
-  resizeterm(size.ws_row, size.ws_col);
-#endif
+  _owl_global_get_size(&g->lines, &g->cols);
+  if (x != 0) {
+    g->lines = x;
+  }
+  if (y != 0) {
+    g->cols = y;
+  }
+
+  resizeterm(g->lines, g->cols);
+
+  owl_function_debugmsg("New size is %i lines, %i cols.", g->lines, g->cols);
+  owl_global_set_relayout_pending(g);
+}
+
+void owl_global_relayout(owl_global *g) {
+  owl_popwin *pw;
+  owl_viewwin *vw;
+
+  if (!g->relayoutpending) return;
+  g->relayoutpending = 0;
+
+  owl_function_debugmsg("Relayouting...");
 
   /* re-initialize the windows */
@@ -513,4 +528,20 @@
    * screen */
   owl_function_calculate_topmsg(OWL_DIRECTION_NONE);
+
+  /* recreate the popwin */
+  pw = owl_global_get_popwin(g);
+  if (owl_popwin_is_active(pw)) {
+    /*
+     * This is somewhat hacky; we probably want a proper windowing layer. We
+     * destroy the popwin and recreate it. Then the viewwin is redirected to
+     * the new window.
+     */
+    vw = owl_global_get_viewwin(g);
+    owl_popwin_close(pw);
+    owl_popwin_up(pw);
+    owl_viewwin_set_curswin(vw, owl_popwin_get_curswin(pw),
+	owl_popwin_get_lines(pw), owl_popwin_get_cols(pw));
+    owl_viewwin_redisplay(vw);
+  }
 
   /* refresh stuff */
@@ -525,5 +556,4 @@
   owl_function_full_redisplay();
 
-  owl_function_debugmsg("New size is %i lines, %i cols.", size.ws_row, size.ws_col);
   owl_function_makemsg("");
 }
@@ -832,5 +862,5 @@
 void owl_global_messagequeue_addmsg(owl_global *g, owl_message *m)
 {
-  owl_list_append_element(&(g->messagequeue), m);
+  g_queue_push_tail(g->messagequeue, m);
 }
 
@@ -843,14 +873,13 @@
   owl_message *out;
 
-  if (owl_list_get_size(&(g->messagequeue))==0) return(NULL);
-  out=owl_list_get_element(&(g->messagequeue), 0);
-  owl_list_remove_element(&(g->messagequeue), 0);
-  return(out);
+  if (g_queue_is_empty(g->messagequeue))
+    return NULL;
+  out = g_queue_pop_head(g->messagequeue);
+  return out;
 }
 
 int owl_global_messagequeue_pending(owl_global *g)
 {
-  if (owl_list_get_size(&(g->messagequeue))==0) return(0);
-  return(1);
+  return !g_queue_is_empty(g->messagequeue);
 }
 
@@ -980,9 +1009,4 @@
 }
 
-const char * owl_global_intern(owl_global *g, const char * string)
-{
-  return owl_obarray_insert(&(g->obarray), string);
-}
-
 owl_list *owl_global_get_io_dispatch_list(owl_global *g)
 {
Index: logging.c
===================================================================
--- logging.c	(revision 91634ec817b2d3dfda0c429002c8450e4f2404d5)
+++ logging.c	(revision 839697d886ff0c8987d4f6233e92a81a5157faed)
@@ -128,4 +128,5 @@
   char filename[MAXPATHLEN], *logpath;
   char *to, *temp;
+  GList *cc;
 
   /* expand ~ in path names */
@@ -135,15 +136,14 @@
   if (owl_message_is_type_zephyr(m)) {
     /* If this has CC's, do all but the "recipient" which we'll do below */
-    to = owl_message_get_cc_without_recipient(m);
-    if (to != NULL) {
-      temp = strtok(to, " ");
-      while (temp != NULL) {
-          temp = short_zuser(temp);
-          snprintf(filename, MAXPATHLEN, "%s/%s", logpath, temp);
-          owl_log_append(m, filename);
-          temp = strtok(NULL, " ");
-      }
-      owl_free(to);
-    }
+    cc = owl_message_get_cc_without_recipient(m);
+    while (cc != NULL) {
+      temp = short_zuser(cc->data);
+      snprintf(filename, MAXPATHLEN, "%s/%s", logpath, temp);
+      owl_log_append(m, filename);
+
+      owl_free(cc->data);
+      cc = g_list_delete_link(cc, cc);
+    }
+
     to = short_zuser(owl_message_get_recipient(m));
   } else if (owl_message_is_type_jabber(m)) {
@@ -325,17 +325,16 @@
      * the sender, as well.
      */
-    char *cc, *temp;
+    char *temp;
+    GList *cc;
     cc = owl_message_get_cc_without_recipient(m);
-    if (cc != NULL) {
-      temp = strtok(cc, " ");
-      while (temp != NULL) {
-        temp = short_zuser(temp);
-        if (strcasecmp(temp, frombuff) != 0) {
-          snprintf(filename, MAXPATHLEN, "%s/%s", logpath, temp);
-          owl_log_append(m, filename);
-        }
-        temp = strtok(NULL, " ");
+    while (cc != NULL) {
+      temp = short_zuser(cc->data);
+      if (strcasecmp(temp, frombuff) != 0) {
+        snprintf(filename, MAXPATHLEN, "%s/%s", logpath, temp);
+        owl_log_append(m, filename);
       }
-      owl_free(cc);
+
+      owl_free(cc->data);
+      cc = g_list_delete_link(cc, cc);
     }
   }
Index: message.c
===================================================================
--- message.c	(revision 9a7b4f23cba7fc71c4e918b5cb8d5ca6789924e3)
+++ message.c	(revision c314f397830b8cfa20a9540a606bad42845e7d9f)
@@ -61,9 +61,11 @@
   owl_pair *p = NULL, *pair = NULL;
 
+  attrname = g_intern_string(attrname);
+
   /* look for an existing pair with this key, */
   j=owl_list_get_size(&(m->attributes));
   for (i=0; i<j; i++) {
     p=owl_list_get_element(&(m->attributes), i);
-    if (!strcmp(owl_pair_get_key(p), attrname)) {
+    if (owl_pair_get_key(p) == attrname) {
       owl_free(owl_pair_get_value(p));
       pair = p;
@@ -74,5 +76,5 @@
   if(pair ==  NULL) {
     pair = owl_malloc(sizeof(owl_pair));
-    owl_pair_create(pair, owl_global_intern(&g, attrname), NULL);
+    owl_pair_create(pair, attrname, NULL);
     owl_list_append_element(&(m->attributes), pair);
   }
@@ -87,9 +89,16 @@
   int i, j;
   owl_pair *p;
+  GQuark quark;
+
+  quark = g_quark_try_string(attrname);
+  if (quark == 0)
+    /* don't bother inserting into string table */
+    return NULL;
+  attrname = g_quark_to_string(quark);
 
   j=owl_list_get_size(&(m->attributes));
   for (i=0; i<j; i++) {
     p=owl_list_get_element(&(m->attributes), i);
-    if (!strcmp(owl_pair_get_key(p), attrname)) {
+    if (owl_pair_get_key(p) == attrname) {
       return(owl_pair_get_value(p));
     }
@@ -496,5 +505,5 @@
 void owl_message_set_hostname(owl_message *m, const char *hostname)
 {
-  m->hostname=owl_global_intern(&g, hostname);
+  m->hostname = g_intern_string(hostname);
 }
 
@@ -584,8 +593,9 @@
 
 /* caller must free return value */
-char *owl_message_get_cc_without_recipient(const owl_message *m)
-{
-  char *cc, *out, *end, *shortuser, *recip;
+GList *owl_message_get_cc_without_recipient(const owl_message *m)
+{
+  char *cc, *shortuser, *recip;
   const char *user;
+  GList *out = NULL;
 
   cc = owl_message_get_cc(m);
@@ -594,6 +604,4 @@
 
   recip = short_zuser(owl_message_get_recipient(m));
-  out = owl_malloc(strlen(cc) + 2);
-  end = out;
 
   user = strtok(cc, " ");
@@ -601,20 +609,12 @@
     shortuser = short_zuser(user);
     if (strcasecmp(shortuser, recip) != 0) {
-      strcpy(end, user);
-      end[strlen(user)] = ' ';
-      end += strlen(user) + 1;
+      out = g_list_prepend(out, owl_strdup(user));
     }
     owl_free(shortuser);
     user = strtok(NULL, " ");
   }
-  end[0] = '\0';
 
   owl_free(recip);
   owl_free(cc);
-
-  if (strlen(out) == 0) {
-    owl_free(out);
-    out = NULL;
-  }
 
   return(out);
@@ -732,4 +732,39 @@
   owl_message_set_recipient(m, "looprecip");
   owl_message_set_isprivate(m);
+}
+
+void owl_message_save_ccs(owl_message *m) {
+  GList *cc;
+  char *tmp;
+
+  cc = owl_message_get_cc_without_recipient(m);
+
+  if (cc != NULL) {
+    GString *recips = g_string_new("");
+    cc = g_list_prepend(cc, short_zuser(owl_message_get_sender(m)));
+    cc = g_list_prepend(cc, short_zuser(owl_message_get_recipient(m)));
+    cc = g_list_sort(cc, (GCompareFunc)strcasecmp);
+
+    while(cc != NULL) {
+      /* Collapse any identical entries */
+      while (cc->next && strcasecmp(cc->data, cc->next->data) == 0) {
+        owl_free(cc->data);
+        cc = g_list_delete_link(cc, cc);
+      }
+
+      tmp = short_zuser(cc->data);
+      g_string_append(recips, tmp);
+
+      owl_free(tmp);
+      owl_free(cc->data);
+      cc = g_list_delete_link(cc, cc);
+
+      if (cc)
+        g_string_append_c(recips, ' ');
+    }
+
+    owl_message_set_attribute(m, "zephyr_ccs", recips->str);
+    g_string_free(recips, true);
+  }
 }
 
@@ -869,4 +904,6 @@
     }
   }
+
+  owl_message_save_ccs(m);
 }
 #else
@@ -963,4 +1000,6 @@
     owl_message_set_isprivate(m);
   }
+
+  owl_message_save_ccs(m);
 }
 
Index: array.c
===================================================================
--- obarray.c	(revision e9c6fc846b34351def7ebc5bf8e5c770d514cc14)
+++ 	(revision )
@@ -1,67 +1,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include "owl.h"
-
-/*
- * At the moment, the obarray is represented as a sorted list of
- * strings. I judge this a reasonable tradeoff between simplicity and
- * reasonable efficient lookup (insertion should be comparatively
- * rare)
- */
-
-/* Helper method: Lookup a key in the obarray. If the key exists,
- * return its index, and the interned value in *val. Otherwise, return
- * the index it should be inserted at.
- */
-static int owl_obarray_lookup(const owl_obarray *oa, const char *key, const char **val)
-{
-  int first, last, mid;
-  const char * str;
-  int cmp;
-
-  mid = 0;
-  first = 0;
-  last = owl_list_get_size(&(oa->strings)) - 1;
-  while(first <= last) {
-    mid = first + (last - first)/2;
-    str = owl_list_get_element(&(oa->strings), mid);
-    cmp = strcmp(key, str);
-    if(cmp == 0) {
-      *val = str;
-      return mid;
-    } else if(cmp < 0) {
-      first = mid + 1;
-    } else {
-      last = mid - 1;
-    }
-  }
-  *val = NULL;
-  return mid;
-}
-
-/* Returns NULL if the string doesn't exist in the obarray */
-const char * owl_obarray_find(const owl_obarray *oa, const char * string)
-{
-  const char *v;
-  owl_obarray_lookup(oa, string, &v);
-  return v;
-}
-
-/* Inserts the string into the obarray if it doesn't exist */
-const char * owl_obarray_insert(owl_obarray *oa, const char * string)
-{
-  const char *v;
-  int i;
-  i = owl_obarray_lookup(oa, string, &v);
-  if(!v) {
-    char *v2 = owl_strdup(string);
-    owl_list_insert_element(&(oa->strings), i, v2);
-    return v2;
-  }
-  return v;
-}
-
-void owl_obarray_init(owl_obarray *oa)
-{
-  owl_list_create(&(oa->strings));
-}
Index: owl.c
===================================================================
--- owl.c	(revision 1cfcab729ebc4dd79d260e510e75b35572c3c5c5)
+++ owl.c	(revision 3aa05226f2c729940957d231891ed429669e255f)
@@ -311,10 +311,7 @@
 {
   owl_input j;
-  WINDOW *typwin;
-
-  typwin = owl_global_get_curs_typwin(&g);
 
   while (1) {
-    j.ch = wgetch(typwin);
+    j.ch = wgetch(g.input_pad);
     if (j.ch == ERR) return;
 
@@ -339,5 +336,5 @@
       
       for (i = 1; i < bytes; i++) {
-        int tmp =  wgetch(typwin);
+        int tmp = wgetch(g.input_pad);
         /* If what we got was not a byte, or not a continuation byte */
         if (tmp > 0xff || !(tmp & 0x80 && ~tmp & 0x40)) {
@@ -458,10 +455,30 @@
 #endif /* OWL_STDERR_REDIR */
 
-void owl_zephyr_buddycheck_timer(owl_timer *t, void *data)
-{
-  if (owl_global_is_pseudologins(&g)) {
-    owl_function_debugmsg("Doing zephyr buddy check");
-    owl_function_zephyr_buddy_check(1);
-  }
+static int owl_refresh_pre_select_action(owl_ps_action *a, void *data)
+{
+  /* if a resize has been scheduled, deal with it */
+  owl_global_resize(&g, 0, 0);
+  /* also handle relayouts */
+  owl_global_relayout(&g);
+
+  /* update the terminal if we need to */
+  if (owl_global_is_needrefresh(&g)) {
+    /* these are here in case a relayout changes the windows */
+    WINDOW *sepwin = owl_global_get_curs_sepwin(&g);
+    WINDOW *typwin = owl_global_get_curs_typwin(&g);
+
+    /* push all changed windows to screen */
+    update_panels();
+    /* leave the cursor in the appropriate window */
+    if (!owl_popwin_is_active(owl_global_get_popwin(&g))
+	&& owl_global_get_typwin(&g)) {
+      owl_function_set_cursor(typwin);
+    } else {
+      owl_function_set_cursor(sepwin);
+    }
+    doupdate();
+    owl_global_set_noneedrefresh(&g);
+  }
+  return 0;
 }
 
@@ -469,5 +486,4 @@
 int main(int argc, char **argv, char **env)
 {
-  WINDOW *sepwin, *typwin;
   int argcsave;
   const char *const *argvsave;
@@ -583,6 +599,4 @@
   owl_function_source(NULL);
 
-  update_panels();
-
   /* Set the default style */
   owl_function_debugmsg("startup: setting startup and default style");
@@ -605,9 +619,5 @@
   owl_global_push_context(&g, OWL_CTX_READCONFIG|OWL_CTX_RECV, NULL, "recv");
 
-  owl_select_add_timer(180, 180, owl_zephyr_buddycheck_timer, NULL, NULL);
-
-  /* If we ever deprecate the mainloop hook, remove this. */
-  owl_select_add_timer(0, 1, owl_perlconfig_mainloop, NULL, NULL);
-
+  owl_select_add_pre_select_action(owl_refresh_pre_select_action, NULL, NULL);
   owl_select_add_pre_select_action(owl_process_messages, NULL, NULL);
 
@@ -615,27 +625,4 @@
   /* main loop */
   while (1) {
-
-    /* if a resize has been scheduled, deal with it */
-    owl_global_resize(&g, 0, 0);
-
-    /* these are here in case a resize changes the windows */
-    sepwin=owl_global_get_curs_sepwin(&g);
-    typwin=owl_global_get_curs_typwin(&g);
-
-    /* update the terminal if we need to */
-    if (owl_global_is_needrefresh(&g)) {
-      /* push all changed windows to screen */
-      update_panels();
-      /* leave the cursor in the appropriate window */
-      if (!owl_popwin_is_active(owl_global_get_popwin(&g))
-	  && owl_global_get_typwin(&g)) {
-	owl_function_set_cursor(typwin);
-      } else {
-	owl_function_set_cursor(sepwin);
-      }
-      doupdate();
-      owl_global_set_noneedrefresh(&g);
-    }
-
     /* select on FDs we know about. */
     owl_select();
Index: owl.h
===================================================================
--- owl.h	(revision 78929637d83d1082477f65f2a8d4867cce7b58a3)
+++ owl.h	(revision 20aced312921e75d69f84133af763117bac62675)
@@ -184,4 +184,8 @@
 #define OWL_VARIABLE_BOOL       2
 #define OWL_VARIABLE_STRING     3
+
+#define OWL_OUTPUT_RETURN       0
+#define OWL_OUTPUT_POPUP        1
+#define OWL_OUTPUT_ADMINMSG     2
 
 #define OWL_FILTER_MAX_DEPTH    300
@@ -518,8 +522,4 @@
 } owl_colorpair_mgr;
 
-typedef struct _owl_obarray {
-  owl_list strings;
-} owl_obarray;
-
 typedef struct _owl_io_dispatch {
   int fd;                                     /* FD to watch for dispatch. */
@@ -565,8 +565,10 @@
   owl_view current_view;
   owl_messagelist msglist;
+  WINDOW *input_pad;
   PANEL *recpan, *seppan, *msgpan, *typpan;
   int needrefresh;
   int rightshift;
   volatile sig_atomic_t resizepending;
+  int relayoutpending;
   int recwinlines;
   char *thishost;
@@ -604,5 +606,5 @@
   char *aim_screenname_for_filters;     /* currently logged in AIM screen name */
   owl_buddylist buddylist;  /* list of logged in AIM buddies */
-  owl_list messagequeue;    /* for queueing up aim and other messages */
+  GQueue *messagequeue;     /* for queueing up aim and other messages */
   owl_dict styledict;       /* global dictionary of available styles */
   char *response;           /* response to the last question asked */
@@ -617,5 +619,4 @@
   int pseudologin_notify;
   struct termios startup_tio;
-  owl_obarray obarray;
   owl_list io_dispatch_list;
   owl_list psa_list;
Index: perl/lib/BarnOwl.pm
===================================================================
--- perl/lib/BarnOwl.pm	(revision ef4700c428af8be6e6c92199bdb59e305d5ae04f)
+++ perl/lib/BarnOwl.pm	(revision 675a9988e7dfd7951f2c289194d11afb5f40cec0)
@@ -535,5 +535,5 @@
     my $func = shift;
     my $delta = shift;
-    $delta = 10 unless int($delta) > 0;
+    $delta = 10 unless defined($delta) && int($delta) > 0;
     my $shift = BarnOwl::recv_getshift();
     BarnOwl::recv_setshift($shift+$delta);
Index: perl/lib/BarnOwl/Hooks.pm
===================================================================
--- perl/lib/BarnOwl/Hooks.pm	(revision b30c2569225bbfe24cb09819d5ac4dfa509b7f1c)
+++ perl/lib/BarnOwl/Hooks.pm	(revision 3aa05226f2c729940957d231891ed429669e255f)
@@ -79,9 +79,11 @@
 our %EXPORT_TAGS = (all => [@EXPORT_OK]);
 
+use BarnOwl::MainLoopCompatHook;
+
 our $startup = BarnOwl::Hook->new;
 our $shutdown = BarnOwl::Hook->new;
 our $receiveMessage = BarnOwl::Hook->new;
 our $newMessage = BarnOwl::Hook->new;
-our $mainLoop = BarnOwl::Hook->new;
+our $mainLoop = BarnOwl::MainLoopCompatHook->new;
 our $getBuddyList = BarnOwl::Hook->new;
 our $getQuickstart = BarnOwl::Hook->new;
@@ -162,4 +164,5 @@
     }
     
+    $mainLoop->check_owlconf();
     $startup->run(0);
     BarnOwl::startup() if *BarnOwl::startup{CODE};
@@ -186,9 +189,4 @@
     
     BarnOwl::new_msg($m) if *BarnOwl::new_msg{CODE};
-}
-
-sub _mainloop_hook {
-    $mainLoop->run;
-    BarnOwl::mainloop_hook() if *BarnOwl::mainloop_hook{CODE};
 }
 
Index: perl/lib/BarnOwl/MainLoopCompatHook.pm
===================================================================
--- perl/lib/BarnOwl/MainLoopCompatHook.pm	(revision 3aa05226f2c729940957d231891ed429669e255f)
+++ perl/lib/BarnOwl/MainLoopCompatHook.pm	(revision 3aa05226f2c729940957d231891ed429669e255f)
@@ -0,0 +1,64 @@
+use strict;
+use warnings;
+
+package BarnOwl::MainLoopCompatHook;
+
+use BarnOwl;
+use BarnOwl::Hook;
+use BarnOwl::Timer;
+use Scalar::Util qw(weaken);
+
+sub new {
+    my $class = shift;
+    my $hook = BarnOwl::Hook->new;
+    return bless {hook => $hook}, $class;
+}
+
+sub check_owlconf {
+  my $self = shift;
+  $self->_ensure_timer() if (*BarnOwl::mainloop_hook{CODE});
+}
+
+sub run {
+    my $self = shift;
+    return $self->{hook}->run(@_);
+}
+
+sub add {
+    my $self = shift;
+    $self->_ensure_timer();
+    $self->{hook}->add(@_);
+}
+
+sub clear {
+    my $self = shift;
+    $self->_kill_timer() unless *BarnOwl::mainloop_hook{CODE};
+    $self->{hook}->clear();
+}
+
+sub _ensure_timer {
+  my $self = shift;
+  BarnOwl::debug("Enabling backwards-compatibility \"main loop\" hook");
+  my $weak = $self;
+  weaken($weak);
+  unless ($self->{timer}) {
+    $self->{timer} = BarnOwl::Timer->new( {
+        after => 0,
+        interval => 1,
+        cb => sub {
+          $weak->run if $weak;
+          BarnOwl::mainloop_hook() if *BarnOwl::mainloop_hook{CODE};
+        },
+      } );
+  }
+}
+
+sub _kill_timer {
+  my $self = shift;
+  if ($self->{timer}) {
+    $self->{timer}->stop;
+    undef $self->{timer};
+  }
+}
+
+1;
Index: perl/lib/BarnOwl/Message/Generic.pm
===================================================================
--- perl/lib/BarnOwl/Message/Generic.pm	(revision ee183beb7b1f02ed315026b95d9d72e0913908bd)
+++ perl/lib/BarnOwl/Message/Generic.pm	(revision 5d1324f0b0edf2200def6c9e613517404a515c42)
@@ -6,4 +6,6 @@
 use base qw( BarnOwl::Message );
 
+sub body { "" }
+
 
 1;
Index: perl/lib/BarnOwl/Style/Default.pm
===================================================================
--- perl/lib/BarnOwl/Style/Default.pm	(revision 0fe69d275af9f0d0a83259b7494566c102b17902)
+++ perl/lib/BarnOwl/Style/Default.pm	(revision 08544e017df1dc0ff7d3735a4c93705de1007707)
@@ -32,4 +32,9 @@
     my $m = shift;
     return $m->is_personal && $m->direction eq "in";
+}
+
+sub maybe {
+    my $x = shift;
+    return defined($x) ? $x : "";
 }
 
@@ -99,5 +104,5 @@
             $header .= ' / ' . $self->humanize($m->subcontext, 1);
         }
-        $header .= ' / @b{' . $m->pretty_sender . '}';
+        $header .= ' / @b{' . maybe($m->pretty_sender) . '}';
     }
 
Index: perl/lib/BarnOwl/Timer.pm
===================================================================
--- perl/lib/BarnOwl/Timer.pm	(revision ee183beb7b1f02ed315026b95d9d72e0913908bd)
+++ perl/lib/BarnOwl/Timer.pm	(revision 8d16e58dfb7d32aaae1378039fbbde334d5ab660)
@@ -21,4 +21,12 @@
 }
 
+sub stop {
+    my $self = shift;
+    if(defined($self->{timer})) {
+        BarnOwl::Internal::remove_timer($self->{timer});
+        undef $self->{timer};
+    }
+}
+
 sub do_callback {
     my $self = shift;
@@ -28,7 +36,5 @@
 sub DESTROY {
     my $self = shift;
-    if(defined($self->{timer})) {
-        BarnOwl::Internal::remove_timer($self->{timer});
-    }
+    $self->stop;
 }
 
Index: perl/modules/Jabber/lib/BarnOwl/Message/Jabber.pm
===================================================================
--- perl/modules/Jabber/lib/BarnOwl/Message/Jabber.pm	(revision c854e74bbef86a0225ca76c3945b9f9485b829db)
+++ perl/modules/Jabber/lib/BarnOwl/Message/Jabber.pm	(revision 82785437649f6d955c06ed7f26124b223cf70d7d)
@@ -77,7 +77,15 @@
     } elsif ($self->jtype eq 'groupchat') {
         my $room = $self->room;
-        $filter = "jabber-room-$room";
-        BarnOwl::command(qw[filter], $filter,
-                         qw[type ^jabber$ and room], "^\Q$room\E\$");
+        if ($inst) {
+            my $subject = $self->subject;
+            $filter = "jabber-room-$room-subject-$subject";
+            BarnOwl::command(qw[filter], $filter,
+                             qw[type ^jabber$ and room], "^\Q$room\E\$",
+                             qw[and subject], "^\Q$subject\E\$");
+        } else {
+            $filter = "jabber-room-$room";
+            BarnOwl::command(qw[filter], $filter,
+                             qw[type ^jabber$ and room], "^\Q$room\E\$");
+        }
         return $filter;
     } elsif ($self->login ne 'none') {
Index: perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm
===================================================================
--- perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm	(revision 87894109aeedcc8ba50bd3b983c0d9558f1e6b32)
+++ perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm	(revision aa0a0b55489e41bbf85f4613156df3e987972b94)
@@ -285,5 +285,5 @@
         {
             summary => "Send a Jabber Message",
-            usage   => "jwrite <jid> [-t <thread>] [-s <subject>] [-a <account>]"
+            usage   => "jwrite <jid> [-t <thread>] [-s <subject>] [-a <account>] [-m <message>]"
         }
     );
@@ -308,5 +308,6 @@
             description => "jmuc sends Jabber commands related to MUC.\n\n"
               . "The following commands are available\n\n"
-              . "join <muc>  Join a MUC.\n\n"
+              . "join <muc>[/<nick>]\n"
+              . "            Join a MUC (with a given nickname, or otherwise your JID).\n\n"
               . "part <muc>  Part a MUC.\n"
               . "            The MUC is taken from the current message if not supplied.\n\n"
@@ -377,6 +378,5 @@
         my $cjidStr = $conn->baseJIDExists($jidStr);
         if ($cjidStr) {
-            BarnOwl::error("Already logged in as $cjidStr.");
-            return;
+            die("Already logged in as $cjidStr.\n");
         }
     }
@@ -387,11 +387,9 @@
 
     if ( !$uid || !$componentname ) {
-        BarnOwl::error("usage: $cmd JID");
-        return;
+        die("usage: $cmd JID\n");
     }
 
     if ( $conn->jidActive($jidStr) ) {
-        BarnOwl::error("Already logged in as $jidStr.");
-        return;
+        die("Already logged in as $jidStr.\n");
     } elsif ($conn->jidExists($jidStr)) {
         return $conn->tryReconnect($jidStr, 1);
@@ -526,6 +524,5 @@
 sub cmd_jlist {
     if ( !( scalar $conn->getJIDs() ) ) {
-        BarnOwl::error("You are not logged in to Jabber.");
-        return;
+        die("You are not logged in to Jabber.\n");
     }
     BarnOwl::popless_ztext( onGetBuddyList() );
@@ -534,6 +531,5 @@
 sub cmd_jwrite {
     if ( !$conn->connected() ) {
-        BarnOwl::error("You are not logged in to Jabber.");
-        return;
+        die("You are not logged in to Jabber.\n");
     }
 
@@ -543,4 +539,5 @@
     my $jwrite_thread  = "";
     my $jwrite_subject = "";
+    my $jwrite_body;
     my ($to, $from);
     my $jwrite_type    = "chat";
@@ -554,12 +551,11 @@
         'subject=s' => \$jwrite_subject,
         'account=s' => \$from,
-        'id=s'     =>  \$jwrite_sid,
+        'id=s'      => \$jwrite_sid,
+        'message=s' => \$jwrite_body,
     ) or die("Usage: jwrite <jid> [-t <thread>] [-s <subject>] [-a <account>]\n");
     $jwrite_type = 'groupchat' if $gc;
 
     if ( scalar @ARGV != 1 ) {
-        BarnOwl::error(
-            "Usage: jwrite <jid> [-t <thread>] [-s <subject>] [-a <account>]");
-        return;
+        die("Usage: jwrite <jid> [-t <thread>] [-s <subject>] [-a <account>]\n");
     }
     else {
@@ -570,5 +566,5 @@
 
     unless(scalar @candidates) {
-        die("Unable to resolve JID $to");
+        die("Unable to resolve JID $to\n");
     }
 
@@ -577,7 +573,7 @@
     unless(scalar @candidates) {
         if(!$from) {
-            die("You must specify an account with -a");
+            die("You must specify an account with -a\n");
         } else {
-            die("Unable to resolve account $from");
+            die("Unable to resolve account $from\n");
         }
     }
@@ -594,4 +590,9 @@
         type    => $jwrite_type
     };
+
+    if (defined($jwrite_body)) {
+        process_owl_jwrite($jwrite_body);
+        return;
+    }
 
     if(scalar @candidates > 1) {
@@ -631,6 +632,5 @@
     my $func = $jmuc_commands{$cmd};
     if ( !$func ) {
-        BarnOwl::error("jmuc: Unknown command: $cmd");
-        return;
+        die("jmuc: Unknown command: $cmd\n");
     }
 
@@ -654,5 +654,5 @@
         }
         else {
-            BarnOwl::error('You must specify an account with -a <jid>');
+            die("You must specify an account with -a <jid>\n");
         }
         return $func->( $jid, $muc, @ARGV );
@@ -667,5 +667,5 @@
 
     $muc = shift @ARGV
-      or die("Usage: jmuc join <muc> [-p <password>] [-a <account>]");
+      or die("Usage: jmuc join <muc> [-p <password>] [-a <account>]\n");
 
     die("Error: Must specify a fully-qualified MUC name (e.g. barnowl\@conference.mit.edu)\n")
@@ -680,5 +680,5 @@
                                                    MaxChars => 0
                                                   });
-    $completion_jids{$muc} = 1;
+    $completion_jids{$muc->GetJID('base')} = 1;
     return;
 }
@@ -688,10 +688,10 @@
 
     $muc = shift @args if scalar @args;
-    die("Usage: jmuc part [<muc>] [-a <account>]") unless $muc;
+    die("Usage: jmuc part [<muc>] [-a <account>]\n") unless $muc;
 
     if($conn->getConnectionFromJID($jid)->MUCLeave(JID => $muc)) {
         queue_admin_msg("$jid has left $muc.");
     } else {
-        die("Error: Not joined to $muc");
+        die("Error: Not joined to $muc\n");
     }
 }
@@ -703,5 +703,5 @@
     $muc = shift @args if scalar @args;
 
-    die('Usage: jmuc invite <jid> [<muc>] [-a <account>]')
+    die("Usage: jmuc invite <jid> [<muc>] [-a <account>]\n")
       unless $muc && $invite_jid;
 
@@ -718,5 +718,5 @@
     my ( $jid, $muc, @args ) = @_;
     $muc = shift @args if scalar @args;
-    die("Usage: jmuc configure [<muc>]") unless $muc;
+    die("Usage: jmuc configure [<muc>]\n") unless $muc;
     my $iq = Net::Jabber::IQ->new();
     $iq->SetTo($muc);
@@ -759,5 +759,5 @@
 
     $muc = shift @args if scalar @args;
-    die("Usage: jmuc presence [<muc>]") unless $muc;
+    die("Usage: jmuc presence [<muc>]\n") unless $muc;
 
     if ($muc eq '-a') {
@@ -774,5 +774,5 @@
     else {
         my $m = $conn->getConnectionFromJID($jid)->FindMUC(jid => $muc);
-        die("No such muc: $muc") unless $m;
+        die("No such muc: $muc\n") unless $m;
         BarnOwl::popless_ztext(jmuc_presence_single($m));
     }
@@ -801,6 +801,5 @@
     my $func = $jroster_commands{$cmd};
     if ( !$func ) {
-        BarnOwl::error("jroster: Unknown command: $cmd");
-        return;
+        die("jroster: Unknown command: $cmd\n");
     }
 
@@ -825,5 +824,5 @@
         }
         else {
-            BarnOwl::error('You must specify an account with -a <jid>');
+            die("You must specify an account with -a <jid>\n");
         }
         return $func->( $jid, $name, \@groups, $purgeGroups,  @ARGV );
@@ -849,5 +848,5 @@
     }
     else {
-        BarnOwl::error('You must specify an account with -a <jid>');
+        die("You must specify an account with -a <jid>\n");
     }
 
@@ -1234,4 +1233,13 @@
         $completion_jids{$room} = 1;
 
+        my $muc;
+        if ($dir eq 'in') {
+            my $connection = $conn->getConnectionFromSid($props{sid});
+            $muc = $connection->FindMUC(jid => $from);
+        } else {
+            my $connection = $conn->getConnectionFromJID($props{from});
+            $muc = $connection->FindMUC(jid => $to);
+        }
+        $props{from} = $muc->GetFullJID($from) || $nick || $room;
         $props{sender} = $nick || $room;
         $props{recipient} = $room;
@@ -1331,5 +1339,5 @@
         return $givenJIDStr if ($conn->jidExists($givenJIDStr) );
         return resolveConnectedJID($givenJID->GetJID('base')) if $loose;
-        die("Invalid account: $givenJIDStr");
+        die("Invalid account: $givenJIDStr\n");
     }
 
@@ -1384,5 +1392,5 @@
         # Not one of ours.
         else {
-            die("Invalid account: $givenJIDStr");
+            die("Invalid account: $givenJIDStr\n");
         }
 
@@ -1430,5 +1438,5 @@
     if($from) {
         $from_jid = resolveConnectedJID($from, 1);
-        die("Unable to resolve account $from") unless $from_jid;
+        die("Unable to resolve account $from\n") unless $from_jid;
         $to_jid = resolveDestJID($to, $from_jid);
         push @matches, [$from_jid, $to_jid] if $to_jid;
Index: perlconfig.c
===================================================================
--- perlconfig.c	(revision 1b1cd2cda4440db58f76fdfc5a6f5ab697a2bdf5)
+++ perlconfig.c	(revision 3aa05226f2c729940957d231891ed429669e255f)
@@ -582,17 +582,4 @@
 }
 
-void owl_perlconfig_mainloop(owl_timer *t, void *data)
-{
-  dSP;
-  if (!owl_perlconfig_is_function("BarnOwl::Hooks::_mainloop_hook"))
-    return;
-  PUSHMARK(SP) ;
-  call_pv("BarnOwl::Hooks::_mainloop_hook", G_DISCARD|G_EVAL);
-  if(SvTRUE(ERRSV)) {
-    owl_function_error("%s", SvPV_nolen(ERRSV));
-  }
-  return;
-}
-
 void owl_perlconfig_io_dispatch(const owl_io_dispatch *d, void *data)
 {
Index: popwin.c
===================================================================
--- popwin.c	(revision f449096479541df1434d1d796890d0bd2939f072)
+++ popwin.c	(revision 0881cdda52baa4677179208b39a3392f06182cf5)
@@ -28,8 +28,4 @@
   popwin = newwin(pw->lines-2, pw->cols-2, startline+1, startcol+1);
   pw->poppanel = new_panel(popwin);
-  
-  meta(popwin,TRUE);
-  nodelay(popwin, 1);
-  keypad(popwin, TRUE);
 
   werase(popwin);
@@ -68,6 +64,4 @@
   pw->active=0;
   owl_global_set_needrefresh(&g);
-  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
-  owl_function_full_redisplay();
   return(0);
 }
@@ -75,6 +69,5 @@
 int owl_popwin_is_active(const owl_popwin *pw)
 {
-  if (pw->active==1) return(1);
-  return(0);
+  return pw->active;
 }
 
Index: scripts/do-release
===================================================================
--- scripts/do-release	(revision 51dbfb51348a8cc7abe2836c37126ba000e82e96)
+++ scripts/do-release	(revision c62c75599e5fe81b2b31731f9ede53512e8020f6)
@@ -94,4 +94,4 @@
 NOW=$(date +"%B %d, %Y")
 cat <<EOF
- * '''$NOW''': BarnOwl $VERS Released. [wiki:Download] it here. or see the [/browser/ChangeLog?rev=$COMMIT ChangeLog]
+ * '''$NOW''': BarnOwl $VERS Released. [wiki:Download] it here. or see the [wiki:release-notes/$VERS Release Notes] or [/browser/ChangeLog?rev=barnowl-$VERS ChangeLog].
 EOF
Index: select.c
===================================================================
--- select.c	(revision 2a17b635c6895121650446d2529f46d7e291a486)
+++ select.c	(revision c3031f3a7e1c44404723ae42a5ab4dc598c454cf)
@@ -273,4 +273,9 @@
 
   sigemptyset(&set);
+  sigaddset(&set, SIGWINCH);
+  sigaddset(&set, SIGALRM);
+  sigaddset(&set, SIGPIPE);
+  sigaddset(&set, SIGTERM);
+  sigaddset(&set, SIGHUP);
   sigaddset(&set, SIGINT);
   sigprocmask(SIG_BLOCK, &set, oldmask);
Index: tester.c
===================================================================
--- tester.c	(revision 4123da1c83ec9ccdf10d87726d4b451f98bdbb62)
+++ tester.c	(revision 3f6555d9e7121e9d0551b2f945cfd93e4a2b5040)
@@ -16,8 +16,10 @@
 int main(int argc, char **argv, char **env)
 {
-  owl_errqueue_init(owl_global_get_errqueue(&g));
-  owl_obarray_init(&(g.obarray));
-  g.context_stack = NULL;
-  owl_global_push_context(&g, OWL_CTX_STARTUP, NULL, NULL);
+  /* initialize a fake ncurses, detached from std{in,out} */
+  FILE *rnull = fopen("/dev/null", "r");
+  FILE *wnull = fopen("/dev/null", "w");
+  newterm("xterm", wnull, rnull);
+  /* initialize global structures */
+  owl_global_init(&g);
 
   numtests = 0;
@@ -31,5 +33,4 @@
   numfailures += owl_variable_regtest();
   numfailures += owl_filter_regtest();
-  numfailures += owl_obarray_regtest();
   numfailures += owl_editwin_regtest();
   if (numfailures) {
@@ -37,4 +38,10 @@
   }
   printf("1..%d\n", numtests);
+
+  /* probably not necessary, but tear down the screen */
+  endwin();
+  fclose(rnull);
+  fclose(wnull);
+
   return(numfailures);
 }
@@ -293,33 +300,4 @@
 }
 
-
-int owl_obarray_regtest(void) {
-  int numfailed = 0;
-  const char *p,*p2;
-
-  owl_obarray oa;
-  owl_obarray_init(&oa);
-
-  printf("# BEGIN testing owl_obarray\n");
-
-  p = owl_obarray_insert(&oa, "test");
-  FAIL_UNLESS("returned string is equal", p && !strcmp(p, "test"));
-  p2 = owl_obarray_insert(&oa, "test");
-  FAIL_UNLESS("returned string is equal", p2 && !strcmp(p2, "test"));
-  FAIL_UNLESS("returned the same string", p2 && p == p2);
-
-  p = owl_obarray_insert(&oa, "test2");
-  FAIL_UNLESS("returned string is equal", p && !strcmp(p, "test2"));
-  p2 = owl_obarray_find(&oa, "test2");
-  FAIL_UNLESS("returned the same string", p2 && !strcmp(p2, "test2"));
-
-  p = owl_obarray_find(&oa, "nothere");
-  FAIL_UNLESS("Didn't find a string that isn't there", p == NULL);
-
-  printf("# END testing owl_obarray (%d failures)\n", numfailed);
-
-  return numfailed;
-}
-
 int owl_editwin_regtest(void) {
   int numfailed = 0;
Index: variable.c
===================================================================
--- variable.c	(revision 66e409c96288dd36cee1498652dc8d6dce9b4c45)
+++ variable.c	(revision d544237f77a88ded81cbe50b88544589a3e918f1)
@@ -110,5 +110,5 @@
 
   OWLVAR_ENUM( "loggingdirection" /* %OwlVarStub */, OWL_LOGGING_DIRECTION_BOTH,
-	       "specifices which kind of messages should be logged",
+	       "specifies which kind of messages should be logged",
 	       "Can be one of 'both', 'in', or 'out'.  If 'in' is\n"
 	       "selected, only incoming messages are logged, if 'out'\n"
@@ -138,5 +138,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 will be created\n",
 		    NULL, owl_variable_pseudologins_set, NULL),
 
@@ -151,5 +151,5 @@
 
 		 "If non empty, any messages matching the given filter will be logged.\n"
-		 "This is a completely separate mechanisim from the other logging\n"
+		 "This is a completely separate mechanism from the other logging\n"
 		 "variables like logging, classlogging, loglogins, loggingdirection,\n"
 		 "etc.  If you want this variable to control all logging, make sure\n"
@@ -198,5 +198,5 @@
   OWLVAR_PATH( "newmsgproc" /* %OwlVarStub:newmsgproc */, NULL,
 	       "name of a program to run when new messages are present",
-	       "The named program will be run when owl recevies new.\n"
+	       "The named program will be run when owl receives new\n"
 	       "messages.  It will not be run again until the first\n"
 	       "instance exits"),
@@ -213,5 +213,5 @@
 		 "Called every time you start a zephyrgram without an\n"
 		 "explicit zsig.  The default setting implements the policy\n"
-		 "descripted in the documentation for the 'zsig' variable.\n"),
+		 "described in the documentation for the 'zsig' variable.\n"),
 
   OWLVAR_STRING( "zsig" /* %OwlVarStub */, "",
@@ -280,27 +280,22 @@
 
   OWLVAR_INT(    "edit:maxfillcols" /* %OwlVarStub:edit_maxfillcols */, 70,
-	         "maximum number of columns for M-q to fill text to",
-		 "This specifies the maximum number of columns for M-q\n"
-		 "to fill text to.  If set to 0, ther will be no maximum\n"
-		 "limit.  In all cases, the current width of the screen\n"
-		 "will also be taken into account.  It will be used instead\n"
-		 "if it is narrower than the maximum, or if this\n"
-		 "is set to 0.\n" ),
-
-  OWLVAR_INT(    "edit:maxwrapcols" /* %OwlVarStub:edit_maxwrapcols */, 0,
+	         "maximum number of columns for M-q (edit:fill-paragraph) to fill text to",
+                 "This specifies the maximum number of columns for M-q to fill text\n"
+                 "to.  If set to 0, M-q will wrap to the width of the window, and\n"
+                 "values less than 0 disable M-q entirely.\n"),
+
+  OWLVAR_INT(    "edit:maxwrapcols" /* %OwlVarStub:edit_maxwrapcols */, 70,
 	         "maximum number of columns for line-wrapping",
-		 "This specifies the maximum number of columns for\n"
-		 "auto-line-wrapping.  If set to 0, ther will be no maximum\n"
-		 "limit.  In all cases, the current width of the screen\n"
-		 "will also be taken into account.  It will be used instead\n"
-		 "if it is narrower than the maximum, or if this\n"
-		 "is set to 0.\n\n"
-		 "It is recommended that outgoing messages be no wider\n"
-		 "than 60 columns, as a courtesy to recipients.\n"),
+                 "This specifies the maximum number of columns for\n"
+                 "auto-line-wrapping.  If set to 0, text will be wrapped at the\n"
+                 "window width. Values less than 0 disable automatic wrapping.\n"
+                 "\n"
+                 "As a courtesy to recipients, it is recommended that outgoing\n"
+                 "Zephyr messages be no wider than 70 columns.\n"),
 
   OWLVAR_INT( "aim_ignorelogin_timer" /* %OwlVarStub */, 15,
 	      "number of seconds after AIM login to ignore login messages",
 	      "This specifies the number of seconds to wait after an\n"
-	      "AIM login before allowing the recipt of AIM login notifications.\n"
+	      "AIM login before allowing the receipt of AIM login notifications.\n"
 	      "By default this is set to 15.  If you would like to view login\n"
 	      "notifications of buddies as soon as you login, set it to 0 instead."),
@@ -405,5 +400,5 @@
   int rv;
   rv = owl_variable_int_set_default(v, newval);
-  if (0 == rv) owl_function_resize();
+  if (0 == rv) owl_global_set_relayout_pending(&g);
   return(rv);
 }
@@ -433,7 +428,16 @@
 int owl_variable_pseudologins_set(owl_variable *v, const void *newval)
 {
+  static owl_timer *timer = NULL;
   if (newval) {
     if (*(const int*)newval == 1) {
       owl_function_zephyr_buddy_check(0);
+      if (timer == NULL) {
+        timer = owl_select_add_timer(180, 180, owl_zephyr_buddycheck_timer, NULL, NULL);
+      }
+    } else {
+      if (timer != NULL) {
+        owl_select_remove_timer(timer);
+        timer = NULL;
+      }
     }
   }
Index: viewwin.c
===================================================================
--- viewwin.c	(revision f449096479541df1434d1d796890d0bd2939f072)
+++ viewwin.c	(revision fe4c786091ae4f138f1edc26a13b2b8d0b3a034d)
@@ -67,4 +67,8 @@
 {
   owl_fmtext fm1, fm2;
+
+  /* avoid segfault when screen too small to create curswin */
+  if (v->curswin == NULL)
+    return;
   
   werase(v->curswin);
Index: zephyr.c
===================================================================
--- zephyr.c	(revision f25812b2029878bb898c301ce9e06adee69692cf)
+++ zephyr.c	(revision 3687413f5bdcd1097db8297d412aaa1792f9ea3c)
@@ -1364,4 +1364,14 @@
 #endif
 
+void owl_zephyr_buddycheck_timer(owl_timer *t, void *data)
+{
+  if (owl_global_is_pseudologins(&g)) {
+    owl_function_debugmsg("Doing zephyr buddy check");
+    owl_function_zephyr_buddy_check(1);
+  } else {
+    owl_function_debugmsg("Warning: owl_zephyr_buddycheck_timer call pointless; timer should have been disabled");
+  }
+}
+
 /*
  * Process zephyrgrams from libzephyr's queue. To prevent starvation,
