diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php
index c0a203646ffd02170cf4c5a1eff44778687722d8..9fa8253a949a7c58f89b63dc4a24851de1e52b5b 100644
--- a/include/class.dynamic_forms.php
+++ b/include/class.dynamic_forms.php
@@ -18,6 +18,7 @@
 **********************************************************************/
 require_once(INCLUDE_DIR . 'class.orm.php');
 require_once(INCLUDE_DIR . 'class.forms.php');
+require_once(INCLUDE_DIR . 'class.list.php');
 require_once(INCLUDE_DIR . 'class.filter.php');
 require_once(INCLUDE_DIR . 'class.signal.php');
 
@@ -900,248 +901,6 @@ class DynamicFormEntryAnswer extends VerySimpleModel {
     }
 }
 
-/**
- * Dynamic lists are used to represent list of arbitrary data that can be
- * used as dropdown or typeahead selections in dynamic forms. This model
- * defines a list. The individual items are stored in the DynamicListItem
- * model.
- */
-class DynamicList extends VerySimpleModel {
-
-    static $meta = array(
-        'table' => LIST_TABLE,
-        'ordering' => array('name'),
-        'pk' => array('id'),
-    );
-
-    var $_items;
-    var $_form;
-
-    function getSortModes() {
-        return array(
-            'Alpha'     => 'Alphabetical',
-            '-Alpha'    => 'Alphabetical (Reversed)',
-            'SortCol'   => 'Manually Sorted'
-        );
-    }
-
-    function getListOrderBy() {
-        switch ($this->sort_mode) {
-            case 'Alpha':   return 'value';
-            case '-Alpha':  return '-value';
-            case 'SortCol': return 'sort';
-        }
-    }
-
-    function getPluralName() {
-        if ($name = $this->get('name_plural'))
-            return $name;
-        else
-            return $this->get('name') . 's';
-    }
-
-    function getAllItems() {
-         return DynamicListItem::objects()->filter(
-                array('list_id'=>$this->get('id')))
-                ->order_by($this->getListOrderBy());
-    }
-
-    function getItems($limit=false, $offset=false) {
-        if (!$this->_items) {
-            $this->_items = DynamicListItem::objects()->filter(
-                array('list_id'=>$this->get('id'),
-                      'status__hasbit'=>DynamicListItem::ENABLED))
-                ->order_by($this->getListOrderBy());
-            if ($limit)
-                $this->_items->limit($limit);
-            if ($offset)
-                $this->_items->offset($offset);
-        }
-        return $this->_items;
-    }
-
-    function getItemCount() {
-        return DynamicListItem::objects()->filter(array('list_id'=>$this->id))
-            ->count();
-    }
-
-    function getConfigurationForm() {
-        if (!$this->_form) {
-            $this->_form = DynamicForm::lookup(
-                array('type'=>'L'.$this->get('id')));
-        }
-        return $this->_form;
-    }
-
-    function getProperties() {
-        if ($f = $this->getForm())
-            return $f->getFields();
-        return array();
-    }
-
-    function getForm() {
-        return $this->getConfigurationForm();
-    }
-
-    function save($refetch=false) {
-        if (count($this->dirty))
-            $this->set('updated', new SqlFunction('NOW'));
-        if (isset($this->dirty['notes']))
-            $this->notes = Format::sanitize($this->notes);
-        return parent::save($refetch);
-    }
-
-    function delete() {
-        $fields = DynamicFormField::objects()->filter(array(
-            'type'=>'list-'.$this->id))->count();
-        if ($fields == 0)
-            return parent::delete();
-        else
-            // Refuse to delete lists that are in use by fields
-            return false;
-    }
-
-    static function create($ht=false) {
-        $inst = parent::create($ht);
-        $inst->set('created', new SqlFunction('NOW'));
-        return $inst;
-    }
-
-    static function getSelections() {
-        $selections = array();
-        foreach (DynamicList::objects() as $list) {
-            $selections['list-'.$list->id] =
-                array($list->getPluralName(),
-                    SelectionField, $list->get('id'));
-        }
-        return $selections;
-    }
-}
-FormField::addFieldTypes('Custom Lists', array('DynamicList', 'getSelections'));
-
-/**
- * Represents a single item in a dynamic list
- *
- * Fields:
- * value - (char * 255) Actual list item content
- * extra - (char * 255) Other values that represent the same item in the
- *      list, such as an abbreviation. In practice, should be a
- *      space-separated list of tokens which should hit this list item in a
- *      search
- * sort - (int) If sorting by this field, represents the numeric sort order
- *      that this item should come in the dropdown list
- */
-class DynamicListItem extends VerySimpleModel {
-
-    static $meta = array(
-        'table' => LIST_ITEM_TABLE,
-        'pk' => array('id'),
-        'joins' => array(
-            'list' => array(
-                'null' => true,
-                'constraint' => array('list_id' => 'DynamicList.id'),
-            ),
-        ),
-    );
-
-    var $_config;
-    var $_form;
-
-    const ENABLED               = 0x0001;
-
-    protected function hasStatus($flag) {
-        return 0 !== ($this->get('status') & $flag);
-    }
-
-    protected function clearStatus($flag) {
-        return $this->set('status', $this->get('status') & ~$flag);
-    }
-
-    protected function setStatus($flag) {
-        return $this->set('status', $this->get('status') | $flag);
-    }
-
-    function isEnabled() {
-        return $this->hasStatus(self::ENABLED);
-    }
-
-    function enable() {
-        $this->setStatus(self::ENABLED);
-    }
-    function disable() {
-        $this->clearStatus(self::ENABLED);
-    }
-
-    function getConfiguration() {
-        if (!$this->_config) {
-            $this->_config = $this->get('properties');
-            if (is_string($this->_config))
-                $this->_config = JsonDataParser::parse($this->_config);
-            elseif (!$this->_config)
-                $this->_config = array();
-        }
-        return $this->_config;
-    }
-
-    function getFilterData() {
-        $raw = $this->getConfiguration();
-        $props = array();
-        if ($form = $this->getConfigurationForm()) {
-            foreach ($form->getFields() as $field) {
-                $tag = $field->get('id');
-                if (isset($raw[$tag]))
-                    $props[".$tag"] = $field->toString($raw[$tag]);
-            }
-        }
-        return $props;
-    }
-
-    function setConfiguration(&$errors=array()) {
-        $config = array();
-        foreach ($this->getConfigurationForm()->getFields() as $field) {
-            $val = $field->to_database($field->getClean());
-            $config[$field->get('id')] = is_array($val) ? $val[1] : $val;
-            $errors = array_merge($errors, $field->errors());
-        }
-        if (count($errors) === 0)
-            $this->set('properties', JsonDataEncoder::encode($config));
-
-        return count($errors) === 0;
-    }
-
-    function getConfigurationForm() {
-        if (!$this->_form) {
-            $this->_form = DynamicForm::lookup(
-                array('type'=>'L'.$this->get('list_id')));
-        }
-        return $this->_form;
-    }
-
-    function getVar($name) {
-        $config = $this->getConfiguration();
-        $name = mb_strtolower($name);
-        foreach ($this->getConfigurationForm()->getFields() as $field) {
-            if (mb_strtolower($field->get('name')) == $name)
-                return $config[$field->get('id')];
-        }
-    }
-
-    function toString() {
-        return $this->get('value');
-    }
-
-    function __toString() {
-        return $this->toString();
-    }
-
-    function delete() {
-        # Don't really delete, just unset the list_id to un-associate it with
-        # the list
-        $this->set('list_id', null);
-        return $this->save();
-    }
-}
-
 class SelectionField extends FormField {
     static $widget = 'SelectionWidget';
 
diff --git a/include/class.list.php b/include/class.list.php
new file mode 100644
index 0000000000000000000000000000000000000000..07c7119d6f4f431158bdc86bc949b3db9b2844d5
--- /dev/null
+++ b/include/class.list.php
@@ -0,0 +1,454 @@
+<?php
+/*********************************************************************
+    class.list.php
+
+    Custom List utils
+
+    Jared Hancock <jared@osticket.com>
+    Peter Rotich <peter@osticket.com>
+    Copyright (c)  2014 osTicket
+    http://www.osticket.com
+
+    Released under the GNU General Public License WITHOUT ANY WARRANTY.
+    See LICENSE.TXT for details.
+
+    vim: expandtab sw=4 ts=4 sts=4:
+**********************************************************************/
+
+require_once(INCLUDE_DIR .'class.dynamic_forms.php');
+
+/**
+ * Interface for Custom Lists
+ *
+ * Custom lists are used to represent list of arbitrary data that can be
+ * used as dropdown or typeahead selections in dynamic forms. This model
+ * defines a list. The individual items are stored in the "Item" model.
+ *
+ */
+
+interface CustomList {
+
+    function getId();
+    function getName();
+    function getPluralName();
+
+    function getNumItems();
+    function getAllItems();
+    function getItems($criteria);
+
+    function getForm(); // Config form
+    function hasProperties();
+
+    function getSortModes();
+    function getListOrderBy();
+
+    function isBuiltIn();
+
+    function update($vars, &$errors);
+    function delete();
+
+    static function create($vars, &$errors);
+}
+
+/*
+ * Base class for Built-in Custom Lists
+ *
+ * Built-in custom lists are lists that can be extended but within the
+ * constrains of system defined parameters.
+ *
+ */
+
+abstract class BuiltInCustomList implements CustomList {
+    static $sort_modes = array(
+            'Alpha'     => 'Alphabetical',
+            '-Alpha'    => 'Alphabetical (Reversed)',
+            'SortCol'   => 'Manually Sorted'
+    );
+
+    var $config = null;
+
+    function __construct() {
+        $this->config = new Config('CL'.$this->getId());
+    }
+
+    abstract function getId();
+    abstract function getName();
+    abstract function getPluralName();
+
+    abstract  function getInfo();
+
+    abstract function getNumItems();
+    abstract function getAllItems();
+    abstract function getItems($criteria);
+
+    abstract function getForm(); // Config form
+    abstract function hasProperties();
+
+    abstract function getListOrderBy();
+
+    function getSortModes() {
+        return static::$sort_modes;
+    }
+
+    function isBuiltIn() {
+        return true;
+    }
+
+    function set($field, $value) {
+
+        if (!$this->config)
+            return false;
+
+        return $this->config->set($field, $value);
+    }
+
+    abstract function update($vars, &$errors);
+
+    // Built-in list cannot be deleted
+    function delete() {
+        return false;
+    }
+
+    // Built-in list is defined - not created.
+    static function create($vars, &$errors) {
+        return false;
+    }
+
+    static function lookup($id) {
+
+        if (!($list=static::getLists())
+                // Built-in list exists
+                || !isset($list[$id])
+                // Handler exits
+                || !($handler = $list[$id]['handler'])
+                // It's a collable handler
+                || !class_exists($handler))
+           return null;
+
+        return new $handler();
+    }
+
+    static function getLists() {
+        //TODO: define built-in lists
+        return array();
+    }
+
+}
+
+/**
+ * Dynamic lists are Custom Lists solely defined by the user.
+ *
+ */
+class DynamicList extends VerySimpleModel implements CustomList {
+
+    static $meta = array(
+        'table' => LIST_TABLE,
+        'ordering' => array('name'),
+        'pk' => array('id'),
+    );
+
+    static $sort_modes = array(
+            'Alpha'     => 'Alphabetical',
+            '-Alpha'    => 'Alphabetical (Reversed)',
+            'SortCol'   => 'Manually Sorted'
+            );
+
+    // Required fields
+    static $fields = array('name', 'name_plural', 'sort_mode', 'notes');
+
+
+    var $_items;
+    var $_form;
+
+    function getId() {
+        return $this->get('id');
+    }
+
+    function isBuiltIn() {
+        return false;
+    }
+
+    function getInfo() {
+        return $this->ht;
+    }
+
+    function hasProperties() {
+        return ($this->getForm() && $this->getForm()->getFields());
+    }
+
+    function getSortModes() {
+       return static::$sort_modes;
+    }
+
+    function getListOrderBy() {
+        switch ($this->sort_mode) {
+            case 'Alpha':   return 'value';
+            case '-Alpha':  return '-value';
+            case 'SortCol': return 'sort';
+        }
+    }
+
+    function getName() {
+        return $this->get('name');
+    }
+
+    function getPluralName() {
+        if ($name = $this->get('name_plural'))
+            return $name;
+        else
+            return $this->get('name') . 's';
+    }
+
+    function getItemCount() {
+        return DynamicListItem::objects()->filter(array('list_id'=>$this->id))
+            ->count();
+    }
+
+    function getNumItems() {
+        return $this->getItemCount();
+    }
+
+    function getAllItems() {
+         return DynamicListItem::objects()->filter(
+                array('list_id'=>$this->get('id')))
+                ->order_by($this->getListOrderBy());
+    }
+
+    function getItems($limit=false, $offset=false) {
+        if (!$this->_items) {
+            $this->_items = DynamicListItem::objects()->filter(
+                array('list_id'=>$this->get('id'),
+                      'status__hasbit'=>DynamicListItem::ENABLED))
+                ->order_by($this->getListOrderBy());
+            if ($limit)
+                $this->_items->limit($limit);
+            if ($offset)
+                $this->_items->offset($offset);
+        }
+        return $this->_items;
+    }
+
+    function addItem($vars) {
+
+        $item = DynamicListItem::create(array(
+            'list_id' => $this->getId(),
+            'sort'  => $vars['sort'],
+            'value' => $vars['value'],
+            'extra' => $vars['abbrev']
+        ));
+
+        $item->save();
+
+        $this->_items = false;
+
+        return $item;
+    }
+
+    function getConfigurationForm() {
+        if (!$this->_form) {
+            $this->_form = DynamicForm::lookup(
+                array('type'=>'L'.$this->get('id')));
+        }
+        return $this->_form;
+    }
+
+    function getForm() {
+        return $this->getConfigurationForm();
+    }
+
+    function update($vars, &$errors) {
+        $required = array('name');
+        foreach (static::$fields as $f) {
+            if (in_array($f, $required) && !$vars[$f])
+                $errors[$f] = sprintf('%s is required', mb_convert_case($f, MB_CASE_TITLE));
+            elseif (isset($vars[$f]))
+                $this->set($f, $vars[$f]);
+        }
+
+        if ($errors)
+            return false;
+
+        return $this->save(true);
+    }
+
+    function save($refetch=false) {
+        if (count($this->dirty))
+            $this->set('updated', new SqlFunction('NOW'));
+        if (isset($this->dirty['notes']))
+            $this->notes = Format::sanitize($this->notes);
+        return parent::save($refetch);
+    }
+
+    function delete() {
+        $fields = DynamicFormField::objects()->filter(array(
+            'type'=>'list-'.$this->id))->count();
+        if ($fields == 0)
+            return parent::delete();
+        else
+            // Refuse to delete lists that are in use by fields
+            return false;
+    }
+
+    static function create($ht=false, &$errors=array()) {
+        $inst = parent::create($ht);
+        $inst->set('created', new SqlFunction('NOW'));
+        return $inst;
+    }
+
+    static function getSelections() {
+        $selections = array();
+        foreach (DynamicList::objects() as $list) {
+            $selections['list-'.$list->id] =
+                array($list->getPluralName(),
+                    SelectionField, $list->get('id'));
+        }
+        return $selections;
+    }
+
+}
+FormField::addFieldTypes('Custom Lists', array('DynamicList', 'getSelections'));
+
+/**
+ * Represents a single item in a dynamic list
+ *
+ * Fields:
+ * value - (char * 255) Actual list item content
+ * extra - (char * 255) Other values that represent the same item in the
+ *      list, such as an abbreviation. In practice, should be a
+ *      space-separated list of tokens which should hit this list item in a
+ *      search
+ * sort - (int) If sorting by this field, represents the numeric sort order
+ *      that this item should come in the dropdown list
+ */
+class DynamicListItem extends VerySimpleModel {
+
+    static $meta = array(
+        'table' => LIST_ITEM_TABLE,
+        'pk' => array('id'),
+        'joins' => array(
+            'list' => array(
+                'null' => true,
+                'constraint' => array('list_id' => 'DynamicList.id'),
+            ),
+        ),
+    );
+
+    var $_config;
+    var $_form;
+
+    const ENABLED               = 0x0001;
+
+    protected function hasStatus($flag) {
+        return 0 !== ($this->get('status') & $flag);
+    }
+
+    protected function clearStatus($flag) {
+        return $this->set('status', $this->get('status') & ~$flag);
+    }
+
+    protected function setStatus($flag) {
+        return $this->set('status', $this->get('status') | $flag);
+    }
+
+    function isEnabled() {
+        return $this->hasStatus(self::ENABLED);
+    }
+
+    function enable() {
+        $this->setStatus(self::ENABLED);
+    }
+    function disable() {
+        $this->clearStatus(self::ENABLED);
+    }
+
+    function getId() {
+        return $this->get('id');
+    }
+
+    function getValue() {
+        return $this->get('value');
+    }
+
+    function getAbbrev() {
+        return $this->get('extra');
+    }
+
+    function getSortOrder() {
+        return $this->get('sort');
+    }
+
+    function getConfiguration() {
+        if (!$this->_config) {
+            $this->_config = $this->get('properties');
+            if (is_string($this->_config))
+                $this->_config = JsonDataParser::parse($this->_config);
+            elseif (!$this->_config)
+                $this->_config = array();
+        }
+        return $this->_config;
+    }
+
+    function setConfiguration(&$errors=array()) {
+        $config = array();
+        foreach ($this->getConfigurationForm()->getFields() as $field) {
+            $val = $field->to_database($field->getClean());
+            $config[$field->get('id')] = is_array($val) ? $val[1] : $val;
+            $errors = array_merge($errors, $field->errors());
+        }
+        if (count($errors) === 0)
+            $this->set('properties', JsonDataEncoder::encode($config));
+
+        return count($errors) === 0;
+    }
+
+    function getConfigurationForm() {
+        if (!$this->_form) {
+            $this->_form = DynamicForm::lookup(
+                array('type'=>'L'.$this->get('list_id')));
+        }
+        return $this->_form;
+    }
+
+    function getVar($name) {
+        $config = $this->getConfiguration();
+        $name = mb_strtolower($name);
+        foreach ($this->getConfigurationForm()->getFields() as $field) {
+            if (mb_strtolower($field->get('name')) == $name)
+                return $config[$field->get('id')];
+        }
+    }
+
+    function toString() {
+        return $this->get('value');
+    }
+
+    function __toString() {
+        return $this->toString();
+    }
+
+    function update($vars, $save = true) {
+
+        foreach (array(
+                    'sort' => 'sort',
+                    'value' => 'value',
+                    'abbrev' => 'extra') as $k => $v) {
+            if (isset($vars[$k]))
+                $this->set($v, $vars[$k]);
+
+        }
+
+        if ($save)
+            $this->save();
+
+        return true;
+    }
+
+    function delete() {
+        # Don't really delete, just unset the list_id to un-associate it with
+        # the list
+        $this->set('list_id', null);
+        return $this->save();
+    }
+}
+
+?>
diff --git a/include/staff/dynamic-list.inc.php b/include/staff/dynamic-list.inc.php
index 32b8921e0707c4bd741f89efe33584c05af468f8..ad0e8d29d2bcd2e46b8e5710a51909c607f16850 100644
--- a/include/staff/dynamic-list.inc.php
+++ b/include/staff/dynamic-list.inc.php
@@ -1,11 +1,11 @@
 <?php
 
 $info=array();
-if($list && !$errors) {
-    $title = 'Update custom list';
+if ($list) {
+    $title = 'Update list';
     $action = 'update';
     $submit_text='Save Changes';
-    $info = $list->ht;
+    $info = $list->getInfo();
     $newcount=2;
 } else {
     $title = 'Add new custom list';
@@ -13,7 +13,8 @@ if($list && !$errors) {
     $submit_text='Add List';
     $newcount=4;
 }
-$info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
+
+$info=Format::htmlchars(($errors && $_POST) ? array_merge($info,$_POST) : $info);
 
 ?>
 <form action="?" method="post" id="save">
@@ -21,7 +22,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
     <input type="hidden" name="do" value="<?php echo $action; ?>">
     <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
     <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
-    <h2>Custom List</h2>
+    <h2>Custom List: <?php echo $list->getName(); ?></h2>
 
 <ul class="tabs">
     <li><a href="#definition" class="active">
@@ -45,17 +46,36 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
     <tbody>
         <tr>
             <td width="180" class="required">Name:</td>
-            <td><input size="50" type="text" name="name" value="<?php echo $info['name']; ?>"/>
-            <span class="error">*<br/><?php echo $errors['name']; ?></td>
+            <td>
+                <?php
+                if ($list->isBuiltIn())
+                    echo $info['name'];
+                else {
+                    echo sprintf('<input size="50" type="text" name="name"
+                            value="%s"/> <span
+                            class="error">*<br/>%s</span>',
+                            $info['name'], $errors['name']);
+                }
+                ?>
+            </td>
         </tr>
         <tr>
             <td width="180">Plural Name:</td>
-            <td><input size="50" type="text" name="name_plural" value="<?php echo $info['name_plural']; ?>"/></td>
+            <td>
+                <?php
+                    if ($list->isBuiltIn())
+                        echo $info['name_plural'];
+                    else
+                        echo sprintf('<input size="50" type="text"
+                                name="name_plural" value="%s"/>',
+                                $info['name_plural']);
+                ?>
+            </td>
         </tr>
         <tr>
             <td width="180">Sort Order:</td>
             <td><select name="sort_mode">
-                <?php foreach (DynamicList::getSortModes() as $key=>$desc) { ?>
+                <?php foreach ($list->getSortModes() as $key=>$desc) { ?>
                 <option value="<?php echo $key; ?>" <?php
                     if ($key == $info['sort_mode']) echo 'selected="selected"';
                     ?>><?php echo $desc; ?></option>
@@ -184,9 +204,9 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
     <thead>
     <?php if ($list) {
         $page = ($_GET['p'] && is_numeric($_GET['p'])) ? $_GET['p'] : 1;
-        $count = $list->getItemCount();
+        $count = $list->getNumItems();
         $pageNav = new Pagenate($count, $page, PAGE_LIMIT);
-        $pageNav->setURL('dynamic-list.php', 'id='.urlencode($_REQUEST['id']));
+        $pageNav->setURL('list.php', 'id='.urlencode($list->getId()));
         $showing=$pageNav->showing().' list items';
         ?>
     <?php }
@@ -200,7 +220,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
         <tr>
             <th></th>
             <th>Value</th>
-            <th>Extra <em style="display:inline">&mdash; abbreviations and such</em></th>
+            <th>Abbrev <em style="display:inline">&mdash; Abbreviations and such</em></th>
             <th>Disabled</th>
             <th>Delete</th>
         </tr>
@@ -208,22 +228,22 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 
     <tbody <?php if ($info['sort_mode'] == 'SortCol') { ?>
             class="sortable-rows" data-sort="sort-"<?php } ?>>
-        <?php if ($list)
-        $icon = ($info['sort_mode'] == 'SortCol')
-            ? '<i class="icon-sort"></i>&nbsp;' : '';
+        <?php
         if ($list) {
+            $icon = ($info['sort_mode'] == 'SortCol')
+                ? '<i class="icon-sort"></i>&nbsp;' : '';
         foreach ($list->getAllItems() as $i) {
-            $id = $i->get('id'); ?>
+            $id = $i->getId(); ?>
         <tr class="<?php if (!$i->isEnabled()) echo 'disabled'; ?>">
             <td><?php echo $icon; ?>
                 <input type="hidden" name="sort-<?php echo $id; ?>"
-                value="<?php echo $i->get('sort'); ?>"/></td>
+                value="<?php echo $i->getSortOrder(); ?>"/></td>
             <td><input type="text" size="40" name="value-<?php echo $id; ?>"
-                value="<?php echo $i->get('value'); ?>"/>
-                <?php if ($form && $form->getFields()) { ?>
+                value="<?php echo $i->getValue(); ?>"/>
+                <?php if ($list->hasProperties()) { ?>
                 <a class="action-button" style="float:none;overflow:inherit"
                     href="#ajax.php/list/item/<?php
-                        echo $i->get('id'); ?>/properties"
+                        echo $id ?>/properties"
                     onclick="javascript:
                         $('#overlay').show();
                         $('#field-config .body').load($(this).attr('href').substr(1));
@@ -231,8 +251,8 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                         return false;
                     "><i class="icon-edit"></i> Properties</a>
                 <?php } ?></td>
-            <td><input type="text" size="30" name="extra-<?php echo $id; ?>"
-                value="<?php echo $i->get('extra'); ?>"/></td>
+            <td><input type="text" size="30" name="abbrev-<?php echo $id; ?>"
+                value="<?php echo $i->getAbbrev(); ?>"/></td>
             <td>
                 <input type="checkbox" name="disable-<?php echo $id; ?>" <?php
                 if (!$i->isEnabled()) echo 'checked="checked"'; ?>/></td>
@@ -246,7 +266,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
             <td><?php echo $icon; ?> <em>+</em>
                 <input type="hidden" name="sort-new-<?php echo $i; ?>"/></td>
             <td><input type="text" size="40" name="value-new-<?php echo $i; ?>"/></td>
-            <td><input type="text" size="30" name="extra-new-<?php echo $i; ?>"/></td>
+            <td><input type="text" size="30" name="abbrev-new-<?php echo $i; ?>"/></td>
             <td></td>
             <td></td>
         </tr>
diff --git a/scp/lists.php b/scp/lists.php
index 57ffad7a26374d13768da9e826a25f6252a5ec7a..1b8e40675aa17dd45d0853c6158edf079b17c372 100644
--- a/scp/lists.php
+++ b/scp/lists.php
@@ -1,6 +1,7 @@
 <?php
 require('admin.inc.php');
-require_once(INCLUDE_DIR."/class.dynamic_forms.php");
+require_once(INCLUDE_DIR.'class.list.php');
+
 
 $list=null;
 if($_REQUEST['id'] && !($list=DynamicList::lookup($_REQUEST['id'])))
@@ -14,42 +15,42 @@ if($_POST) {
     $required = array('name');
     switch(strtolower($_POST['do'])) {
         case 'update':
-            foreach ($fields as $f)
-                if (in_array($f, $required) && !$_POST[$f])
-                    $errors[$f] = sprintf('%s is required',
-                        mb_convert_case($f, MB_CASE_TITLE));
-                elseif (isset($_POST[$f]))
-                    $list->set($f, $_POST[$f]);
-            if ($errors)
-                $errors['err'] = 'Unable to update custom list. Correct any error(s) below and try again.';
-            elseif ($list->save(true))
+            if ($list->update($_POST, $errors))
                 $msg = 'Custom list updated successfully';
+            elseif ($errors)
+                $errors['err'] = 'Unable to update custom list. Correct any error(s) below and try again.';
             else
                 $errors['err'] = 'Unable to update custom list. Unknown internal error';
 
-            foreach ($list->getAllItems() as $item) {
-                $id = $item->get('id');
-                if ($_POST["delete-$id"] == 'on') {
-                    $item->delete();
-                    continue;
-                }
-                foreach (array('sort','value','extra') as $i)
-                    if (isset($_POST["$i-$id"]))
-                        $item->set($i, $_POST["$i-$id"]);
+            if ($list->getNumItems()) {
+                foreach ($list->getAllItems() as $item) {
+                    $id = $item->getId();
+                    if ($_POST["delete-$id"] == 'on') {
+                        $item->delete();
+                        continue;
+                    }
 
-                if ($_POST["disable-$id"] == 'on')
-                    $item->disable();
-                else
-                    $item->enable();
+                    $item->update(array(
+                                'value' => $_POST["value-$id"],
+                                'abbrev' => $_POST["abbrev-$id"],
+                                'sort' => $_POST["name-$id"],
+                                ),
+                            false);
+
+                    if ($_POST["disable-$id"] == 'on')
+                        $item->disable();
+                    else
+                        $item->enable();
 
-                $item->save();
+                    $item->save();
+                }
             }
 
             $names = array();
             if (!$form) {
                 $form = DynamicForm::create(array(
-                    'type'=>'L'.$_REQUEST['id'],
-                    'title'=>$_POST['name'] . ' Properties'
+                    'type' => 'L'.$list->getId(),
+                    'title' => $list->getName() . ' Properties'
                 ));
                 $form->save(true);
             }
@@ -138,19 +139,16 @@ if($_POST) {
     }
 
     if ($list) {
-        for ($i=0; isset($_POST["prop-sort-new-$i"]); $i++) {
+        for ($i=0; isset($_POST["sort-new-$i"]); $i++) {
             if (!$_POST["value-new-$i"])
                 continue;
-            $item = DynamicListItem::create(array(
-                'list_id'=>$list->get('id'),
-                'sort'=>$_POST["sort-new-$i"],
-                'value'=>$_POST["value-new-$i"],
-                'extra'=>$_POST["extra-new-$i"]
-            ));
-            $item->save();
+
+            $list->addItem(array(
+                        'value' => $_POST["value-new-$i"],
+                        'abbrev' =>$_POST["abbrev-new-$i"],
+                        'sort' => $_POST["sort-new-$i"]
+                        ));
         }
-        # Invalidate items cache
-        $list->_items = false;
     }
 
     if ($form) {