diff --git a/include/class.charset.php b/include/class.charset.php
index d33c3abd105e067c169cff6a348f774b2d3bf079..160c26fadb59a8bc3dc10a4aba7277e2f269af21 100644
--- a/include/class.charset.php
+++ b/include/class.charset.php
@@ -77,4 +77,32 @@ class Charset {
         return self::transcode($text, $charset, self::UTF8);
     }
 }
+
+class transcode_filter extends php_user_filter {
+  var $from;
+  var $to;
+
+  function filter($in, $out, &$consumed, $closing) {
+      while ($bucket = stream_bucket_make_writeable($in)) {
+        $bucket->data = Charset::transcode($bucket->data, $this->from,
+                $this->to);
+        $consumed += $bucket->datalen;
+        stream_bucket_append($out, $bucket);
+      }
+      return PSFS_PASS_ON;
+  }
+
+  function onCreate() {
+      switch ($this->filtername) {
+      case 'transcode.utf8-ascii':
+          $this->from ='utf-8';
+          $this->to = 'ISO-8859-1';
+          break;
+      default:
+          return false;
+      }
+      return true;
+  }
+}
+stream_filter_register('transcode.*', 'transcode_filter');
 ?>
diff --git a/include/class.filter.php b/include/class.filter.php
index 690a97e62f7a2ea852d69583ab5d20ebe757bf25..4a66737c11bb468c6184c1c1b8431e97d93a09fd 100644
--- a/include/class.filter.php
+++ b/include/class.filter.php
@@ -471,29 +471,9 @@ class Filter {
     }
 
     function save($id,$vars,&$errors) {
-      //get current filter actions (they're validated before saving)
-      self::save_actions($id, $vars, $errors);
-
-      if ($this) {
-        foreach ($this->getActions() as $A) {
-          $config = JsonDataParser::parse($A->configuration);
-          if ($A->type == 'dept') {
-            $dept = Dept::lookup($config['dept_id']);
-            $dept_action = $A->getId();
-          }
-
-          if ($A->type == 'topic') {
-            $topic = Topic::lookup($config['topic_id']);
-            $topic_action = $A->getId();
-          }
-        }
-      }
-
-      if($dept && !$dept->isActive() && (is_array($vars['actions']) && !in_array('D' . $dept_action,$vars['actions'])))
-        $errors['err'] = sprintf(__('%s selected for %s must be active'), __('Department'), __('Filter Action'));
-
-      if($topic && !$topic->isActive() && (is_array($vars['actions']) && !in_array('D' . $topic_action,$vars['actions'])))
-        $errors['err'] = sprintf(__('%s selected for %s must be active'), __('Help Topic'), __('Filter Action'));
+        //validate filter actions before moving on
+        if (!self::validate_actions($vars, $errors))
+            return false;
 
         if(!$vars['execorder'])
             $errors['execorder'] = __('Order required');
@@ -551,42 +531,67 @@ class Filter {
         # Don't care about errors stashed in $xerrors
         $xerrors = array();
         self::save_rules($id,$vars,$xerrors);
+        self::save_actions($id, $vars, $errors);
 
         return count($errors) == 0;
     }
 
-    function validate_actions($action) {
-      $errors = array();
-      $config = json_decode($action->ht['configuration'], true);
-      switch ($action->ht['type']) {
-        case 'dept':
-          $dept = Dept::lookup($config['dept_id']);
-          if (!$dept || !$dept->isActive()) {
-            $errors['err'] = sprintf(__('Unable to save: Please choose an active %s'), 'Department');
-            return $errors;
-          }
-          break;
+    function validate_actions($vars, &$errors) {
+        if (!is_array(@$vars['actions']))
+            return;
 
-        case 'topic':
-          $topic = Topic::lookup($config['topic_id']);
-          if (!$topic || !$topic->isActive()) {
-            $errors['err'] = sprintf(__('Unable to save: Please choose an active %s'), 'Help Topic');
-            return $errors;
+      foreach ($vars['actions'] as $sort=>$v) {
+          if (is_array($v)) {
+              $info = $v['type'];
+              $sort = $v['sort'] ?: $sort;
+          } else
+              $info = substr($v, 1);
+
+          $action = new FilterAction(array(
+              'type'=>$info,
+              'sort' => (int) $sort,
+          ));
+          $errors = array();
+          $action->setConfiguration($errors, $vars);
+
+          $config = json_decode($action->ht['configuration'], true);
+          if (is_numeric($action->ht['type'])) {
+              foreach ($config as $key => $value) {
+                  if ($key == 'topic_id') {
+                      $action->ht['type'] = 'topic';
+                      $config['topic_id'] = $value;
+                  }
+                  if ($key == 'dept_id') {
+                      $action->ht['type'] = 'dept';
+                      $config['dept_id'] = $value;
+                  }
+              }
           }
-          break;
 
-        default:
-          foreach ($config as $key => $value) {
-            if (!$value) {
-              $errors['err'] = sprintf(__('Unable to save: Please insert a value for %s'), ucfirst($action->ht['type']));
-              return $errors;
-            }
+          switch ($action->ht['type']) {
+            case 'dept':
+              $dept = Dept::lookup($config['dept_id']);
+              if (!$dept || !$dept->isActive()) {
+                $errors['err'] = sprintf(__('Unable to save: Please choose an active %s'), 'Department');
+              }
+              break;
+            case 'topic':
+              $topic = Topic::lookup($config['topic_id']);
+              if (!$topic || !$topic->isActive()) {
+                $errors['err'] = sprintf(__('Unable to save: Please choose an active %s'), 'Help Topic');
+              }
+              break;
+            default:
+              foreach ($config as $key => $value) {
+                if (!$value) {
+                  $errors['err'] = sprintf(__('Unable to save: Please insert a value for %s'), ucfirst($action->ht['type']));
+                }
+              }
+              break;
           }
-          break;
       }
 
-      return false;
-
+      return count($errors) == 0;
     }
 
     function save_actions($id, $vars, &$errors) {
@@ -598,7 +603,8 @@ class Filter {
                 $info = $v['type'];
                 $sort = $v['sort'] ?: $sort;
                 $action = 'N';
-            } else {
+            }
+            else {
                 $action = $v[0];
                 $info = substr($v, 1);
             }
@@ -612,24 +618,12 @@ class Filter {
                 ));
                 $I->setConfiguration($errors, $vars);
 
-                $invalid = self::validate_actions($I);
-                if ($invalid) {
-                  $errors['err'] = sprintf($invalid['err']);
-                  return;
-                }
-
                 $I->save();
                 break;
             case 'I': # existing filter action
                 if ($I = FilterAction::lookup($info)) {
                     $I->setConfiguration($errors, $vars);
 
-                    $invalid = self::validate_actions($I);
-                    if ($invalid) {
-                      $errors['err'] = sprintf($invalid['err']);
-                      return;
-                    }
-
                     $I->sort = (int) $sort;
                     $I->save();
                 }
diff --git a/include/class.filter_action.php b/include/class.filter_action.php
index 59bafbf57ebfe40205adbfe2dbecd60b33525083..181935af263d4ea863b6b36b8a1da25adc1a3406 100644
--- a/include/class.filter_action.php
+++ b/include/class.filter_action.php
@@ -69,7 +69,9 @@ class FilterAction extends VerySimpleModel {
 
     function getImpl() {
         if (!isset($this->_impl)) {
-            if (!($I = self::lookupByType($this->type, $this)))
+            //TODO: Figure out why $this->type gives an id
+            $existing = is_numeric($this->type) ? (self::lookup($this->type)) : $this;
+            if (!($I = self::lookupByType($existing->type, $existing)))
                 throw new Exception(sprintf(
                     '%s: No such filter action registered', $this->type));
             $this->_impl = $I;
diff --git a/include/class.format.php b/include/class.format.php
index 05d8699881bfb67ea117b916bb22aa8f45fb8f96..a2d72340dcf02e3cba45990e4e455ab8146604e3 100644
--- a/include/class.format.php
+++ b/include/class.format.php
@@ -308,8 +308,9 @@ class Format {
                   ':<html[^>]+:i',              # drop html attributes
                   ':<(a|span) (name|style)="(mso-bookmark\:)?_MailEndCompose">(.+)?<\/(a|span)>:', # Drop _MailEndCompose
                   ':<div dir=(3D)?"ltr">(.*?)<\/div>(.*):is', # drop Gmail "ltr" attributes
+                  ':data-cid="[^"]*":',         # drop image cid attributes
             ),
-            array('', '', '', '', '<html', '$4', '$2 $3'),
+            array('', '', '', '', '<html', '$4', '$2 $3', ''),
             $html);
 
         // HtmLawed specific config only
diff --git a/include/class.staff.php b/include/class.staff.php
index a9024227332507d9dce728d05ed8bf0512886f08..3833c63533505f740f8ca1da3ed13d494e9fec96 100644
--- a/include/class.staff.php
+++ b/include/class.staff.php
@@ -76,7 +76,9 @@ implements AuthenticatedUser, EmailContact, TemplateVariable, Searchable {
         if (isset($this->_config[$field]))
             return $this->_config[$field];
 
-        return parent::get($field, $default);
+        try {
+            return parent::get($field, $default);
+        } catch (Exception $e) {}
     }
 
     function getConfig() {