diff --git a/include/class.filter.php b/include/class.filter.php
index 06e5fa1295a2739bbceb9bdd523b473f3b74bf3c..acc3a3590a7921d1bee8599417c20fd1714e011a 100644
--- a/include/class.filter.php
+++ b/include/class.filter.php
@@ -316,9 +316,13 @@ class Filter {
         #       Override name with reply-to information from the TicketFilter
         #       match
         if ($this->useReplyToEmail() && $info['reply-to']) {
+            $changed = $info['reply-to'] != $ticket['email']
+                || ($info['reply-to-name'] && $ticket['name'] != $info['reply-to-name']);
             $ticket['email'] = $info['reply-to'];
             if ($info['reply-to-name'])
                 $ticket['name'] = $info['reply-to-name'];
+            if ($changed)
+                throw new FilterDataChanged();
         }
 
         # Use canned response.
@@ -776,7 +780,7 @@ class TicketFilter {
     function apply(&$ticket) {
         foreach ($this->getMatchingFilterList() as $filter) {
             if ($filter->rejectOnMatch())
-                throw new RejectedException($filter);
+                throw new RejectedException($filter, $ticket);
             $filter->apply($ticket, $this->vars);
             if ($filter->stopOnMatch()) break;
         }
@@ -940,17 +944,25 @@ class TicketFilter {
 
 class RejectedException extends Exception {
     var $filter;
+    var $vars;
 
-    function __construct(Filter $filter) {
+    function __construct(Filter $filter, $vars) {
         parent::__construct('Ticket rejected by a filter');
         $this->filter = $filter;
+        $this->vars = $vars;
     }
 
     function getRejectingFilter() {
         return $this->filter;
     }
+
+    function get($what) {
+        return $this->vars[$what];
+    }
 }
 
+class FilterDataChanged extends Exception {}
+
 /**
  * Function: endsWith
  *
diff --git a/include/class.ticket.php b/include/class.ticket.php
index a017a7b575a20a8a61e01104fe9996d6567ce8b3..06d417313b8b8a45dac075c7d0d41cde8970cd86 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -2323,6 +2323,64 @@ class Ticket {
         return db_fetch_array(db_query($sql));
     }
 
+    protected function filterTicketData($origin, $vars, $forms, $user=false) {
+        global $cfg;
+
+        // Unset all the filter data field data in case things change
+        // during recursive calls
+        foreach ($vars as $k=>$v)
+            if (strpos($k, 'field.') === 0)
+                unset($vars[$k]);
+
+        foreach ($forms as $F) {
+            if ($F) {
+                $vars += $F->getFilterData();
+            }
+        }
+
+        // Add in user and organization data for filtering
+        if ($user) {
+            $vars += $user->getFilterData();
+            $vars['email'] = $user->getEmail();
+            $vars['name'] = $user->getName();
+            if ($org = $user->getOrganization()) {
+                $vars += $org->getFilterData();
+            }
+        }
+        // Unpack the basic user information
+        else {
+            $interesting = array('name', 'email');
+            $user_form = UserForm::getUserForm()->getForm($vars);
+            // Add all the user-entered info for filtering
+            foreach ($user_form->getFields() as $f) {
+                $vars['field.'.$f->get('id')] = $f->toString($f->getClean());
+                if (in_array($f->get('name'), $interesting))
+                    $vars[$f->get('name')] = $vars['field.'.$f->get('id')];
+            }
+            // Add in organization data if one exists for this email domain
+            list($mailbox, $domain) = explode('@', $vars['email'], 2);
+            if ($org = Organization::forDomain($domain)) {
+                $vars += $org->getFilterData();
+            }
+        }
+
+        try {
+            // Make sure the email address is not banned
+            if (TicketFilter::isBanned($vars['email'])) {
+                throw new RejectedException(Banlist::getFilter(), $vars);
+            }
+
+            // Init ticket filters...
+            $ticket_filter = new TicketFilter($origin, $vars);
+            $ticket_filter->apply($vars);
+        }
+        catch (FilterDataChanged $ex) {
+            // Don't pass user recursively, assume the user has changed
+            return self::filterTicketData($origin, $vars, $forms);
+        }
+        return $vars;
+    }
+
     /*
      * The mother of all functions...You break it you fix it!
      *
@@ -2381,71 +2439,8 @@ class Ticket {
         if (!$form->isValid($field_filter('ticket')))
             $errors += $form->errors();
 
-        // Unpack dynamic variables into $vars for filter application
-        $vars += $form->getFilterData();
-
-        // Unpack the basic user information
-        if ($vars['uid'] && ($user = User::lookup($vars['uid']))) {
-            $vars['email'] = $user->getEmail();
-            $vars['name'] = $user->getName();
-            // Add in user and organization data for filtering
-            $vars += $user->getFilterData();
-            if ($org = $user->getOrganization()) {
-                $vars += $org->getFilterData();
-            }
-        }
-        else {
-            $interesting = array('name', 'email');
-            $user_form = UserForm::getUserForm()->getForm($vars);
-            // Add all the user-entered info for filtering
-            foreach ($user_form->getFields() as $f) {
-                $vars['field.'.$f->get('id')] = $f->toString($f->getClean());
-                if (in_array($f->get('name'), $interesting))
-                    $vars[$f->get('name')] = $vars['field.'.$f->get('id')];
-            }
-            // Add in organization data if one exists for this email domain
-            list($mailbox, $domain) = explode('@', $vars['email'], 2);
-            if ($org = Organization::forDomain($domain)) {
-                $vars += $org->getFilterData();
-            }
-        }
-
-
-        //Check for 403
-        if ($vars['email']
-                && Validator::is_email($vars['email'])) {
-
-            //Make sure the email address is not banned
-            if (TicketFilter::isBanned($vars['email'])) {
-                return $reject_ticket(sprintf(_S('Banned email - %s'), $vars['email']));
-            }
-
-            //Make sure the open ticket limit hasn't been reached. (LOOP CONTROL)
-            if ($cfg->getMaxOpenTickets() > 0
-                    && strcasecmp($origin, 'staff')
-                    && ($_user=TicketUser::lookupByEmail($vars['email']))
-                    && ($openTickets=$_user->getNumOpenTickets())
-                    && ($openTickets>=$cfg->getMaxOpenTickets()) ) {
-
-                $errors = array('err' => __("You've reached the maximum open tickets allowed."));
-                $ost->logWarning(sprintf(_S('Ticket denied - %s'), $vars['email']),
-                        sprintf(_S('Max open tickets (%1$d) reached for %2$s'),
-                            $cfg->getMaxOpenTickets(), $vars['email']),
-                        false);
-
-                return 0;
-            }
-        }
-
-        if ($vars['topicId']) {
-            if (($__topic=Topic::lookup($vars['topicId']))
-                && $__form = $__topic->getForm()
-            ) {
-                $__form = $__form->instanciate();
-                $__form->setSource($vars);
-                $vars += $__form->getFilterData();
-            }
-        }
+        if ($vars['uid'])
+            $user = User::lookup($vars['uid']);
 
         $id=0;
         $fields=array();
@@ -2485,18 +2480,43 @@ class Ticket {
         if (!$errors) {
 
             # Perform ticket filter actions on the new ticket arguments
+            $__form = null;
+            if ($vars['topicId']) {
+                if (($__topic=Topic::lookup($vars['topicId']))
+                    && $__form = $__topic->getForm()
+                ) {
+                    $__form = $__form->instanciate();
+                    $__form->setSource($vars);
+                }
+            }
+
             try {
-                // Init ticket filters...
-                $ticket_filter = new TicketFilter($origin, $vars);
-                $ticket_filter->apply($vars);
+                $vars = self::filterTicketData($origin, $vars,
+                    array($form, $__form), $user);
             }
             catch (RejectedException $ex) {
                 return $reject_ticket(
                     sprintf(_S('Ticket rejected (%s) by filter "%s"'),
-                    $vars['email'], $ex->getRejectingFilter()->getName())
+                    $ex->vars['email'], $ex->getRejectingFilter()->getName())
                 );
             }
 
+            //Make sure the open ticket limit hasn't been reached. (LOOP CONTROL)
+            if ($cfg->getMaxOpenTickets() > 0
+                    && strcasecmp($origin, 'staff')
+                    && ($_user=TicketUser::lookupByEmail($vars['email']))
+                    && ($openTickets=$_user->getNumOpenTickets())
+                    && ($openTickets>=$cfg->getMaxOpenTickets()) ) {
+
+                $errors = array('err' => __("You've reached the maximum open tickets allowed."));
+                $ost->logWarning(sprintf(_S('Ticket denied - %s'), $vars['email']),
+                        sprintf(_S('Max open tickets (%1$d) reached for %2$s'),
+                            $cfg->getMaxOpenTickets(), $vars['email']),
+                        false);
+
+                return 0;
+            }
+
             // Allow vars to be changed in ticket filter and applied to the user
             // account created or detected
             if (!$user && $vars['email'])