diff --git a/include/class.config.php b/include/class.config.php
index cb1f15d5c4f96447db712798a2a6a8bcfbd548ec..522c93c5d441683cacc3a8839f29e1db1ba611ae 100644
--- a/include/class.config.php
+++ b/include/class.config.php
@@ -154,7 +154,7 @@ class OsticketConfig extends Config {
     var $defaults = array(
         'allow_pw_reset' =>     true,
         'pw_reset_window' =>    30,
-        'enable_html_thread' => true,
+        'enable_richtext' => true,
         'allow_attachments' =>  true,
         'name_format' =>        'full', # First Last
         'auto_claim_tickets'=>  true,
@@ -361,7 +361,7 @@ class OsticketConfig extends Config {
     }
 
     function isHtmlThreadEnabled() {
-        return $this->get('enable_html_thread');
+        return $this->get('enable_richtext');
     }
 
     function getClientTimeout() {
@@ -1132,7 +1132,7 @@ class OsticketConfig extends Config {
             'show_answered_tickets'=>isset($vars['show_answered_tickets'])?0:1,
             'show_related_tickets'=>isset($vars['show_related_tickets'])?1:0,
             'hide_staff_name'=>isset($vars['hide_staff_name'])?1:0,
-            'enable_html_thread'=>isset($vars['enable_html_thread'])?1:0,
+            'enable_richtext'=>isset($vars['enable_html_thread'])?1:0,
             'allow_client_updates'=>isset($vars['allow_client_updates'])?1:0,
             'max_file_size'=>$vars['max_file_size'],
         ));
diff --git a/include/class.dept.php b/include/class.dept.php
index 4e42d9335fca4fe40f339266012c8f400868100e..49ff05a8b473c541c71a8770cc066ff693b3e03f 100644
--- a/include/class.dept.php
+++ b/include/class.dept.php
@@ -62,11 +62,7 @@ implements TemplateVariable {
     const ALERTS_DEPT_AND_GROUPS = 1;
     const ALERTS_DEPT_ONLY = 0;
 
-    function getConfig() {
-        if (!isset($this->config))
-            $this->config = new Config('dept.'. $this->getId());
-        return $this->config;
-    }
+    const FLAG_ASSIGN_MEMBERS_ONLY = 0x0001;
 
     function asVar() {
         return $this->getName();
@@ -301,7 +297,7 @@ implements TemplateVariable {
     }
 
     function assignMembersOnly() {
-        return $this->getConfig()->get('assign_members_only', 0);
+        return $this->flags & self::FLAG_ASSIGN_MEMBERS_ONLY;
     }
 
     function isGroupMembershipEnabled() {
@@ -314,11 +310,12 @@ implements TemplateVariable {
             foreach (static::$meta['joins'] as $k => $v)
                 unset($ht[$k]);
 
+        $ht['assign_members_only'] = $this->flags & self::FLAG_ASSIGN_MEMBERS_ONLY;
         return $ht;
     }
 
     function getInfo() {
-        return $this->getConfig()->getInfo() + $this->getHashtable();
+        return $this->getHashtable();
     }
 
     function getAllowedGroups() {
@@ -368,7 +365,6 @@ implements TemplateVariable {
 
     function updateSettings($vars) {
         $this->updateGroups($vars['groups'] ?: array(), $vars);
-        $this->getConfig()->set('assign_members_only', $vars['assign_members_only']);
         $this->path = $this->getFullPath();
         $this->save();
         return true;
@@ -386,10 +382,8 @@ implements TemplateVariable {
             return 0;
         }
 
-        parent::delete();
         $id = $this->getId();
-        $sql='DELETE FROM '.DEPT_TABLE.' WHERE id='.db_input($id).' LIMIT 1';
-        if(db_query($sql) && ($num=db_affected_rows())) {
+        if (parent::delete()) {
             // DO SOME HOUSE CLEANING
             //Move tickets to default Dept. TODO: Move one ticket at a time and send alerts + log notes.
             db_query('UPDATE '.TICKET_TABLE.' SET dept_id='.db_input($cfg->getDefaultDeptId()).' WHERE dept_id='.db_input($id));
@@ -403,9 +397,6 @@ implements TemplateVariable {
 
             //Delete group access
             db_query('DELETE FROM '.GROUP_DEPT_TABLE.' WHERE dept_id='.db_input($id));
-
-            // Destrory config settings
-            $this->getConfig()->destroy();
         }
 
         return $num;
@@ -602,6 +593,7 @@ implements TemplateVariable {
         $this->group_membership = $vars['group_membership'];
         $this->ticket_auto_response = isset($vars['ticket_auto_response'])?$vars['ticket_auto_response']:1;
         $this->message_auto_response = isset($vars['message_auto_response'])?$vars['message_auto_response']:1;
+        $this->flags = isset($vars['assign_members_only']) ? self::FLAG_ASSIGN_MEMBERS_ONLY : 0;
 
         if ($this->save())
             return $this->updateSettings($vars);
diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php
index 8bb94d81c792c4c407b6b0801de9a44f7dbae4a4..0d089fe58fa3fb1e0faf8406aa30a0493b85bbb1 100644
--- a/include/class.dynamic_forms.php
+++ b/include/class.dynamic_forms.php
@@ -46,6 +46,9 @@ class DynamicForm extends VerySimpleModel {
         'O' => 'Organization Information',
     );
 
+    const FLAG_DELETABLE    = 0x0001;
+    const FLAG_DELETED      = 0x0002;
+
     var $_form;
     var $_fields;
     var $_has_data = false;
@@ -124,7 +127,11 @@ class DynamicForm extends VerySimpleModel {
     }
 
     function isDeletable() {
-        return $this->get('deletable');
+        return $this->flags & self::FLAG_DELETABLE;
+    }
+
+    function setFlag($flag) {
+        $this->flags |= $flag;
     }
 
     function hasAnyVisibleFields($user=false) {
@@ -173,6 +180,7 @@ class DynamicForm extends VerySimpleModel {
     function save($refetch=false) {
         if (count($this->dirty))
             $this->set('updated', new SqlFunction('NOW'));
+        // XXX: This should go to an update routine
         if (isset($this->dirty['notes']))
             $this->notes = Format::sanitize($this->notes);
         if ($rv = parent::save($refetch | $this->dirty))
@@ -183,8 +191,9 @@ class DynamicForm extends VerySimpleModel {
     function delete() {
         if (!$this->isDeletable())
             return false;
-        else
-            return parent::delete();
+
+        $this->setFlag(self::FLAG_DELETED);
+        return $this->save();
     }
 
     function getExportableFields($exclude=array()) {
@@ -278,7 +287,7 @@ class DynamicForm extends VerySimpleModel {
 
     static function buildDynamicDataView($cdata) {
         $sql = 'CREATE TABLE `'.$cdata['table'].'` (PRIMARY KEY
-                ('.$cdata['object_id'].')) AS '
+                ('.$cdata['object_id'].')) DEFAULT CHARSET=utf8 AS '
              .  static::getCrossTabQuery( $cdata['object_type'], $cdata['object_id']);
         db_query($sql);
     }
@@ -874,12 +883,15 @@ class DynamicFormField extends VerySimpleModel {
         if (!$this->get('label'))
             $this->addError(
                 __("Label is required for custom form fields"), "label");
-        if ($this->get('required') && !$this->get('name'))
+        if (($this->isRequiredForStaff() || $this->isRequiredForUsers())
+            && !$this->get('name')
+        ) {
             $this->addError(
                 __("Variable name is required for required fields"
                 /* `required` is a visibility setting fields */
                 /* `variable` is used for automation. Internally it's called `name` */
                 ), "name");
+        }
         if (preg_match('/[.{}\'"`; ]/u', $this->get('name')))
             $this->addError(__(
                 'Invalid character in variable name. Please use letters and numbers only.'
diff --git a/include/class.forms.php b/include/class.forms.php
index 73e89287bab0c1529558fdbe59fc3977ace94105..9f4ece823e177d93a81a0df42d2a2f97923edc12 100644
--- a/include/class.forms.php
+++ b/include/class.forms.php
@@ -498,7 +498,7 @@ class FormField {
      */
 
     function isEditable() {
-        return (($this->get('edit_mask') & 32) == 0);
+        return (($this->get('flags') & DynamicFormField::FLAG_MASK_EDIT) == 0);
     }
 
     /**
diff --git a/include/class.list.php b/include/class.list.php
index e873f4ee9a37d683422cd5e32cb3de19baaba3f5..a182ef3ce7ed46ef1dc2d6f4087016ef62cfc222 100644
--- a/include/class.list.php
+++ b/include/class.list.php
@@ -148,12 +148,6 @@ class DynamicList extends VerySimpleModel implements CustomList {
 
     var $_items;
     var $_form;
-    var $_config;
-
-    function __construct() {
-        call_user_func_array(array('parent', '__construct'), func_get_args());
-        $this->_config = new Config('list.'.$this->getId());
-    }
 
     function getId() {
         return $this->get('id');
@@ -318,7 +312,7 @@ class DynamicList extends VerySimpleModel implements CustomList {
     }
 
     function getConfiguration() {
-        return JsonDataParser::parse($this->_config->get('configuration'));
+        return JsonDataParser::parse($this->configuration);
     }
 
     function getTranslateTag($subtag) {
@@ -402,6 +396,10 @@ class DynamicList extends VerySimpleModel implements CustomList {
     }
 
     static function create($ht=false, &$errors=array()) {
+        if (isset($ht['configuration'])) {
+            $ht['configuration'] = JsonDataEncoder::encode($ht['configuration']);
+        }
+
         $inst = parent::create($ht);
         $inst->set('created', new SqlFunction('NOW'));
 
@@ -412,12 +410,6 @@ class DynamicList extends VerySimpleModel implements CustomList {
             $form->save();
         }
 
-        if (isset($ht['configuration'])) {
-            $inst->save();
-            $c = new Config('list.'.$inst->getId());
-            $c->set('configuration', JsonDataEncoder::encode($ht['configuration']));
-        }
-
         if (isset($ht['items'])) {
             $inst->save();
             foreach ($ht['items'] as $i) {
diff --git a/include/class.page.php b/include/class.page.php
index a49a7b263d12632ee662aba4c1288c2bcf4616b9..2e502548acadf4aa2ce56e3ce9e3cfc5d55c5ad6 100644
--- a/include/class.page.php
+++ b/include/class.page.php
@@ -275,13 +275,9 @@ class Page extends VerySimpleModel {
         $this->isactive = (bool) $vars['isactive'];
         $this->notes = Format::sanitize($vars['notes']);
 
-        if (!isset($this->id)) {
-            if ($this->save()) {
-                $this->content_id = $this->id;
-                $rv = $this->save();
-            }
-        }
-        elseif ($this->save())
+        $isnew = !isset($this->id);
+        $rv = $this->save();
+        if (!$isnew)
             $rv = $this->saveTranslations($vars, $errors);
 
         // Attach inline attachments from the editor
diff --git a/include/class.sla.php b/include/class.sla.php
index c1b4ead65df6f5d1ec796f7655e1d0a4322519f1..66e06d94cf188098e1f2b92dcff636283e5e9a8f 100644
--- a/include/class.sla.php
+++ b/include/class.sla.php
@@ -21,7 +21,10 @@ implements TemplateVariable {
         'pk' => array('id'),
     );
 
-    //TODO: Use flags
+    const FLAG_ACTIVE       = 0x0001;
+    const FLAG_ESCALATE     = 0x0002;
+    const FLAG_NOALERTS     = 0x0004;
+    const FLAG_TRANSIENT    = 0x0008;
 
     var $_config;
 
@@ -37,19 +40,13 @@ implements TemplateVariable {
         return $this->grace_period;
     }
 
-    function getHashtable() {
-        $this->getHashtable();
-    }
-
     function getInfo() {
-        return array_merge($this->getConfig()->getInfo(), $this->ht);
-    }
-
-    function getConfig() {
-        if (!isset($this->_config))
-            $this->_config = new SlaConfig($this->getId());
-
-        return $this->_config;
+        $base = $this->ht;
+        $base['isactive'] = $this->flags & self::FLAG_ACTIVE;
+        $base['disable_overdue_alerts'] = $this->flags & self::FLAG_NOALERTS;
+        $base['enable_priority_escalation'] = $this->flags & self::FLAG_ESCALATE;
+        $base['transient'] = $this->flags & self::FLAG_TRANSIENT;
+        return $base;
     }
 
     function getCreateDate() {
@@ -61,15 +58,15 @@ implements TemplateVariable {
     }
 
     function isActive() {
-        return ($this->isactive);
+        return $this->flags & self::FLAG_ACTIVE;
     }
 
     function isTransient() {
-        return $this->getConfig()->get('transient', false);
+        return $this->flags & self::FLAG_TRANSIENT;
     }
 
     function sendAlerts() {
-        return $this->disable_overdue_alerts;
+        return 0 === ($this->flags & self::FLAG_NOALERTS);
     }
 
     function alertOnOverdue() {
@@ -77,7 +74,7 @@ implements TemplateVariable {
     }
 
     function priorityEscalation() {
-        return ($this->enable_priority_escalation);
+        return $this->flags && self::FLAG_ESCALATE;
     }
 
     function getTranslateTag($subtag) {
@@ -123,17 +120,17 @@ implements TemplateVariable {
         if ($errors)
             return false;
 
-        $this->isactive = $vars['isactive'];
         $this->name = $vars['name'];
         $this->grace_period = $vars['grace_period'];
-        $this->disable_overdue_alerts = isset($vars['disable_overdue_alerts']) ? 1 : 0;
-        $this->enable_priority_escalation = isset($vars['enable_priority_escalation'])? 1: 0;
         $this->notes = Format::sanitize($vars['notes']);
+        $this->flags =
+              ($vars['isactive'] ? self::FLAG_ACTIVE : 0)
+            | (isset($vars['disable_overdue_alerts']) ? self::FLAG_NOALERTS : 0)
+            | (isset($vars['enable_priority_escalation']) ? self::FLAG_ESCALATE : 0)
+            | (isset($vars['transient']) ? self::FLAG_TRANSIENT : 0);
 
-        if ($this->save()) {
-            $this->getConfig()->set('transient', isset($vars['transient']) ? 1 : 0);
+        if ($this->save())
             return true;
-        }
 
         if (isset($this->id)) {
             $errors['err']=sprintf(__('Unable to update %s.'), __('this SLA plan'))
@@ -176,10 +173,11 @@ implements TemplateVariable {
 
        $slas = self::objects()
            ->order_by('name')
-           ->values_flat('id', 'name', 'isactive', 'grace_period');
+           ->values_flat('id', 'name', 'flags', 'grace_period');
 
         $entries = array();
         foreach ($slas as $row) {
+            $row[2] = $row[2] & self::FLAG_ACTIVE;
             $entries[$row[0]] = sprintf(__('%s (%d hours - %s)'
                         /* Tokens are <name> (<#> hours - <Active|Disabled>) */),
                         self::getLocalById($row[0], 'name', $row[1]),
@@ -211,13 +209,4 @@ implements TemplateVariable {
         return $sla;
     }
 }
-
-require_once(INCLUDE_DIR.'class.config.php');
-class SlaConfig extends Config {
-    var $table = CONFIG_TABLE;
-
-    function __construct($id) {
-        parent::__construct("sla.$id");
-    }
-}
 ?>
diff --git a/include/class.team.php b/include/class.team.php
index f172f1ede5a97ab980a657d5c3d39b80107bc6ad..12d14e71382714cd42cb1c1991fc804ac9e703e4 100644
--- a/include/class.team.php
+++ b/include/class.team.php
@@ -33,6 +33,9 @@ implements TemplateVariable {
         ),
     );
 
+    const FLAG_ENABLED  = 0x0001;
+    const FLAG_NOALERTS = 0x0002;
+
     var $_members;
 
     function asVar() {
@@ -101,6 +104,8 @@ implements TemplateVariable {
 
     function getHashtable() {
         $base = $this->ht;
+        $base['isenabled'] = $this->isEnabled();
+        $base['noalerts'] = !$this->alertsEnabled();
         unset($base['staffmembers']);
         return $base;
     }
@@ -110,7 +115,7 @@ implements TemplateVariable {
     }
 
     function isEnabled() {
-        return $this->isenabled;
+        return $this->flags & self::FLAG_ENABLED;
     }
 
     function isActive() {
@@ -118,7 +123,7 @@ implements TemplateVariable {
     }
 
     function alertsEnabled() {
-        return !$this->noalerts;
+        return ($this->flags & self::FLAG_NOALERTS) == 0;
     }
 
     function getTranslateTag($subtag) {
@@ -153,8 +158,9 @@ implements TemplateVariable {
                 && in_array($this->lead_id, $vars['remove']))
             $vars['lead_id'] =0 ;
 
-        $this->isenabled = $vars['isenabled'];
-        $this->noalerts = isset($vars['noalerts']) ? $vars['noalerts'] : 0;
+        $this->flags =
+              ($vars['isenabled'] ? self::FLAG_ENABLED : 0)
+            | (isset($vars['noalerts']) ? self::FLAG_NOALERTS : 0);
         $this->lead_id = $vars['lead_id'] ?: 0;
         $this->name = $vars['name'];
         $this->notes = Format::sanitize($vars['notes']);
@@ -225,13 +231,13 @@ implements TemplateVariable {
         if (!$teams || $criteria) {
             $teams = array();
             $query = static::objects()
-                ->values_flat('team_id', 'name', 'isenabled')
+                ->values_flat('team_id', 'name', 'flags')
                 ->order_by('name');
 
             if (isset($criteria['active']) && $criteria['active']) {
                 $query->annotate(array('members_count'=>SqlAggregate::COUNT('members')))
                 ->filter(array(
-                    'isenabled'=>1,
+                    'flags__hasbit'=>self::FLAG_ENABLED,
                     'members__staff__isactive'=>1,
                     'members__staff__onvacation'=>0,
                     'members__staff__group__flags__hasbit'=>Group::FLAG_ENABLED,
@@ -242,7 +248,8 @@ implements TemplateVariable {
             $items = array();
             foreach ($query as $row) {
                 //TODO: Fix enabled - flags is a bit field.
-                list($id, $name, $enabled) = $row;
+                list($id, $name, $flags) = $row;
+                $enabled = $flags & self::FLAG_ENABLED;
                 $items[$id] = sprintf('%s%s',
                     self::getLocalById($id, 'name', $name),
                     ($enabled || isset($criteria['active']))
diff --git a/include/i18n/en_US/form.yaml b/include/i18n/en_US/form.yaml
index 7d1eb9aa2f5303d1c35b2c04c9a9b15102b1e9de..cea0b559ceba8378f1dfc571eebe780d750d5c2a 100644
--- a/include/i18n/en_US/form.yaml
+++ b/include/i18n/en_US/form.yaml
@@ -7,7 +7,8 @@
 # title:    Bold section title of the form
 # instructions: Title deck, detailed instructions on entering form data
 # notes:    Notes for the form, shown under the fields
-# deletable: True if the form can be removed from the system
+# flags:
+#   0x0001  If the form can be removed from the system
 # fields:   List of fields for the form
 #   type:       Field type (short name) (eg. 'text', 'memo', 'phone', ...)
 #   label:      Field label shown to the user
@@ -35,7 +36,7 @@
 - id: 1
   type: U # notrans
   title: Contact Information
-  deletable: false
+  flags: 0
   fields:
     - type: text # notrans
       name: email # notrans
@@ -75,7 +76,7 @@
       This form will be attached to every ticket, regardless of its source.
       You can add any fields to this form and they will be available to all
       tickets, and will be searchable with advanced search and filterable.
-  deletable: false
+  flags: 0
   fields:
     - id: 20
       type: text # notrans
@@ -102,7 +103,7 @@
 - type: C # notrans
   title: Company Information
   instructions: Details available in email templates
-  deletable: false
+  flags: 0
   fields:
     - type: text # notrans
       name: name # notrans
@@ -140,7 +141,7 @@
 - type: O # notrans
   title: Organization Information
   instructions: Details on user organization
-  deletable: false
+  flags: 0
   fields:
     - type: text # notrans
       name: name # notrans
@@ -186,7 +187,7 @@
   instructions: Please Describe The Issue
   notes: |
       This form is used to create a task.
-  deletable: false
+  flags: 0
   fields:
     - type: text # notrans
       name: title # notrans
diff --git a/include/i18n/en_US/sla.yaml b/include/i18n/en_US/sla.yaml
index 3b91325475edfed4025cfc9e95bdcd9e78fe12c4..4bbcfae98c8921eb014ae3d8e3d58e465efe2617 100644
--- a/include/i18n/en_US/sla.yaml
+++ b/include/i18n/en_US/sla.yaml
@@ -3,20 +3,21 @@
 #
 # Fields:
 # id - (int:optional) id number in the database
-# isactive - (bool:0|1) true of false if the SLA should initially be active
-# enable_priority_escalation - (bool:0|1) true or false if the SLA should
+# flags - (int:bitmask)
+#   isactive - (flag:1) true of false if the SLA should initially be active
+#   enable_priority_escalation - (flag:2) true or false if the SLA should
 #       cause the ticket priority to be escalated when it is marked overdue
-# disable_overdue_alerts - (bool:0|1) - true or false if the overdue alert
+#   disable_overdue_alerts - (flag:4) - true or false if the overdue alert
 #       emails should _not_ go out for tickets assigned to this SLA
+#   transient - (flag:8) - true if the SLA should change when changing
+#       department or help topic.
 # grace_period - (int) number or hours after the ticket is opened before it
 #       is marked overdue
 # name - (string) descriptive name of the SLA
 # notes - (string) administrative notes (viewable internally only)
 ---
 - id: 1
-  isactive: 1
-  enable_priority_escalation: 1
-  disable_overdue_alert: 0
+  flags: 3
   grace_period: 48
   name: Default SLA
   notes: |
diff --git a/include/staff/dynamic-forms.inc.php b/include/staff/dynamic-forms.inc.php
index 55f1fc04fb0404c63618a19da932994774ef4f1c..47754fd054b9749ca5bab4a5c553109d96ea7916 100644
--- a/include/staff/dynamic-forms.inc.php
+++ b/include/staff/dynamic-forms.inc.php
@@ -7,8 +7,12 @@
 <div class="clear"></div>
 
 <?php
+$other_forms = DynamicForm::objects()
+    ->filter(array('type'=>'G'))
+    ->exclude(array('flags__hasbit' => DynamicForm::FLAG_DELETED));
+
 $page = ($_GET['p'] && is_numeric($_GET['p'])) ? $_GET['p'] : 1;
-$count = DynamicForm::objects()->filter(array('type__in'=>array('G')))->count();
+$count = $other_forms->count();
 $pageNav = new Pagenate($count, $page, PAGE_LIMIT);
 $pageNav->setURL('forms.php');
 $showing=$pageNav->showing().' '._N('form','forms',$count);
@@ -56,8 +60,7 @@ $showing=$pageNav->showing().' '._N('form','forms',$count);
         </tr>
     </thead>
     <tbody>
-    <?php foreach (DynamicForm::objects()->filter(array('type'=>'G'))
-                ->order_by('title')
+<?php foreach ($other_forms->order_by('title')
                 ->limit($pageNav->getLimit())
                 ->offset($pageNav->getStart()) as $form) {
             $sel=false;
diff --git a/include/upgrader/streams/core/9143a511-00000000.cleanup.sql b/include/upgrader/streams/core/9143a511-00000000.cleanup.sql
new file mode 100644
index 0000000000000000000000000000000000000000..9597462e1f906207b921b12513a18924c0b71983
--- /dev/null
+++ b/include/upgrader/streams/core/9143a511-00000000.cleanup.sql
@@ -0,0 +1,72 @@
+/**
+ * @signature 959aca6ed189cd918d227a3ea8a135a3
+ * @version v1.9.6
+ * @title Retire `private`, `required`, and `edit_mask` for fields
+ *
+ */
+
+ALTER TABLE `%TABLE_PREFIX%form_field`
+    DROP `private`,
+    DROP `required`,
+    DROP `edit_mask`;
+
+ALTER TABLE `%TABLE_PREFIX%content`
+    DROP `lang`;
+
+-- DROP IF EXISTS `%content.content_id`
+SET @s = (SELECT IF(
+    (SELECT COUNT(*)
+        FROM INFORMATION_SCHEMA.COLUMNS
+        WHERE table_name = '%TABLE_PREFIX%content'
+        AND table_schema = DATABASE()
+        AND column_name = 'content_id'
+    ) > 0,
+    "SELECT 1",
+    "ALTER TABLE `%TABLE_PREFIX%content` DROP `content_id`"
+));
+PREPARE stmt FROM @s;
+EXECUTE stmt;
+
+-- DROP IF EXISTS `%task.sla_id`
+SET @s = (SELECT IF(
+    (SELECT COUNT(*)
+        FROM INFORMATION_SCHEMA.COLUMNS
+        WHERE table_name = '%TABLE_PREFIX%task'
+        AND table_schema = DATABASE()
+        AND column_name = 'sla_id'
+    ) > 0,
+    "SELECT 1",
+    "ALTER TABLE `%TABLE_PREFIX%task` DROP `sla_id`"
+));
+PREPARE stmt FROM @s;
+EXECUTE stmt;
+
+-- Retire %team.[flag fields]
+ALTER TABLE `%TABLE_PREFIX%team`
+    DROP `isenabled`,
+    DROP `noalerts`;
+
+-- Retire %dept.[flag fields]
+DELETE FROM `%TABLE_PREFIX%config`
+WHERE `key`='assign_members_only' AND `namespace` LIKE 'dept.%';
+
+-- Retire %sla.[flag fields]
+ALTER TABLE `%TABLE_PREFIX%sla`
+  DROP `isactive`,
+  DROP `enable_priority_escalation`,
+  DROP `disable_overdue_alerts`;
+
+DELETE FROM `%TABLE_PREFIX%config`
+WHERE `key`='transient' AND `namespace` LIKE 'sla.%';
+
+DELETE FROM `%TABLE_PREFIX%config`
+WHERE `key`='configuration' AND `namespace` LIKE 'list.%';
+
+DELETE FROM `%TABLE_PREFIX%config`
+WHERE `key`='name_format' AND `namespace` = 'core';
+
+-- Orphan users who don't know they're orphans
+UPDATE `%TABLE_PREFIX%user` A1
+  LEFT JOIN `%TABLE_PREFIX%organization` A2 ON (A1.`org_id` = A2.`id`)
+  SET A1.`org_id` = 0
+  WHERE A2.`id` IS NULL;
diff --git a/include/upgrader/streams/core/9143a511-00000000.patch.sql b/include/upgrader/streams/core/9143a511-00000000.patch.sql
index 10a6a23214346ab8fdc42578ae01fcdf867ef5a8..83bfa49cc58d80a53dc9b873e55eee5b5ebf7767 100644
--- a/include/upgrader/streams/core/9143a511-00000000.patch.sql
+++ b/include/upgrader/streams/core/9143a511-00000000.patch.sql
@@ -1,3 +1,9 @@
+/**
+ * @signature 959aca6ed189cd918d227a3ea8a135a3
+ * @version v1.9.6
+ * @title Retire `private`, `required`, and `edit_mask` for fields
+ *
+ */
 
 ALTER TABLE `%TABLE_PREFIX%ticket_event`
   ADD `id` int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST,
@@ -26,3 +32,84 @@ UPDATE `%TABLE_PREFIX%thread_event` A1
     LEFT JOIN `%TABLE_PREFIX%staff` A2 ON (A2.`username` = A1.`username`)
     SET A1.`uid` = A2.`staff_id`
     WHERE A1.`username` != 'SYSTEM';
+
+ALTER TABLE `%TABLE_PREFIX%user_email`
+  ADD `flags` int(10) unsigned NOT NULL DEFAULT 0 AFTER `user_id`;
+
+ALTER TABLE `%TABLE_PREFIX%thread_entry`
+  ADD `editor` int(10) unsigned NULL AFTER `poster`,
+  ADD `editor_type` char(1) NULL AFTER `editor`;
+
+ALTER TABLE `%TABLE_PREFIX%form`
+  CHANGE `deletable` `flags` int(10) unsigned NOT NULL DEFAULT 1;
+
+-- Previous versions did not correctly mark the internal forms as NOT deletable
+UPDATE `%TABLE_PREFIX%form`
+  SET `flags` = 0 WHERE `type` IN ('T','U','C','O','A');
+
+ALTER TABLE `%TABLE_PREFIX%team`
+  ADD `flags` int(10) unsigned NOTN ULL default 1 AFTER `lead_id`;
+
+UPDATE `%TABLE_PREFIX%team`
+  SET `flags` = CASE WHEN `isenabled` THEN 1 ELSE 0 END
+              + CASE WHEN `noalerts` THEN 2 ELSE 0 END;
+
+-- Migrate %config[namespace=dept.x, key=alert_members_only]
+ALTER TABLE `%TABLE_PREFIX%department`
+  ADD `flags` int(10) unsigned NOT NULL default 0 AFTER `manager_id`;
+
+UPDATE `%TABLE_PREFIX%department` A1
+  JOIN (SELECT `value` FROM `%TABLE_PREFIX%config`) `config`
+    ON (`config`.`namespace` = CONCAT('dept.', A1.`id`) AND `config`.`key` = 'assign_members_only')
+  SET A1.`flags` = 1 WHERE `config`.`value` != '';
+
+-- Migrate %config[namespace=sla.x, key=transient]
+ALTER TABLE `%TABLE_PREFIX%sla`
+  ADD `flags` int(10) unsigned NOT NULL default 3 AFTER `id`;
+
+UPDATE `%TABLE_PREFIX%sla` A1
+  SET A1.`flags` =
+      (CASE WHEN A1.`isactive` THEN 1 ELSE 0 END)
+    | (CASE WHEN A1.`enable_priority_escalation` THEN 2 ELSE 0 END)
+    | (CASE WHEN A1.`disable_overdue_alerts` THEN 4 ELSE 0 END)
+    | (CASE WHEN (SELECT `value` FROM `%TABLE_PREFIX%config` `config`
+            WHERE`config`.`namespace` = CONCAT('sla.', A1.`id`) AND `config`.`key` = 'transient')
+            = '1' THEN 8 ELSE 0 END);
+
+ALTER TABLE `%TABLE_PREFIX%ticket`
+  ADD `source_extra` varchar(40) NULL default NULL AFTER `source`;
+
+-- Retire %config[namespace=list.x, key=configuration]
+ALTER TABLE `%TABLE_PREFIX%list`
+  ADD `configuration` text NOT NULL DEFAULT '' AFTER `type`;
+
+UPDATE `%TABLE_PREFIX%list` A1
+  JOIN (SELECT `value` FROM `%TABLE_PREFIX%config`) `config`
+    ON (`config`.`namespace` = CONCAT('list.', A1.`id`) AND `config`.`key` = 'configuration')
+  SET A1.`configuration` = `config`.`value`;
+
+-- Rebuild %ticket__cdata as UTF8
+DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket__cdata`;
+
+-- Move `enable_html_thread` to `enable_richtext`
+UPDATE `%TABLE_PREFIX%config`
+  SET `key` = 'enable_richtext'
+  WHERE `namespace` = 'core' AND `key` = 'enable_html_thread';
+
+SET @name_format = (SELECT `value` FROM `%TABLE_PREFIX%config` A1
+    WHERE A1.`namespace` = 'core' AND A1.`key` = 'name_format');
+INSERT INTO `%TABLE_PREFIX%config`
+    (`namespace`, `key`, `value`) VALUES
+    ('core', 'agent_name_format', @name_format),
+    ('core', 'client_name_format', @name_format);
+
+-- Drop search table and turn on reindexing
+DROP TABLE IF EXISTS `%TABLE_PREFIX%_search`;
+
+UPDATE `%TABLE_PREFIX%config` SET `value` = '1'
+  WHERE `key` = 'reindex' and `namespace` = 'mysqlsearch';
+
+-- Finished with patch
+UPDATE `%TABLE_PREFIX%config`
+    SET `value` = '00000000000000000000000000000000'
+    WHERE `key` = 'schema_signature' AND `namespace` = 'core';
diff --git a/include/upgrader/streams/core/f5692e24-4323a6a8.patch.sql b/include/upgrader/streams/core/f5692e24-4323a6a8.patch.sql
index 39d7cb4698d1aa81e7f3fc2e48b0a7943fe86931..67a21aa7759080efc95cc08428285ce8490462c9 100644
--- a/include/upgrader/streams/core/f5692e24-4323a6a8.patch.sql
+++ b/include/upgrader/streams/core/f5692e24-4323a6a8.patch.sql
@@ -69,11 +69,7 @@ ALTER TABLE `%TABLE_PREFIX%help_topic`
 -- Add `content_id` to the content table to allow for translations
 RENAME TABLE `%TABLE_PREFIX%page` TO `%TABLE_PREFIX%content`;
 ALTER TABLE `%TABLE_PREFIX%content`
-  CHANGE `type` `type` varchar(32) NOT NULL default 'other',
-  ADD `content_id` int(10) unsigned NOT NULL default 0 AFTER `id`;
-
-UPDATE `%TABLE_PREFIX%content`
-  SET `content_id` = `id`;
+  CHANGE `type` `type` varchar(32) NOT NULL default 'other';
 
 DROP TABLE IF EXISTS `%TABLE_PREFIX%user_account`;
 CREATE TABLE `%TABLE_PREFIX%user_account` (
diff --git a/setup/inc/streams/core/install-mysql.sql b/setup/inc/streams/core/install-mysql.sql
index 3ecb6bff63ea7a9df79958e498b18981fdde17f1..873da492077dee0aa9ac826c7f9e6be4fa122558 100644
--- a/setup/inc/streams/core/install-mysql.sql
+++ b/setup/inc/streams/core/install-mysql.sql
@@ -83,9 +83,7 @@ CREATE TABLE `%TABLE_PREFIX%sequence` (
 DROP TABLE IF EXISTS `%TABLE_PREFIX%sla`;
 CREATE TABLE `%TABLE_PREFIX%sla` (
   `id` int(11) unsigned NOT NULL auto_increment,
-  `isactive` tinyint(1) unsigned NOT NULL default '1',
-  `enable_priority_escalation` tinyint(1) unsigned NOT NULL default '1',
-  `disable_overdue_alerts` tinyint(1) unsigned NOT NULL default '0',
+  `flags` int(10) unsigned NOT NULL default 3,
   `grace_period` int(10) unsigned NOT NULL default '0',
   `name` varchar(64) NOT NULL default '',
   `notes` text,
@@ -117,7 +115,7 @@ CREATE TABLE `%TABLE_PREFIX%form` (
     `id` int(11) unsigned NOT NULL auto_increment,
     `pid` int(10) unsigned DEFAULT NULL,
     `type` varchar(8) NOT NULL DEFAULT 'G',
-    `deletable` tinyint(1) NOT NULL DEFAULT 1,
+    `flags` int(10) unsigned NOT NULL DEFAULT 1,
     `title` varchar(255) NOT NULL,
     `instructions` varchar(512),
     `name` varchar(64) NOT NULL DEFAULT '',
@@ -134,9 +132,6 @@ CREATE TABLE `%TABLE_PREFIX%form_field` (
     `flags` int(10) unsigned DEFAULT 1,
     `type` varchar(255) NOT NULL DEFAULT 'text',
     `label` varchar(255) NOT NULL,
-    `required` tinyint(1) NOT NULL DEFAULT 0,
-    `private` tinyint(1) NOT NULL DEFAULT 0,
-    `edit_mask` tinyint(1) NOT NULL DEFAULT 0,
     `name` varchar(64) NOT NULL,
     `configuration` text,
     `sort` int(11) unsigned NOT NULL,
@@ -178,6 +173,7 @@ CREATE TABLE `%TABLE_PREFIX%list` (
     `sort_mode` enum('Alpha', '-Alpha', 'SortCol') NOT NULL DEFAULT 'Alpha',
     `masks` int(11) unsigned NOT NULL DEFAULT 0,
     `type` VARCHAR( 16 ) NULL DEFAULT NULL,
+    `configuration` text NOT NULL DEFAULT '',
     `notes` text,
     `created` datetime NOT NULL,
     `updated` datetime NOT NULL,
@@ -209,6 +205,7 @@ CREATE TABLE `%TABLE_PREFIX%department` (
   `email_id` int(10) unsigned NOT NULL default '0',
   `autoresp_email_id` int(10) unsigned NOT NULL default '0',
   `manager_id` int(10) unsigned NOT NULL default '0',
+  `flags` int(10) unsigned NOT NULL default 0,
   `name` varchar(128) NOT NULL default '',
   `signature` text NOT NULL,
   `ispublic` tinyint(1) unsigned NOT NULL default '1',
@@ -593,8 +590,7 @@ DROP TABLE IF EXISTS `%TABLE_PREFIX%team`;
 CREATE TABLE `%TABLE_PREFIX%team` (
   `team_id` int(10) unsigned NOT NULL auto_increment,
   `lead_id` int(10) unsigned NOT NULL default '0',
-  `isenabled` tinyint(1) unsigned NOT NULL default '1',
-  `noalerts` tinyint(1) unsigned NOT NULL default '0',
+  `flags` int(10) unsigned NOTN ULL default 1,
   `name` varchar(125) NOT NULL default '',
   `notes` text,
   `created` datetime NOT NULL,
@@ -635,6 +631,8 @@ CREATE TABLE `%TABLE_PREFIX%thread_entry` (
   `type` char(1) NOT NULL default '',
   `flags` int(11) unsigned NOT NULL default '0',
   `poster` varchar(128) NOT NULL default '',
+  `editor` int(10) unsigned NULL,
+  `editor_type` char(1) NULL,
   `source` varchar(32) NOT NULL default '',
   `title` varchar(255),
   `body` text NOT NULL,
@@ -677,6 +675,7 @@ CREATE TABLE `%TABLE_PREFIX%ticket` (
   `flags` int(10) unsigned NOT NULL default '0',
   `ip_address` varchar(64) NOT NULL default '',
   `source` enum('Web','Email','Phone','API','Other') NOT NULL default 'Other',
+  `source_extra` varchar(40) NULL default NULL,
   `isoverdue` tinyint(1) unsigned NOT NULL default '0',
   `isanswered` tinyint(1) unsigned NOT NULL default '0',
   `duedate` datetime default NULL,
@@ -782,7 +781,6 @@ CREATE TABLE `%TABLE_PREFIX%task` (
   `object_type` char(1) NOT NULL,
   `number` varchar(20) DEFAULT NULL,
   `dept_id` int(10) unsigned NOT NULL DEFAULT '0',
-  `sla_id` int(10) unsigned NOT NULL DEFAULT '0',
   `staff_id` int(10) unsigned NOT NULL DEFAULT '0',
   `team_id` int(10) unsigned NOT NULL DEFAULT '0',
   `lock_id` int(11) unsigned NOT NULL DEFAULT '0',
@@ -802,12 +800,10 @@ CREATE TABLE `%TABLE_PREFIX%task` (
 -- pages
 CREATE TABLE IF NOT EXISTS `%TABLE_PREFIX%content` (
   `id` int(10) unsigned NOT NULL auto_increment,
-  `content_id` int(10) unsigned NOT NULL default '0',
   `isactive` tinyint(1) unsigned NOT NULL default '0',
   `type` varchar(32) NOT NULL default 'other',
   `name` varchar(255) NOT NULL,
   `body` text NOT NULL,
-  `lang` varchar(16) NOT NULL default 'en_US',
   `notes` text,
   `created` datetime NOT NULL,
   `updated` datetime NOT NULL,
@@ -876,6 +872,7 @@ DROP TABLE IF EXISTS `%TABLE_PREFIX%user_email`;
 CREATE TABLE `%TABLE_PREFIX%user_email` (
   `id` int(10) unsigned NOT NULL auto_increment,
   `user_id` int(10) unsigned NOT NULL,
+  `flags` int(10) unsigned NOT NULL DEFAULT 0,
   `address` varchar(128) NOT NULL,
   PRIMARY KEY  (`id`),
   UNIQUE KEY `address` (`address`),