Index: functions.c
===================================================================
--- functions.c	(revision 451becbfdcd41f0116a8d564535df359ea7e1c13)
+++ functions.c	(revision 25729b21b3c139d2c02bdf0250c26f5b18d07051)
@@ -2835,10 +2835,10 @@
 
   /* narrow personal and login messages to the sender or recip as appropriate */
-  if (owl_message_is_personal(m) || owl_message_is_loginout(m)) {
-    if (owl_message_is_type_zephyr(m)) {
+  if (owl_message_is_type_zephyr(m)) {
+    if (owl_message_is_personal(m) || owl_message_is_loginout(m)) {
       if (owl_message_is_direction_in(m)) {
-	zperson=short_zuser(owl_message_get_sender(m));
+        zperson=short_zuser(owl_message_get_sender(m));
       } else {
-	zperson=short_zuser(owl_message_get_recipient(m));
+        zperson=short_zuser(owl_message_get_recipient(m));
       }
       filtname=owl_function_zuserfilt(zperson);
@@ -2846,20 +2846,26 @@
       return(filtname);
     }
-    return(NULL);
-  }
-
-  /* narrow class MESSAGE, instance foo, recip * messages to class, inst */
-  if (!strcasecmp(owl_message_get_class(m), "message") && !owl_message_is_personal(m)) {
-    filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
+
+    /* narrow class MESSAGE, instance foo, recip * messages to class, inst */
+    if (!strcasecmp(owl_message_get_class(m), "message") && !owl_message_is_personal(m)) {
+      filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
+      return(filtname);
+    }
+
+    /* otherwise narrow to the class */
+    if (type==0) {
+      filtname=owl_function_classinstfilt(owl_message_get_class(m), NULL);
+    } else if (type==1) {
+      filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
+    }
     return(filtname);
   }
 
-  /* otherwise narrow to the class */
-  if (type==0) {
-    filtname=owl_function_classinstfilt(owl_message_get_class(m), NULL);
-  } else if (type==1) {
-    filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
-  }
-  return(filtname);
+  /* pass it off to perl */
+  char *argv[1];
+  if(type) {
+    argv[0] = "-i";
+  };
+  return owl_perlconfig_message_call_method(m, "smartfilter", type ? 1 : 0, argv);
 }
 
Index: perl/modules/jabber.pl
===================================================================
--- perl/modules/jabber.pl	(revision 9667006cc3e2689434c539f0991ee7ffdc3c0383)
+++ perl/modules/jabber.pl	(revision 25729b21b3c139d2c02bdf0250c26f5b18d07051)
@@ -1156,3 +1156,34 @@
 }
 
+#####################################################################
+#####################################################################
+
+package owl::Message::Jabber;
+
+our @ISA = qw( owl::Message );
+
+sub jtype { shift->{jtype} };
+sub from { shift->{from} };
+sub to { shift->{to} };
+
+sub smartfilter {
+    my $self = shift;
+    my $inst = shift;
+
+    if($self->jtype eq 'chat') {
+        my ($user, $filter, $ftext);
+        if($self->direction eq 'in') {
+            $user = $self->from;
+        } else {
+            $user = $self->to;
+        }
+        $user = Net::Jabber::JID->new($user)->GetJID($inst ? 'full' : 'base');
+        $filter = "jabber-user-$user";
+        $ftext = qq{type ^jabber\$ and ( ( direction ^in\$ and from ^$user ) } .
+                 qq{or ( direction ^out\$ and to ^$user ) ) };
+        owl::filter("$filter $ftext");
+        return $filter;
+    }
+}
+
 1;
Index: perlconfig.c
===================================================================
--- perlconfig.c	(revision a55abb35d01b5557db234392d4874fafb756eb78)
+++ perlconfig.c	(revision 25729b21b3c139d2c02bdf0250c26f5b18d07051)
@@ -161,4 +161,62 @@
   return out;
 }
+
+
+/* Calls a method on a perl object representing a message.
+   If the return value is non-null, the caller must free it.
+ */
+char * owl_perlconfig_message_call_method(owl_message *m, char *method, int argc, char ** argv)
+{
+  dSP;
+  unsigned int count, len, i;
+  SV *msgref, *srv;
+  char *out, *preout;
+
+  msgref = owl_perlconfig_message2hashref(m);
+
+  ENTER;
+  SAVETMPS;
+
+  PUSHMARK(SP);
+  XPUSHs(msgref);
+  for(i=0;i<argc;i++) {
+    XPUSHs(sv_2mortal(newSVpv(argv[i], 0)));
+  }
+  PUTBACK;
+
+  count = call_method(method, G_SCALAR|G_KEEPERR|G_EVAL);
+
+  SPAGAIN;
+
+  if(count != 1) {
+    fprintf(stderr, "perl returned wrong count %d\n", count);
+    abort();
+  }
+
+  if (SvTRUE(ERRSV)) {
+    STRLEN n_a;
+    owl_function_error("Error: '%s'", SvPV(ERRSV, n_a));
+    /* and clear the error */
+    sv_setsv (ERRSV, &PL_sv_undef);
+  }
+
+  srv = POPs;
+
+  if (srv) {
+    preout=SvPV(srv, len);
+    out = owl_malloc(strlen(preout)+1);
+    strncpy(out, preout, len);
+    out[len] = '\0';
+  } else {
+    out = NULL;
+  }
+
+  PUTBACK;
+  FREETMPS;
+  LEAVE;
+
+  return out;
+}
+
 
 char *owl_perlconfig_readconfig(void)
Index: perlwrap.pm
===================================================================
--- perlwrap.pm	(revision 23be736e424c0d186cd671eb2cd9857479ad260c)
+++ perlwrap.pm	(revision 25729b21b3c139d2c02bdf0250c26f5b18d07051)
@@ -187,4 +187,8 @@
 }
 
+sub smartfilter {
+    die("smartfilter not supported for this message");
+}
+
 #####################################################################
 #####################################################################
@@ -274,11 +278,4 @@
 #####################################################################
 #####################################################################
-
-package owl::Message::Jabber;
-
-@ISA = qw( owl::Message );
-
-#####################################################################
-#####################################################################
 ################################################################################
 package owl;
@@ -317,5 +314,4 @@
 {
     my $hook = shift;
-    use Data::Dumper;
     my @args = @_;
     return join("\n", map {$_->(@args)} @$hook);
