From 53666db6be6655630c42b05a551bb13e2b3bd06e Mon Sep 17 00:00:00 2001
From: Jared Hancock <jared@osticket.com>
Date: Thu, 19 Sep 2013 18:46:28 +0000
Subject: [PATCH] Move client information to separate formset

This moves client information like name and email address out of the general
dynamic forms data for a ticket. It really paves the way for the first-class
user of the future.
---
 bootstrap.php                                 |  44 +-
 include/ajax.forms.php                        |  61 ++
 include/ajax.tickets.php                      |  20 +-
 include/ajax.users.php                        |   7 +-
 include/api.tickets.php                       |   2 +-
 include/class.client.php                      |  31 +-
 include/class.dynamic_forms.php               |  84 +-
 include/class.forms.php                       |  60 +-
 include/class.orm.php                         | 186 +++-
 include/class.ticket.php                      |  57 +-
 include/class.user.php                        | 218 +++++
 include/client/open.inc.php                   |   1 +
 include/client/tickets.inc.php                |  23 +-
 include/staff/dynamic-form.inc.php            |  34 +-
 include/staff/templates/dynamic-form.tmpl.php |   2 +
 include/staff/templates/user-info.tmpl.php    |  36 +
 include/staff/ticket-edit.inc.php             |   8 -
 include/staff/ticket-open.inc.php             |  13 +-
 include/staff/ticket-view.inc.php             |  46 +-
 include/staff/tickets.inc.php                 |  22 +-
 main.inc.php                                  |   1 +
 open.php                                      |  29 +-
 scp/ajax.php                                  |   4 +-
 scp/css/scp.css                               |   8 +
 scp/tickets.php                               |  31 +-
 setup/inc/sql/osTicket-mysql.sql              | 861 ------------------
 setup/inc/streams/core/install-mysql.sql      |  25 +-
 27 files changed, 875 insertions(+), 1039 deletions(-)
 create mode 100644 include/class.user.php
 create mode 100644 include/staff/templates/user-info.tmpl.php
 delete mode 100644 setup/inc/sql/osTicket-mysql.sql

diff --git a/bootstrap.php b/bootstrap.php
index 6132c2d1b..55b747cb6 100644
--- a/bootstrap.php
+++ b/bootstrap.php
@@ -65,6 +65,8 @@ class Bootstrap {
         define('FILE_CHUNK_TABLE',$prefix.'file_chunk');
 
         define('ATTACHMENT_TABLE',$prefix.'attachment');
+        define('USER_TABLE',$prefix.'user');
+        define('USER_EMAIL_TABLE',$prefix.'user_email');
 
         define('STAFF_TABLE',$prefix.'staff');
         define('TEAM_TABLE',$prefix.'team');
@@ -162,6 +164,27 @@ class Bootstrap {
             self::croak($ferror);
     }
 
+    function loadCode() {
+        #include required files
+        require(INCLUDE_DIR.'class.ostsession.php');
+        require(INCLUDE_DIR.'class.usersession.php');
+        require(INCLUDE_DIR.'class.pagenate.php'); //Pagenate helper!
+        require(INCLUDE_DIR.'class.log.php');
+        require(INCLUDE_DIR.'class.crypto.php');
+        require(INCLUDE_DIR.'class.timezone.php');
+        require(INCLUDE_DIR.'class.http.php');
+        require(INCLUDE_DIR.'class.signal.php');
+        require(INCLUDE_DIR.'class.nav.php');
+        require(INCLUDE_DIR.'class.page.php');
+        require(INCLUDE_DIR.'class.format.php'); //format helpers
+        require(INCLUDE_DIR.'class.validator.php'); //Class to help with basic form input validation...please help improve it.
+        require(INCLUDE_DIR.'class.mailer.php');
+        if (extension_loaded('mysqli'))
+            require_once INCLUDE_DIR.'mysqli.php';
+        else
+            require(INCLUDE_DIR.'mysql.php');
+    }
+
     function croak($message) {
         $msg = $message."\n\n".THISPAGE;
         Mailer::sendmail(ADMIN_EMAIL, 'osTicket Fatal Error', $msg,
@@ -196,6 +219,7 @@ if(!defined('PATH_SEPARATOR')){
 ini_set('include_path', './'.PATH_SEPARATOR.INCLUDE_DIR.PATH_SEPARATOR.PEAR_DIR);
 
 require(INCLUDE_DIR.'class.osticket.php');
+require(INCLUDE_DIR.'class.misc.php');
 
 // Determine the path in the URI used as the base of the osTicket
 // installation
@@ -204,26 +228,6 @@ if (!defined('ROOT_PATH') && ($rp = osTicket::get_root_path(dirname(__file__))))
 
 Bootstrap::init();
 
-#include required files
-require(INCLUDE_DIR.'class.ostsession.php');
-require(INCLUDE_DIR.'class.usersession.php');
-require(INCLUDE_DIR.'class.pagenate.php'); //Pagenate helper!
-require(INCLUDE_DIR.'class.log.php');
-require(INCLUDE_DIR.'class.crypto.php');
-require(INCLUDE_DIR.'class.misc.php');
-require(INCLUDE_DIR.'class.timezone.php');
-require(INCLUDE_DIR.'class.http.php');
-require(INCLUDE_DIR.'class.signal.php');
-require(INCLUDE_DIR.'class.nav.php');
-require(INCLUDE_DIR.'class.page.php');
-require(INCLUDE_DIR.'class.format.php'); //format helpers
-require(INCLUDE_DIR.'class.validator.php'); //Class to help with basic form input validation...please help improve it.
-require(INCLUDE_DIR.'class.mailer.php');
-if (extension_loaded('mysqli'))
-    require_once INCLUDE_DIR.'mysqli.php';
-else
-    require(INCLUDE_DIR.'mysql.php');
-
 #CURRENT EXECUTING SCRIPT.
 define('THISPAGE', Misc::currentURL());
 define('THISURI', $_SERVER['REQUEST_URI']);
diff --git a/include/ajax.forms.php b/include/ajax.forms.php
index 37c8657c0..ac49c8cdb 100644
--- a/include/ajax.forms.php
+++ b/include/ajax.forms.php
@@ -39,6 +39,67 @@ class DynamicFormsAjaxAPI extends AjaxController {
         else
             $field->save();
     }
+
+    function _getUserForms() {
+        $static = new Form(array(
+            'first' => new TextboxField(array(
+                'label'=>'First Name', 'configuration'=>array('size'=>30))
+            ),
+            'last' => new TextboxField(array(
+                'label'=>'Last Name', 'configuration'=>array('size'=>30))
+            ),
+            'email' => new TextboxField(array(
+                'label'=>'Default Email', 'configuration'=>array(
+                    'validator'=>'email', 'size'=>40))
+            ),
+        ));
+
+        return $static;
+    }
+
+    function getUserInfo($user_id) {
+        $user = User::lookup($user_id);
+        $static = $this->_getUserForms();
+
+        $data = $user->ht;
+        $data['email'] = $user->default_email->address;
+        $static->data($data);
+
+        $custom = array();
+        foreach ($user->getDynamicData() as $cd)
+            $custom[] = $cd->getForm();
+
+        include(STAFFINC_DIR . 'templates/user-info.tmpl.php');
+    }
+
+    function saveUserInfo($user_id) {
+        $user = User::lookup($user_id);
+        $static = $this->_getUserForms();
+        $valid = $static->isValid();
+
+        $custom_data = $user->getDynamicData();
+        $custom = array();
+        foreach ($custom_data as $cd) {
+            $cf = $custom[] = $cd->getForm();
+            $valid &= $cf->isValid();
+        }
+
+        if (!$valid) {
+            include(STAFFINC_DIR . 'templates/user-info.tmpl.php');
+            return;
+        }
+
+        $data = $static->getClean();
+        $user->first = $data['first'];
+        $user->last = $data['last'];
+        $user->default_email->address = $data['email'];
+        $user->save();
+        $user->default_email->save();
+
+        // Save custom data
+        foreach ($custom_data as $cd)
+            $cd->save();
+    }
 }
 
 ?>
diff --git a/include/ajax.tickets.php b/include/ajax.tickets.php
index a981e5ae4..771dcf7f6 100644
--- a/include/ajax.tickets.php
+++ b/include/ajax.tickets.php
@@ -30,13 +30,11 @@ class TicketsAjaxAPI extends AjaxController {
         $limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25;
         $tickets=array();
 
-        $sql='SELECT DISTINCT ticketID, email.value AS email'
+        $sql='SELECT DISTINCT ticketID, email.address AS email'
             .' FROM '.TICKET_TABLE.' ticket'
-            .' LEFT JOIN '.FORM_ENTRY_TABLE.' entry ON entry.ticket_id = ticket.ticket_id '
-            .' LEFT JOIN '.FORM_ANSWER_TABLE.' email ON email.entry_id = entry.id '
-            .' LEFT JOIN '.FORM_FIELD_TABLE.' field ON email.field_id = field.id '
-            .' WHERE field.name = "email"'
-            .' AND ticketID LIKE \''.db_input($_REQUEST['q'], false).'%\'';
+            .' LEFT JOIN '.USER_TABLE.' user ON user.id = ticket.user_id'
+            .' LEFT JOIN '.USER_EMAIL_TABLE.' email ON user.id = email.user_id'
+            .' WHERE ticketID LIKE \''.db_input($_REQUEST['q'], false).'%\'';
 
         $sql.=' AND ( staff_id='.db_input($thisstaff->getId());
 
@@ -64,13 +62,11 @@ class TicketsAjaxAPI extends AjaxController {
         $limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25;
         $tickets=array();
 
-        $sql='SELECT email.value AS email, count(ticket.ticket_id) as tickets '
+        $sql='SELECT email.address AS email, count(ticket.ticket_id) as tickets '
             .' FROM '.TICKET_TABLE.' ticket'
-            .' JOIN '.FORM_ENTRY_TABLE.' entry ON entry.ticket_id = ticket.ticket_id '
-            .' JOIN '.FORM_ANSWER_TABLE.' email ON email.entry_id = entry.id '
-            .' JOIN '.FORM_FIELD_TABLE.' field ON email.field_id = field.id '
-            .' WHERE field.name = "email"'
-            .' AND email.value LIKE \'%'.db_input(strtolower($_REQUEST['q']), false).'%\' ';
+            .' JOIN '.USER_TABLE.' user ON user.id = ticket.user_id'
+            .' JOIN '.USER_EMAIL_TABLE.' email ON user.id = email.user_id'
+            .' WHERE email.address LIKE \'%'.db_input(strtolower($_REQUEST['q']), false).'%\' ';
 
         $sql.=' AND ( staff_id='.db_input($thisstaff->getId());
 
diff --git a/include/ajax.users.php b/include/ajax.users.php
index d18f3c332..46e868827 100644
--- a/include/ajax.users.php
+++ b/include/ajax.users.php
@@ -31,9 +31,10 @@ class UsersAjaxAPI extends AjaxController {
         $limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25;
         $users=array();
 
-        $sql='SELECT DISTINCT email, name '
-            .' FROM '.TICKET_TABLE
-            .' WHERE email LIKE \'%'.db_input(strtolower($_REQUEST['q']), false).'%\' '
+        $sql='SELECT DISTINCT email.address, concat_ws(" ", first, last) as name '
+            .' FROM '.USER_TABLE.' user '
+            .' JOIN '.USER_EMAIL_TABLE.' email ON user.id = email.user_id '
+            .' WHERE email.address LIKE \'%'.db_input(strtolower($_REQUEST['q']), false).'%\' '
             .' ORDER BY created '
             .' LIMIT '.$limit;
            
diff --git a/include/api.tickets.php b/include/api.tickets.php
index a648d10f7..b57f65125 100644
--- a/include/api.tickets.php
+++ b/include/api.tickets.php
@@ -126,7 +126,7 @@ class TicketApiController extends ApiController {
 
         # Save dynamic forms
         foreach ($forms as $f) {
-            $f->set('ticket_id', $ticket->getId());
+            $f->setTicketId($ticket->getId());
             $f->save();
         }
 
diff --git a/include/class.client.php b/include/class.client.php
index 8cf29e31d..3c4ce5243 100644
--- a/include/class.client.php
+++ b/include/class.client.php
@@ -40,17 +40,19 @@ class Client {
         if(!$id && !($id=$this->getId()))
             return false;
 
-        $sql='SELECT ticket.ticket_id, ticketID, email.value as email, phone.value as phone '
+        $sql='SELECT ticket.ticket_id, ticketID, email.address as email, phone.value as phone '
             .' FROM '.TICKET_TABLE.' ticket '
-            .' LEFT JOIN '.FORM_ENTRY_TABLE.' entry ON entry.ticket_id = ticket.ticket_id '
-            .' LEFT JOIN '.FORM_ANSWER_TABLE.' email ON email.entry_id = entry.id '
-            .' LEFT JOIN '.FORM_FIELD_TABLE.' field1 ON email.field_id = field1.id '
-            .' LEFT JOIN '.FORM_ANSWER_TABLE.' phone ON email.entry_id = entry.id '
-            .' LEFT JOIN '.FORM_FIELD_TABLE.' field2 ON phone.field_id = field2.id '
-            .' WHERE field1.name = "email" AND field2.name="phone" AND ticketID='.db_input($id);
+            .' LEFT JOIN '.USER_TABLE.' user ON user.id = ticket.user_id'
+            .' LEFT JOIN '.USER_EMAIL_TABLE.' email ON user.id = email.user_id'
+            .' LEFT JOIN '.FORM_ENTRY_TABLE.' entry ON
+                    (entry.object_id = ticket.ticket_id AND entry.object_type = "T")'
+            .' LEFT JOIN '.FORM_ANSWER_TABLE.' phone ON phone.entry_id = entry.id'
+            .' LEFT JOIN '.FORM_FIELD_TABLE.' field ON
+                   (phone.field_id = field.id AND field.name="phone")'
+            .' WHERE ticketID='.db_input($id);
 
         if($email)
-            $sql.=' AND email.value = '.db_input($email);
+            $sql.=' AND email.address = '.db_input($email);
 
         if(!($res=db_query($sql)) || !db_num_rows($res))
             return NULL;
@@ -60,10 +62,8 @@ class Client {
         $this->ticket_id  = $this->ht['ticket_id'];
         $this->ticketID   = $this->ht['ticketID'];
 
-        $entry = DynamicFormEntry::forTicket($this->ticket_id);
-        foreach ($entry as $form)
-            if ($form->getAnswer('name'))
-                $this->fullname = $form->getAnswer('name');
+        $user = User::lookup(array('emails__address'=>$this->ht['email']));
+        $this->fullname   = $user->getFullName();
 
         $this->username   = $this->ht['email'];
         $this->email      = $this->ht['email'];
@@ -132,10 +132,9 @@ class Client {
     /* ------------- Static ---------------*/
     function getLastTicketIdByEmail($email) {
         $sql='SELECT ticket.ticketID '.TICKET_TABLE.' ticket '
-            .' LEFT JOIN '.FORM_ENTRY_TABLE.' entry ON entry.ticket_id = ticket.ticket_id '
-            .' LEFT JOIN '.FORM_ANSWER_TABLE.' email ON email.entry_id = entry.id '
-            .' LEFT JOIN '.FORM_FIELD_TABLE.' field ON email.field_id = field.id '
-            .' WHERE field.name = "email" AND email.value = '.db_input($email)
+            .' LEFT JOIN '.USER_TABLE.' user ON user.id = ticket.user_id'
+            .' LEFT JOIN '.USER_EMAIL_TABLE.' email ON user.id = email.user_id'
+            .' WHERE email.address = '.db_input($email)
             .' ORDER BY ticket.created '
             .' LIMIT 1';
         if(($res=db_query($sql)) && db_num_rows($res))
diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php
index 6aad0b264..0418bab1e 100644
--- a/include/class.dynamic_forms.php
+++ b/include/class.dynamic_forms.php
@@ -31,6 +31,13 @@ class DynamicForm extends VerySimpleModel {
         'pk' => array('id'),
     );
 
+    // Registered form types
+    static $types = array(
+        'T' => 'Ticket Information',
+        'U' => 'User Information',
+    );
+
+    var $_form;
     var $_fields;
     var $_dfields;
 
@@ -51,6 +58,12 @@ class DynamicForm extends VerySimpleModel {
         return $this->_dfields;
     }
 
+    // Multiple inheritance -- delegate to Form
+    function __call($what, $args) {
+        return call_user_func_array(
+            array($this->getForm(), $what), $args);
+    }
+
     function hasField($name) {
         foreach ($this->getDynamicFields() as $f)
             if ($f->get('name') == $name)
@@ -61,10 +74,11 @@ class DynamicForm extends VerySimpleModel {
     function getInstructions() { return $this->get('instructions'); }
 
     function getForm() {
-        $fields = $this->getFields();
-        foreach ($fields as &$f)
-            $f = $f->getField();
-        return new Form($fields, $this->title, $this->instructions);
+        if (!$this->_form) {
+            $fields = $this->getFields();
+            $this->_form = new Form($fields, $this->title, $this->instructions);
+        }
+        return $this->_form;
     }
 
     function instanciate($sort=1) {
@@ -72,6 +86,12 @@ class DynamicForm extends VerySimpleModel {
             'form_id'=>$this->get('id'), 'sort'=>$sort));
     }
 
+    function data($data) {
+        if ($data instanceof DynamicFormEntry) {
+            $this->_fields = $data->getFields();
+        }
+    }
+
     function save() {
         if (count($this->dirty))
             $this->set('updated', new SqlFunction('NOW'));
@@ -91,6 +111,42 @@ class DynamicForm extends VerySimpleModel {
         }
         return $inst;
     }
+
+    static function addFormTypes($types) {
+        static::$types += $types;
+    }
+
+    static function allTypes() {
+        return static::$types;
+    }
+}
+
+class UserForm extends DynamicForm {
+    static function objects() {
+        $os = parent::objects();
+        return $os->filter(array('type'=>'U'));
+    }
+
+    function getStaticForm() {
+        static $form = null;
+        if (!$form)
+            $form = new Form(array(
+            'email' => new TextboxField(array(
+                'id'=>'email', 'label'=>'Email Address', 'required'=>true,
+                'validator' => 'email', 'configuration'=>array(
+                    'autocomplete'=>false, 'classes'=>array('typeahead'),
+                    'size'=>40)
+            )),
+            'name' => new TextboxField(array(
+                'id'=>'name', 'label'=>'Full Name', 'required'=>true,
+                'configuration' => array('size'=>40),
+            )),
+            'phone' => new PhoneField(array(
+                'id'=>'c', 'label'=>'Phone Number', 'required'=>false, 'default'=>'',
+                )),
+            ), 'User Information');
+        return $form;
+    }
 }
 
 require_once(INCLUDE_DIR . "class.json.php");
@@ -236,8 +292,11 @@ class DynamicFormEntry extends VerySimpleModel {
     function getInstructions() { return $this->getForm()->getInstructions(); }
 
     function getForm() {
-        if (!$this->_form)
+        if (!$this->_form) {
             $this->_form = DynamicForm::lookup($this->get('form_id'));
+            if ($this->id)
+                $this->_form->data($this);
+        }
         return $this->_form;
     }
 
@@ -274,9 +333,22 @@ class DynamicFormEntry extends VerySimpleModel {
         static $entries = array();
         if (!isset($entries[$ticket_id]))
             $entries[$ticket_id] = DynamicFormEntry::objects()
-                ->filter(array('ticket_id'=>$ticket_id));
+                ->filter(array('object_id'=>$ticket_id, 'object_type'=>'T'));
         return $entries[$ticket_id];
     }
+    function setTicketId($ticket_id) {
+        $this->object_type = 'T';
+        $this->object_id = $ticket_id;
+    }
+
+    function forClient($user_id) {
+        return DynamicFormEntry::objects()
+            ->filter(array('object_id'=>$user_id, 'object_type'=>'U'));
+    }
+    function setClientId($user_id) {
+        $this->object_type = 'U';
+        $this->object_id = $user_id;
+    }
 
     /**
      * addMissingFields
diff --git a/include/class.forms.php b/include/class.forms.php
index d01017843..cc5d07f07 100644
--- a/include/class.forms.php
+++ b/include/class.forms.php
@@ -23,14 +23,21 @@ class Form {
     var $title = 'Unnamed Form';
     var $instructions = '';
 
+    var $_errors;
+
     function Form() {
         call_user_func_array(array($this, '__construct'), func_get_args());
     }
-    function __construct($fields=array(), $title='Unnamed', $instructions='') {
+    function __construct($fields=array(), $title=false, $instructions=false) {
         $this->fields = $fields;
         $this->title = $title;
         $this->instructions = $instructions;
     }
+    function data($source) {
+        foreach ($this->fields as $name=>$f)
+            if (isset($source[$name]))
+                $f->value = $source[$name];
+    }
 
     function getFields() {
         return $this->fields;
@@ -39,16 +46,39 @@ class Form {
     function getInstructions() { return $this->instructions; }
 
     function isValid() {
-        $this->validate();
-        foreach ($this->fields as $f)
-            if (!$f->isValidEntry())
-                return false;
-        return true;
+        if (!is_array($this->_errors)) {
+            $this->_errors = array();
+            $this->getClean();
+            foreach ($this->getFields() as $field)
+                if ($field->errors())
+                    $this->_errors[$field->get('id')] = $field->errors();
+        }
+        return !$this->_errors;
+    }
+
+    function getClean() {
+        if (!$this->_clean) {
+            $this->_clean = array();
+            foreach ($this->getFields() as $key=>$field)
+                $this->_clean[$key] = $field->getClean();
+        }
+        return $this->_clean;
+    }
+
+    function errors() {
+        return $this->_errors;
     }
 
-    function validate() {
-        foreach ($this->fields as $f)
-            $f->validateEntry();
+    function render($staff=true, $title=false, $instructions=false) {
+        if ($title)
+            $this->title = $title;
+        if ($instructions)
+            $this->instructions = $instructions;
+        $form = $this;
+        if ($staff)
+            include(STAFFINC_DIR . 'templates/dynamic-form.tmpl.php');
+        else
+            include(CLIENTINC_DIR . 'templates/dynamic-form.tmpl.php');
     }
 }
 
@@ -159,7 +189,7 @@ class FormField {
      * useful error message indicating what is wrong with the input.
      */
     function parse($value) {
-        return $value;
+        return trim($value);
     }
 
     /**
@@ -233,7 +263,10 @@ class FormField {
     function getAnswer() { return $this->answer; }
 
     function getFormName() {
-        return '-field-id-'.$this->get('id');
+        if (is_numeric($this->get('id')))
+            return '-field-id-'.$this->get('id');
+        else
+            return $this->get('id');
     }
 
     function render() {
@@ -512,10 +545,15 @@ class TextboxWidget extends Widget {
             $size = "size=\"{$config['size']}\"";
         if (isset($config['length']))
             $maxlength = "maxlength=\"{$config['length']}\"";
+        if (isset($config['classes']))
+            $classes = 'class="'.implode(' ', $config['classes']).'"';
+        if (isset($config['autocomplete']))
+            $autocomplete = 'autocomplete="'.($config['autocomplete']?'on':'off').'"';
         ?>
         <span style="display:inline-block">
         <input type="text" id="<?php echo $this->name; ?>"
             <?php echo $size . " " . $maxlength; ?>
+            <?php echo $classes.' '.$autocomplete; ?>
             name="<?php echo $this->name; ?>"
             value="<?php echo Format::htmlchars($this->value); ?>"/>
         </span>
diff --git a/include/class.orm.php b/include/class.orm.php
index 02e6baeaa..86d3015f1 100644
--- a/include/class.orm.php
+++ b/include/class.orm.php
@@ -29,6 +29,7 @@ class VerySimpleModel {
 
     function __construct($row) {
         $this->ht = $row;
+        $this->__setupForeignLists();
         $this->dirty = array();
     }
 
@@ -38,10 +39,29 @@ class VerySimpleModel {
     function __get($field) {
         if (array_key_exists($field, $this->ht))
             return $this->ht[$field];
-        return $this->{$field};
+        elseif (isset(static::$meta['joins'][$field])) {
+            // TODO: Support instrumented lists and such
+            $j = static::$meta['joins'][$field];
+            $class = $j['fkey'][0];
+            $v = $this->ht[$field] = $class::lookup($this->ht[$j['local']]);
+            return $v;
+        }
     }
 
     function set($field, $value) {
+        // Update of foreign-key by assignment to model instance
+        if (isset(static::$meta['joins'][$field])) {
+            $j = static::$meta['joins'][$field];
+            // XXX: Ensure $value instanceof $j['fkey'][0]
+            if ($value->__new__)
+                $value->save();
+            // Capture the object under the object's field name
+            $this->ht[$field] = $value;
+            // Capture the foreign key id value
+            $field = $j['local'];
+            $value = $value->{$j['fkey'][1]};
+            // Fall through to the standard logic below
+        }
         // XXX: Fully support or die if updating pk
         // XXX: The contents of $this->dirty should be the value after the
         // previous fetch or save. For instance, if the value is changed more
@@ -62,10 +82,45 @@ class VerySimpleModel {
             $this->set($field, $value);
     }
 
-    function _inspect() {
+    function __setupForeignLists() {
+        // Construct related lists
+        if (isset(static::$meta['joins'])) {
+            foreach (static::$meta['joins'] as $name => $j) {
+                if (isset($j['list']) && $j['list']) {
+                    $fkey = $j['fkey'];
+                    $this->{$name} = new InstrumentedList(
+                        // Send Model, Foriegn-Field, Local-Id
+                        array($fkey[0], $fkey[1], $this->{$j['local']})
+                    );
+                }
+            }
+        }
+    }
+
+    static function _inspect() {
         if (!static::$meta['table'])
             throw new OrmConfigurationError(
-                'Model does not define meta.table', $this);
+                'Model does not define meta.table', get_called_class());
+
+        // Break down foreign-key metadata
+        foreach (static::$meta['joins'] as $field => &$j) {
+            if (isset($j['reverse'])) {
+                list($model, $key) = explode('.', $j['reverse']);
+                $info = $model::$meta['joins'][$key];
+                $constraint = array();
+                foreach ($info['constraint'] as $foreign => $local) {
+                    list(,$field) = explode('.', $local);
+                    $constraint[$field] = "$model.$foreign";
+                }
+                $j['constraint'] = $constraint;
+                $j['list'] = true;
+            }
+            // XXX: Make this better (ie. composite keys)
+            $keys = array_keys($j['constraint']);
+            $foreign = $j['constraint'][$keys[0]];
+            $j['fkey'] = explode('.', $foreign);
+            $j['local'] = $keys[0];
+        }
     }
 
     static function objects() {
@@ -127,6 +182,8 @@ class VerySimpleModel {
             if (count($pk) == 1)
                 $this->ht[$pk[0]] = db_insert_id();
             $this->__new__ = false;
+            // Setup lists again
+            $this->__setupForeignLists();
         }
         # Refetch row from database
         # XXX: Too much voodoo
@@ -233,6 +290,12 @@ class QuerySet implements IteratorAggregate, ArrayAccess {
         return $this;
     }
 
+    function values_flat() {
+        $this->values = func_get_args();
+        $this->iterator = 'FlatArrayIterator';
+        return $this;
+    }
+
     function all() {
         return $this->getIterator()->asArray();
     }
@@ -242,6 +305,10 @@ class QuerySet implements IteratorAggregate, ArrayAccess {
         return $compiler->compileCount($this);
     }
 
+    function exists() {
+        return $this->count() > 0;
+    }
+
     // IteratorAggregate interface
     function getIterator() {
         if (!isset($this->_iterator))
@@ -267,7 +334,7 @@ class QuerySet implements IteratorAggregate, ArrayAccess {
         return (string)$this->getQuery();
     }
 
-    function getQuery() {
+    function getQuery($options=array()) {
         if (isset($this->query))
             return $this->query;
 
@@ -276,7 +343,7 @@ class QuerySet implements IteratorAggregate, ArrayAccess {
         if (!$this->ordering && isset($model::$meta['ordering']))
             $this->ordering = $model::$meta['ordering'];
 
-        $compiler = new $this->compiler();
+        $compiler = new $this->compiler($options);
         $this->query = $compiler->compileSelect($this);
 
         return $this->query;
@@ -290,9 +357,11 @@ class ModelInstanceIterator implements Iterator, ArrayAccess {
     var $position = 0;
     var $queryset;
 
-    function __construct($queryset) {
-        $this->model = $queryset->model;
-        $this->resource = $queryset->getQuery();
+    function __construct($queryset=false) {
+        if ($queryset) {
+            $this->model = $queryset->model;
+            $this->resource = $queryset->getQuery();
+        }
     }
 
     function buildModel($row) {
@@ -353,7 +422,58 @@ class ModelInstanceIterator implements Iterator, ArrayAccess {
     }
 }
 
+class FlatArrayIterator extends ModelInstanceIterator {
+    function __construct($queryset) {
+        $this->resource = $queryset->getQuery();
+    }
+    function fillTo($index) {
+        while ($this->resource && $index >= count($this->cache)) {
+            if ($row = $this->resource->getRow()) {
+                $this->cache += $row;
+            } else {
+                $this->resource->close();
+                $this->resource = null;
+                break;
+            }
+        }
+    }
+}
+
+class InstrumentedList extends ModelInstanceIterator {
+    var $key;
+    var $id;
+
+    function __construct($fkey, $queryset=false) {
+        list($model, $this->key, $this->id) = $fkey;
+        if (!$queryset)
+            $queryset = $model::objects()->filter(array($this->key=>$this->id));
+        parent::__construct($queryset);
+        if (!$this->id)
+            $this->resource = null;
+    }
+
+    function add($object) {
+        $object->{$this->key} = $this->id;
+        $object->save();
+        $this->list[] = $object;
+    }
+    function remove($object) {
+        $object->delete();
+    }
+
+    function offsetUnset($a) {
+        $this->fillTo($a);
+        $this->cache[$a]->delete();
+    }
+    function offsetSet($a, $b) {
+        $this->fillTo($a);
+        $this->cache[$a]->delete();
+        $this->add($b);
+    }
+}
+
 class SqlCompiler {
+    var $options = array();
     var $params = array();
     var $joins = array();
     var $aliases = array();
@@ -363,6 +483,11 @@ class SqlCompiler {
         'exact' => '%$1s = %$2s'
     );
 
+    function __construct($options=false) {
+        if ($options)
+            $this->options = array_merge($this->options, $options);
+    }
+
     /**
      * Handles breaking down a field or model search descriptor into the
      * model search path, field, and operator parts. When used in a queryset
@@ -508,7 +633,7 @@ class SqlCompiler {
                 // Allow operators to be callable rather than sprintf
                 // strings
                 if (is_callable($op))
-                    $filter[] = $op($field, $value);
+                    $filter[] = call_user_func($op, $field, $value);
                 else
                     $filter[] = sprintf($op, $field, $this->input($value));
             }
@@ -605,8 +730,8 @@ class MySqlCompiler extends SqlCompiler {
     }
 
     function input($what) {
-        if ($b instanceof QuerySet) {
-            $q = $b->getQuery();
+        if ($what instanceof QuerySet) {
+            $q = $what->getQuery(array('nosort'=>true));
             $this->params += $q->params;
             return '(' . (string)$q . ')';
         }
@@ -664,7 +789,7 @@ class MySqlCompiler extends SqlCompiler {
         }
 
         $sort = '';
-        if ($queryset->ordering) {
+        if ($queryset->ordering && !isset($this->options['nosort'])) {
             $orders = array();
             foreach ($queryset->ordering as $sort) {
                 $dir = 'ASC';
@@ -753,13 +878,15 @@ class MysqlExecutor {
 
         $types = '';
         $ps = array();
-        foreach ($params as $p) {
+        foreach ($params as &$p) {
             if (is_int($p))
                 $types .= 'i';
             elseif (is_string($p))
                 $types .= 's';
+            // TODO: Emit error if param is null
             $ps[] = &$p;
         }
+        unset($p);
         array_unshift($ps, $types);
         call_user_func_array(array($this->stmt,'bind_param'), $ps);
     }
@@ -804,6 +931,39 @@ class MysqlExecutor {
         return $output;
     }
 
+    function getRow() {
+        $output = array();
+        $variables = array();
+
+        if (!isset($this->stmt))
+            $this->_prepare();
+
+        foreach ($this->fields as $f)
+            $variables[] = &$output[]; // pass by reference
+
+        call_user_func_array(array($this->stmt, 'bind_result'), $variables);
+        if (!$this->next())
+            return false;
+        return $output;
+    }
+
+    function getStruct() {
+        $output = array();
+        $variables = array();
+
+        if (!isset($this->stmt))
+            $this->_prepare();
+
+        foreach ($this->fields as $f)
+            $variables[] = &$output[$f->table][$f->name]; // pass by reference
+
+        // TODO: Figure out what the table alias for the root model will be
+        call_user_func_array(array($this->stmt, 'bind_result'), $variables);
+        if (!$this->next())
+            return false;
+        return $output;
+    }
+
     function close() {
         if (!$this->stmt)
             return;
diff --git a/include/class.ticket.php b/include/class.ticket.php
index 2f22a1169..12c30c02a 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -31,6 +31,7 @@ include_once(INCLUDE_DIR.'class.priority.php');
 include_once(INCLUDE_DIR.'class.sla.php');
 include_once(INCLUDE_DIR.'class.canned.php');
 require_once(INCLUDE_DIR.'class.dynamic_forms.php');
+require_once(INCLUDE_DIR.'class.user.php');
 
 class Ticket {
 
@@ -181,8 +182,31 @@ class Ticket {
         return $this->number;
     }
 
+    function getOwnerId() {
+        return $this->ht['user_id'];
+    }
+
+    function getOwner() {
+        if (!isset($this->user))
+            $this->user = User::lookup($this->getOwnerId());
+        return $this->user;
+    }
+
     function getEmail(){
-        return $this->_answers['email'];
+        if ($o = $this->getOwner())
+            return $o->getEmail();
+        return null;
+    }
+
+    function getReplyToEmail() {
+        if ($this->ht['user_email_id']) {
+            if (!isset($this->reply_email))
+                $this->reply_email = UserEmail::lookup($this->ht['user_email_id']);
+            return $this->reply_email->address;
+        }
+        else {
+            return $this->getEmail();
+        }
     }
 
     function getAuthToken() {
@@ -191,7 +215,9 @@ class Ticket {
     }
 
     function getName(){
-        return $this->_answers['name'];
+        if ($o = $this->getOwner())
+            return $o->getFullName();
+        return null;
     }
 
     function getSubject() {
@@ -1704,13 +1730,12 @@ class Ticket {
             return 0;
 
         $sql ='SELECT ticket.ticket_id FROM '.TICKET_TABLE.' ticket '
-             .' LEFT JOIN '.FORM_ENTRY_TABLE.' entry ON entry.ticket_id = ticket.ticket_id '
-             .' LEFT JOIN '.FORM_ANSWER_TABLE.' email ON email.entry_id = entry.id '
-             .' LEFT JOIN '.FORM_FIELD_TABLE.' field ON email.field_id = field.id '
-             .' WHERE field.name = "email" AND ticket.ticketID='.db_input($extId);
+             .' LEFT JOIN '.USER_TABLE.' user ON user.id = ticket.user_id'
+             .' LEFT JOIN '.USER_EMAIL_TABLE.' email ON user.id = email.user_id'
+             .' WHERE ticket.ticketID='.db_input($extId);
 
         if($email)
-            $sql .= ' AND email.value = '.db_input($email);
+            $sql .= ' AND email.address = '.db_input($email);
 
         if(($res=db_query($sql)) && db_num_rows($res))
             list($id)=db_fetch_row($res);
@@ -1817,6 +1842,8 @@ class Ticket {
 
         if(!$email || !Validator::is_email($email))
             return null;
+        if (!$user = User::lookup(array('emails__address'=>$email)))
+            return null;
 
         $sql='SELECT count(open.ticket_id) as open, count(closed.ticket_id) as closed '
             .' FROM '.TICKET_TABLE.' ticket '
@@ -1824,10 +1851,7 @@ class Ticket {
                 ON (open.ticket_id=ticket.ticket_id AND open.status=\'open\') '
             .' LEFT JOIN '.TICKET_TABLE.' closed
                 ON (closed.ticket_id=ticket.ticket_id AND closed.status=\'closed\')'
-            .' LEFT JOIN '.FORM_ENTRY_TABLE.' entry ON entry.ticket_id = ticket.ticket_id '
-            .' LEFT JOIN '.FORM_ANSWER_TABLE.' email ON email.entry_id = entry.id '
-            .' LEFT JOIN '.FORM_FIELD_TABLE.' field ON email.field_id = field.id '
-            .' WHERE field.name = "email" AND email.value = '.db_input($email);
+            .' WHERE ticket.user_id = '.db_input($user->getId());
 
         return db_fetch_array(db_query($sql));
     }
@@ -1841,7 +1865,7 @@ class Ticket {
         global $ost, $cfg, $thisclient, $_FILES;
 
         // Drop extra whitespace
-        foreach (array('email', 'phone', 'subject', 'name') as $f)
+        foreach (array('phone', 'subject') as $f)
             if (isset($vars[$f]))
                 $vars[$f] = trim($vars[$f]);
 
@@ -1924,6 +1948,13 @@ class Ticket {
         //Any error above is fatal.
         if($errors)  return 0;
 
+        # Identify the user creating the ticket
+        $user_info = UserForm::getStaticForm()->getClean();
+        if (isset($vars['emailId']) || !isset($user_info['email']))
+            $user_info = $vars;
+        $user = User::fromForm($user_info);
+        $user_email = UserEmail::ensure($user_info['email']);
+
         # Perform ticket filter actions on the new ticket arguments
         if ($ticket_filter) $ticket_filter->apply($vars);
 
@@ -1972,6 +2003,8 @@ class Ticket {
         $extId=Ticket::genExtRandID();
         $sql='INSERT INTO '.TICKET_TABLE.' SET created=NOW() '
             .' ,lastmessage= NOW()'
+            .' ,user_id='.db_input($user->id)
+            .' ,user_email_id='.db_input($user_email->id)
             .' ,ticketID='.db_input($extId)
             .' ,dept_id='.db_input($deptId)
             .' ,topic_id='.db_input($topicId)
diff --git a/include/class.user.php b/include/class.user.php
new file mode 100644
index 000000000..b6bc367f3
--- /dev/null
+++ b/include/class.user.php
@@ -0,0 +1,218 @@
+<?php
+/*********************************************************************
+    class.user.php
+
+    External end-user identification for osTicket
+
+    Peter Rotich <peter@osticket.com>
+    Jared Hancock <jared@osticket.com>
+    Copyright (c)  2006-2013 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.orm.php');
+
+class UserEmailModel extends VerySimpleModel {
+    static $meta = array(
+        'table' => USER_EMAIL_TABLE,
+        'pk' => array('id'),
+        'joins' => array(
+            'user' => array(
+                'constraint' => array('user_id' => 'UserModel.id')
+            )
+        )
+    );
+}
+
+class UserModel extends VerySimpleModel {
+    static $meta = array(
+        'table' => USER_TABLE,
+        'pk' => array('id'),
+        'joins' => array(
+            'emails' => array(
+                'reverse' => 'UserEmailModel.user',
+            ),
+            'default_email' => array(
+                'null' => true,
+                'constraint' => array('default_email_id' => 'UserEmailModel.id')
+            ),
+        )
+    );
+
+    var $emails;
+
+    static function objects() {
+        $qs = parent::objects();
+        #$qs->select_related('default_email');
+        return $qs;
+    }
+
+    function getId() {
+        return $this->id;
+    }
+
+    function getDefaultEmailAddress() {
+        return $this->getDefaultEmail()->address;
+    }
+
+    function getDefaultEmail() {
+        return $this->default_email;
+    }
+}
+
+class User extends UserModel {
+
+    function __construct($ht) {
+        parent::__construct($ht);
+        // TODO: Make this automatic with select_related()
+        if (isset($ht['default_email_id']))
+            $this->default_email = UserEmail::lookup($ht['default_email_id']);
+    }
+
+    static function fromForm($data=false) {
+        // Try and lookup by email address
+        $user = User::lookup(array('emails__address'=>$data['email']));
+        if (!$user) {
+            $user = User::create(array('name'=>$data['name'],
+                'default_email'=>
+                UserEmail::create(array('address'=>$data['email']))
+            ));
+            $user->save();
+            $user->emails->add($user->default_email);
+        }
+
+        return $user;
+    }
+
+    function getEmail() {
+        return $this->default_email->address;
+    }
+
+    function getFullName() {
+        return $this->name;
+    }
+
+    function getName() {
+        return new PersonsName($this->name);
+    }
+
+    function getDynamicData() {
+        $data = DynamicFormEntry::forClient($this->id);
+        if (!$data[0]) {
+            $data = array();
+            foreach (UserForm::objects() as $f) {
+                $g = $f->instanciate();
+                $g->setClientId($this->id);
+                $data[] = $g;
+            }
+        }
+        return $data;
+    }
+}
+User::_inspect();
+
+class PersonsName {
+    var $parts;
+    var $name;
+
+    function __construct($name) {
+        $this->parts = static::splitName($name);
+        $this->name = $name;
+    }
+
+    function getFirst() {
+        return $this->parts['first'];
+    }
+
+    function getLast() {
+        return $this->parts['last'];
+    }
+
+    function getFormal() {
+        return trim($this->parts['salutation'].' '.$this->parts['last']);
+    }
+
+    function getFull() {
+        return trim($this->parts['first'].' '.$this->parts['last']);
+    }
+
+    function getComplete() {
+        return trim($this->parts['salutation'].' '.$this->parts['first']
+            .' '.$this->parts['last'].' '.$this->parts['suffix']);
+    }
+
+    function getLastFirst() {
+        return $this->parts['last'].', '.$this->parts['first'];
+    }
+
+    function __toString() {
+        return $this->getLastFirst();
+    }
+
+    /**
+     * Thanks, http://stackoverflow.com/a/14420217
+     */
+    static function splitName($name) {
+        $results = array();
+
+        // If there is a comma in the name, reverse the name
+        if (mb_strpos($name, ',' !== false)) {
+            list($last, $first) = explode(',', $name);
+            $name = $first.' '.$last;
+        }
+
+        $r = explode(' ', $name);
+        $size = count($r);
+
+        //check first for period, assume salutation if so
+        if (mb_strpos($r[0], '.') === false)
+        {
+            $results['salutation'] = '';
+            $results['first'] = $r[0];
+        }
+        else
+        {
+            $results['salutation'] = $r[0];
+            $results['first'] = $r[1];
+        }
+
+        //check last for period, assume suffix if so
+        if (mb_strpos($r[$size - 1], '.') === false)
+        {
+            $results['suffix'] = '';
+        }
+        else
+        {
+            $results['suffix'] = $r[$size - 1];
+        }
+
+        //combine remains into last
+        $start = ($results['salutation']) ? 2 : 1;
+        $end = ($results['suffix']) ? $size - 2 : $size - 1;
+
+        $last = '';
+        for ($i = $start; $i <= $end; $i++)
+        {
+            $last .= ' '.$r[$i];
+        }
+        $results['last'] = trim($last);
+
+        return $results;
+    }
+
+}
+
+class UserEmail extends UserEmailModel {
+    static function ensure($address) {
+        $email = static::lookup(array('address'=>$address));
+        if (!$email) {
+            $email = static::create(array('address'=>$address));
+            $email->save();
+        }
+        return $email;
+    }
+}
diff --git a/include/client/open.inc.php b/include/client/open.inc.php
index f39a0ded1..ac8a9353d 100644
--- a/include/client/open.inc.php
+++ b/include/client/open.inc.php
@@ -39,6 +39,7 @@ $info=($_POST && $errors)?Format::htmlchars($_POST):$info;
             <font class="error">*&nbsp;<?php echo $errors['topicId']; ?></font>
         </td>
     </tr>
+    <?php UserForm::getStaticForm()->render(false, 'Your Information'); ?>
     </tbody>
     <tbody id="dynamic-form">
         <?php if ($forms) {
diff --git a/include/client/tickets.inc.php b/include/client/tickets.inc.php
index 81284b271..04898d5e4 100644
--- a/include/client/tickets.inc.php
+++ b/include/client/tickets.inc.php
@@ -18,8 +18,8 @@ if(isset($_REQUEST['status'])) { //Query string status has nothing to do with th
     $status='open'; //Defaulting to open
 }
 
-$sortOptions=array('id'=>'ticketID', 'name'=>'ticket.name', 'subject'=>'ticket.subject',
-                    'email'=>'ticket.email', 'status'=>'ticket.status', 'dept'=>'dept_name','date'=>'ticket.created');
+$sortOptions=array('id'=>'ticketID', 'name'=>'user.name', 'subject'=>'subject.value',
+                    'email'=>'email.address', 'status'=>'ticket.status', 'dept'=>'dept_name','date'=>'ticket.created');
 $orderWays=array('DESC'=>'DESC','ASC'=>'ASC');
 //Sorting options...
 $order_by=$order=null;
@@ -39,24 +39,23 @@ $x=$sort.'_sort';
 $$x=' class="'.strtolower($order).'" ';
 
 $qselect='SELECT ticket.ticket_id,ticket.ticketID,ticket.dept_id,isanswered, '
-        .'dept.ispublic, subject.value as subject, name.value as name, email.value as email, '
-        .'dept_name,ticket. status, ticket.source, ticket.created ';
+    .'dept.ispublic, subject.value as subject, '
+    .'user.name, email.address as email, '
+    .'dept_name,ticket. status, ticket.source, ticket.created ';
 
-$dynfields='(SELECT entry.ticket_id, value FROM '.FORM_ANSWER_TABLE.' ans '.
+$dynfields='(SELECT entry.object_id, value FROM '.FORM_ANSWER_TABLE.' ans '.
          'LEFT JOIN '.FORM_ENTRY_TABLE.' entry ON entry.id=ans.entry_id '.
          'LEFT JOIN '.FORM_FIELD_TABLE.' field ON field.id=ans.field_id '.
-         'WHERE field.name = "%1$s") %1$s ON ticket.ticket_id = %1$s.ticket_id ';
+         'WHERE field.name = "%1$s" entry.object_type="T") %1$s ON ticket.ticket_id = %1$s.ticket_id ';
 $subject_sql = sprintf($dynfields, 'subject');
-$email_sql = sprintf($dynfields, 'email');
-$name_sql = sprintf($dynfields, 'name');
 
 $qfrom='FROM '.TICKET_TABLE.' ticket '
       .' LEFT JOIN '.DEPT_TABLE.' dept ON (ticket.dept_id=dept.dept_id) '
-      .' LEFT JOIN '.$subject_sql
-      .' LEFT JOIN '.$email_sql
-      .' LEFT JOIN '.$name_sql;
+      .' LEFT JOIN '.USER_TABLE.' user ON user.id = ticket.user_id'
+      .' LEFT JOIN '.USER_EMAIL_TABLE.' email ON user.id = email.user_id'
+      .' LEFT JOIN '.$subject_sql;
 
-$qwhere =' WHERE email.value='.db_input($thisclient->getEmail());
+$qwhere =' WHERE email.address='.db_input($thisclient->getEmail());
 
 if($status){
     $qwhere.=' AND ticket.status='.db_input($status);
diff --git a/include/staff/dynamic-form.inc.php b/include/staff/dynamic-form.inc.php
index 9ce167350..4af7cde38 100644
--- a/include/staff/dynamic-form.inc.php
+++ b/include/staff/dynamic-form.inc.php
@@ -55,7 +55,39 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
     <thead>
         <tr>
             <th colspan="7">
-                <em>Form Fields</em>
+                <em><strong>User Information Fields</strong> more information here</em>
+            </th>
+        </tr>
+        <tr>
+            <th></th>
+            <th>Label</th>
+            <th>Type</th>
+            <th>Name</th>
+            <th>Private</th>
+            <th>Required</th>
+        </tr>
+    </thead>
+    <tbody>
+        <tr>
+            <td><input type="checkbox" disabled="disabled"/></td>
+            <td>Full Name</td><td>Short Answer</td><td>name</td>
+            <td><input type="checkbox" disabled="disabled"/></td>
+            <td><input type="checkbox" disabled="disabled" checked="checked"/></td></tr>
+        <tr>
+            <td><input type="checkbox" disabled="disabled"/></td>
+            <td>Email Address</td><td>Short Answer</td><td>email</td>
+            <td><input type="checkbox" disabled="disabled"/></td>
+            <td><input type="checkbox" disabled="disabled" checked="checked"/></td></tr>
+        <tr>
+            <td><input type="checkbox" disabled="disabled"/></td>
+            <td>Phone Number</td><td>Phone Number</td><td>phone</td>
+            <td><input type="checkbox" disabled="disabled"/></td>
+            <td><input type="checkbox" disabled="disabled"/></td></tr>
+    </tbody>
+    <thead>
+        <tr>
+            <th colspan="7">
+                <em><strong>Form Fields</strong> fields available for ticket information</em>
             </th>
         </tr>
         <tr>
diff --git a/include/staff/templates/dynamic-form.tmpl.php b/include/staff/templates/dynamic-form.tmpl.php
index 93bb577ea..e54d5bfc1 100644
--- a/include/staff/templates/dynamic-form.tmpl.php
+++ b/include/staff/templates/dynamic-form.tmpl.php
@@ -1,8 +1,10 @@
+    <?php if ($form->getTitle()) { ?>
     <tr><th colspan="2">
         <em><strong><?php echo Format::htmlchars($form->getTitle()); ?></strong>:
         <?php echo Format::htmlchars($form->getInstructions()); ?></em>
     </th></tr>
     <?php
+    }
     foreach ($form->getFields() as $field) {
         ?>
         <tr><td class="multi-line <?php if ($field->get('required')) echo 'required'; ?>">
diff --git a/include/staff/templates/user-info.tmpl.php b/include/staff/templates/user-info.tmpl.php
new file mode 100644
index 000000000..b07e19561
--- /dev/null
+++ b/include/staff/templates/user-info.tmpl.php
@@ -0,0 +1,36 @@
+<h3>User Information &mdash; <?php echo $user->getFullName() ?></h3>
+<a class="close" href="">&times;</a>
+<hr/>
+<form method="post" action="ajax.php/form/user-info/<?php
+        echo $user->get('id'); ?>" onsubmit="javascript:
+        var form = $(this);
+        $.post(this.action, form.serialize(), function(data, status, xhr) {
+            if (!data.length) {
+                form.closest('.dialog').hide();
+                $('#overlay').hide();
+            } else {
+                form.closest('.dialog').empty().append(data);
+            }
+        });
+        return false;
+        ">
+    <table width="100%">
+    <?php
+        echo csrf_token();
+        $static->render();
+        foreach ($custom as $form)
+            $form->render();
+    ?>
+    </table>
+    <hr style="margin-top:3em"/>
+    <p class="full-width">
+        <span class="buttons" style="float:left">
+            <input type="reset" value="Reset">
+            <input type="button" value="Cancel" class="close">
+        </span>
+        <span class="buttons" style="float:right">
+            <input type="submit" value="Save">
+        </span>
+     </p>
+</form>
+<div class="clear"></div>
diff --git a/include/staff/ticket-edit.inc.php b/include/staff/ticket-edit.inc.php
index 10e042588..643e147c0 100644
--- a/include/staff/ticket-edit.inc.php
+++ b/include/staff/ticket-edit.inc.php
@@ -10,14 +10,6 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$ticket->getUpdateInfo());
  <input type="hidden" name="id" value="<?php echo $ticket->getId(); ?>">
  <h2>Update Ticket #<?php echo $ticket->getExtId(); ?></h2>
  <table class="form_table" width="940" border="0" cellspacing="0" cellpadding="2">
-    <thead>
-        <tr>
-            <th colspan="2">
-                <h4>Ticket Update</h4>
-                <em><strong>User Information</strong>: Make sure the email address is valid.</em>
-            </th>
-        </tr>
-    </thead>
     <tbody>
         <tr>
             <th colspan="2">
diff --git a/include/staff/ticket-open.inc.php b/include/staff/ticket-open.inc.php
index c06117c27..e72514b93 100644
--- a/include/staff/ticket-open.inc.php
+++ b/include/staff/ticket-open.inc.php
@@ -17,21 +17,16 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
         </tr>
     </thead>
     <tbody>
-    <?php
-    if($cfg->notifyONNewStaffTicket()) { ?>
+        <?php
+        UserForm::getStaticForm()->render();
+        if($cfg->notifyONNewStaffTicket()) {  ?>
         <tr>
-            <th>
-            <em><strong>User Information</strong></em>
-            </th>
-        </tr>
             <td width="160">Alert:</td>
             <td>
-            &nbsp;&nbsp;&nbsp;
             <input type="checkbox" name="alertuser" <?php echo (!$errors || $info['alertuser'])? 'checked="checked"': ''; ?>>Send alert to user.
             </td>
         </tr>
-            <?php
-             } ?>
+        <?php } ?>
         <tr>
             <th colspan="2">
                 <em><strong>Ticket Information &amp; Options</strong>:</em>
diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php
index 5b4359c78..e99560eb6 100644
--- a/include/staff/ticket-view.inc.php
+++ b/include/staff/ticket-view.inc.php
@@ -143,29 +143,32 @@ if($ticket->isOverdue())
         <td width="50%">
             <table border="0" cellspacing="" cellpadding="4" width="100%">
                 <tr>
-                    <th width="100">Name:</th>
-                    <td><?php echo Format::htmlchars($ticket->getName()); ?></td>
-                </tr>
-                <tr>
-                    <th>Email:</th>
-                    <td>
-                    <?php
-                        echo $ticket->getEmail();
+                    <th width="100">Client:</th>
+                    <td><a href="ajax.php/form/user-info/<?php
+                            echo $ticket->getOwnerId(); ?>"
+                        onclick="javascript:
+                            $('#overlay').show();
+                            $('#user-info .body').load(this.href);
+                            $('#user-info').show();
+                            return false;
+                            "><i class="icon-user"></i> <?php
+                        echo Format::htmlchars($ticket->getName()); ?></a>
+                        <?php
                         if(($client=$ticket->getClient())) {
-                            echo sprintf('&nbsp;&nbsp;<a href="tickets.php?a=search&query=%s" title="Related Tickets" data-dropdown="#action-dropdown-stats">(<b>%d</b>)</a>',
-                                    urlencode($ticket->getEmail()), $client->getNumTickets());
+                            echo sprintf('&nbsp;&nbsp;<a href="tickets.php?a=search&ownerId=%d" title="Related Tickets" data-dropdown="#action-dropdown-stats">(<b>%d</b>)</a>',
+                                    urlencode($ticket->getOwnerId()), $client->getNumTickets());
                         ?>
                             <div id="action-dropdown-stats" class="action-dropdown anchor-right">
                                 <ul>
                                     <?php
                                     if(($open=$client->getNumOpenTickets()))
-                                        echo sprintf('<li><a href="tickets.php?a=search&status=open&query=%s"><i class="icon-folder-open-alt"></i> %d Open Tickets</a></li>',
-                                                $ticket->getEmail(), $open);
+                                        echo sprintf('<li><a href="tickets.php?a=search&status=open&ownerId=%s"><i class="icon-folder-open-alt"></i> %d Open Tickets</a></li>',
+                                                $ticket->getOwnerId(), $open);
                                     if(($closed=$client->getNumClosedTickets()))
-                                        echo sprintf('<li><a href="tickets.php?a=search&status=closed&query=%s"><i class="icon-folder-close-alt"></i> %d Closed Tickets</a></li>',
-                                                $ticket->getEmail(), $closed);
+                                        echo sprintf('<li><a href="tickets.php?a=search&status=closed&ownerId=%d"><i class="icon-folder-close-alt"></i> %d Closed Tickets</a></li>',
+                                                $ticket->getOwnerId(), $closed);
                                     ?>
-                                    <li><a href="tickets.php?a=search&query=<?php echo $ticket->getEmail(); ?>"><i class="icon-double-angle-right"></i> All Tickets</a></li>
+                                    <li><a href="tickets.php?a=search&ownerId=<?php echo $ticket->getOwnerId(); ?>"><i class="icon-double-angle-right"></i> All Tickets</a></li>
                                 </u>
                             </div>
                     <?php
@@ -173,6 +176,12 @@ if($ticket->isOverdue())
                     ?>
                     </td>
                 </tr>
+                <tr>
+                    <th>Default Email:</th>
+                    <td>
+                    <?php echo $ticket->getEmail(); ?>
+                    </td>
+                </tr>
                 <tr>
                     <th>Phone:</th>
                     <td><?php echo $ticket->getPhoneNumber(); ?></td>
@@ -447,9 +456,9 @@ if(!$cfg->showNotesInline()) { ?>
                 </td>
                 <td width="765">
                     <?php
-                    $to = $ticket->getEmail();
+                    $to = $ticket->getReplyToEmail();
                     if(($name=$ticket->getName()) && !strpos($name,'@'))
-                        $to =sprintf('%s <em>&lt;%s&gt;</em>', $name, $ticket->getEmail());
+                        $to =sprintf('%s <em>&lt;%s&gt;</em>', $name, $to);
                     echo $to;
                     ?>
                     &nbsp;&nbsp;&nbsp;
@@ -821,6 +830,9 @@ if(!$cfg->showNotesInline()) { ?>
     <?php
     } ?>
 </div>
+<div style="display:none;" class="dialog" id="user-info">
+    <div class="body"></div>
+</div>
 <div style="display:none;" class="dialog" id="print-options">
     <h3>Ticket Print Options</h3>
     <a class="close" href="">&times;</a>
diff --git a/include/staff/tickets.inc.php b/include/staff/tickets.inc.php
index 732c5c277..5d1ea6238 100644
--- a/include/staff/tickets.inc.php
+++ b/include/staff/tickets.inc.php
@@ -114,13 +114,17 @@ if($search):
         }elseif(strpos($searchTerm,'@') && Validator::is_email($searchTerm)){ //pulling all tricks!
             # XXX: What about searching for email addresses in the body of
             #      the thread message
-            $qwhere.=" AND email.value='$queryterm'";
+            $qwhere.=" AND email.address='$queryterm'";
         }else{//Deep search!
             //This sucks..mass scan! search anything that moves!
 
             $deep_search=true;
         }
     }
+    // OwnerId
+    if ($_REQUEST['ownerId']) {
+        $qwhere .= ' AND ticket.user_id='.db_input($_REQUEST['ownerId']);
+    }
     //department
     if($_REQUEST['deptId'] && in_array($_REQUEST['deptId'],$thisstaff->getDepts())) {
         //This is dept based search..perm taken care above..put the sucker in.
@@ -237,23 +241,23 @@ $$x=' class="'.strtolower($order).'" ';
 if($_GET['limit'])
     $qstr.='&limit='.urlencode($_GET['limit']);
 
-$dynfields='(SELECT entry.ticket_id, value FROM '.FORM_ANSWER_TABLE.' ans '.
+$dynfields='(SELECT entry.object_id, value FROM '.FORM_ANSWER_TABLE.' ans '.
          'LEFT JOIN '.FORM_ENTRY_TABLE.' entry ON entry.id=ans.entry_id '.
          'LEFT JOIN '.FORM_FIELD_TABLE.' field ON field.id=ans.field_id '.
-         'WHERE field.name = "%1$s")';
+         'WHERE field.name = "%1$s" AND entry.object_type="T")';
 $subject_sql=sprintf($dynfields, 'subject');
-$name_sql=sprintf($dynfields, 'name');
-$email_sql=sprintf($dynfields, 'email');
 
 $qselect ='SELECT DISTINCT ticket.ticket_id,lock_id,ticketID,ticket.dept_id,ticket.staff_id,ticket.team_id '
-         .' ,subject.value as subject,name.value as name,email.value as email,dept_name '
+    .' ,subject.value as subject'
+    .' ,user.name'
+    .' ,email.address as email, dept_name '
          .' ,ticket.status,ticket.source,isoverdue,isanswered,ticket.created,pri.* ';
 
 $qfrom=' FROM '.TICKET_TABLE.' ticket '.
+       ' LEFT JOIN '.USER_TABLE.' user ON user.id = ticket.user_id'.
+       ' LEFT JOIN '.USER_EMAIL_TABLE.' email ON user.id = email.user_id'.
        ' LEFT JOIN '.DEPT_TABLE.' dept ON ticket.dept_id=dept.dept_id '.
-       ' LEFT JOIN '.$subject_sql.' subject ON subject.ticket_id = ticket.ticket_id '.
-       ' LEFT JOIN '.$name_sql.' name ON name.ticket_id = ticket.ticket_id '.
-       ' LEFT JOIN '.$email_sql.' email ON email.ticket_id = ticket.ticket_id ';
+       ' LEFT JOIN '.$subject_sql.' subject ON subject.object_id = ticket.ticket_id';
 
 $sjoin='';
 if($search && $deep_search) {
diff --git a/main.inc.php b/main.inc.php
index 286f3ef11..56da2cb71 100644
--- a/main.inc.php
+++ b/main.inc.php
@@ -21,6 +21,7 @@ if(!strcasecmp(basename($_SERVER['SCRIPT_NAME']),basename(__FILE__))) die('kwahe
 require('bootstrap.php');
 Bootstrap::loadConfig();
 Bootstrap::defineTables(TABLE_PREFIX);
+Bootstrap::loadCode();
 Bootstrap::connect();
 
 if(!($ost=osTicket::start()) || !($cfg = $ost->getConfig()))
diff --git a/open.php b/open.php
index 372c33839..1d1511c3a 100644
--- a/open.php
+++ b/open.php
@@ -31,19 +31,22 @@ if($_POST):
     }
 
     $interest=array('name','email','subject');
-    $topic=Topic::lookup($vars['topicId']);
-    $form=DynamicForm::lookup($topic->ht['form_id'])->instanciate();
-    # Collect name, email, and subject address for banning and such
-    foreach ($form->getAnswers() as $answer) {
-        $fname = $answer->getField()->get('name');
-        if (in_array($fname, $interest))
-            # XXX: Assigning to _POST not considered great PHP
-            #      coding style
-            $vars[$fname] = $answer->getField()->getClean();
+    if ($topic=Topic::lookup($vars['topicId'])) {
+        $form=DynamicForm::lookup($topic->ht['form_id'])->instanciate();
+        # Collect name, email, and subject address for banning and such
+        foreach ($form->getAnswers() as $answer) {
+            $fname = $answer->getField()->get('name');
+            if (in_array($fname, $interest))
+                # XXX: Assigning to _POST not considered great PHP
+                #      coding style
+                $vars[$fname] = $answer->getField()->getClean();
+        }
+        if (!$form->isValid())
+            $errors = array_merge($errors, $form->errors());
     }
-    if (!$form->isValid())
-        $errors = array_merge($errors, $form->errors());
-
+    $form2 = UserForm::getStaticForm();
+    if (!$form2->isValid())
+        $errors += $form2->errors();
     if(!$errors && $cfg->allowOnlineAttachments() && $_FILES['attachments'])
         $vars['files'] = AttachmentFile::format($_FILES['attachments'], true);
 
@@ -52,7 +55,7 @@ if($_POST):
         $msg='Support ticket request created';
         Draft::deleteForNamespace('ticket.client.'.substr(session_id(), -12));
         # TODO: Save dynamic form(s)
-        $form->set('ticket_id', $ticket->getId());
+        $form->setTicketId($ticket->getId());
         $form->save();
         $ticket->loadDynamicData();
         //Logged in...simply view the newly created ticket.
diff --git a/scp/ajax.php b/scp/ajax.php
index 7fae11f1f..46fc6385c 100644
--- a/scp/ajax.php
+++ b/scp/ajax.php
@@ -48,7 +48,9 @@ $dispatcher = patterns('',
     url('^/form/', patterns('ajax.forms.php:DynamicFormsAjaxAPI',
         url_get('^help-topic/(?P<id>\d+)$', 'getFormsForHelpTopic'),
         url_get('^field-config/(?P<id>\d+)$', 'getFieldConfiguration'),
-        url_post('^field-config/(?P<id>\d+)$', 'saveFieldConfiguration')
+        url_post('^field-config/(?P<id>\d+)$', 'saveFieldConfiguration'),
+        url_get('^user-info/(?P<id>\d+)$', 'getUserInfo'),
+        url_post('^user-info/(?P<id>\d+)$', 'saveUserInfo')
     )),
     url('^/report/overview/', patterns('ajax.reports.php:OverviewReportAjaxAPI',
         # Send
diff --git a/scp/css/scp.css b/scp/css/scp.css
index 4fa5ba620..8f58ac452 100644
--- a/scp/css/scp.css
+++ b/scp/css/scp.css
@@ -1330,6 +1330,14 @@ time {
     background-position:bottom left;
 }
 
+/* Dynamic forms in dialogs */
+.dialog th {
+    background-color: #eee;
+    padding: 0.3em;
+    text-align: left;
+    padding-left: 1em;
+}
+
 #result-count div {
     padding:5px 10px;
     text-align:left;
diff --git a/scp/tickets.php b/scp/tickets.php
index f7ee1ac9c..296bbc7b2 100644
--- a/scp/tickets.php
+++ b/scp/tickets.php
@@ -205,6 +205,7 @@ if($_POST && !$errors):
                 $_REQUEST['a'] = null; //Clear edit action - going back to view.
                 //Check to make sure the staff STILL has access post-update (e.g dept change).
                 foreach ($forms as $f) $f->save();
+                $ticket->setOwner($form2->getClean());
                 if(!$ticket->checkStaffAccess($thisstaff))
                     $ticket=null;
             } elseif(!$errors['err']) {
@@ -458,19 +459,23 @@ if($_POST && !$errors):
             case 'open':
                 $ticket=null;
                 $interest=array('name','email','subject');
-                $topic=Topic::lookup($_POST['topicId']);
-                $form=DynamicForm::lookup($topic->ht['form_id']);
-                $form=$form->instanciate();
-                # Collect name, email, and subject address for banning and such
-                foreach ($form->getAnswers() as $answer) {
-                    $fname = $answer->getField()->get('name');
-                    if (in_array($fname, $interest))
-                        # XXX: Assigning to _POST not considered great PHP
-                        #      coding style
-                        $_POST[$fname] = $answer->getField()->getClean();
+                if ($topic=Topic::lookup($_POST['topicId'])) {
+                    $form = DynamicForm::lookup($topic->ht['form_id']);
+                    $form = $form->instanciate();
+                    # Collect name, email, and subject address for banning and such
+                    foreach ($form->getAnswers() as $answer) {
+                        $fname = $answer->getField()->get('name');
+                        if (in_array($fname, $interest))
+                            # XXX: Assigning to _POST not considered great PHP
+                            #      coding style
+                            $_POST[$fname] = $answer->getField()->getClean();
+                    }
+                    if (!$form->isValid())
+                        $errors = array_merge($errors, $form->errors());
                 }
-                if (!$form->isValid())
-                    $errors = array_merge($errors, $form->errors());
+                $form2 = UserForm::getStaticForm();
+                if (!$form2->isValid())
+                    $errors = array_merge($errors, $form2->errors());
                 if(!$thisstaff || !$thisstaff->canCreateTickets()) {
                      $errors['err']='You do not have permission to create tickets. Contact admin for such access';
                 } else {
@@ -482,7 +487,7 @@ if($_POST && !$errors):
                         $msg='Ticket created successfully';
                         $_REQUEST['a']=null;
                         # TODO: Save dynamic form(s)
-                        $form->set('ticket_id', $ticket->getId());
+                        $form->setTicketId($ticket->getId());
                         $form->save();
                         $ticket->loadDynamicData();
                         if(!$ticket->checkStaffAccess($thisstaff) || $ticket->isClosed())
diff --git a/setup/inc/sql/osTicket-mysql.sql b/setup/inc/sql/osTicket-mysql.sql
deleted file mode 100644
index 4d613ca61..000000000
--- a/setup/inc/sql/osTicket-mysql.sql
+++ /dev/null
@@ -1,861 +0,0 @@
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%api_key`;
-CREATE TABLE `%TABLE_PREFIX%api_key` (
-  `id` int(10) unsigned NOT NULL auto_increment,
-  `isactive` tinyint(1) NOT NULL default '1',
-  `ipaddr` varchar(64) NOT NULL,
-  `apikey` varchar(255) NOT NULL,
-  `can_create_tickets` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT  '1',
-  `can_exec_cron` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT  '1',
-  `notes` text,
-  `updated` datetime NOT NULL,
-  `created` datetime NOT NULL,
-  PRIMARY KEY  (`id`),
-  KEY `ipaddr` (`ipaddr`),
-  UNIQUE KEY `apikey` (`apikey`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%faq`;
-CREATE TABLE IF NOT EXISTS `%TABLE_PREFIX%faq` (
-  `faq_id` int(10) unsigned NOT NULL auto_increment,
-  `category_id` int(10) unsigned NOT NULL default '0',
-  `ispublished` tinyint(1) unsigned NOT NULL default '0',
-  `question` varchar(255) NOT NULL,
-  `answer` text NOT NULL,
-  `keywords` tinytext,
-  `notes` text,
-  `created` date NOT NULL,
-  `updated` date NOT NULL,
-  PRIMARY KEY  (`faq_id`),
-  UNIQUE KEY `question` (`question`),
-  KEY `category_id` (`category_id`),
-  KEY `ispublished` (`ispublished`),
-  FULLTEXT KEY `faq` (`question`,`answer`,`keywords`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%faq_attachment`;
-CREATE TABLE IF NOT EXISTS `%TABLE_PREFIX%faq_attachment` (
-  `faq_id` int(10) unsigned NOT NULL,
-  `file_id` int(10) unsigned NOT NULL,
-  PRIMARY KEY  (`faq_id`,`file_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%faq_category`;
-CREATE TABLE IF NOT EXISTS `%TABLE_PREFIX%faq_category` (
-  `category_id` int(10) unsigned NOT NULL auto_increment,
-  `ispublic` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0',
-  `name` varchar(125) default NULL,
-  `description` TEXT NOT NULL,
-  `notes` tinytext NOT NULL,
-  `created` date NOT NULL,
-  `updated` date NOT NULL,
-  PRIMARY KEY  (`category_id`),
-  KEY (`ispublic`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%faq_topic`;
-CREATE TABLE IF NOT EXISTS `%TABLE_PREFIX%faq_topic` (
-  `faq_id` int(10) unsigned NOT NULL,
-  `topic_id` int(10) unsigned NOT NULL,
-  PRIMARY KEY  (`faq_id`,`topic_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%config`;
-CREATE TABLE `%TABLE_PREFIX%config` (
-  `id` tinyint(1) unsigned NOT NULL auto_increment,
-  `isonline` tinyint(1) unsigned NOT NULL default '0',
-  `timezone_offset` float(3,1) NOT NULL default '0.0',
-  `enable_daylight_saving` tinyint(1) unsigned NOT NULL default '0',
-  `staff_ip_binding` tinyint(1) unsigned NOT NULL default '1',
-  `staff_max_logins` tinyint(3) unsigned NOT NULL default '4',
-  `staff_login_timeout` int(10) unsigned NOT NULL default '2',
-  `staff_session_timeout` int(10) unsigned NOT NULL default '30',
-  `passwd_reset_period` int(10) unsigned NOT NULL default '0',
-  `client_max_logins` tinyint(3) unsigned NOT NULL default '4',
-  `client_login_timeout` int(10) unsigned NOT NULL default '2',
-  `client_session_timeout` int(10) unsigned NOT NULL default '30',
-  `max_page_size` tinyint(3) unsigned NOT NULL default '25',
-  `max_open_tickets` tinyint(3) unsigned NOT NULL default '0',
-  `max_file_size` int(11) unsigned NOT NULL default '1048576',
-  `max_user_file_uploads` tinyint(3) unsigned NOT NULL,
-  `max_staff_file_uploads` tinyint(3) unsigned NOT NULL,
-  `autolock_minutes` tinyint(3) unsigned NOT NULL default '3',
-  `overdue_grace_period` int(10) unsigned NOT NULL default '0',
-  `alert_email_id` tinyint(4) unsigned NOT NULL default '0',
-  `default_email_id` tinyint(4) unsigned NOT NULL default '0',
-  `default_dept_id` tinyint(3) unsigned NOT NULL default '0',
-  `default_sla_id` int(10) unsigned NOT NULL default '0',
-  `default_priority_id` tinyint(2) unsigned NOT NULL default '2',
-  `default_template_id` tinyint(4) unsigned NOT NULL default '1',
-  `default_timezone_id` int(10) unsigned NOT NULL default '0',
-  `default_smtp_id` tinyint(4) unsigned NOT NULL default '0',
-  `allow_email_spoofing` tinyint(1) unsigned NOT NULL default '0',
-  `clickable_urls` tinyint(1) unsigned NOT NULL default '1',
-  `allow_priority_change` tinyint(1) unsigned NOT NULL default '0',
-  `use_email_priority` tinyint(1) unsigned NOT NULL default '0',
-  `enable_kb` tinyint(1) unsigned NOT NULL default '0',
-  `enable_premade` tinyint(1) unsigned NOT NULL default '1',
-  `enable_captcha` tinyint(1) unsigned NOT NULL default '0',
-  `enable_auto_cron` tinyint(1) unsigned NOT NULL default '0',
-  `enable_mail_polling` tinyint(1) unsigned NOT NULL default '0',
-  `send_sys_errors` tinyint(1) unsigned NOT NULL default '1',
-  `send_sql_errors` tinyint(1) unsigned NOT NULL default '1',
-  `send_mailparse_errors` tinyint(1) unsigned NOT NULL default '1',
-  `send_login_errors` tinyint(1) unsigned NOT NULL default '1',
-  `save_email_headers` tinyint(1) unsigned NOT NULL default '1',
-  `strip_quoted_reply` tinyint(1) unsigned NOT NULL default '1',
-  `log_ticket_activity` tinyint(1) unsigned NOT NULL default '1',
-  `ticket_autoresponder` tinyint(1) unsigned NOT NULL default '0',
-  `message_autoresponder` tinyint(1) unsigned NOT NULL default '0',
-  `ticket_notice_active` tinyint(1) unsigned NOT NULL default '0',
-  `ticket_alert_active` tinyint(1) unsigned NOT NULL default '0',
-  `ticket_alert_admin` tinyint(1) unsigned NOT NULL default '1',
-  `ticket_alert_dept_manager` tinyint(1) unsigned NOT NULL default '1',
-  `ticket_alert_dept_members` tinyint(1) unsigned NOT NULL default '0',
-  `message_alert_active` tinyint(1) unsigned NOT NULL default '0',
-  `message_alert_laststaff` tinyint(1) unsigned NOT NULL default '1',
-  `message_alert_assigned` tinyint(1) unsigned NOT NULL default '1',
-  `message_alert_dept_manager` tinyint(1) unsigned NOT NULL default '0',
-  `note_alert_active` tinyint(1) unsigned NOT NULL default '0',
-  `note_alert_laststaff` tinyint(1) unsigned NOT NULL default '1',
-  `note_alert_assigned` tinyint(1) unsigned NOT NULL default '1',
-  `note_alert_dept_manager` tinyint(1) unsigned NOT NULL default '0',
-  `transfer_alert_active` tinyint(1) unsigned NOT NULL default '0',
-  `transfer_alert_assigned` tinyint(1) unsigned NOT NULL default '0',
-  `transfer_alert_dept_manager` tinyint(1) unsigned NOT NULL default '1',
-  `transfer_alert_dept_members` tinyint(1) unsigned NOT NULL default '0',
-  `overdue_alert_active` tinyint(1) unsigned NOT NULL default '0',
-  `overdue_alert_assigned` tinyint(1) unsigned NOT NULL default '1',
-  `overdue_alert_dept_manager` tinyint(1) unsigned NOT NULL default '1',
-  `overdue_alert_dept_members` tinyint(1) unsigned NOT NULL default '0',
-  `assigned_alert_active` tinyint(1) unsigned NOT NULL default '1',
-  `assigned_alert_staff` tinyint(1) unsigned NOT NULL default '1',
-  `assigned_alert_team_lead` tinyint(1) unsigned NOT NULL default '0',
-  `assigned_alert_team_members` tinyint(1) unsigned NOT NULL default '0',
-  `auto_assign_reopened_tickets` tinyint(1) unsigned NOT NULL default '1',
-  `show_related_tickets` tinyint(1) unsigned NOT NULL default '1',
-  `show_assigned_tickets` tinyint(1) unsigned NOT NULL default '1',
-  `show_answered_tickets` tinyint(1) unsigned NOT NULL default '0',
-  `show_notes_inline` tinyint(1) unsigned NOT NULL default '1',
-  `hide_staff_name` tinyint(1) unsigned NOT NULL default '0',
-  `overlimit_notice_active` tinyint(1) unsigned NOT NULL default '0',
-  `email_attachments` tinyint(1) unsigned NOT NULL default '1',
-  `allow_attachments` tinyint(1) unsigned NOT NULL default '0',
-  `allow_email_attachments` tinyint(1) unsigned NOT NULL default '0',
-  `allow_online_attachments` tinyint(1) unsigned NOT NULL default '0',
-  `allow_online_attachments_onlogin` tinyint(1) unsigned NOT NULL default
-    '0',
-  `random_ticket_ids` tinyint(1) unsigned NOT NULL default '1',
-  `log_level` tinyint(1) unsigned NOT NULL default '2',
-  `log_graceperiod` int(10) unsigned NOT NULL default '12',
-  `upload_dir` varchar(255) NOT NULL default '',
-  `allowed_filetypes` varchar(255) NOT NULL default '.doc, .pdf',
-  `time_format` varchar(32) NOT NULL default ' h:i A',
-  `date_format` varchar(32) NOT NULL default 'm/d/Y',
-  `datetime_format` varchar(60) NOT NULL default 'm/d/Y g:i a',
-  `daydatetime_format` varchar(60) NOT NULL default 'D, M j Y g:ia',
-  `reply_separator` varchar(60) NOT NULL default '-- do not edit --',
-  `admin_email` varchar(125) NOT NULL default '',
-  `helpdesk_title` varchar(255) NOT NULL default
-    'osTicket Support Ticket System',
-  `helpdesk_url` varchar(255) NOT NULL default '',
-  `schema_signature` char(32) NOT NULL default '',
-  `updated` timestamp NOT NULL default CURRENT_TIMESTAMP,
-  PRIMARY KEY  (`id`),
-  KEY `isoffline` (`isonline`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%dynamic_formset`;
-CREATE TABLE `%TABLE_PREFIX%dynamic_formset` (
-    `id` int(11) unsigned auto_increment,
-    `title` varchar(255) NOT NULL,
-    `instructions` varchar(512),
-    `notes` text,
-    `created` datetime NOT NULL,
-    `updated` datetime NOT NULL,
-    PRIMARY KEY (`id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%dynamic_formset_sections`;
-CREATE TABLE `%TABLE_PREFIX%dynamic_formset_sections` (
-    `id` int(11) unsigned NOT NULL auto_increment,
-    `formset_id` int(11) NOT NULL,
-    `section_id` int(11) NOT NULL,
-    `title` varchar(255),
-    `instructions` text,
-    -- Allow more than one form, sorted in this order
-    `sort` int(11) NOT NULL DEFAULT 1,
-    PRIMARY KEY (`id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%dynamic_form_section`;
-CREATE TABLE `%TABLE_PREFIX%dynamic_form_section` (
-    `id` int(11) unsigned NOT NULL auto_increment,
-    `title` varchar(255) NOT NULL,
-    `instructions` varchar(512),
-    `notes` text,
-    `created` datetime NOT NULL,
-    `updated` datetime NOT NULL,
-    PRIMARY KEY (`id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%dynamic_form_field`;
-CREATE TABLE `%TABLE_PREFIX%dynamic_form_field` (
-    `id` int(11) unsigned NOT NULL auto_increment,
-    `section_id` int(11) unsigned NOT NULL,
-    `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,
-    `name` varchar(64) NOT NULL,
-    `configuration` text,
-    `sort` int(11) unsigned NOT NULL,
-    `hint` varchar(512),
-    `created` datetime NOT NULL,
-    `updated` datetime NOT NULL,
-    PRIMARY KEY (`id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
--- Create a default form to mimic the previous default form of osTicket < 1.7.1
-INSERT INTO `%TABLE_PREFIX%dynamic_form_section` SET
-    `id` = 1, `title` = 'User Information', `created` = NOW(),
-    `updated` = NOW();
-INSERT INTO `%TABLE_PREFIX%dynamic_form_section` SET
-    `id` = 2, `title` = 'Ticket Details', `created` = NOW(),
-    `updated` = NOW();
-
-INSERT INTO `%TABLE_PREFIX%dynamic_formset` SET
-    `id` = 1, `title` = 'Default', `created` = NOW(), `updated` = NOW();
-
-INSERT INTO `%TABLE_PREFIX%dynamic_formset_sections` SET
-    `formset_id` = 1, `section_id` = 1, `sort` = 10;
-INSERT INTO `%TABLE_PREFIX%dynamic_formset_sections` SET
-    `formset_id` = 1, `section_id` = 2, `sort` = 20;
-
-INSERT INTO `%TABLE_PREFIX%dynamic_form_field` SET
-    `section_id` = 1, `type` = 'text', `label` = 'Email Address',
-    `required` = 1, `configuration` = '{"size":40,"length":40,"validator":"email"}',
-    `name` = 'email', `sort` = 10, `created` = NOW(), `updated` = NOW();
-INSERT INTO `%TABLE_PREFIX%dynamic_form_field` SET
-    `section_id` = 1, `type` = 'text', `label` = 'Full Name',
-    `required` = 1, `configuration` = '{"size":40,"length":40}',
-    `name` = 'name', `sort` = 20, `created` = NOW(), `updated` = NOW();
-INSERT INTO `%TABLE_PREFIX%dynamic_form_field` SET
-    `section_id` = 1, `type` = 'phone', `label` = 'Phone Number',
-    `name` = 'phone', `sort` = 30, `created` = NOW(), `updated` = NOW();
-
-INSERT INTO `%TABLE_PREFIX%dynamic_form_field` SET
-    `section_id` = 2, `type` = 'text', `label` = 'Subject',
-    `hint` = 'Issue summary', `required` = 1,
-    `configuration` = '{"size":40,"length":50}',
-    `name` = 'subject', `sort` = 10, `created` = NOW(), `updated` = NOW();
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%dynamic_form_entry`;
-CREATE TABLE `%TABLE_PREFIX%dynamic_form_entry` (
-    `id` int(11) unsigned NOT NULL auto_increment,
-    `section_id` int(11) unsigned NOT NULL,
-    `ticket_id` int(11) unsigned,
-    `sort` int(11) unsigned NOT NULL DEFAULT 1,
-    `created` datetime NOT NULL,
-    `updated` datetime NOT NULL,
-    PRIMARY KEY (`id`),
-    KEY `ticket_dyn_form_lookup` (`ticket_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%dynamic_form_entry_values`;
-CREATE TABLE `%TABLE_PREFIX%dynamic_form_entry_values` (
-    -- references dynamic_form_entry.id
-    `entry_id` int(11) unsigned NOT NULL,
-    `field_id` int(11) unsigned NOT NULL,
-    `value` text,
-    PRIMARY KEY (`entry_id`, `field_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%dynamic_list`;
-CREATE TABLE `%TABLE_PREFIX%dynamic_list` (
-    `id` int(11) unsigned NOT NULL auto_increment,
-    `name` varchar(255) NOT NULL,
-    `name_plural` varchar(255),
-    `sort_mode` enum('Alpha', '-Alpha', 'SortCol') NOT NULL DEFAULT 'Alpha',
-    `notes` text,
-    `created` datetime NOT NULL,
-    `updated` datetime NOT NULL,
-    PRIMARY KEY (`id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%dynamic_list_items`;
-CREATE TABLE `%TABLE_PREFIX%dynamic_list_items` (
-    `id` int(11) unsigned NOT NULL auto_increment,
-    `list_id` int(11),
-    `value` varchar(255) NOT NULL,
-    -- extra value such as abbreviation
-    `extra` varchar(255),
-    `sort` int(11) NOT NULL DEFAULT 1,
-    PRIMARY KEY (`id`),
-    KEY `dynamic_list_item_lookup` (`list_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%department`;
-CREATE TABLE `%TABLE_PREFIX%department` (
-  `dept_id` int(11) unsigned NOT NULL auto_increment,
-  `tpl_id` int(10) unsigned NOT NULL default '0',
-  `sla_id` int(10) unsigned NOT NULL default '0',
-  `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',
-  `dept_name` varchar(128) NOT NULL default '',
-  `dept_signature` tinytext NOT NULL,
-  `ispublic` tinyint(1) unsigned NOT NULL default '1',
-  `group_membership` tinyint(1) NOT NULL default '0',
-  `ticket_auto_response` tinyint(1) NOT NULL default '1',
-  `message_auto_response` tinyint(1) NOT NULL default '0',
-  `updated` datetime NOT NULL,
-  `created` datetime NOT NULL,
-  PRIMARY KEY  (`dept_id`),
-  UNIQUE KEY `dept_name` (`dept_name`),
-  KEY `manager_id` (`manager_id`),
-  KEY `autoresp_email_id` (`autoresp_email_id`),
-  KEY `tpl_id` (`tpl_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%department` (`dept_id`, `tpl_id`, `sla_id`, `email_id`, `autoresp_email_id`, `manager_id`, `dept_name`, `dept_signature`, `ispublic`, `ticket_auto_response`, `message_auto_response`) VALUES
-    (1, 0, 0, 1, 1, 0, 'Support', 'Support Dept', 1, 1, 1),
-    (2, 0, 1, 1, 1, 0, 'Billing', 'Billing Dept', 1, 1, 1);
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%email`;
-CREATE TABLE `%TABLE_PREFIX%email` (
-  `email_id` int(11) unsigned NOT NULL auto_increment,
-  `noautoresp` tinyint(1) unsigned NOT NULL default '0',
-  `priority_id` tinyint(3) unsigned NOT NULL default '2',
-  `dept_id` tinyint(3) unsigned NOT NULL default '0',
-  `email` varchar(255) NOT NULL default '',
-  `name` varchar(255) NOT NULL default '',
-  `userid` varchar(255) NOT NULL,
-  `userpass` varchar(125) NOT NULL,
-  `mail_active` tinyint(1) NOT NULL default '0',
-  `mail_host` varchar(255) NOT NULL,
-  `mail_protocol` enum('POP','IMAP') NOT NULL default 'POP',
-  `mail_encryption` enum('NONE','SSL') NOT NULL,
-  `mail_port` int(6) default NULL,
-  `mail_fetchfreq` tinyint(3) NOT NULL default '5',
-  `mail_fetchmax` tinyint(4) NOT NULL default '30',
-  `mail_archivefolder` varchar(255) default NULL,
-  `mail_delete` tinyint(1) NOT NULL default '0',
-  `mail_errors` tinyint(3) NOT NULL default '0',
-  `mail_lasterror` datetime default NULL,
-  `mail_lastfetch` datetime default NULL,
-  `smtp_active` tinyint(1) default '0',
-  `smtp_host` varchar(255) NOT NULL,
-  `smtp_port` int(6) default NULL,
-  `smtp_secure` tinyint(1) NOT NULL default '1',
-  `smtp_auth` tinyint(1) NOT NULL default '1',
-  `smtp_spoofing` tinyint(1) unsigned NOT NULL default '0',
-  `notes` text,
-  `created` datetime NOT NULL,
-  `updated` datetime NOT NULL,
-  PRIMARY KEY  (`email_id`),
-  UNIQUE KEY `email` (`email`),
-  KEY `priority_id` (`priority_id`),
-  KEY `dept_id` (`dept_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%filter`;
-CREATE TABLE `%TABLE_PREFIX%filter` (
-  `id` int(11) unsigned NOT NULL auto_increment,
-  `execorder` int(10) unsigned NOT NULL default '99',
-  `isactive` tinyint(1) unsigned NOT NULL default '1',
-  `match_all_rules` tinyint(1) unsigned NOT NULL default '0',
-  `stop_onmatch` tinyint(1) unsigned NOT NULL default '0',
-  `reject_ticket` tinyint(1) unsigned NOT NULL default '0',
-  `use_replyto_email` tinyint(1) unsigned NOT NULL default '0',
-  `disable_autoresponder` tinyint(1) unsigned NOT NULL default '0',
-  `canned_response_id` int(11) unsigned NOT NULL default '0',
-  `email_id` int(10) unsigned NOT NULL default '0',
-  `priority_id` int(10) unsigned NOT NULL default '0',
-  `dept_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',
-  `sla_id` int(10) unsigned NOT NULL default '0',
-  `target` ENUM(  'Any',  'Web',  'Email',  'API' ) NOT NULL DEFAULT  'Any',
-  `name` varchar(32) NOT NULL default '',
-  `notes` text,
-  `created` datetime NOT NULL,
-  `updated` datetime NOT NULL,
-  PRIMARY KEY  (`id`),
-  KEY `target` (`target`),
-  KEY `email_id` (`email_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-
-INSERT INTO `%TABLE_PREFIX%filter` (
-  `id`,`isactive`,`execorder`,`reject_ticket`,`name`,`notes`,`created`)
-    VALUES (1, 1, 99, 1, 'SYSTEM BAN LIST', 'Internal list for email banning. Do not remove', NOW());
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%filter_rule`;
-CREATE TABLE `%TABLE_PREFIX%filter_rule` (
-  `id` int(11) unsigned NOT NULL auto_increment,
-  `filter_id` int(10) unsigned NOT NULL default '0',
-  `what` enum('name','email','subject','body','header') NOT NULL,
-  `how` enum('equal','not_equal','contains','dn_contain','starts','ends') NOT NULL,
-  `val` varchar(255) NOT NULL,
-  `isactive` tinyint(1) unsigned NOT NULL DEFAULT '1',
-  `notes` tinytext NOT NULL,
-  `created` datetime NOT NULL,
-  `updated` datetime NOT NULL,
-  PRIMARY KEY  (`id`),
-  KEY `filter_id` (`filter_id`),
-  UNIQUE `filter` (`filter_id`, `what`, `how`, `val`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%filter_rule` (
-  `id`, `filter_id`, `isactive`, `what`,`how`,`val`,`created`)
-    VALUES (1, 1, 1, 'email', 'equal', 'test@example.com',NOW());
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%email_template`;
-CREATE TABLE `%TABLE_PREFIX%email_template` (
-  `tpl_id` int(11) NOT NULL auto_increment,
-  `cfg_id` int(10) unsigned NOT NULL default '0',
-  `isactive` tinyint(1) unsigned NOT NULL default '0',
-  `name` varchar(32) NOT NULL default '',
-  `notes` text,
-  `ticket_autoresp_subj` varchar(255) NOT NULL default '',
-  `ticket_autoresp_body` text NOT NULL,
-  `ticket_autoreply_subj` varchar(255) NOT NULL default '',
-  `ticket_autoreply_body` text NOT NULL,
-  `ticket_notice_subj` varchar(255) NOT NULL,
-  `ticket_notice_body` text NOT NULL,
-  `ticket_alert_subj` varchar(255) NOT NULL default '',
-  `ticket_alert_body` text NOT NULL,
-  `message_autoresp_subj` varchar(255) NOT NULL default '',
-  `message_autoresp_body` text NOT NULL,
-  `message_alert_subj` varchar(255) NOT NULL default '',
-  `message_alert_body` text NOT NULL,
-  `note_alert_subj` varchar(255) NOT NULL,
-  `note_alert_body` text NOT NULL,
-  `assigned_alert_subj` varchar(255) NOT NULL default '',
-  `assigned_alert_body` text NOT NULL,
-  `transfer_alert_subj` varchar(255) NOT NULL default '',
-  `transfer_alert_body` text NOT NULL,
-  `ticket_overdue_subj` varchar(255) NOT NULL default '',
-  `ticket_overdue_body` text NOT NULL,
-  `ticket_overlimit_subj` varchar(255) NOT NULL default '',
-  `ticket_overlimit_body` text NOT NULL,
-  `ticket_reply_subj` varchar(255) NOT NULL default '',
-  `ticket_reply_body` text NOT NULL,
-  `created` datetime NOT NULL,
-  `updated` datetime NOT NULL,
-  PRIMARY KEY  (`tpl_id`),
-  KEY `cfg_id` (`cfg_id`),
-  FULLTEXT KEY `message_subj` (`ticket_reply_subj`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
--- TODO: Dump revised copy before release!!!
-INSERT INTO `%TABLE_PREFIX%email_template` (`tpl_id`, `cfg_id`, `isactive`, `name`, `notes`, `ticket_autoresp_subj`, `ticket_autoresp_body`, `ticket_autoreply_subj`, `ticket_autoreply_body`, `ticket_notice_subj`, `ticket_notice_body`, `ticket_alert_subj`, `ticket_alert_body`, `message_autoresp_subj`, `message_autoresp_body`, `message_alert_subj`, `message_alert_body`, `note_alert_subj`, `note_alert_body`, `assigned_alert_subj`, `assigned_alert_body`, `transfer_alert_subj`, `transfer_alert_body`, `ticket_overdue_subj`, `ticket_overdue_body`, `ticket_overlimit_subj`, `ticket_overlimit_body`, `ticket_reply_subj`, `ticket_reply_body`, `created`, `updated`) VALUES
-(1, 1, 1, 'osTicket Default Template', 'Default osTicket templates', 'Support Ticket Opened [#%{ticket.number}]', '%{ticket.name},\r\n\r\nA request for support has been created and assigned ticket #%{ticket.number}. A representative will follow-up with you as soon as possible.\r\n\r\nYou can view this ticket''s progress online here: %{ticket.client_link}.\r\n\r\nIf you wish to send additional comments or information regarding this issue, please don''t open a new ticket. Simply login using the link above and update the ticket.\r\n\r\n%{signature}', 'Support Ticket Opened [#%{ticket.number}]', '%{ticket.name},\r\n\r\nA request for support has been created and assigned ticket #%{ticket.number} with the following auto-reply:\r\n\r\n%{response}\r\n\r\n\r\nWe hope this response has sufficiently answered your questions. If not, please do not open another ticket. If need be, representative will follow-up with you as soon as possible.\r\n\r\nYou can view this ticket''s progress online here: %{ticket.client_link}.', '[#%{ticket.number}] %{ticket.subject}', '%{ticket.name},\r\n\r\nOur customer care team has created a ticket, #%{ticket.number} on your behalf, with the following message.\r\n\r\n%{message}\r\n\r\nIf you wish to provide additional comments or information regarding this issue, please don''t open a new ticket. You can update or view this ticket''s progress online here: %{ticket.client_link}.\r\n\r\n%{signature}', 'New Ticket Alert', '%{recipient},\r\n\r\nNew ticket #%{ticket.number} created.\r\n\r\n-----------------------\r\nName: %{ticket.name}\r\nEmail: %{ticket.email}\r\nDept: %{ticket.dept.name}\r\n\r\n%{message}\r\n-----------------------\r\n\r\nTo view/respond to the ticket, please login to the support ticket system.\r\n\r\n%{ticket.staff_link}\r\n\r\n- Your friendly Customer Support System - powered by osTicket.', '[#%{ticket.number}] Message Added', '%{ticket.name},\r\n\r\nYour reply to support request #%{ticket.number} has been noted.\r\n\r\nYou can view this support request progress online here: %{ticket.client_link}.\r\n\r\n%{signature}', 'New Message Alert', '%{recipient},\r\n\r\nNew message appended to ticket #%{ticket.number}\r\n\r\n----------------------\r\nName: %{ticket.name}\r\nEmail: %{ticket.email}\r\nDept: %{ticket.dept.name}\r\n\r\n%{message}\r\n----------------------\r\n\r\nTo view/respond to the ticket, please login to the support ticket system.\r\n\r\n%{ticket.staff_link}\r\n\r\n- Your friendly Customer Support System - powered by osTicket.', 'New Internal Note Alert', '%{recipient},\r\n\r\nInternal note appended to ticket #%{ticket.number}\r\n\r\n----------------------\r\n* %{note.title} *\r\n\r\n%{note.message}\r\n----------------------\r\n\r\nTo view/respond to the ticket, please login to the support ticket system.\r\n\r\n%{ticket.staff_link}\r\n\r\n- Your friendly Customer Support System - powered by osTicket.', 'Ticket #%{ticket.number} Assigned to you', '%{assignee},\r\n\r\nTicket #%{ticket.number} has been assigned to you by %{assigner}\r\n\r\n----------------------\r\n\r\n%{comments}\r\n\r\n----------------------\r\n\r\nTo view complete details, simply login to the support system.\r\n\r\n%{ticket.staff_link}\r\n\r\n- Your friendly Support Ticket System - powered by osTicket.', 'Ticket Transfer #%{ticket.number} - %{ticket.dept.name}', '%{recipient},\r\n\r\nTicket #%{ticket.number} has been transferred to %{ticket.dept.name} department by %{staff.name}\r\n\r\n----------------------\r\n\r\n%{comments}\r\n\r\n----------------------\r\n\r\nTo view/respond to the ticket, please login to the support ticket system.\r\n\r\n%{ticket.staff_link}\r\n\r\n- Your friendly Customer Support System - powered by osTicket.', 'Stale Ticket Alert', '%{recipient},\r\n\r\nA ticket, #%{ticket.number} assigned to you or in your department is seriously overdue.\r\n\r\n%{ticket.staff_link}\r\n\r\nWe should all work hard to guarantee that all tickets are being addressed in a timely manner.\r\n\r\n- Your friendly (although with limited patience) Support Ticket System - powered by osTicket.', 'Open Tickets Limit Reached', '%{ticket.name}\r\n\r\nYou have reached the maximum number of open tickets allowed.\r\n\r\nTo be able to open another ticket, one of your pending tickets must be closed. To update or add comments to an open ticket simply login using the link below.\r\n\r\n%{url}/tickets.php?e=%{ticket.email}\r\n\r\nThank you.\r\n\r\nSupport Ticket System', '[#%{ticket.number}] %{ticket.subject}', '%{ticket.name},\r\n\r\nA customer support staff member has replied to your support request, #%{ticket.number} with the following response:\r\n\r\n%{response}\r\n\r\nWe hope this response has sufficiently answered your questions. If not, please do not send another email. Instead, reply to this email or login to your account for a complete archive of all your support requests and responses.\r\n\r\n%{ticket.client_link}\r\n\r\n%{signature}', NOW(), NOW());
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%file`;
-CREATE TABLE `%TABLE_PREFIX%file` (
-  `id` int(11) NOT NULL auto_increment,
-  `type` varchar(255) NOT NULL default '',
-  `size` varchar(25) NOT NULL default '',
-  `hash` varchar(125) NOT NULL,
-  `name` varchar(255) NOT NULL default '',
-  `created` datetime NOT NULL,
-  PRIMARY KEY  (`id`),
-  KEY `hash` (`hash`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%file` (`id`, `type`, `size`, `hash`, `name`, `created`) VALUES
-(1, 'text/plain', '25', '670c6cc1d1dfc97fad20e5470251b255', 'osTicket.txt', NOW());
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%file_chunk`;
-CREATE TABLE `%TABLE_PREFIX%file_chunk` (
-    `file_id` int(11) NOT NULL,
-    `chunk_id` int(11) NOT NULL,
-    `filedata` longblob NOT NULL,
-    PRIMARY KEY (`file_id`, `chunk_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%file_chunk` (`file_id`, `chunk_id`, `filedata`)
-VALUES (1, 0, 0x43616e6e6564206174746163686d656e747320726f636b210a);
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%groups`;
-CREATE TABLE `%TABLE_PREFIX%groups` (
-  `group_id` int(10) unsigned NOT NULL auto_increment,
-  `group_enabled` tinyint(1) unsigned NOT NULL default '1',
-  `group_name` varchar(50) NOT NULL default '',
-  `can_create_tickets` tinyint(1) unsigned NOT NULL default '1',
-  `can_edit_tickets` tinyint(1) unsigned NOT NULL default '1',
-  `can_post_ticket_reply` tinyint( 1 ) unsigned NOT NULL DEFAULT  '1',
-  `can_delete_tickets` tinyint(1) unsigned NOT NULL default '0',
-  `can_close_tickets` tinyint(1) unsigned NOT NULL default '1',
-  `can_assign_tickets` tinyint(1) unsigned NOT NULL default '1',
-  `can_transfer_tickets` tinyint(1) unsigned NOT NULL default '1',
-  `can_ban_emails` tinyint(1) unsigned NOT NULL default '0',
-  `can_manage_premade` tinyint(1) unsigned NOT NULL default '0',
-  `can_manage_faq` tinyint(1) unsigned NOT NULL default '0',
-  `can_view_staff_stats` tinyint( 1 ) unsigned NOT NULL DEFAULT  '0',
-  `notes` text,
-  `created` datetime NOT NULL,
-  `updated` datetime NOT NULL,
-  PRIMARY KEY  (`group_id`),
-  KEY `group_active` (`group_enabled`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%groups` (`group_id`, `group_enabled`, `group_name`, `can_create_tickets`, `can_edit_tickets`, `can_delete_tickets`, `can_close_tickets`, `can_assign_tickets`, `can_transfer_tickets`, `can_ban_emails`, `can_manage_premade`, `can_manage_faq`, `notes`, `created`, `updated`) VALUES
-    (1, 1, 'Admins', 1, 1, 1, 1, 1, 1, 1, 1, 1, 'overlords', NOW(), NOW()),
-    (2, 1, 'Managers', 1, 1, 1, 1, 1, 1, 1, 1, 1, '', NOW(), NOW()),
-    (3, 1, 'Staff', 1, 1, 0, 1, 1, 1, 0, 0, 0, '', NOW(), NOW());
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%group_dept_access`;
-CREATE TABLE `%TABLE_PREFIX%group_dept_access` (
-  `group_id` int(10) unsigned NOT NULL default '0',
-  `dept_id` int(10) unsigned NOT NULL default '0',
-  UNIQUE KEY `group_dept` (`group_id`,`dept_id`),
-  KEY `dept_id`  (`dept_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%group_dept_access` (`group_id`, `dept_id`) VALUES
-    (1, 1), (1, 2), (2, 1), (2, 2), (3, 1), (3, 2);
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%help_topic`;
-CREATE TABLE `%TABLE_PREFIX%help_topic` (
-  `topic_id` int(11) unsigned NOT NULL auto_increment,
-  `topic_pid` int(10) unsigned NOT NULL default '0',
-  `isactive` tinyint(1) unsigned NOT NULL default '1',
-  `ispublic` tinyint(1) unsigned NOT NULL default '1',
-  `noautoresp` tinyint(3) unsigned NOT NULL default '0',
-  `priority_id` tinyint(3) unsigned NOT NULL default '0',
-  `dept_id` tinyint(3) unsigned NOT NULL default '0',
-  `staff_id` int(10) unsigned NOT NULL default '0',
-  `team_id` int(10) unsigned NOT NULL default '0',
-  `sla_id` int(10) unsigned NOT NULL default '0',
-  `formset_id` int(11) unsigned NOT NULL default '0',
-  `topic` varchar(32) NOT NULL default '',
-  `notes` text,
-  `created` datetime NOT NULL,
-  `updated` datetime NOT NULL,
-  PRIMARY KEY  (`topic_id`),
-  UNIQUE KEY `topic` ( `topic` ,  `topic_pid` ),
-  KEY `topic_pid` (`topic_pid`),
-  KEY `priority_id` (`priority_id`),
-  KEY `dept_id` (`dept_id`),
-  KEY `staff_id` (`staff_id`,`team_id`),
-  KEY `sla_id` (`sla_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%help_topic` (`topic_id`, `isactive`, `ispublic`,
-        `noautoresp`, `priority_id`, `dept_id`, `staff_id`, `team_id`,
-        `sla_id`, `formset_id`, `topic`, `notes`) VALUES
-    (1, 1, 1, 0, 2, 1, 0, 0, 1, 1, 'Support', NULL),
-    (2, 1, 1, 0, 3, 1, 0, 0, 0, 1, 'Billing', NULL);
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%canned_response`;
-CREATE TABLE `%TABLE_PREFIX%canned_response` (
-  `canned_id` int(10) unsigned NOT NULL auto_increment,
-  `dept_id` int(10) unsigned NOT NULL default '0',
-  `isenabled` tinyint(1) unsigned NOT NULL default '1',
-  `title` varchar(255) NOT NULL default '',
-  `response` text NOT NULL,
-  `notes` text,
-  `created` datetime NOT NULL,
-  `updated` datetime NOT NULL,
-  PRIMARY KEY  (`canned_id`),
-  UNIQUE KEY `title` (`title`),
-  KEY `dept_id` (`dept_id`),
-  KEY `active` (`isenabled`),
-  FULLTEXT KEY `resp` (`title`,`response`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%canned_response` (`canned_id`, `dept_id`, `isenabled`, `title`, `response`) VALUES
-    (1, 0, 1, 'What is osTicket (sample)?', '\r\nosTicket is a widely-used open source support ticket system, an attractive alternative to higher-cost and complex customer support systems - simple, lightweight, reliable, open source, web-based and easy to setup and use.'),
-    (2, 0, 1, 'Sample (with variables)', '\r\n%{ticket.name},\r\n\r\nYour ticket #%{ticket.number} created on %{ticket.create_date} is in %{ticket.dept.name} department.\r\n\r\n');
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%canned_attachment`;
-CREATE TABLE IF NOT EXISTS `%TABLE_PREFIX%canned_attachment` (
-  `canned_id` int(10) unsigned NOT NULL,
-  `file_id` int(10) unsigned NOT NULL,
-  PRIMARY KEY  (`canned_id`,`file_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%canned_attachment` (`canned_id`, `file_id`) VALUES (1,1);
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%session`;
-CREATE TABLE `%TABLE_PREFIX%session` (
-  `session_id` varchar(256) collate utf8_unicode_ci NOT NULL default '',
-  `session_data` longtext collate utf8_unicode_ci,
-  `session_expire` datetime default NULL,
-  `session_updated` datetime default NULL,
-  `user_id` int(10) unsigned NOT NULL default '0' COMMENT 'osTicket staff ID',
-  `user_ip` varchar(64) NOT NULL,
-  `user_agent` varchar(255) collate utf8_unicode_ci NOT NULL,
-  PRIMARY KEY  (`session_id`),
-  KEY `updated` (`session_updated`),
-  KEY `user_id` (`user_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-
-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',
-  `grace_period` int(10) unsigned NOT NULL default '0',
-  `name` varchar(64) NOT NULL default '',
-  `notes` text,
-  `created` datetime NOT NULL,
-  `updated` datetime NOT NULL,
-  PRIMARY KEY  (`id`),
-  UNIQUE KEY `name` (`name`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%sla` (`isactive`, `enable_priority_escalation`,
-        `disable_overdue_alerts`, `grace_period`, `name`, `notes`, `created`, `updated`)
-    VALUES (1, 1, 0, 48, 'Default SLA', NULL, NOW(), NOW());
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%staff`;
-CREATE TABLE `%TABLE_PREFIX%staff` (
-  `staff_id` int(11) unsigned NOT NULL auto_increment,
-  `group_id` int(10) unsigned NOT NULL default '0',
-  `dept_id` int(10) unsigned NOT NULL default '0',
-  `timezone_id` int(10) unsigned NOT NULL default '0',
-  `username` varchar(32) NOT NULL default '',
-  `firstname` varchar(32) default NULL,
-  `lastname` varchar(32) default NULL,
-  `passwd` varchar(128) default NULL,
-  `email` varchar(128) default NULL,
-  `phone` varchar(24) NOT NULL default '',
-  `phone_ext` varchar(6) default NULL,
-  `mobile` varchar(24) NOT NULL default '',
-  `signature` tinytext NOT NULL,
-  `notes` text,
-  `isactive` tinyint(1) NOT NULL default '1',
-  `isadmin` tinyint(1) NOT NULL default '0',
-  `isvisible` tinyint(1) unsigned NOT NULL default '1',
-  `onvacation` tinyint(1) unsigned NOT NULL default '0',
-  `assigned_only` tinyint(1) unsigned NOT NULL default '0',
-  `show_assigned_tickets` tinyint(1) unsigned NOT NULL default '0',
-  `daylight_saving` tinyint(1) unsigned NOT NULL default '0',
-  `change_passwd` tinyint(1) unsigned NOT NULL default '0',
-  `max_page_size` int(11) unsigned NOT NULL default '0',
-  `auto_refresh_rate` int(10) unsigned NOT NULL default '0',
-  `default_signature_type` ENUM( 'none', 'mine', 'dept' ) NOT NULL DEFAULT 'none',
-  `default_paper_size` ENUM( 'Letter', 'Legal', 'Ledger', 'A4', 'A3' ) NOT NULL DEFAULT 'Letter',
-  `created` datetime NOT NULL,
-  `lastlogin` datetime default NULL,
-  `passwdreset` datetime default NULL,
-  `updated` datetime NOT NULL,
-  PRIMARY KEY  (`staff_id`),
-  UNIQUE KEY `username` (`username`),
-  KEY `dept_id` (`dept_id`),
-  KEY `issuperuser` (`isadmin`),
-  KEY `group_id` (`group_id`,`staff_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%syslog`;
-CREATE TABLE `%TABLE_PREFIX%syslog` (
-  `log_id` int(11) unsigned NOT NULL auto_increment,
-  `log_type` enum('Debug','Warning','Error') NOT NULL,
-  `title` varchar(255) NOT NULL,
-  `log` text NOT NULL,
-  `logger` varchar(64) NOT NULL,
-  `ip_address` varchar(64) NOT NULL,
-  `created` datetime NOT NULL,
-  `updated` datetime NOT NULL,
-  PRIMARY KEY  (`log_id`),
-  KEY `log_type` (`log_type`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-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',
-  `name` varchar(125) NOT NULL default '',
-  `notes` text,
-  `created` datetime NOT NULL,
-  `updated` datetime NOT NULL,
-  PRIMARY KEY  (`team_id`),
-  UNIQUE KEY `name` (`name`),
-  KEY `isnabled` (`isenabled`),
-  KEY `lead_id` (`lead_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%team` (`lead_id`, `isenabled`, `noalerts`, `name`, `notes`, `created`, `updated`)
-    VALUES (0, 1, 0, 'Level I Support', '', NOW(), NOW());
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%team_member`;
-CREATE TABLE `%TABLE_PREFIX%team_member` (
-  `team_id` int(10) unsigned NOT NULL default '0',
-  `staff_id` int(10) unsigned NOT NULL,
-  `updated` datetime NOT NULL,
-  PRIMARY KEY  (`team_id`,`staff_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket`;
-CREATE TABLE `%TABLE_PREFIX%ticket` (
-  `ticket_id` int(11) unsigned NOT NULL auto_increment,
-  `ticketID` int(11) unsigned NOT NULL default '0',
-  `dept_id` int(10) unsigned NOT NULL default '1',
-  `sla_id` int(10) unsigned NOT NULL default '0',
-  `priority_id` int(10) unsigned NOT NULL default '2',
-  `topic_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',
-  `ip_address` varchar(64) NOT NULL default '',
-  `status` enum('open','closed') NOT NULL default 'open',
-  `source` enum('Web','Email','Phone','API','Other') NOT NULL default
-'Other',
-  `isoverdue` tinyint(1) unsigned NOT NULL default '0',
-  `isanswered` tinyint(1) unsigned NOT NULL default '0',
-  `duedate` datetime default NULL,
-  `reopened` datetime default NULL,
-  `closed` datetime default NULL,
-  `lastmessage` datetime default NULL,
-  `lastresponse` datetime default NULL,
-  `created` datetime NOT NULL,
-  `updated` datetime NOT NULL,
-  PRIMARY KEY  (`ticket_id`),
-  KEY `dept_id` (`dept_id`),
-  KEY `staff_id` (`staff_id`),
-  KEY `team_id` (`staff_id`),
-  KEY `status` (`status`),
-  KEY `priority_id` (`priority_id`),
-  KEY `created` (`created`),
-  KEY `closed` (`closed`),
-  KEY `duedate` (`duedate`),
-  KEY `topic_id` (`topic_id`),
-  KEY `sla_id` (`sla_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_attachment`;
-CREATE TABLE `%TABLE_PREFIX%ticket_attachment` (
-  `attach_id` int(11) unsigned NOT NULL auto_increment,
-  `ticket_id` int(11) unsigned NOT NULL default '0',
-  `file_id` int(10) unsigned NOT NULL default '0',
-  `ref_id` int(11) unsigned NOT NULL default '0',
-  `ref_type` enum('M','R','N') NOT NULL default 'M',
-  `created` datetime NOT NULL,
-  PRIMARY KEY  (`attach_id`),
-  KEY `ticket_id` (`ticket_id`),
-  KEY `ref_type` (`ref_type`),
-  KEY `ref_id` (`ref_id`),
-  KEY `file_id` (`file_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_lock`;
-CREATE TABLE `%TABLE_PREFIX%ticket_lock` (
-  `lock_id` int(11) unsigned NOT NULL auto_increment,
-  `ticket_id` int(11) unsigned NOT NULL default '0',
-  `staff_id` int(10) unsigned NOT NULL default '0',
-  `expire` datetime default NULL,
-  `created` datetime NOT NULL,
-  PRIMARY KEY  (`lock_id`),
-  UNIQUE KEY `ticket_id` (`ticket_id`),
-  KEY `staff_id` (`staff_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_email_info`;
-CREATE TABLE `%TABLE_PREFIX%ticket_email_info` (
-  `message_id` int(11) unsigned NOT NULL,
-  `email_mid` varchar(255) NOT NULL,
-  `headers` text,
-  KEY `message_id` (`email_mid`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_event`;
-CREATE TABLE `%TABLE_PREFIX%ticket_event` (
-  `ticket_id` int(11) unsigned NOT NULL default '0',
-  `staff_id` int(11) unsigned NOT NULL,
-  `team_id` int(11) unsigned NOT NULL,
-  `dept_id` int(11) unsigned NOT NULL,
-  `topic_id` int(11) unsigned NOT NULL,
-  `state` enum('created','closed','reopened','assigned','transferred','overdue') NOT NULL,
-  `staff` varchar(255) NOT NULL default 'SYSTEM',
-  `annulled` tinyint(1) unsigned NOT NULL default '0',
-  `timestamp` datetime NOT NULL,
-  KEY `ticket_state` (`ticket_id`, `state`, `timestamp`),
-  KEY `ticket_stats` (`timestamp`, `state`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_priority`;
-CREATE TABLE `%TABLE_PREFIX%ticket_priority` (
-  `priority_id` tinyint(4) NOT NULL auto_increment,
-  `priority` varchar(60) NOT NULL default '',
-  `priority_desc` varchar(30) NOT NULL default '',
-  `priority_color` varchar(7) NOT NULL default '',
-  `priority_urgency` tinyint(1) unsigned NOT NULL default '0',
-  `ispublic` tinyint(1) NOT NULL default '1',
-  PRIMARY KEY  (`priority_id`),
-  UNIQUE KEY `priority` (`priority`),
-  KEY `priority_urgency` (`priority_urgency`),
-  KEY `ispublic` (`ispublic`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%ticket_priority` (`priority_id`, `priority`, `priority_desc`, `priority_color`, `priority_urgency`, `ispublic`) VALUES
-    (1, 'low', 'Low', '#DDFFDD', 4, 1),
-    (2, 'normal', 'Normal', '#FFFFF0', 3, 1),
-    (3, 'high', 'High', '#FEE7E7', 2, 1),
-    (4, 'emergency', 'Emergency', '#FEE7E7', 1, 0);
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_thread`;
-CREATE TABLE `%TABLE_PREFIX%ticket_thread` (
-  `id` int(11) unsigned NOT NULL auto_increment,
-  `pid` int(11) unsigned NOT NULL default '0',
-  `ticket_id` int(11) unsigned NOT NULL default '0',
-  `staff_id` int(11) unsigned NOT NULL default '0',
-  `thread_type` enum('M','R','N') NOT NULL,
-  `poster` varchar(128) NOT NULL default '',
-  `source` varchar(32) NOT NULL default '',
-  `title` varchar(255),
-  `body` text NOT NULL,
-  `ip_address` varchar(64) NOT NULL default '',
-  `created` datetime NOT NULL,
-  `updated` datetime NOT NULL,
-  PRIMARY KEY  (`id`),
-  KEY `ticket_id` (`ticket_id`),
-  KEY `staff_id` (`staff_id`),
-  KEY `pid` (`pid`),
-  FULLTEXT KEY `body` (`body`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%timezone`;
-CREATE TABLE `%TABLE_PREFIX%timezone` (
-  `id` int(11) unsigned NOT NULL auto_increment,
-  `offset` float(3,1) NOT NULL default '0.0',
-  `timezone` varchar(255) NOT NULL default '',
-  PRIMARY KEY  (`id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%timezone` (`id`, `offset`, `timezone`) VALUES
-(1, -12.0, 'Eniwetok, Kwajalein'),
-(2, -11.0, 'Midway Island, Samoa'),
-(3, -10.0, 'Hawaii'),
-(4, -9.0, 'Alaska'),
-(5, -8.0, 'Pacific Time (US & Canada)'),
-(6, -7.0, 'Mountain Time (US & Canada)'),
-(7, -6.0, 'Central Time (US & Canada), Mexico City'),
-(8, -5.0, 'Eastern Time (US & Canada), Bogota, Lima'),
-(9, -4.0, 'Atlantic Time (Canada), Caracas, La Paz'),
-(10, -3.5, 'Newfoundland'),
-(11, -3.0, 'Brazil, Buenos Aires, Georgetown'),
-(12, -2.0, 'Mid-Atlantic'),
-(13, -1.0, 'Azores, Cape Verde Islands'),
-(14, 0.0, 'Western Europe Time, London, Lisbon, Casablanca'),
-(15, 1.0, 'Brussels, Copenhagen, Madrid, Paris'),
-(16, 2.0, 'Kaliningrad, South Africa'),
-(17, 3.0, 'Baghdad, Riyadh, Moscow, St. Petersburg'),
-(18, 3.5, 'Tehran'),
-(19, 4.0, 'Abu Dhabi, Muscat, Baku, Tbilisi'),
-(20, 4.5, 'Kabul'),
-(21, 5.0, 'Ekaterinburg, Islamabad, Karachi, Tashkent'),
-(22, 5.5, 'Bombay, Calcutta, Madras, New Delhi'),
-(23, 6.0, 'Almaty, Dhaka, Colombo'),
-(24, 7.0, 'Bangkok, Hanoi, Jakarta'),
-(25, 8.0, 'Beijing, Perth, Singapore, Hong Kong'),
-(26, 9.0, 'Tokyo, Seoul, Osaka, Sapporo, Yakutsk'),
-(27, 9.5, 'Adelaide, Darwin'),
-(28, 10.0, 'Eastern Australia, Guam, Vladivostok'),
-(29, 11.0, 'Magadan, Solomon Islands, New Caledonia'),
-(30, 12.0, 'Auckland, Wellington, Fiji, Kamchatka');
diff --git a/setup/inc/streams/core/install-mysql.sql b/setup/inc/streams/core/install-mysql.sql
index 8d27e2076..8faf7ac5c 100644
--- a/setup/inc/streams/core/install-mysql.sql
+++ b/setup/inc/streams/core/install-mysql.sql
@@ -173,6 +173,7 @@ INSERT INTO `%TABLE_PREFIX%config` (`namespace`, `key`, `value`) VALUES
 DROP TABLE IF EXISTS `%TABLE_PREFIX%form`;
 CREATE TABLE `%TABLE_PREFIX%form` (
     `id` int(11) unsigned NOT NULL auto_increment,
+    `type` char(1) NOT NULL DEFAULT 'T',
     `title` varchar(255) NOT NULL,
     `instructions` varchar(512),
     `notes` text,
@@ -203,7 +204,7 @@ CREATE TABLE `%TABLE_PREFIX%form_entry` (
     `id` int(11) unsigned NOT NULL auto_increment,
     `form_id` int(11) unsigned NOT NULL,
     `object_id` int(11) unsigned,
-    `object_type` char(1),
+    `object_type` char(1) NOT NULL DEFAULT 'T',
     `sort` int(11) unsigned NOT NULL DEFAULT 1,
     `created` datetime NOT NULL,
     `updated` datetime NOT NULL,
@@ -579,6 +580,8 @@ DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket`;
 CREATE TABLE `%TABLE_PREFIX%ticket` (
   `ticket_id` int(11) unsigned NOT NULL auto_increment,
   `ticketID` int(11) unsigned NOT NULL default '0',
+  `user_id` int(11) unsigned NOT NULL default '0',
+  `user_email_id` int(11) unsigned NOT NULL default '0',
   `dept_id` int(10) unsigned NOT NULL default '0',
   `sla_id` int(10) unsigned NOT NULL default '0',
   `priority_id` int(10) unsigned NOT NULL default '0',
@@ -748,3 +751,23 @@ CREATE TABLE IF NOT EXISTS `%TABLE_PREFIX%page` (
   PRIMARY KEY  (`id`),
   UNIQUE KEY `name` (`name`)
 ) DEFAULT CHARSET=utf8;
+
+DROP TABLE IF EXISTS `%TABLE_PREFIX%user`;
+CREATE TABLE `%TABLE_PREFIX%user` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `default_email_id` int(10) NOT NULL,
+  `first` varchar(64) NOT NULL,
+  `last` varchar(64),
+  `created` datetime NOT NULL,
+  `updated` datetime NOT NULL,
+  PRIMARY KEY  (`id`)
+);
+
+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,
+  `address` varchar(128) NOT NULL,
+  PRIMARY KEY  (`id`),
+  UNIQUE KEY `address` (`address`)
+);
-- 
GitLab