Index: functions.c
===================================================================
--- functions.c	(revision ce74deb58042b1730d2ae4ab1a4ab9d1dd5ca933)
+++ functions.c	(revision 13a3c1db689b9429147996774625ca630c1b93cd)
@@ -164,34 +164,4 @@
 }
 
-
-/* Add the given message to Owl's internal queue.  If displayoutgoing
- * is disabled, the message is NOT added to any internal queue, -1 is
- * returned and THE CALLER IS EXPECTED TO FREE THE GIVEN MESSAGE.
- * Otherwise 0 is returned and the caller need do nothing more
- */
-int owl_function_add_message(owl_message *m)
-{
-  /* if displayoutgoing is disabled, nuke the message and move on */
-  if (! owl_global_is_displayoutgoing(&g)) {
-    return(-1);
-  }
-
-  /* add it to the global list and current view */
-  owl_messagelist_append_element(owl_global_get_msglist(&g), m);
-  owl_view_consider_message(owl_global_get_current_view(&g), m);
-
-  /* do followlast if necessary */
-  if (owl_global_should_followlast(&g)) owl_function_lastmsg_noredisplay();
-
-  /* redisplay etc. */
-  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
-  if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
-    owl_popwin_refresh(owl_global_get_popwin(&g));
-  }
-  wnoutrefresh(owl_global_get_curs_recwin(&g));
-  owl_global_set_needrefresh(&g);
-  return(0);
-}
-
 /* Create an admin message, append it to the global list of messages
  * and redisplay if necessary.
@@ -413,13 +383,5 @@
 
     if (m) {
-      /* log it */
-      owl_log_message(m);
-      
-      /* add it or nuke it */
-      if (owl_global_is_displayoutgoing(&g)) {
-	owl_function_add_message(m);
-      } else {
-	owl_message_free(m);
-      }
+      owl_global_messagequeue_addmsg(&g, m);
     } else {
       owl_function_error("Could not create outgoing zephyr message");
@@ -477,13 +439,5 @@
     m=owl_function_make_outgoing_zephyr(mymsg, line, owl_zwrite_get_zsig(&z));
     if (m) {
-      /* log it */
-      owl_log_message(m);
-      
-      /* add it or nuke it */
-      if (owl_global_is_displayoutgoing(&g)) {
-	owl_function_add_message(m);
-      } else {
-	owl_message_free(m);
-      }
+      owl_global_messagequeue_addmsg(&g, m);
     } else {
       owl_function_error("Could not create outgoing zephyr message");
@@ -525,13 +479,5 @@
 
   if (m) {
-    /* log it */
-    owl_log_message(m);
-    
-    /* display it or nuke it */
-    if (owl_global_is_displayoutgoing(&g)) {
-      owl_function_add_message(m);
-    } else {
-      owl_message_free(m);
-    }
+    owl_global_messagequeue_addmsg(&g, m);
   } else {
     owl_function_error("Could not create outgoing AIM message");
@@ -562,13 +508,5 @@
   m=owl_function_make_outgoing_aim(msg, to);
   if (m) {
-    /* log it */
-    owl_log_message(m);
-
-    /* display it or nuke it */
-    if (owl_global_is_displayoutgoing(&g)) {
-      owl_function_add_message(m);
-    } else {
-      owl_message_free(m);
-    }
+    owl_global_messagequeue_addmsg(&g, m);
   } else {
     owl_function_error("Could not create AIM message");
@@ -588,15 +526,15 @@
    * an incoming message */
   min=owl_malloc(sizeof(owl_message));
+  mout=owl_function_make_outgoing_loopback(msg);
+
+  if (owl_global_is_displayoutgoing(&g)) {
+    owl_global_messagequeue_addmsg(&g, mout);
+  } else {
+    owl_message_free(mout);
+  }
+
   owl_message_create_loopback(min, msg);
   owl_message_set_direction_in(min);
   owl_global_messagequeue_addmsg(&g, min);
-
-  mout=owl_function_make_outgoing_loopback(msg);
-  owl_log_message(mout);
-  if (owl_global_is_displayoutgoing(&g)) {
-    owl_function_add_message(mout);
-  } else {
-    owl_message_free(mout);
-  }
 
   /* fake a makemsg */
Index: global.c
===================================================================
--- global.c	(revision a387d12ee4e32845e2a021fb4ecd3cf11d6c18a8)
+++ global.c	(revision 13a3c1db689b9429147996774625ca630c1b93cd)
@@ -779,5 +779,5 @@
  * necessary.
  */
-owl_message *owl_global_messageuque_popmsg(owl_global *g)
+owl_message *owl_global_messagequeue_popmsg(owl_global *g)
 {
   owl_message *out;
Index: owl.c
===================================================================
--- owl.c	(revision f178fb5aaf79c6a8780a6d0ff74209fbb3381ecd)
+++ owl.c	(revision 13a3c1db689b9429147996774625ca630c1b93cd)
@@ -70,5 +70,5 @@
   owl_popwin *pw;
   int j, ret, initialsubs, debug, argcsave, followlast;
-  int newmsgs, zpendcount, nexttimediff;
+  int newmsgs, nexttimediff;
   struct sigaction sigact;
   char *configfile, *tty, *perlout, *perlerr, **argvsave, buff[LINE], startupmsg[LINE];
@@ -79,7 +79,5 @@
   char *dir;
   struct termios tio;
-#ifdef HAVE_LIBZEPHYR
-  ZNotice_t notice;
-#endif
+  owl_message *m;
 #if OWL_STDERR_REDIR
   int newstderr;
@@ -453,131 +451,14 @@
     }
 
+    owl_zephyr_process_events();
+    
     /* Grab incoming messages. */
     newmsgs=0;
-    zpendcount=0;
-    while(owl_zephyr_zpending() || owl_global_messagequeue_pending(&g)) {
-#ifdef HAVE_LIBZEPHYR
-      struct sockaddr_in from;
-#endif
-      owl_message *m=NULL;
-      owl_filter *f;
-
-      /* grab the new message, stick it in 'm' */
-      if (owl_zephyr_zpending()) {
-#ifdef HAVE_LIBZEPHYR
-	/* grab a zephyr notice, but if we've done 20 without stopping,
-	   take a break to process keystrokes etc. */
-	if (zpendcount>20) break;
-	ZReceiveNotice(&notice, &from);
-	zpendcount++;
-	
-	/* is this an ack from a zephyr we sent? */
-	if (owl_zephyr_notice_is_ack(&notice)) {
-	  owl_zephyr_handle_ack(&notice);
-	  continue;
-	}
-	
-	/* if it's a ping and we're not viewing pings then skip it */
-	if (!owl_global_is_rxping(&g) && !strcasecmp(notice.z_opcode, "ping")) {
-	  continue;
-	}
-
-	/* create the new message */
-	m=owl_malloc(sizeof(owl_message));
-	owl_message_create_from_znotice(m, &notice);
-#endif
-      } else if (owl_global_messagequeue_pending(&g)) {
-	/* pick up the non-zephyr message in the message queue */
-	m=owl_global_messageuque_popmsg(&g);
-      } else {
-	/* Not supposed to happen, but we seem to get here on resizes */
-	owl_function_debugmsg("Bottomed out looking for zephyr");
-      }
-
-      /* If we didn't pick up a message for some reason, don't go on */
-      if (m==NULL) {
-	owl_function_debugmsg("m is null in main loop");
-	continue;
-      }
-      
-      /* if this message it on the puntlist, nuke it and continue */
-      if (owl_global_message_is_puntable(&g, m)) {
-	owl_message_free(m);
-	continue;
-      }
-
-      /*  login or logout that should be ignored? */
-      if (owl_global_is_ignorelogins(&g) && owl_message_is_loginout(m)) {
-	owl_message_free(m);
-	continue;
-      }
-
-      /* otherwise add it to the global list */
-      owl_messagelist_append_element(owl_global_get_msglist(&g), m);
-      newmsgs=1;
-
-      /* let the config know the new message has been received */
-      owl_perlconfig_getmsg(m, 0, NULL);
-
-      /* add it to any necessary views; right now there's only the current view */
-      owl_view_consider_message(owl_global_get_current_view(&g), m);
-
-      /* do we need to autoreply? */
-      if (owl_global_is_zaway(&g) && !owl_message_get_attribute_value(m, "isauto")) {
-	if (owl_message_is_type_zephyr(m)) {
-	  owl_zephyr_zaway(m);
-	} else if (owl_message_is_type_aim(m)) {
-	  if (owl_message_is_private(m)) {
-	    owl_function_send_aimawymsg(owl_message_get_sender(m), owl_global_get_zaway_msg(&g));
-	  }
-	}
-      }
-
-      /* ring the bell if it's a personal */
-      if (!strcmp(owl_global_get_personalbell(&g), "on")) {
-	  if (!owl_message_is_loginout(m) &&
-	      !owl_message_is_mail(m) &&
-	      owl_message_is_personal(m)) {
-	    owl_function_beep();
-	  }
-      } else if (!strcmp(owl_global_get_personalbell(&g), "off")) {
-	/* do nothing */
-      } else {
-	f=owl_global_get_filter(&g, owl_global_get_personalbell(&g));
-	if (f && owl_filter_message_match(f, m)) {
-	  owl_function_beep();
-	}
-      }
-
-
-      /* if it matches the alert filter, do the alert action */
-      f=owl_global_get_filter(&g, owl_global_get_alert_filter(&g));
-      if (f && owl_filter_message_match(f, m)) {
-	owl_function_command(owl_global_get_alert_action(&g));
-      }
-
-      /* if it's a zephyr login or logout, update the zbuddylist */
-      if (owl_message_is_type_zephyr(m) && owl_message_is_loginout(m)) {
-	if (owl_message_is_login(m)) {
-	  owl_zbuddylist_adduser(owl_global_get_zephyr_buddylist(&g), owl_message_get_sender(m));
-	} else if (owl_message_is_logout(m)) {
-	  owl_zbuddylist_deluser(owl_global_get_zephyr_buddylist(&g), owl_message_get_sender(m));
-	} else {
-	  owl_function_error("Internal error: received login notice that is neither login nor logout");
-	}
-      }
-
-      /* 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();
-      }
-
-      /* log the message if we need to */
-      owl_log_message(m);
+    while(owl_global_messagequeue_pending(&g)) {
+
+      m = owl_global_messagequeue_popmsg(&g);
+
+      if(owl_process_message(m))
+        newmsgs = 1;
     }
 
@@ -694,4 +575,106 @@
 }
 
+/*
+ * Process a new message passed to us on the message queue from some
+ * protocol. This includes adding it to the message list, updating the
+ * view and scrolling if appropriate, logging it, and so on.
+ *
+ * Either a pointer is kept to the message internally, or it is freed
+ * if unneeded. The caller no longer ``owns'' the message's memory.
+ *
+ * Returns 1 if the message was added to the message list, and 0 if it
+ * was ignored due to user settings or otherwise.
+ */
+int owl_process_message(owl_message *m) {
+  owl_filter *f;
+  /* if this message it on the puntlist, nuke it and continue */
+  if (owl_global_message_is_puntable(&g, m)) {
+    owl_message_free(m);
+    return 0;
+  }
+
+  /*  login or logout that should be ignored? */
+  if (owl_global_is_ignorelogins(&g)
+      && owl_message_is_loginout(m)) {
+    owl_message_free(m);
+    return 0;
+  }
+
+  if (!owl_global_is_displayoutgoing(&g)
+      && owl_message_is_direction_out(m)) {
+    owl_message_free(m);
+    return 0;
+  }
+
+  /* add it to the global list */
+  owl_messagelist_append_element(owl_global_get_msglist(&g), m);
+  /* add it to any necessary views; right now there's only the current view */
+  owl_view_consider_message(owl_global_get_current_view(&g), m);
+
+  if(owl_message_is_direction_in(m)) {
+    /* let perl know about it*/
+    owl_perlconfig_getmsg(m, 0, NULL);
+
+    /* do we need to autoreply? */
+    if (owl_global_is_zaway(&g) && !owl_message_get_attribute_value(m, "isauto")) {
+      if (owl_message_is_type_zephyr(m)) {
+        owl_zephyr_zaway(m);
+      } else if (owl_message_is_type_aim(m)) {
+        if (owl_message_is_private(m)) {
+          owl_function_send_aimawymsg(owl_message_get_sender(m), owl_global_get_zaway_msg(&g));
+        }
+      }
+    }
+
+    /* ring the bell if it's a personal */
+    if (!strcmp(owl_global_get_personalbell(&g), "on")) {
+      if (!owl_message_is_loginout(m) &&
+          !owl_message_is_mail(m) &&
+          owl_message_is_personal(m)) {
+        owl_function_beep();
+      }
+    } else if (!strcmp(owl_global_get_personalbell(&g), "off")) {
+      /* do nothing */
+    } else {
+      f=owl_global_get_filter(&g, owl_global_get_personalbell(&g));
+      if (f && owl_filter_message_match(f, m)) {
+        owl_function_beep();
+      }
+    }
+
+    /* if it matches the alert filter, do the alert action */
+    f=owl_global_get_filter(&g, owl_global_get_alert_filter(&g));
+    if (f && owl_filter_message_match(f, m)) {
+      owl_function_command(owl_global_get_alert_action(&g));
+    }
+
+    /* if it's a zephyr login or logout, update the zbuddylist */
+    if (owl_message_is_type_zephyr(m) && owl_message_is_loginout(m)) {
+      if (owl_message_is_login(m)) {
+        owl_zbuddylist_adduser(owl_global_get_zephyr_buddylist(&g), owl_message_get_sender(m));
+      } else if (owl_message_is_logout(m)) {
+        owl_zbuddylist_deluser(owl_global_get_zephyr_buddylist(&g), owl_message_get_sender(m));
+      } else {
+        owl_function_error("Internal error: received login notice that is neither login nor logout");
+      }
+    }
+
+    /* 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();
+    }
+  }
+
+  /* log the message if we need to */
+  owl_log_message(m);
+
+  return 1;
+}
+
 void sig_handler(int sig, siginfo_t *si, void *data)
 {
Index: perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm
===================================================================
--- perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm	(revision 1fd5e4c1fdc6e798cb9c09c4ae72fbd9a0815b9b)
+++ perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm	(revision 13a3c1db689b9429147996774625ca630c1b93cd)
@@ -860,5 +860,5 @@
     my $m = j2o( $j, { direction => 'out' } );
     if ( $vars{jwrite}{type} ne 'groupchat') {
-        BarnOwl::add_and_log_message($m);
+        BarnOwl::queue_message($m);
     }
 
Index: perlglue.xs
===================================================================
--- perlglue.xs	(revision a695a687a2b27f1b4164d054121186f9bb1b0b6c)
+++ perlglue.xs	(revision 13a3c1db689b9429147996774625ca630c1b93cd)
@@ -129,54 +129,4 @@
 	}
 
-void add_message(msg) 
-	SV *msg
-	PREINIT:
-		owl_message *m;
-	CODE:
-	{
-		if(!SvROK(msg) || SvTYPE(SvRV(msg)) != SVt_PVHV) {
-			croak("Usage: BarnOwl::add_message($message)");
-		}
-
-		if (owl_global_is_displayoutgoing(&g)) {
-			m = owl_perlconfig_hashref2message(msg);
-			owl_function_add_message(m);
-		}
-	}
-
-void log_message(msg) 
-	SV *msg
-	PREINIT:
-		owl_message *m;
-	CODE:
-	{
-		if(!SvROK(msg) || SvTYPE(SvRV(msg)) != SVt_PVHV) {
-			croak("Usage: BarnOwl::log_message($message)");
-		}
-
-		m = owl_perlconfig_hashref2message(msg);
-		owl_log_message(m);
-		owl_message_free(m);
-	}
-
-void add_and_log_message(msg) 
-	SV *msg
-	PREINIT:
-		owl_message *m;
-	CODE:
-	{
-		if(!SvROK(msg) || SvTYPE(SvRV(msg)) != SVt_PVHV) {
-			croak("Usage: BarnOwl::add_and_log_message($message)");
-		}
-
-		m = owl_perlconfig_hashref2message(msg);
-		owl_log_message(m);
-		if (owl_global_is_displayoutgoing(&g)) {
-			owl_function_add_message(m);
-		} else {
-			owl_message_free(m);
-		}
-	}
-
 void admin_message(header, body) 
 	char *header
Index: zephyr.c
===================================================================
--- zephyr.c	(revision 85d1795974357393450740592a2c4ec288bcc63f)
+++ zephyr.c	(revision 13a3c1db689b9429147996774625ca630c1b93cd)
@@ -638,5 +638,5 @@
   /* display the message as an admin message in the receive window */
   mout=owl_function_make_outgoing_zephyr(owl_global_get_zaway_msg(&g), tmpbuff, "Automated reply:");
-  owl_function_add_message(mout);
+  owl_global_messagequeue_addmsg(&g, mout);
   owl_free(tmpbuff);
 #endif
@@ -1054,2 +1054,40 @@
 #endif
 }
+
+#ifdef HAVE_LIBZEPHYR
+void owl_zephyr_process_events() {
+  int zpendcount=0;
+  ZNotice_t notice;
+  struct sockaddr_in from;
+  owl_message *m=NULL;
+
+  while(owl_zephyr_zpending() && zpendcount < 20) {
+    if (owl_zephyr_zpending()) {
+      ZReceiveNotice(&notice, &from);
+      zpendcount++;
+
+      /* is this an ack from a zephyr we sent? */
+      if (owl_zephyr_notice_is_ack(&notice)) {
+        owl_zephyr_handle_ack(&notice);
+        continue;
+      }
+
+      /* if it's a ping and we're not viewing pings then skip it */
+      if (!owl_global_is_rxping(&g) && !strcasecmp(notice.z_opcode, "ping")) {
+        continue;
+      }
+
+      /* create the new message */
+      m=owl_malloc(sizeof(owl_message));
+      owl_message_create_from_znotice(m, &notice);
+
+      owl_global_messagequeue_addmsg(&g, m);
+    }
+  }
+}
+
+#else
+void owl_zephyr_process_events() {
+  
+}
+#endif
