Index: logging.c
===================================================================
--- logging.c	(revision 9bfab40b6e10c70af6a97c0c1be89abbb557c3db)
+++ logging.c	(revision 5093c6f01fd51f20f4fe96ce622a09811e6eeaae)
@@ -30,47 +30,7 @@
   }
 
-  /* should we be logging this message? */
-  if (!owl_log_shouldlog_message(m)) {
-    owl_function_debugmsg("owl_log_message: not logging message");
-    return;
-  }
-
-  owl_log_perl(m);
+  g_free(owl_perlconfig_call_with_message("BarnOwl::Logging::log", m));
 
   owl_function_debugmsg("owl_log_message: leaving");
-}
-
-/* Return 1 if we should log the given message, otherwise return 0 */
-int owl_log_shouldlog_message(const owl_message *m) {
-  const owl_filter *f;
-
-  /* If there's a logfilter and this message matches it, log */
-  f=owl_global_get_filter(&g, owl_global_get_logfilter(&g));
-  if (f && owl_filter_message_match(f, m)) return(1);
-
-  /* otherwise we do things based on the logging variables */
-
-  /* skip login/logout messages if appropriate */
-  if (!owl_global_is_loglogins(&g) && owl_message_is_loginout(m)) return(0);
-      
-  /* check direction */
-  if ((owl_global_get_loggingdirection(&g)==OWL_LOGGING_DIRECTION_IN) && owl_message_is_direction_out(m)) {
-    return(0);
-  }
-  if ((owl_global_get_loggingdirection(&g)==OWL_LOGGING_DIRECTION_OUT) && owl_message_is_direction_in(m)) {
-    return(0);
-  }
-
-  if (owl_message_is_type_zephyr(m)) {
-    if (owl_message_is_personal(m) && !owl_global_is_logging(&g)) return(0);
-    if (!owl_message_is_personal(m) && !owl_global_is_classlogging(&g)) return(0);
-  } else {
-    if (owl_message_is_private(m) || owl_message_is_loginout(m)) {
-      if (!owl_global_is_logging(&g)) return(0);
-    } else {
-      if (!owl_global_is_classlogging(&g)) return(0);
-    }
-  }
-  return(1);
 }
 
@@ -302,49 +262,11 @@
 }
 
-void owl_log_append(const owl_message *m, const char *filename) {
-  char *buffer = owl_perlconfig_message_call_method(m, "log", 0, NULL);
-  owl_log_enqueue_message(buffer, filename);
-  g_free(buffer);
-}
-
 void owl_log_outgoing_zephyr_error(const owl_zwrite *zw, const char *text)
 {
-  owl_message *m;
-  /* create a present message so we can pass it to
-   * owl_log_shouldlog_message(void)
-   */
-  m = g_slice_new(owl_message);
+  owl_message *m = g_slice_new(owl_message);
   /* recip_index = 0 because there can only be one recipient anyway */
   owl_message_create_from_zwrite(m, zw, text, 0);
-  if (!owl_log_shouldlog_message(m)) {
-    owl_message_delete(m);
-    return;
-  }
-  char *buffer = owl_perlconfig_message_call_method(m, "log_outgoing_error", 0, NULL);
-  char *filenames_string = owl_perlconfig_call_with_message("BarnOwl::Logging::get_filenames_as_string", m);
-  char **filenames = g_strsplit(filenames_string, " ", 0);
-  char **filename_ptr;
-
-  for (filename_ptr = filenames; *filename_ptr != NULL; filename_ptr++) {
-    owl_log_enqueue_message(buffer, *filename_ptr);
-  }
-
-  g_free(filenames_string);
-  g_strfreev(filenames);
+  g_free(owl_perlconfig_call_with_message("BarnOwl::Logging::log_outgoing_error", m));
   owl_message_delete(m);
-}
-
-void owl_log_perl(const owl_message *m)
-{
-  char *filenames_string = owl_perlconfig_call_with_message("BarnOwl::Logging::get_filenames_as_string", m);
-  char **filenames = g_strsplit(filenames_string, "\n", 0);
-  char **filename_ptr;
-  g_free(filenames_string);
-
-  for (filename_ptr = filenames; *filename_ptr != NULL; filename_ptr++) {
-    owl_log_append(m, *filename_ptr);
-  }
-
-  g_strfreev(filenames);
 }
 
Index: perl/lib/BarnOwl/Logging.pm
===================================================================
--- perl/lib/BarnOwl/Logging.pm	(revision eea7bed400b55cdc510b806ea4230d174b165470)
+++ perl/lib/BarnOwl/Logging.pm	(revision 5093c6f01fd51f20f4fe96ce622a09811e6eeaae)
@@ -15,4 +15,8 @@
 Modules wishing to customize how messages are logged should override the
 relevant subroutines in the appropriate subclass of L<BarnOwl::Message>.
+
+Modules wishing to log errors sending outgoing messages should call
+L<BarnOwl::Logging::log_outgoing_error> with the message that failed
+to be sent.
 
 =head2 EXPORTS
@@ -76,12 +80,68 @@
 }
 
-# For ease of use in C
-sub get_filenames_as_string {
-    my @rtn;
-    foreach my $filename (BarnOwl::Logging::get_filenames(@_)) {
-        $filename =~ s/\n/_/g;
-        push @rtn, $filename;
+=head2 should_log_message MESSAGE
+
+Determines whether or not the passed message should be logged.
+
+To customize the behavior of this method, override
+L<BarnOwl::Message::should_log>.
+
+=cut
+
+sub should_log_message {
+    my ($m) = @_;
+    # If there's a logfilter and this message matches it, log.
+    # pass quiet=1, because we don't care if the filter doesn't exist
+    return 1 if BarnOwl::message_matches_filter($m, BarnOwl::getvar('logfilter'), 1);
+    # otherwise we do things based on the logging variables
+    # skip login/logout messages if appropriate
+    return 0 if $m->is_loginout && BarnOwl::getvar('loglogins') eq 'off';
+    # check direction
+    return 0 if $m->is_outgoing && BarnOwl::getvar('loggingdirection') eq 'in';
+    return 0 if $m->is_incoming && BarnOwl::getvar('loggingdirection') eq 'out';
+    return $m->should_log;
+}
+
+=head2 log MESSAGE
+
+Call this method to (potentially) log a message.
+
+To customize the behavior of this method for your messages, override
+L<BarnOwl::Message::log>, L<BarnOwl::Message::should_log>,
+L<BarnOwl::Message::log_base_path>, and/or
+L<BarnOwl::Message::log_filenames>.
+
+=cut
+
+sub log {
+    my ($m) = @_;
+    return unless BarnOwl::Logging::should_log_message($m);
+    my $log_text = $m->log;
+    foreach my $filename (BarnOwl::Logging::get_filenames($m)) {
+        BarnOwl::Logging::enqueue_text($log_text, $filename);
     }
-    return join("\n", @rtn);
+}
+
+=head2 log_outgoing_error MESSAGE
+
+Call this method to (potentially) log an error in sending an
+outgoing message.  Errors get logged to the same file(s) as
+successful messages.
+
+To customize the behavior of this method for your messages, override
+L<BarnOwl::Message::log_outgoing_error>,
+L<BarnOwl::Message::should_log>,
+L<BarnOwl::Message::log_base_path>, and/or
+L<BarnOwl::Message::log_filenames>.
+
+=cut
+
+sub log_outgoing_error {
+    my ($m) = @_;
+    return unless BarnOwl::Logging::should_log_message($m);
+    my $log_text = $m->log_outgoing_error;
+    foreach my $filename (BarnOwl::Logging::get_filenames($m)) {
+        BarnOwl::Logging::enqueue_text($log_text, $filename);
+    }
 }
 
Index: perl/lib/BarnOwl/Message.pm
===================================================================
--- perl/lib/BarnOwl/Message.pm	(revision 9bfab40b6e10c70af6a97c0c1be89abbb557c3db)
+++ perl/lib/BarnOwl/Message.pm	(revision 5093c6f01fd51f20f4fe96ce622a09811e6eeaae)
@@ -225,4 +225,24 @@
     chomp $body;
     return "ERROR (BarnOwl): $recipient\n$body\n\n";
+}
+
+=head2 should_log MESSAGE
+
+Returns true if we should log C<MESSAGE>.  This does not override
+user settings; if the BarnOwl variable C<loggingdirection> is in,
+and C<MESSAGE> is outgoing and does not match the C<logfilter>, it
+will not get logged regardless of what this method returns.
+
+Note that this method I<does> override the BarnOwl C<logging>
+variable; if a derived class overrides this method and does not
+provide an alternative BarnOwl variable (such as C<classlogging>),
+the overriding method should check the BarnOwl C<logging> variable.
+
+Defaults to returning the value of the BarnOwl variable C<logging>.
+
+=cut
+
+sub should_log {
+    return BarnOwl::getvar('logging') eq 'on';
 }
 
Index: perl/lib/BarnOwl/Message/Zephyr.pm
===================================================================
--- perl/lib/BarnOwl/Message/Zephyr.pm	(revision eea7bed400b55cdc510b806ea4230d174b165470)
+++ perl/lib/BarnOwl/Message/Zephyr.pm	(revision 5093c6f01fd51f20f4fe96ce622a09811e6eeaae)
@@ -281,3 +281,12 @@
 }
 
+sub should_log {
+    my ($m) = @_;
+    if ($m->log_to_class_file) {
+        return BarnOwl::getvar('classlogging') eq 'on';
+    } else {
+        return BarnOwl::getvar('logging') eq 'on';
+    }
+}
+
 1;
Index: perlglue.xs
===================================================================
--- perlglue.xs	(revision da7341e48ef4a151ee32fe828f2bbe30f4406019)
+++ perlglue.xs	(revision 5093c6f01fd51f20f4fe96ce622a09811e6eeaae)
@@ -683,2 +683,11 @@
 	OUTPUT:
 		RETVAL
+
+MODULE = BarnOwl		PACKAGE = BarnOwl::Logging
+
+void
+enqueue_text(log_text, filename)
+	const char * log_text
+	const char * filename
+	CODE:
+		owl_log_enqueue_message(log_text, filename);
