Index: commands.c
===================================================================
--- commands.c	(revision f89cc6fa54344f8f6b48601228af46e8fc95caea)
+++ commands.c	(revision f89cc6fa54344f8f6b48601228af46e8fc95caea)
@@ -479,13 +479,10 @@
 
   OWLCMD_ARGS("away", owl_command_away, OWL_CTX_INTERACTIVE,
-	      "Set, enable or disable both AIM and zephyr away messages",
+	      "Set, enable or disable all away messages",
 	      "away [ on | off | toggle ]\n"
 	      "away <message>",
-	      "Turn on or off the AIM and zephyr away message.  If\n"
+	      "Turn on or off all away messages.  If\n"
 	      "'message' is specified turn them on with that message,\n"
 	      "otherwise use the default.\n"
-	      "\n"
-	      "This command really just runs the 'aaway' and 'zaway'\n"
-	      "commands together\n"
 	      "\n"
 	      "SEE ALSO: aaway, zaway"),
@@ -1531,42 +1528,40 @@
 char *owl_command_away(int argc, const char *const *argv, const char *buff)
 {
-  if ((argc==1) ||
-      ((argc==2) && !strcmp(argv[1], "on"))) {
+  bool away_off;
+  const char *message = NULL;
+
+  if (argc == 1 ||
+      (argc == 2 && !strcmp(argv[1], "on"))) {
+    away_off = false;
     owl_global_set_aaway_msg(&g, owl_global_get_aaway_msg_default(&g));
     owl_global_set_zaway_msg(&g, owl_global_get_zaway_msg_default(&g));
+  } else if (argc == 2 && !strcmp(argv[1], "off")) {
+    away_off = true;
+  } else if (argc == 2 && !strcmp(argv[1], "toggle")) {
+    away_off = owl_function_is_away();
+  } else {
+    away_off = false;
+    message = skiptokens(buff, 1);
+  }
+
+  if (away_off) {
+    owl_function_aaway_off();
+    owl_function_zaway_off();
+    owl_perlconfig_perl_call_norv("BarnOwl::Hooks::_away_off", 0, NULL);
+    owl_function_makemsg("Away messages off.");
+  } else if (message != NULL) {
+    owl_global_set_aaway_msg(&g, message);
+    owl_global_set_zaway_msg(&g, message);
     owl_function_aaway_on();
     owl_function_zaway_on();
+    owl_perlconfig_perl_call_norv("BarnOwl::Hooks::_away_on", 1, &message);
+    owl_function_makemsg("Away messages set (%s).", message);
+  } else {
+    owl_function_aaway_on();
+    owl_function_zaway_on();
+    owl_perlconfig_perl_call_norv("BarnOwl::Hooks::_away_on", 0, NULL);
     owl_function_makemsg("Away messages set.");
-    return NULL;
-  }
-
-  if (argc==2 && !strcmp(argv[1], "off")) {
-    owl_function_aaway_off();
-    owl_function_zaway_off();
-    return NULL;
-  }
-
-  if (argc==2 && !strcmp(argv[1], "toggle")) {
-    /* if either one is on, turn it off, otherwise toggle both (turn
-     *  them both on)
-     */
-    if (!owl_global_is_zaway(&g) && !owl_global_is_aaway(&g)) {
-      owl_function_aaway_toggle();
-      owl_function_zaway_toggle();
-      owl_function_makemsg("Away messages set.");
-    } else {
-      if (owl_global_is_zaway(&g)) owl_function_zaway_toggle();
-      if (owl_global_is_aaway(&g)) owl_function_aaway_toggle();
-      owl_function_makemsg("Away messages off.");
-    }
-    return NULL;
-  }
-
-  buff = skiptokens(buff, 1);
-  owl_global_set_aaway_msg(&g, buff);
-  owl_global_set_zaway_msg(&g, buff);
-  owl_function_aaway_on();
-  owl_function_zaway_on();
-  owl_function_makemsg("Away messages set.");
+  }
+
   return NULL;
 }
Index: functions.c
===================================================================
--- functions.c	(revision ecfbdcc06a30d5fafd080b2fb19bead01f26e9ab)
+++ functions.c	(revision ecfbdcc06a30d5fafd080b2fb19bead01f26e9ab)
@@ -993,4 +993,11 @@
 }
 
+bool owl_function_is_away(void)
+{
+  return owl_global_is_zaway(&g) ||
+         owl_global_is_aaway(&g) ||
+         owl_perlconfig_perl_call_bool("BarnOwl::Hooks::_get_is_away", 0, NULL);
+}
+
 void owl_function_quit(void)
 {
Index: owl_perl.h
===================================================================
--- owl_perl.h	(revision f271129fbb186598811b923e406d65f9d2b3031a)
+++ owl_perl.h	(revision 0c71c58bb99d8f8814101c336852ba2d47493751)
@@ -4,53 +4,70 @@
 #include <stdio.h>
 
-#define OWL_PERL_VOID_CALL (void)POPs;
+/*
+ * This macro defines a convenience wrapper around the boilerplate
+ * of pushing char * arguments on to the stack for perl calling.
+ *
+ * Arguments are
+ * * i     - the counter variable to use, which must be declared prior
+ *           to calling this macro
+ * * argc  - the number of arguments
+ * * argv  - an array of char*s, of length at least argc; the arguments
+ *           to push on to the stack
+ */
+#define OWL_PERL_PUSH_ARGS(i, argc, argv) { \
+  for (i = 0; i < argc; i++) { \
+    XPUSHs(sv_2mortal(owl_new_sv(argv[i]))); \
+  } \
+}
 
 /*
  * This macro defines a convenience wrapper around the boilerplate of
- * calling a method on a perl object (SV*) from C.
+ * the perlcall methods.
  *
  * Arguments are
- * * obj    - the SV* to call the method on
- * * meth   - a char* method name
- * * args   - a code block responsible for pushing args (other than the object)
- * * err    - a string with a %s format specifier to log in case of error
- * * fatalp - if true, perl errors terminate BarnOwl
- * * ret    - a code block executed if the call succeeded
+ * * call       - the line of code to make the perl call
+ * * args       - a code block responsible for pushing args
+ * * err        - a string with a %s format specifier to log in case of error
+ * * fatalp     - if true, perl errors terminate BarnOwl
+ * * discardret - should be true if no return is expected
+ *                (if the call is passed the flag G_DISCARD or G_VOID)
+ * * ret        - a code block executed if the call succeeded
  *
  * See also: `perldoc perlcall', `perldoc perlapi'
  */
-#define OWL_PERL_CALL_METHOD(obj, meth, args, err, fatalp, ret) { \
-    int count; \
-    dSP; \
-    ENTER; \
-    SAVETMPS; \
-    PUSHMARK(SP); \
-    XPUSHs(obj); \
-    {args} \
-    PUTBACK; \
-    \
-    count = call_method(meth, G_SCALAR|G_EVAL); \
-    \
-    SPAGAIN; \
-    \
-    if(count != 1) { \
-      fprintf(stderr, "perl returned wrong count: %d\n", count); \
-      abort();                                                   \
+#define OWL_PERL_CALL(call, args, err, fatalp, discardret, ret) { \
+  int count; \
+  dSP; \
+  \
+  ENTER; \
+  SAVETMPS; \
+  \
+  PUSHMARK(SP); \
+  {args} \
+  PUTBACK; \
+  \
+  count = call; \
+  \
+  SPAGAIN; \
+  \
+  if (!discardret && count != 1) { \
+    croak("Perl returned wrong count: %d\n", count); \
+  } \
+  \
+  if (SvTRUE(ERRSV)) { \
+    if (fatalp) { \
+      fprintf(stderr, err, SvPV_nolen(ERRSV)); \
+      exit(-1); \
+    } else { \
+      owl_function_error(err, SvPV_nolen(ERRSV)); \
+      if (!discardret) (void)POPs; \
+      sv_setsv(ERRSV, &PL_sv_undef); \
     } \
-    if (SvTRUE(ERRSV)) { \
-      if(fatalp) { \
-        printf(err, SvPV_nolen(ERRSV)); \
-        exit(-1); \
-      } else { \
-        owl_function_error(err, SvPV_nolen(ERRSV)); \
-        (void)POPs; \
-        sv_setsv(ERRSV, &PL_sv_undef); \
-      } \
-    } else { \
-      ret; \
-    } \
-    PUTBACK; \
-    FREETMPS; \
-    LEAVE; \
+  } else if (!discardret) { \
+    ret; \
+  } \
+  PUTBACK; \
+  FREETMPS; \
+  LEAVE; \
 }
 
Index: perl/lib/BarnOwl/Hooks.pm
===================================================================
--- perl/lib/BarnOwl/Hooks.pm	(revision b8a3e0025038d7a71f4d13206b772d904f95b8a0)
+++ perl/lib/BarnOwl/Hooks.pm	(revision 6df57d4264483d81d678c5981c422da79199945e)
@@ -57,4 +57,19 @@
 from every function registered with this hook will be appended and
 displayed in a popup window, with zephyr formatting parsed.
+
+=item $awayOn
+
+Called, for all protocol handlers, to go away, with the away message,
+if any.
+
+=item $awayOff
+
+Called, for all protocol handlers, to come back from away.
+
+=item $getIsAway
+
+Called to check away status for all protocol handlers.  Protocol
+handlers should return a true value if any account of the user is away
+for the given protocol, and a false value otherwise.
 
 =item $getQuickstart
@@ -75,5 +90,6 @@
                     $receiveMessage $newMessage
                     $mainLoop $getBuddyList
-                    $getQuickstart);
+                    $getQuickstart
+                    $awayOn $awayOff $getIsAway);
 
 our %EXPORT_TAGS = (all => [@EXPORT_OK]);
@@ -88,4 +104,7 @@
 our $getBuddyList = BarnOwl::Hook->new;
 our $getQuickstart = BarnOwl::Hook->new;
+our $awayOn = BarnOwl::Hook->new;
+our $awayOff = BarnOwl::Hook->new;
+our $getIsAway = BarnOwl::Hook->new;
 
 # Internal startup/shutdown routines called by the C code
@@ -201,4 +220,17 @@
 }
 
+sub _away_on {
+    $awayOn->run(@_);
+}
+
+sub _away_off {
+    $awayOff->run();
+}
+
+sub _get_is_away {
+    my @is_away = grep { $_ } $getIsAway->run();
+    return scalar @is_away;
+}
+
 sub _new_command {
     my $command = shift;
Index: perlconfig.c
===================================================================
--- perlconfig.c	(revision 78033261fc599d8d986e1c32b68523132b853d40)
+++ perlconfig.c	(revision 57ad328a2552d45865fb6712ba6bf43ed6f9dc81)
@@ -224,44 +224,23 @@
 CALLER_OWN char *owl_perlconfig_call_with_message(const char *subname, const owl_message *m)
 {
-  dSP ;
-  int count;
-  SV *msgref, *srv;
-  char *out;
-  
-  ENTER ;
-  SAVETMPS;
-  
-  PUSHMARK(SP) ;
+  SV *msgref, *rv;
+  char *out = NULL;
+
   msgref = owl_perlconfig_message2hashref(m);
-  XPUSHs(sv_2mortal(msgref));
-  PUTBACK ;
-  
-  count = call_pv(subname, G_SCALAR|G_EVAL);
-  
-  SPAGAIN ;
-
-  if (SvTRUE(ERRSV)) {
-    owl_function_error("Perl Error: '%s'", SvPV_nolen(ERRSV));
-    /* and clear the error */
-    sv_setsv (ERRSV, &PL_sv_undef);
-  }
-
-  if (count != 1) {
-    fprintf(stderr, "bad perl!  no biscuit!  returned wrong count!\n");
-    abort();
-  }
-
-  srv = POPs;
-
-  if (srv) {
-    out = g_strdup(SvPV_nolen(srv));
-  } else {
-    out = NULL;
-  }
-  
-  PUTBACK ;
-  FREETMPS ;
-  LEAVE ;
-
+
+  OWL_PERL_CALL((call_pv(subname, G_SCALAR|G_EVAL))
+                ,
+                XPUSHs(sv_2mortal(msgref));
+                ,
+                "Perl Error: '%s'"
+                ,
+                false
+                ,
+                false
+                ,
+                rv = POPs;
+                if (rv && SvPOK(rv))
+                  out = g_strdup(SvPV_nolen(rv));
+                );
   return out;
 }
@@ -273,48 +252,25 @@
 CALLER_OWN char *owl_perlconfig_message_call_method(const owl_message *m, const char *method, int argc, const char **argv)
 {
-  dSP;
-  unsigned int count, i;
-  SV *msgref, *srv;
-  char *out;
+  SV *msgref, *rv;
+  char *out = NULL;
+  int i;
 
   msgref = owl_perlconfig_message2hashref(m);
 
-  ENTER;
-  SAVETMPS;
-
-  PUSHMARK(SP);
-  XPUSHs(sv_2mortal(msgref));
-  for(i=0;i<argc;i++) {
-    XPUSHs(sv_2mortal(owl_new_sv(argv[i])));
-  }
-  PUTBACK;
-
-  count = call_method(method, G_SCALAR|G_EVAL);
-
-  SPAGAIN;
-
-  if(count != 1) {
-    fprintf(stderr, "perl returned wrong count %u\n", count);
-    abort();
-  }
-
-  if (SvTRUE(ERRSV)) {
-    owl_function_error("Error: '%s'", SvPV_nolen(ERRSV));
-    /* and clear the error */
-    sv_setsv (ERRSV, &PL_sv_undef);
-  }
-
-  srv = POPs;
-
-  if (srv) {
-    out = g_strdup(SvPV_nolen(srv));
-  } else {
-    out = NULL;
-  }
-
-  PUTBACK;
-  FREETMPS;
-  LEAVE;
-
+  OWL_PERL_CALL(call_method(method, G_SCALAR|G_EVAL)
+                ,
+                XPUSHs(sv_2mortal(msgref));
+                OWL_PERL_PUSH_ARGS(i, argc, argv);
+                ,
+                "Perl Error: '%s'"
+                ,
+                false
+                ,
+                false
+                ,
+                rv = POPs;
+                if (rv && SvPOK(rv))
+                  out = g_strdup(SvPV_nolen(rv));
+                );
   return out;
 }
@@ -455,23 +411,97 @@
 void owl_perlconfig_new_command(const char *name)
 {
-  dSP;
-
-  ENTER;
-  SAVETMPS;
-
-  PUSHMARK(SP);
-  XPUSHs(sv_2mortal(owl_new_sv(name)));
-  PUTBACK;
-
-  call_pv("BarnOwl::Hooks::_new_command", G_VOID|G_EVAL);
-
-  SPAGAIN;
-
-  if(SvTRUE(ERRSV)) {
-    owl_function_error("%s", SvPV_nolen(ERRSV));
-  }
-
-  FREETMPS;
-  LEAVE;
+  OWL_PERL_CALL(call_pv("BarnOwl::Hooks::_new_command", G_VOID|G_EVAL);
+                ,
+                XPUSHs(sv_2mortal(owl_new_sv(name)));
+                ,
+                "Perl Error: '%s'"
+                ,
+                false
+                ,
+                true
+                ,
+                );
+}
+
+CALLER_OWN char *owl_perlconfig_perl_call(const char *method, int argc, const char *const *argv)
+{
+  SV *rv;
+  char *out = NULL;
+  int i;
+  OWL_PERL_CALL(call_pv(method, G_SCALAR|G_EVAL)
+                ,
+                OWL_PERL_PUSH_ARGS(i, argc, argv);
+                ,
+                "Perl Error: '%s'"
+                ,
+                false
+                ,
+                false
+                ,
+                rv = POPs;
+                if (rv && SvPOK(rv))
+                  out = g_strdup(SvPV_nolen(rv));
+                );
+  return out;
+}
+
+int owl_perlconfig_perl_call_int(const char *method, int argc, const char *const *argv)
+{
+  SV *rv;
+  int ret = -1;
+  int i;
+  OWL_PERL_CALL(call_pv(method, G_SCALAR|G_EVAL)
+                ,
+                OWL_PERL_PUSH_ARGS(i, argc, argv);
+                ,
+                "Perl Error: '%s'"
+                ,
+                false
+                ,
+                false
+                ,
+                rv = POPs;
+                if (rv && SvIOK(rv))
+                  ret = SvIV(rv);
+                );
+  return ret;
+}
+
+bool owl_perlconfig_perl_call_bool(const char *method, int argc, const char *const *argv)
+{
+  SV *rv;
+  bool ret = false;
+  int i;
+  OWL_PERL_CALL(call_pv(method, G_SCALAR|G_EVAL)
+                ,
+                OWL_PERL_PUSH_ARGS(i, argc, argv);
+                ,
+                "Perl Error: '%s'"
+                ,
+                false
+                ,
+                false
+                ,
+                rv = POPs;
+                if (rv)
+                  ret = SvTRUE(rv);
+                );
+  return ret;
+}
+
+void owl_perlconfig_perl_call_norv(const char *method, int argc, const char *const *argv)
+{
+  int i;
+  OWL_PERL_CALL(call_pv(method, G_DISCARD|G_EVAL)
+                ,
+                OWL_PERL_PUSH_ARGS(i, argc, argv);
+                ,
+                "Perl Error: '%s'"
+                ,
+                false
+                ,
+                true
+                ,
+                );
 }
 
@@ -479,38 +509,23 @@
 CALLER_OWN char *owl_perlconfig_perlcmd(const owl_cmd *cmd, int argc, const char *const *argv)
 {
-  int i, count;
-  char * ret = NULL;
-  SV *rv;
-  dSP;
-
-  ENTER;
-  SAVETMPS;
-
-  PUSHMARK(SP);
-  for(i=0;i<argc;i++) {
-    XPUSHs(sv_2mortal(owl_new_sv(argv[i])));
-  }
-  PUTBACK;
-
-  count = call_sv(cmd->cmd_perl, G_SCALAR|G_EVAL);
-
-  SPAGAIN;
-
-  if(SvTRUE(ERRSV)) {
-    owl_function_error("%s", SvPV_nolen(ERRSV));
-    (void)POPs;
-  } else {
-    if(count != 1)
-      croak("Perl command %s returned more than one value!", cmd->name);
-    rv = POPs;
-    if(SvTRUE(rv)) {
-      ret = g_strdup(SvPV_nolen(rv));
-    }
-  }
-
-  FREETMPS;
-  LEAVE;
-
-  return ret;
+  int i;
+  SV* rv;
+  char *out = NULL;
+
+  OWL_PERL_CALL(call_sv(cmd->cmd_perl, G_SCALAR|G_EVAL)
+                ,
+                OWL_PERL_PUSH_ARGS(i, argc, argv);
+                ,
+                "Perl Error: '%s'"
+                ,
+                false
+                ,
+                false
+                ,
+                rv = POPs;
+                if (rv && SvPOK(rv))
+                  out = g_strdup(SvPV_nolen(rv));
+                );
+  return out;
 }
 
@@ -523,29 +538,23 @@
 {
   SV *cb = owl_editwin_get_cbdata(e);
-  SV *text;
-  dSP;
-
-  if(cb == NULL) {
+  SV *text = owl_new_sv(owl_editwin_get_text(e));
+
+  if (cb == NULL) {
     owl_function_error("Perl callback is NULL!");
     return;
   }
-  text = owl_new_sv(owl_editwin_get_text(e));
-
-  ENTER;
-  SAVETMPS;
-
-  PUSHMARK(SP);
-  XPUSHs(sv_2mortal(text));
-  XPUSHs(sv_2mortal(newSViv(success)));
-  PUTBACK;
-  
-  call_sv(cb, G_DISCARD|G_EVAL);
-
-  if(SvTRUE(ERRSV)) {
-    owl_function_error("%s", SvPV_nolen(ERRSV));
-  }
-
-  FREETMPS;
-  LEAVE;
+
+  OWL_PERL_CALL(call_sv(cb, G_DISCARD|G_EVAL)
+                ,
+                XPUSHs(sv_2mortal(text));
+                XPUSHs(sv_2mortal(newSViv(success)));
+                ,
+                "Perl Error: '%s'"
+                ,
+                false
+                ,
+                true
+                ,
+                );
 }
 
Index: sepbar.c
===================================================================
--- sepbar.c	(revision 6eb3ed9ee6c4b94d35628e5b6b2bbaeccca565a9)
+++ sepbar.c	(revision 6df57d4264483d81d678c5981c422da79199945e)
@@ -67,16 +67,10 @@
   }
 
-  if (owl_global_is_zaway(&g) || owl_global_is_aaway(&g)) {
+  if (owl_function_is_away()) {
     getyx(sepwin, y, x);
     wmove(sepwin, y, x+2);
     wattron(sepwin, A_BOLD);
     wattroff(sepwin, A_REVERSE);
-    if (owl_global_is_zaway(&g) && owl_global_is_aaway(&g)) {
-      waddstr(sepwin, " AWAY ");
-    } else if (owl_global_is_zaway(&g)) {
-      waddstr(sepwin, " Z-AWAY ");
-    } else if (owl_global_is_aaway(&g)) {
-      waddstr(sepwin, " A-AWAY ");
-    }
+    waddstr(sepwin, " AWAY ");
     wattron(sepwin, A_REVERSE);
     wattroff(sepwin, A_BOLD);
Index: style.c
===================================================================
--- style.c	(revision 14be3a516baee0a39a99eada3fd50d39455b4724)
+++ style.c	(revision 0c71c58bb99d8f8814101c336852ba2d47493751)
@@ -23,12 +23,12 @@
 {
   SV *sv = NULL;
-  OWL_PERL_CALL_METHOD(s->perlobj,
-                       "description",
-                       ;,
-                       "Error in style_get_description: %s",
-                       0,
-                       sv = SvREFCNT_inc(POPs);
-                       );
-  if(sv) {
+  OWL_PERL_CALL(call_method("description", G_SCALAR|G_EVAL),
+                XPUSHs(s->perlobj);,
+                "Error in style_get_description: %s",
+                0,
+                false,
+                sv = SvREFCNT_inc(POPs);
+                );
+  if (sv) {
     return SvPV_nolen(sv_2mortal(sv));
   } else {
@@ -50,13 +50,14 @@
   
   /* Call the perl object */
-  OWL_PERL_CALL_METHOD(s->perlobj,
-                       "format_message",
-                       XPUSHs(sv_2mortal(owl_perlconfig_message2hashref(m)));,
-                       "Error in format_message: %s",
-                       0,
-                       sv = SvREFCNT_inc(POPs);
-                       );
+  OWL_PERL_CALL(call_method("format_message", G_SCALAR|G_EVAL),
+                XPUSHs(s->perlobj);
+                XPUSHs(sv_2mortal(owl_perlconfig_message2hashref(m)));,
+                "Error in format_message: %s",
+                0,
+                false,
+                sv = SvREFCNT_inc(POPs);
+                );
 
-  if(sv) {
+  if (sv) {
     body = SvPV_nolen(sv);
   } else {
