diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000000000000000000000000000000000000..8246670fb05e453860e1a84426c4fb8e8a49cde5
--- /dev/null
+++ b/ISSUE_TEMPLATE.md
@@ -0,0 +1,28 @@
+### Prerequisites
+
+* [ ] Can you reproduce the problem in a fresh installation of the "develop" branch?
+* [ ] Do you have any errors in the PHP error log, or javascript console?
+* [ ] Did you check the [osTicket forums](http://osticket.com/forum/categories)?
+* [ ] Did you [perform a cursory search](https://github.com/osTicket/osTicket/issues) to see if your bug or enhancement is already reported?
+
+For more information on how to write a good [bug report](https://github.com/osTicket/osTicket/wiki/Github-Issues-Guidelines)
+
+### Description
+
+[Description of the bug or feature]
+
+### Steps to Reproduce
+
+1. [First Step]
+2. [Second Step]
+3. [and so on...]
+
+**Expected behavior:** [What you expected to happen]
+
+**Actual behavior:** [What actually happened]
+
+### Versions
+
+Admin panel -> Dashboard -> Information which also additionally gives you information about you server.
+
+Also, please include the OS and what version of the OS you're running. As well as your browser and browser version.
diff --git a/WHATSNEW.md b/WHATSNEW.md
index b7162b2285383954e7fa8bae4159b4a83f0d3772..f10997f753c6ff10ac5022112dfef7cacb76ddca 100644
--- a/WHATSNEW.md
+++ b/WHATSNEW.md
@@ -1,3 +1,28 @@
+osTicket v1.10
+==============
+### Enhancements
+ * Support Passive Email Threading (#3276)
+ * Account for agents name format setting when sorting agents (#3274, 5c548c7)
+ * Ticket Filters: Support Lookup By Name (#3274, ef9b743)
+ * Enable preloaded canned responses by default (#3274, 7267531)
+
+### Improvements
+ * Task: Missing Description on create (#3274, 865db9)
+ * Save task due date on create (#3438)
+ * Show overlay on forms submit (#3426, #3391)
+ * upgrader: Fix crash on SequenceLoader (#3421)
+ * upgrader: Fix undefined js function when upgrading due to stale JS file (#3424)
+ * Use help topic as the subject line when issue summary is disabled (#3274, 74bdc02)
+ * PEAR: Turn off peer name verification by default (SMTP) (#3274, 4f68aeb)
+ * Cast orm objects to string when doing db_real_escape (#3274, e63ba58)
+ * Save department on __create (#3274, c664c93)
+ * Limit records to be indexed per cron run to 500 (#3274, 9174bab)
+
+### Performance and Security
+ * Fix memory leak when applying 'Use Reply-To Email' ticket filter action (#3437, 84f085d)
+ * XSS: Sanitize and validate HTTP_X_FORWARDED_FOR header (#3439, b794c599)
+ * XSS: Encode html chars on help desk title/name (#3439, a57de770)
+
 osTicket v1.10-rc.3
 ===================
 ### Enhancements
diff --git a/bootstrap.php b/bootstrap.php
index e70c79a6bb9801b06c49e4aaa5349a93e84b6de6..fe3dd2155b8fdd0e2dbb21d249d5eeba247fadc0 100644
--- a/bootstrap.php
+++ b/bootstrap.php
@@ -50,11 +50,7 @@ class Bootstrap {
     }
 
     function https() {
-       return
-            (isset($_SERVER['HTTPS'])
-                && strtolower($_SERVER['HTTPS']) == 'on')
-            || (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
-                && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https');
+       return osTicket::is_https();
     }
 
     static function defineTables($prefix) {
@@ -335,6 +331,7 @@ ini_set('include_path', './'.PATH_SEPARATOR.INCLUDE_DIR.PATH_SEPARATOR.PEAR_DIR)
 require(INCLUDE_DIR.'class.osticket.php');
 require(INCLUDE_DIR.'class.misc.php');
 require(INCLUDE_DIR.'class.http.php');
+require(INCLUDE_DIR.'class.validator.php');
 
 // Determine the path in the URI used as the base of the osTicket
 // installation
@@ -346,12 +343,7 @@ Bootstrap::init();
 #CURRENT EXECUTING SCRIPT.
 define('THISPAGE', Misc::currentURL());
 
-define('DEFAULT_MAX_FILE_UPLOADS',ini_get('max_file_uploads')?ini_get('max_file_uploads'):5);
-define('DEFAULT_PRIORITY_ID',1);
+define('DEFAULT_MAX_FILE_UPLOADS', ini_get('max_file_uploads') ?: 5);
+define('DEFAULT_PRIORITY_ID', 1);
 
-#Global override
-if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
-    // Take the left-most item for X-Forwarded-For
-    $_SERVER['REMOTE_ADDR'] = trim(array_pop(
-        explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])));
 ?>
diff --git a/css/flags.css b/css/flags.css
index 8e67320909401edbc33f4d4495ebd4d463cb9506..b517a8eaf28154b0ef4b18b0cd856f4e30e84759 100644
--- a/css/flags.css
+++ b/css/flags.css
@@ -70,7 +70,7 @@
 .flag.flag-england {background-position: -240px -33px}
 .flag.flag-er {background-position: 0 -44px}
 .flag.flag-es {background-position: -16px -44px}
-.flag.flag-et {background-position: -32px -44px}
+.flag.flag-et {background-position: -192px -33px}
 .flag.flag-eu {background-position: -48px -44px}
 .flag.flag-fi {background-position: -64px -44px}
 .flag.flag-fj {background-position: -80px -44px}
diff --git a/file.php b/file.php
index d62d588eb5942b0c0c1f5639ba22cf511f3a8884..ed0a4465e845f90377e05905c53d9b1b37962f58 100644
--- a/file.php
+++ b/file.php
@@ -51,7 +51,7 @@ if ($file->verifySignature($_GET['signature'], $_GET['expires'])) {
         // Download the file..
         $file->download(@$_GET['disposition'] ?: false, $_GET['expires']);
     }
-    catch (Exception $x) {
+    catch (Exception $ex) {
         Http::response(500, 'Unable to find that file: '.$ex->getMessage());
     }
 }
diff --git a/include/ajax.forms.php b/include/ajax.forms.php
index 520e8584a80b6107d4b63af9f7bd5b309694ac54..77b4638bf43560075ad56341de2ae693ab18f2c6 100644
--- a/include/ajax.forms.php
+++ b/include/ajax.forms.php
@@ -149,22 +149,32 @@ class DynamicFormsAjaxAPI extends AjaxController {
             Http::response(403, 'Login required');
 
         $list = DynamicList::lookup($list_id);
+        if (!$list)
+            Http::response(404, 'No such list item');
+
+        $list = CustomListHandler::forList($list);
         if (!$list || !($item = $list->getItem( (int) $item_id)))
             Http::response(404, 'No such list item');
 
         $item_form = $list->getListItemBasicForm($_POST, $item);
 
         if ($valid = $item_form->isValid()) {
-            // Update basic information
-            $basic = $item_form->getClean();
-            $item->extra = $basic['extra'];
-            $item->value = $basic['value'];
-
             if ($_item = DynamicListItem::lookup(array(
-                            'list_id' => $list->getId(), 'value'=>$item->value)))
+                'list_id' => $list->getId(), 'value'=>$item->getValue()))
+            ) {
                 if ($_item && $_item->id != $item->id)
                     $item_form->getField('value')->addError(
                         __('Value already in use'));
+            }
+            if ($item_form->isValid()) {
+                // Update basic information
+                $basic = $item_form->getClean();
+                $item->update([
+                    'name' =>   $basic['name'],
+                    'value' =>  $basic['value'],
+                    'abbrev' =>  $basic['extra'],
+                ]);
+            }
         }
 
         // Context
diff --git a/include/class.canned.php b/include/class.canned.php
index c0232099178cab1b4e43076df402ec6daffc33cc..21cd9aa6367f2b4ec81959d1790177fbb751ad65 100644
--- a/include/class.canned.php
+++ b/include/class.canned.php
@@ -21,6 +21,10 @@ extends VerySimpleModel {
         'table' => CANNED_TABLE,
         'pk' => array('canned_id'),
         'joins' => array(
+            'dept' => array(
+                'constraint' => array('dept_id' => 'Dept.id'),
+                'null' => true,
+            ),
             'attachments' => array(
                 'constraint' => array(
                     "'C'" => 'Attachment.type',
diff --git a/include/class.dept.php b/include/class.dept.php
index 5c348237da6bfa9d6e97e6537dcb6fc26e5adc81..ceff70a47084409a9b5b02eebcff703db808b139 100644
--- a/include/class.dept.php
+++ b/include/class.dept.php
@@ -320,7 +320,7 @@ implements TemplateVariable {
         if (is_object($staff))
             $staff = $staff->getId();
 
-        return $members->getIterator()->findFirst(array(
+        return $this->getMembers()->findFirst(array(
             'staff_id' => $staff
         ));
     }
@@ -469,7 +469,7 @@ implements TemplateVariable {
     }
 
     /*----Static functions-------*/
-	static function getIdByName($name, $pid=null) {
+    static function getIdByName($name, $pid=null) {
         $row = static::objects()
             ->filter(array(
                         'name' => $name,
@@ -579,9 +579,12 @@ implements TemplateVariable {
 
     static function __create($vars, &$errors) {
         $dept = self::create($vars);
-        $dept->update($vars, $errors);
+        if (!$dept->update($vars, $errors))
+          return false;
+
+       $dept->save();
 
-        return isset($dept->id) ? $dept : null;
+       return $dept;
     }
 
     function save($refetch=false) {
diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php
index 7bb040814714eeaa7b6f4400ef84d3e98391cccf..9abe6467a74f6b91d5641e679d06548ecac04ee2 100644
--- a/include/class.dynamic_forms.php
+++ b/include/class.dynamic_forms.php
@@ -951,15 +951,11 @@ class DynamicFormEntry extends VerySimpleModel {
     }
 
     function setAnswer($name, $value, $id=false) {
-        foreach ($this->getAnswers() as $ans) {
+
+        if ($ans=$this->getAnswer($name)) {
             $f = $ans->getField();
-            if ($f->isStorable() && $f->get('name') == $name) {
-                $f->reset();
-                $ans->set('value', $value);
-                if ($id !== false)
-                    $ans->set('value_id', $id);
-                break;
-            }
+            if ($f->isStorable())
+                $ans->setValue($value, $id);
         }
     }
 
@@ -1269,7 +1265,7 @@ class DynamicFormEntry extends VerySimpleModel {
             }
             if ($a->dirty)
                 $dirty++;
-            $a->save();
+            $a->save($refetch);
         }
         return $dirty;
     }
@@ -1359,6 +1355,14 @@ class DynamicFormEntryAnswer extends VerySimpleModel {
         return $this->_value;
     }
 
+    function setValue($value, $id=false) {
+        $this->getField()->reset();
+        $this->_value = null;
+        $this->set('value', $value);
+        if ($id !== false)
+            $this->set('value_id', $id);
+    }
+
     function getLocal($tag) {
         return $this->field->getLocal($tag);
     }
@@ -1621,8 +1625,10 @@ class SelectionField extends FormField {
                 }
             } elseif ($config['typeahead']
                     && ($entered = $this->getWidget()->getEnteredValue())
-                    && !in_array($entered, $entry))
+                    && !in_array($entered, $entry)
+                    && $entered != $entry) {
                 $this->_errors[] = __('Select a value from the list');
+           }
         }
     }
 
diff --git a/include/class.filter.php b/include/class.filter.php
index 20bac5ce53b856d13d439a0afedd8e8abe1ab97a..29f49d904949b2318dbd4da9d16c6ebed7f1f299 100644
--- a/include/class.filter.php
+++ b/include/class.filter.php
@@ -383,6 +383,10 @@ class Filter {
     }
 
     function lookup($id) {
+
+        if ($id && !is_numeric($id))
+            $id = self::getIdByName($id);
+
         return ($id && is_numeric($id) && ($f= new Filter($id)) && $f->getId()==$id)?$f:null;
     }
 
diff --git a/include/class.filter_action.php b/include/class.filter_action.php
index 7d639d9d186634592d787c79e44605d8493d4554..f5dc14abbc77740d58a368e434603568b6f64fca 100644
--- a/include/class.filter_action.php
+++ b/include/class.filter_action.php
@@ -188,17 +188,18 @@ class FA_UseReplyTo extends TriggerAction {
     static $name = /* @trans */ 'Use Reply-To Email';
 
     function apply(&$ticket, array $info) {
-        if (!$info['reply-to'])
+        if (!$info['reply-to']
+            || !$ticket['email']
+            || !strcasecmp($info['reply-to'], $ticket['email']))
             // Nothing to do
             return;
-        $changed = $info['reply-to'] != $ticket['email']
-            || ($info['reply-to-name'] && $ticket['name'] != $info['reply-to-name']);
-        if ($changed) {
-            $ticket['email'] = $info['reply-to'];
-            if ($info['reply-to-name'])
-                $ticket['name'] = $info['reply-to-name'];
-            throw new FilterDataChanged($ticket);
-        }
+
+        // Change email and  throw data changed exception
+        $ticket['email'] = $info['reply-to'];
+        if ($info['reply-to-name'])
+            $ticket['name'] = $info['reply-to-name'];
+
+        throw new FilterDataChanged($ticket);
     }
 
     function getConfigurationOptions() {
diff --git a/include/class.format.php b/include/class.format.php
index d25579051f6c8b2f376ce35688bb382c925466b9..864bc6456c6e36863339f612e7e7fa9f2c91c581 100644
--- a/include/class.format.php
+++ b/include/class.format.php
@@ -305,8 +305,9 @@ class Format {
                   ':<!\[[^]<]+\]>:',            # <![if !mso]> and friends
                   ':<!DOCTYPE[^>]+>:',          # <!DOCTYPE ... >
                   ':<\?[^>]+>:',                # <?xml version="1.0" ... >
+                  ':<html[^>]+:i',              # drop html attributes
             ),
-            array('', '', '', ''),
+            array('', '', '', '', '<html'),
             $html);
 
         // HtmLawed specific config only
diff --git a/include/class.forms.php b/include/class.forms.php
index 318adbbc12b4f3053921f9b13d63f8e10cfa3718..b7bb2f93a54f4afb651b96191e8ee0b635d42e47 100644
--- a/include/class.forms.php
+++ b/include/class.forms.php
@@ -1582,15 +1582,19 @@ class ChoiceField extends FormField {
             $value = JsonDataParser::parse($value) ?: $value;
 
         // CDATA table may be built with comma-separated key,value,key,value
-        if (is_string($value)) {
+        if (is_string($value) && strpos($value, ',')) {
             $values = array();
             $choices = $this->getChoices();
-            foreach (explode(',', $value) as $V) {
+            $vals = explode(',', $value);
+            foreach ($vals as $V) {
                 if (isset($choices[$V]))
                     $values[$V] = $choices[$V];
             }
             if (array_filter($values))
                 $value = $values;
+            elseif($vals)
+                list($value) = $vals;
+
         }
         $config = $this->getConfiguration();
         if (!$config['multiselect'] && is_array($value) && count($value) < 2) {
@@ -1762,7 +1766,7 @@ class DatetimeField extends FormField {
 
     function to_database($value) {
         // Store time in gmt time, unix epoch format
-        return date('Y-m-d H:i:s', $value);
+        return $value ? date('Y-m-d H:i:s', $value) : $value;
     }
 
     function to_php($value) {
diff --git a/include/class.i18n.php b/include/class.i18n.php
index a7e23a8ee63d3fabbcbb2e4568a25b60ab3eb3ef..ac6db0a332a0e97da6b216b5ac56f3c262087222 100644
--- a/include/class.i18n.php
+++ b/include/class.i18n.php
@@ -140,6 +140,7 @@ class Internationalization {
         if (($tpl = $this->getTemplate('templates/premade.yaml'))
                 && ($canned = $tpl->getData())) {
             foreach ($canned as $c) {
+                $c['isenabled'] = 1;
                 if (!($premade = Canned::create($c)) || !$premade->save())
                     continue;
                 if (isset($c['attachments'])) {
diff --git a/include/class.orm.php b/include/class.orm.php
index 3e7dc64dfaab83eebc7b583cf522fd48e8463ea8..1f37f679b60d64ad62dec1939563d16a2f2b405f 100644
--- a/include/class.orm.php
+++ b/include/class.orm.php
@@ -396,9 +396,10 @@ class VerySimpleModel {
     }
 
     function __isset($field) {
-        return array_key_exists($field, $this->ht)
+        return ($this->ht && array_key_exists($field, $this->ht))
             || isset(static::$meta['joins'][$field]);
     }
+
     function __unset($field) {
         if ($this->__isset($field))
             unset($this->ht[$field]);
@@ -1468,6 +1469,13 @@ implements IteratorAggregate, Countable, ArrayAccess {
         }
     }
 
+    function reset() {
+        $this->eoi = false;
+        $this->cache = array();
+        // XXX: Should the inner be recreated to refetch?
+        $this->inner->rewind();
+    }
+
     function asArray() {
         $this->fillTo(PHP_INT_MAX);
         return $this->getCache();
@@ -1908,11 +1916,6 @@ extends ModelResultSet {
                 $object->set($field, null);
     }
 
-    function reset() {
-        $this->cache = array();
-        unset($this->resource);
-    }
-
     /**
      * Slight edit to the standard iteration method which will skip deleted
      * items.
@@ -3106,12 +3109,11 @@ class MySqlPreparedExecutor {
             case is_int($p):
             case is_float($p):
                 return $p;
-
             case $p instanceof DateTime:
                 $p = $p->format('Y-m-d H:i:s');
             default:
-                return db_real_escape($p, true);
-            }
+                return db_real_escape((string) $p, true);
+           }
         }, $this->sql);
     }
 }
diff --git a/include/class.osticket.php b/include/class.osticket.php
index 40c939c0493a30d685ea7c51fac0d808eb5b39a5..db48388e03dc852c9a9ddc06ffe9c9bf7a030211 100644
--- a/include/class.osticket.php
+++ b/include/class.osticket.php
@@ -444,6 +444,37 @@ class osTicket {
         }
     }
 
+   /*
+    * getTrustedProxies
+    *
+    * Get defined trusted proxies
+    */
+
+    static function getTrustedProxies() {
+        static $proxies = null;
+        // Parse trusted proxies from config file
+        if (!isset($proxies) && defined('TRUSTED_PROXIES'))
+            $proxies = array_filter(
+                    array_map('trim', explode(',', TRUSTED_PROXIES)));
+
+        return $proxies ?: array();
+    }
+
+    /*
+     * getLocalNetworkAddresses
+     *
+     * Get defined local network addresses
+     */
+    static function getLocalNetworkAddresses() {
+        static $ips = null;
+        // Parse local addreses from config file
+        if (!isset($ips) && defined('LOCAL_NETWORKS'))
+            $ips = array_filter(
+                    array_map('trim', explode(',', LOCAL_NETWORKS)));
+
+        return $ips ?: array();
+    }
+
     static function get_root_path($dir) {
 
         /* If run from the commandline, DOCUMENT_ROOT will not be set. It is
@@ -488,14 +519,96 @@ class osTicket {
         return null;
     }
 
+    /*
+     * get_client_ip
+     *
+     * Get client IP address from "Http_X-Forwarded-For" header by following a
+     * chain of trusted proxies.
+     *
+     * "Http_X-Forwarded-For" header value is a comma+space separated list of IP
+     * addresses, the left-most being the original client, and each successive
+     * proxy that passed the request all the way to the originating IP address.
+     *
+     */
+    static function get_client_ip($header='HTTP_X_FORWARDED_FOR') {
+
+        // Request IP
+        $ip = $_SERVER['REMOTE_ADDR'];
+        // Trusted proxies.
+        $proxies = self::getTrustedProxies();
+        // Return current IP address if header is not set and
+        // request is not from a trusted proxy.
+        if (!isset($_SERVER[$header])
+                || !$proxies
+                || !self::is_trusted_proxy($ip, $proxies))
+            return $ip;
+
+        // Get chain of proxied ip addresses
+        $ips = array_map('trim', explode(',', $_SERVER[$header]));
+        // Add request IP to the chain
+        $ips[] = $ip;
+        // Walk the chain in reverse - remove invalid IPs
+        $ips = array_reverse($ips);
+        foreach ($ips as $k => $ip) {
+            // Make sure the IP is valid and not a trusted proxy
+            if ($k && !Validator::is_ip($ip))
+                unset($ips[$k]);
+            elseif ($k && !self::is_trusted_proxy($ip, $proxies))
+                return $ip;
+        }
+
+        // We trust the 400 lb hacker... return left most valid IP
+        return array_pop($ips);
+    }
+
+    /*
+     * Checks if the IP is that of a trusted proxy
+     *
+     */
+    static function is_trusted_proxy($ip, $proxies=array()) {
+        $proxies = $proxies ?: self::getTrustedProxies();
+        // We don't have any proxies set.
+        if (!$proxies)
+            return false;
+        // Wildcard set - trust all proxies
+        else if ($proxies == '*')
+            return true;
+
+        return ($proxies && Validator::check_ip($ip, $proxies));
+    }
+
+    /**
+     * is_local_ip
+     *
+     * Check if a given IP is part of defined local address blocks
+     *
+     */
+    static function is_local_ip($ip, $ips=array()) {
+        $ips = $ips
+            ?: self::getLocalNetworkAddresses()
+            ?: array();
+
+        foreach ($ips as $addr) {
+            if (Validator::check_ip($ip, $addr))
+                return true;
+        }
+
+        return false;
+    }
+
     /**
      * Returns TRUE if the request was made via HTTPS and false otherwise
      */
     function is_https() {
-        return (isset($_SERVER['HTTPS'])
+
+        // Local server flags
+        if (isset($_SERVER['HTTPS'])
                 && strtolower($_SERVER['HTTPS']) == 'on')
-            || (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
-                && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https');
+            return true;
+
+        // Check if SSL was terminated by a loadbalancer
+        return (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
+                && !strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https'));
     }
 
     /* returns true if script is being executed via commandline */
diff --git a/include/class.page.php b/include/class.page.php
index 7219e88c8db2e1085e8affeae37c4ac516162e7a..c296e9feef025ddc7860c5fb6771d2397f8cdee4 100644
--- a/include/class.page.php
+++ b/include/class.page.php
@@ -319,7 +319,7 @@ class Page extends VerySimpleModel {
                 return false;
         }
         // New translations (?)
-        foreach ($vars['trans'] as $lang=>$parts) {
+        foreach ($vars['trans'] ?: array() as $lang=>$parts) {
             $content = array('name' => @$parts['title'], 'body' => Format::sanitize(@$parts['body']));
             if (!array_filter($content))
                 continue;
diff --git a/include/class.search.php b/include/class.search.php
index 6249498b05601fcc09afa23f753ae5c61fcb6466..61b56a41e61f6c14dd4fa44ccaa6fd914d36453b 100644
--- a/include/class.search.php
+++ b/include/class.search.php
@@ -478,7 +478,7 @@ class MysqlSearchBackend extends SearchBackend {
             LEFT JOIN `".TABLE_PREFIX."_search` A2 ON (A1.`id` = A2.`object_id` AND A2.`object_type`='H')
             WHERE A2.`object_id` IS NULL AND (A1.poster <> 'SYSTEM')
             AND (LENGTH(A1.`title`) + LENGTH(A1.`body`) > 0)
-            ORDER BY A1.`id` DESC";
+            ORDER BY A1.`id` DESC LIMIT 500";
         if (!($res = db_query_unbuffered($sql, $auto_create)))
             return false;
 
@@ -498,7 +498,7 @@ class MysqlSearchBackend extends SearchBackend {
         $sql = "SELECT A1.`ticket_id` FROM `".TICKET_TABLE."` A1
             LEFT JOIN `".TABLE_PREFIX."_search` A2 ON (A1.`ticket_id` = A2.`object_id` AND A2.`object_type`='T')
             WHERE A2.`object_id` IS NULL
-            ORDER BY A1.`ticket_id` DESC";
+            ORDER BY A1.`ticket_id` DESC LIMIT 300";
         if (!($res = db_query_unbuffered($sql, $auto_create)))
             return false;
 
diff --git a/include/class.sequence.php b/include/class.sequence.php
index 912e7cd28e910f2ba16c6b7345d56c70d2c94166..867aa210fd193c48731a2b6501470a9b33021eea 100644
--- a/include/class.sequence.php
+++ b/include/class.sequence.php
@@ -205,7 +205,7 @@ class Sequence extends VerySimpleModel {
     }
 
     function __create($data) {
-        $instance = new static($data);
+        $instance = new self($data);
         $instance->save();
         return $instance;
     }
diff --git a/include/class.task.php b/include/class.task.php
index 30b6b673fbabf8d2b1a1fef294eb79d58dc14f9f..4b98ff1d4a861ff9d3cab3ed906fc3ae12db34d6 100644
--- a/include/class.task.php
+++ b/include/class.task.php
@@ -1004,13 +1004,15 @@ class Task extends TaskModel implements RestrictedAccess, Threadable {
         case 'phone':
         case 'phone_number':
             return $this->getPhoneNumber();
-            break;
+        case 'ticket_link':
+            if ($ticket = $this->ticket) {
+                return sprintf('%s/scp/tickets.php?id=%d#tasks',
+                    $cfg->getBaseUrl(), $ticket->getId());
+            }
         case 'staff_link':
             return sprintf('%s/scp/tasks.php?id=%d', $cfg->getBaseUrl(), $this->getId());
-            break;
         case 'create_date':
             return new FormattedDate($this->getCreateDate());
-            break;
          case 'due_date':
             if ($due = $this->getEstDueDate())
                 return new FormattedDate($due);
@@ -1061,6 +1063,8 @@ class Task extends TaskModel implements RestrictedAccess, Threadable {
             'thread' => array(
                 'class' => 'TaskThread', 'desc' => __('Task Thread'),
             ),
+            'staff_link' => __('Link to view the task'),
+            'ticket_link' => __('Link to view the task inside the ticket'),
             'last_update' => array(
                 'class' => 'FormattedDate', 'desc' => __('Time of last update'),
             ),
@@ -1281,7 +1285,7 @@ class Task extends TaskModel implements RestrictedAccess, Threadable {
         if ($vars['internal_formdata']['dept_id'])
             $task->dept_id = $vars['internal_formdata']['dept_id'];
         if ($vars['internal_formdata']['duedate'])
-            $task->duedate = $vars['internal_formdata']['duedate'];
+	    $task->duedate = date('Y-m-d G:i', Misc::dbtime($vars['internal_formdata']['duedate']));
 
         if (!$task->save(true))
             return false;
@@ -1453,7 +1457,7 @@ class TaskForm extends DynamicForm {
     static $cdata = array(
             'table' => TASK_CDATA_TABLE,
             'object_id' => 'task_id',
-            'object_type' => 'A',
+            'object_type' => ObjectModel::OBJECT_TYPE_TASK,
         );
 
     static function objects() {
@@ -1516,7 +1520,7 @@ extends AbstractForm {
                     'configuration' => array(
                         'min' => Misc::gmtime(),
                         'time' => true,
-                        'gmt' => true,
+                        'gmt' => false,
                         'future' => true,
                         ),
                     )),
@@ -1541,8 +1545,7 @@ class TaskThread extends ObjectThread {
         $vars['threadId'] = $this->getId();
         $vars['message'] = $vars['description'];
         unset($vars['description']);
-
-        return MessageThreadEntry::create($vars, $errors);
+        return MessageThreadEntry::add($vars, $errors);
     }
 
     static function create($task=false) {
diff --git a/include/class.template.php b/include/class.template.php
index 1f53922dd409bc9cc13861a9fd1dbc6a507974f0..53f1caf431a542d115bcfe49a5baa5d08bdf3eb7 100644
--- a/include/class.template.php
+++ b/include/class.template.php
@@ -616,16 +616,16 @@ class EmailTemplate {
 
     function save($id, $vars, &$errors) {
         if(!$vars['subject'])
-            $errors['subject']='Message subject is required';
+            $errors['subject'] = __('Message subject is required');
 
         if(!$vars['body'])
-            $errors['body']='Message body is required';
+            $errors['body'] = __('Message body is required');
 
         if (!$id) {
             if (!$vars['tpl_id'])
-                $errors['tpl_id']='Template set is required';
+                $errors['tpl_id'] = __('Template set is required');
             if (!$vars['code_name'])
-                $errors['code_name']='Code name is required';
+                $errors['code_name'] = __('Code name is required');
         }
 
         if ($errors)
diff --git a/include/class.thread.php b/include/class.thread.php
index b6fc9b5f15504d779dc7619d0e4a6fc384ab8bd2..164624d35c6b8ab34300f07cda5a8f4cd9a2b1cc 100644
--- a/include/class.thread.php
+++ b/include/class.thread.php
@@ -312,6 +312,7 @@ class Thread extends VerySimpleModel {
             'reply_to' => $entry,
             'recipients' => $mailinfo['recipients'],
             'to-email-id' => $mailinfo['to-email-id'],
+            'autorespond' => !isset($mailinfo['passive']),
         );
 
         // XXX: Is this necessary?
@@ -913,9 +914,18 @@ implements TemplateVariable {
                         _S($error_descriptions[$error]));
                 }
                 // No need to log the missing-file error number
-                if ($error != UPLOAD_ERR_NO_FILE)
-                    $this->getThread()->getObject()->logNote(
-                        _S('File Import Error'), $error, _S('SYSTEM'), false);
+                if ($error != UPLOAD_ERR_NO_FILE
+                    && ($thread = $this->getThread())
+                ) {
+                    // Log to the thread directly, since alerts should be
+                    // suppressed and this is defintely a system message
+                    $thread->addNote(array(
+                        'title' => _S('File Import Error'),
+                        'note' => new TextThreadEntryBody($error),
+                        'poster' => 'SYSTEM',
+                        'staffId' => 0,
+                    ));
+                }
                 continue;
             }
 
@@ -1112,11 +1122,13 @@ implements TemplateVariable {
     function lookupByEmailHeaders(&$mailinfo, &$seen=false) {
         // Search for messages using the References header, then the
         // in-reply-to header
-        if ($entry = ThreadEntry::objects()
-            ->filter(array('email_info__mid' => $mailinfo['mid']))
-            ->order_by(false)
-            ->first()
-        ) {
+        if ($mailinfo['mid'] &&
+                ($entry = ThreadEntry::objects()
+                 ->filter(array('email_info__mid' => $mailinfo['mid']))
+                 ->order_by(false)
+                 ->first()
+                 )
+         ) {
             $seen = true;
             return $entry;
         }
@@ -1178,40 +1190,19 @@ implements TemplateVariable {
                 // ThreadEntry was positively identified
                 return $t;
             }
-
-            // Try to determine if it's a reply to a tagged email.
-            // (Deprecated)
-            $ref = null;
-            if (strpos($mid, '+')) {
-                list($left, $right) = explode('@',$mid);
-                list($left, $ref) = explode('+', $left);
-                $mid = "$left@$right";
-            }
-            $entries = ThreadEntry::objects()
-                ->filter(array('email_info__mid' => $mid))
-                ->order_by(false);
-            foreach ($entries as $t) {
-                // Capture the first match thread item
-                if (!$thread)
-                    $thread = $t;
-                // We found a match  - see if we can ID the user.
-                // XXX: Check access of ref is enough?
-                if ($ref && ($uid = $t->getUIDFromEmailReference($ref))) {
-                    if ($ref[0] =='s') //staff
-                        $mailinfo['staffId'] = $uid;
-                    else // user or collaborator.
-                        $mailinfo['userId'] = $uid;
-
-                    // Best possible case — found the thread and the
-                    // user
-                    return $t;
-                }
-            }
         }
-        // Second best case — found a thread but couldn't identify the
-        // user from the header. Return the first thread entry matched
-        if ($thread)
-            return $thread;
+        // Passive threading - listen mode
+        if (count($possibles)
+                && ($entry = ThreadEntry::objects()
+                    ->filter(array('email_info__mid__in' => array_map(
+                        function ($a) { return "<$a>"; },
+                    $possibles)))
+                    ->first()
+                )
+         ) {
+            $mailinfo['passive'] = true;
+            return $entry;
+        }
 
         // Search for ticket by the [#123456] in the subject line
         // This is the last resort -  emails must match to avoid message
@@ -2478,7 +2469,7 @@ implements TemplateVariable {
         ));
     }
 
-    function addNote($vars, &$errors) {
+    function addNote($vars, &$errors=array()) {
 
         //Add ticket Id.
         $vars['threadId'] = $this->getId();
diff --git a/include/class.ticket.php b/include/class.ticket.php
index 8b75335a76874ac6e9f6b91b16b361573f8b2ffe..7cc661f9595c6a68e4dc8ee8d47b04b7fd13ddda 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -1535,7 +1535,7 @@ implements RestrictedAccess, Threadable {
         }
     }
 
-    function onMessage($message, $autorespond=true) {
+    function onMessage($message, $autorespond=true, $reopen=true) {
         global $cfg;
 
         $this->isanswered = 0;
@@ -1547,7 +1547,7 @@ implements RestrictedAccess, Threadable {
         // We're also checking autorespond flag because we don't want to
         // reopen closed tickets on auto-reply from end user. This is not to
         // confused with autorespond on new message setting
-        if ($autorespond && $this->isClosed() && $this->isReopenable()) {
+        if ($reopen && $this->isClosed() && $this->isReopenable()) {
             $this->reopen();
             // Auto-assign to closing staff or the last respondent if the
             // agent is available and has access. Otherwise, put the ticket back
@@ -2334,10 +2334,13 @@ implements RestrictedAccess, Threadable {
         $autorespond = isset($vars['mailflags'])
                 ? !$vars['mailflags']['bounce'] && !$vars['mailflags']['auto-reply']
                 : true;
+        $reopen = $autorespond; // Do not reopen bounces
         if ($autorespond && $message->isBounceOrAutoReply())
-            $autorespond = false;
+            $autorespond = $reopen= false;
+        elseif ($autorespond && isset($vars['autorespond']))
+            $autorespond = $vars['autorespond'];
 
-        $this->onMessage($message, ($autorespond && $alerts)); //must be called b4 sending alerts to staff.
+        $this->onMessage($message, ($autorespond && $alerts), $reopen); //must be called b4 sending alerts to staff.
 
         if ($autorespond && $alerts && $cfg && $cfg->notifyCollabsONNewMessage())
             $this->notifyCollaborators($message, array('signature' => ''));
@@ -2404,6 +2407,7 @@ implements RestrictedAccess, Threadable {
                 $sentlist[] = $staff->getEmail();
             }
         }
+
         return $message;
     }
 
@@ -2825,6 +2829,7 @@ implements RestrictedAccess, Threadable {
         if (!$this->save())
             return false;
 
+	$vars['note'] = ThreadEntryBody::clean($vars['note']);
         if ($vars['note'])
             $this->logNote(_S('Ticket Updated'), $vars['note'], $thisstaff);
 
@@ -2897,9 +2902,11 @@ implements RestrictedAccess, Threadable {
     }
 
     static function isTicketNumberUnique($number) {
-        return 0 === static::objects()
+        $num = static::objects()
             ->filter(array('number' => $number))
-            ->count();
+	    ->count();
+
+	return ($num === 0);
     }
 
     /* Quick staff's tickets stats */
@@ -2994,8 +3001,8 @@ implements RestrictedAccess, Threadable {
             $user_form = UserForm::getUserForm()->getForm($vars);
             // Add all the user-entered info for filtering
             foreach ($interesting as $F) {
-                $field = $user_form->getField($F);
-                $vars[$F] = $field->toString($field->getClean());
+                if ($field = $user_form->getField($F))
+                    $vars[$F] = $field->toString($field->getClean());
             }
             // Attempt to lookup the user and associated data
             $user = User::lookupByEmail($vars['email']);
@@ -3373,11 +3380,9 @@ implements RestrictedAccess, Threadable {
         // Save the (common) dynamic form
         // Ensure we have a subject
         $subject = $form->getAnswer('subject');
-        if ($subject && !$subject->getValue()) {
-            if ($topic) {
-                $form->setAnswer('subject', $topic->getFullName());
-            }
-        }
+        if ($subject && !$subject->getValue() && $topic)
+            $subject->setValue($topic->getFullName());
+
         $form->setTicketId($ticket->getId());
         $form->save();
 
diff --git a/include/class.timezone.php b/include/class.timezone.php
index 272444b458130a7f6eff208708ab1e0b48c15743..eb2afca6771cc7e545e0805b9a0dde325fe4888f 100644
--- a/include/class.timezone.php
+++ b/include/class.timezone.php
@@ -166,12 +166,20 @@ class DbTimezone {
         // Attempt to fetch timezone direct from the database
         $TZ = db_timezone();
 
+        // Translate ambiguous 'GMT' timezone
+        if ($TZ === 'GMT') {
+            // PHP assumes GMT == UTC, MySQL assumes GMT == Europe/London.
+            // To shore up the difference, assuming use of MySQL, use the
+            // timezone in PHP which honors BST (British Summer Time)
+            return 'Europe/London';
+        }
         // Forbid timezone abbreviations like 'CDT'
-        if (!in_array($TZ, array('UTC', 'GMT')) && strpos($TZ, '/') === false)
+        elseif ($TZ !== 'UTC' && strpos($TZ, '/') === false) {
             // Attempt to lookup based on the abbreviation
             if (!($TZ = timezone_name_from_abbr($TZ)))
                 // Abbreviation doesn't point to anything valid
                 return false;
+        }
 
         // SYSTEM does not describe a time zone, ensure we have a valid zone
         // by attempting to create an instance of DateTimeZone()
diff --git a/include/class.validator.php b/include/class.validator.php
index 2cce38f21432dc457efbae59bd4277bec9d213d3..14be7ccaf005423bf34c395aa375c04227e9671e 100644
--- a/include/class.validator.php
+++ b/include/class.validator.php
@@ -185,23 +185,7 @@ class Validator {
     }
 
     static function is_ip($ip) {
-
-        if(!$ip or empty($ip))
-            return false;
-
-        $ip=trim($ip);
-        # Thanks to http://stackoverflow.com/a/1934546
-        if (function_exists('inet_pton')) { # PHP 5.1.0
-            # Let the built-in library parse the IP address
-            return @inet_pton($ip) !== false;
-        } else if (preg_match(
-            '/^(?>(?>([a-f0-9]{1,4})(?>:(?1)){7}|(?!(?:.*[a-f0-9](?>:|$)){7,})'
-            .'((?1)(?>:(?1)){0,5})?::(?2)?)|(?>(?>(?1)(?>:(?1)){5}:|(?!(?:.*[a-f0-9]:){5,})'
-            .'(?3)?::(?>((?1)(?>:(?1)){0,3}):)?)?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])'
-            .'(?>\.(?4)){3}))$/iD', $ip)) {
-            return true;
-        }
-        return false;
+        return filter_var(trim($ip), FILTER_VALIDATE_IP) !== false;
     }
 
     static function is_username($username, &$error='') {
@@ -212,6 +196,100 @@ class Validator {
         return $error == '';
     }
 
+
+    /*
+     * check_ip
+     * Checks if an IP (IPv4 or IPv6) address is contained in the list of given IPs or subnets.
+     *
+     * @credit - borrowed from Symfony project
+     *
+     */
+    public static function check_ip($ip, $ips) {
+
+        if (!Validator::is_ip($ip))
+            return false;
+
+        $method = substr_count($ip, ':') > 1 ? 'check_ipv6' : 'check_ipv4';
+        $ips = is_array($ips) ? $ips : array($ips);
+        foreach ($ips as $_ip) {
+            if (self::$method($ip, $_ip)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * check_ipv4
+     * Compares two IPv4 addresses.
+     * In case a subnet is given, it checks if it contains the request IP.
+     *
+     * @credit - borrowed from Symfony project
+     */
+    public static function check_ipv4($ip, $cidr) {
+
+        if (false !== strpos($cidr, '/')) {
+            list($address, $netmask) = explode('/', $cidr, 2);
+
+            if ($netmask === '0')
+                return filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
+
+            if ($netmask < 0 || $netmask > 32)
+                return false;
+
+        } else {
+            $address = $cidr;
+            $netmask = 32;
+        }
+
+        return 0 === substr_compare(
+                sprintf('%032b', ip2long($ip)),
+                sprintf('%032b', ip2long($address)),
+                0, $netmask);
+    }
+
+    /**
+     * Compares two IPv6 addresses.
+     * In case a subnet is given, it checks if it contains the request IP.
+     *
+     * @credit - borrowed from Symfony project
+     * @author David Soria Parra <dsp at php dot net>
+     *
+     * @see https://github.com/dsp/v6tools
+     *
+     */
+    public static function check_ipv6($ip, $cidr) {
+
+        if (!((extension_loaded('sockets') && defined('AF_INET6')) || @inet_pton('::1')))
+            return false;
+
+        if (false !== strpos($cidr, '/')) {
+            list($address, $netmask) = explode('/', $cidr, 2);
+            if ($netmask < 1 || $netmask > 128)
+                return false;
+        } else {
+            $address = $cidr;
+            $netmask = 128;
+        }
+
+        $bytesAddr = unpack('n*', @inet_pton($address));
+        $bytesTest = unpack('n*', @inet_pton($ip));
+        if (!$bytesAddr || !$bytesTest)
+            return false;
+
+        for ($i = 1, $ceil = ceil($netmask / 16); $i <= $ceil; ++$i) {
+            $left = $netmask - 16 * ($i - 1);
+            $left = ($left <= 16) ? $left : 16;
+            $mask = ~(0xffff >> $left) & 0xffff;
+            if (($bytesAddr[$i] & $mask) != ($bytesTest[$i] & $mask)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
     function process($fields,$vars,&$errors){
 
         $val = new Validator();
diff --git a/include/client/header.inc.php b/include/client/header.inc.php
index 42b7b6c781fbd55834b77da9872ad1a4aebfe977..2e93d012db87de7f2fa984e12b6110dcef13be4b 100644
--- a/include/client/header.inc.php
+++ b/include/client/header.inc.php
@@ -28,7 +28,7 @@ if ($lang) {
     <title><?php echo Format::htmlchars($title); ?></title>
     <meta name="description" content="customer support platform">
     <meta name="keywords" content="osTicket, Customer support system, support ticket system">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
 	<link rel="stylesheet" href="<?php echo ROOT_PATH; ?>css/osticket.css" media="screen">
     <link rel="stylesheet" href="<?php echo ASSETS_PATH; ?>css/theme.css" media="screen">
     <link rel="stylesheet" href="<?php echo ASSETS_PATH; ?>css/print.css" media="print">
diff --git a/include/client/kb-categories.inc.php b/include/client/kb-categories.inc.php
index 236847fb6dbf75439b83d8e08932df4d767e8997..c4df171c59d466adc540111ee315b4a559499ad6 100644
--- a/include/client/kb-categories.inc.php
+++ b/include/client/kb-categories.inc.php
@@ -45,7 +45,7 @@
         <input type="hidden" name="a" value="search"/>
         <select name="topicId"  style="width:100%;max-width:100%"
             onchange="javascript:this.form.submit();">
-            <option value="">— Browse by Topic —</option>
+            <option value="">—<?php echo __("Browse by Topic"); ?>—</option>
 <?php
 $topics = Topic::objects()
     ->annotate(array('has_faqs'=>SqlAggregate::COUNT('faqs')))
diff --git a/include/client/tickets.inc.php b/include/client/tickets.inc.php
index f37874b55a8916081c924599130f64c863d36f37..6840c252b0715c9b9ad5a5e4df52d1db5e7cc47b 100644
--- a/include/client/tickets.inc.php
+++ b/include/client/tickets.inc.php
@@ -47,8 +47,10 @@ if($sort && $sortOptions[$sort])
     $order_by =$sortOptions[$sort];
 
 $order_by=$order_by ?: $sortOptions['date'];
-if($_REQUEST['order'] && $orderWays[strtoupper($_REQUEST['order'])])
-    $order=$orderWays[strtoupper($_REQUEST['order'])];
+if ($_REQUEST['order'] && $orderWays[strtoupper($_REQUEST['order'])])
+    $order = $orderWays[strtoupper($_REQUEST['order'])];
+else
+    $order = $orderWays['DESC'];
 
 $x=$sort.'_sort';
 $$x=' class="'.strtolower($_REQUEST['order'] ?: 'desc').'" ';
@@ -103,7 +105,7 @@ $tickets->distinct('ticket_id');
 
 TicketForm::ensureDynamicDataView();
 
-$total=$tickets->count();
+$total=$visibility->count();
 $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
 $pageNav=new Pagenate($total, $page, PAGE_LIMIT);
 $qstr = '&amp;'. Http::build_query($qs);
@@ -123,6 +125,7 @@ if($search)
 
 $negorder=$order=='-'?'ASC':'DESC'; //Negate the sorting
 
+$tickets->order_by($order.$order_by);
 $tickets->values(
     'ticket_id', 'number', 'created', 'isanswered', 'source', 'status_id',
     'status__state', 'status__name', 'cdata__subject', 'dept_id',
@@ -241,12 +244,12 @@ if ($closedTickets) {?>
                 <a class="Icon <?php echo strtolower($T['source']); ?>Ticket" title="<?php echo $T['user__default_email__address']; ?>"
                     href="tickets.php?id=<?php echo $T['ticket_id']; ?>"><?php echo $ticketNumber; ?></a>
                 </td>
-                <td>&nbsp;<?php echo Format::date($T['created']); ?></td>
-                <td>&nbsp;<?php echo $status; ?></td>
+                <td><?php echo Format::date($T['created']); ?></td>
+                <td><?php echo $status; ?></td>
                 <td>
                     <div style="max-height: 1.2em; max-width: 320px;" class="link truncate" href="tickets.php?id=<?php echo $T['ticket_id']; ?>"><?php echo $subject; ?></div>
                 </td>
-                <td>&nbsp;<span class="truncate"><?php echo $dept; ?></span></td>
+                <td><span class="truncate"><?php echo $dept; ?></span></td>
             </tr>
         <?php
         }
diff --git a/include/html2text.php b/include/html2text.php
index 0fcaa5cab999744bac97d90e0c8092b476bfbe4c..e7ddedeaf4afb33f5e6c5166cdf0f433d0924bfb 100644
--- a/include/html2text.php
+++ b/include/html2text.php
@@ -1014,7 +1014,7 @@ function mb_wordwrap($string, $width=75, $break="\n", $cut=false) {
   } else {
     // Anchor the beginning of the pattern with a lookahead
     // to avoid crazy backtracking when words are longer than $width
-    $pattern = '/(?=[\s\p{Ps}])(.{1,'.$width.'})(?:\s|$|(\p{Ps}))/uS';
+    $search = '/(?=[\s\p{Ps}])(.{1,'.$width.'})(?:\s|$|(\p{Ps}))/uS';
     $replace = '$1'.$break.'$2';
   }
   return rtrim(preg_replace($search, $replace, $string), $break);
diff --git a/include/ost-sampleconfig.php b/include/ost-sampleconfig.php
index 0b26400698271c1d89ab46f55a209d501b5b1dae..b4a5049f4d01b5a9596c0142211f41bd19e73cbd 100644
--- a/include/ost-sampleconfig.php
+++ b/include/ost-sampleconfig.php
@@ -107,6 +107,39 @@ define('TABLE_PREFIX','%CONFIG-PREFIX');
 
 # define('ROOT_PATH', '/support/');
 
+
+# Option: TRUSTED_PROXIES (default: <none>)
+#
+# To support running osTicket installation on a web servers that sit behind a
+# load balancer, HTTP cache, or other intermediary (reverse) proxy; it's
+# necessary to define trusted proxies to protect against forged http headers
+#
+# osTicket supports passing the following http headers from a trusted proxy;
+# - HTTP_X_FORWARDED_FOR    =>  Chain of client's IPs
+# - HTTP_X_FORWARDED_PROTO  =>  Client's HTTP protocal (http | https)
+#
+# You'll have to explicitly define comma separated IP addreseses or CIDR of
+# upstream proxies to trust. Wildcard "*" (not recommended) can be used to
+# trust all chained IPs as proxies in cases that ISP/host doesn't provide
+# IPs of loadbalancers or proxies.
+#
+# References:
+# http://en.wikipedia.org/wiki/X-Forwarded-For
+#
+
+define('TRUSTED_PROXIES', '');
+
+
+# Option: LOCAL_NETWORKS (default: 127.0.0.0/24)
+#
+# When running osTicket as part of a cluster it might become necessary to
+# whitelist local/virtual networks that can bypass some authentication/checks.
+#
+# define comma separated IP addreseses or enter CIDR of local network.
+
+define('LOCAL_NETWORKS', '127.0.0.0/24');
+
+
 #
 # Session Storage Options
 # ---------------------------------------------------
diff --git a/include/pear/Net/SMTP.php b/include/pear/Net/SMTP.php
index 8f4e92b7532a0c51f97219017a246574d3d17d8c..530f558c9c39e0fca73fa98a431eeb5bd3cbd9fd 100644
--- a/include/pear/Net/SMTP.php
+++ b/include/pear/Net/SMTP.php
@@ -166,6 +166,13 @@ class Net_SMTP
 
         $this->pipelining      = $pipelining;
         $this->socket         = new Net_Socket();
+
+        // Turn off peer name verification by default
+        if (!$socket_options)
+            $socket_options = array(
+                    'ssl' => array('verify_peer_name' => false)
+                    );
+
         $this->socket_options = $socket_options;
         $this->timeout        = $timeout;
 
diff --git a/include/staff/apikey.inc.php b/include/staff/apikey.inc.php
index c3b41fb0c41d14abc18ccb196666f7066fbe9128..c7da2e8e9e6550e85591122933964cd019e9e217 100644
--- a/include/staff/apikey.inc.php
+++ b/include/staff/apikey.inc.php
@@ -17,7 +17,7 @@ if($api && $_REQUEST['a']!='add'){
 }
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
-<form action="apikeys.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
+<form action="apikeys.php?<?php echo Http::build_query($qs); ?>" method="post" class="save">
  <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
diff --git a/include/staff/banrule.inc.php b/include/staff/banrule.inc.php
index 6b4b5cea101f0fe457eb04f2c4dbfb7909630f45..ad8c69b81f8952b2451522ffeb929184188b91f4 100644
--- a/include/staff/banrule.inc.php
+++ b/include/staff/banrule.inc.php
@@ -19,7 +19,7 @@ if($rule && $_REQUEST['a']!='add'){
 
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
-<form action="banlist.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
+<form action="banlist.php?<?php echo Http::build_query($qs); ?>" method="post" class="save">
  <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
diff --git a/include/staff/cannedresponse.inc.php b/include/staff/cannedresponse.inc.php
index 0dabac6fd3319fd5dca169521e47da16f7693bb6..20818d994242254f10fe2c85e5747742e9a944ef 100644
--- a/include/staff/cannedresponse.inc.php
+++ b/include/staff/cannedresponse.inc.php
@@ -21,7 +21,7 @@ if($canned && $_REQUEST['a']!='add'){
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 
 ?>
-<form action="canned.php?<?php echo Http::build_query($qs); ?>" method="post" id="save" enctype="multipart/form-data">
+<form action="canned.php?<?php echo Http::build_query($qs); ?>" method="post" class="save" enctype="multipart/form-data">
  <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
diff --git a/include/staff/category.inc.php b/include/staff/category.inc.php
index 5ac65cc2131e550dd05bf61f60e602c7fd981829..4eac204218ad029b49f49945442b41401c20582a 100644
--- a/include/staff/category.inc.php
+++ b/include/staff/category.inc.php
@@ -36,7 +36,7 @@ if($category && $_REQUEST['a']!='add'){
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 
 ?>
-<form action="categories.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
+<form action="categories.php?<?php echo Http::build_query($qs); ?>" method="post" class="save">
  <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
@@ -51,9 +51,9 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
     <div style="margin:8px 0"><strong><?php echo __('Category Type');?>:</strong>
         <span class="error">*</span></div>
     <div style="margin-left:5px">
-    <input type="radio" name="ispublic" value="2" <?php echo $info['ispublic']?'checked="checked"':''; ?>><b><?php echo __('Featured');?></b> <?php echo __('(on front-page sidebar)');?>
+    <input type="radio" name="ispublic" value="2" <?php echo $info['ispublic']==2?'checked="checked"':''; ?>><b><?php echo __('Featured');?></b> <?php echo __('(on front-page sidebar)');?>
     <br/>
-    <input type="radio" name="ispublic" value="1" <?php echo $info['ispublic']?'checked="checked"':''; ?>><b><?php echo __('Public');?></b> <?php echo __('(publish)');?>
+    <input type="radio" name="ispublic" value="1" <?php echo $info['ispublic']==1?'checked="checked"':''; ?>><b><?php echo __('Public');?></b> <?php echo __('(publish)');?>
     <br/>
     <input type="radio" name="ispublic" value="0" <?php echo !$info['ispublic']?'checked="checked"':''; ?>><?php echo __('Private');?> <?php echo __('(internal)');?>
     <br/>
diff --git a/include/staff/department.inc.php b/include/staff/department.inc.php
index 1d32543973633c1817bbe1a0e141c82259c74ae1..2ea8825e35c787bdcba95078a23e50f8e46f1192 100644
--- a/include/staff/department.inc.php
+++ b/include/staff/department.inc.php
@@ -26,7 +26,7 @@ if($dept && $_REQUEST['a']!='add') {
 
 $info = Format::htmlchars(($errors && $_POST) ? $_POST : $info);
 ?>
-<form action="departments.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
+<form action="departments.php?<?php echo Http::build_query($qs); ?>" method="post" class="save">
  <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
diff --git a/include/staff/dynamic-form.inc.php b/include/staff/dynamic-form.inc.php
index 775e058792ccb28790e1b21b55ba479734879105..563766f0217135f464217569034e115cd650432d 100644
--- a/include/staff/dynamic-form.inc.php
+++ b/include/staff/dynamic-form.inc.php
@@ -31,7 +31,7 @@ if($form && $_REQUEST['a']!='add') {
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 
 ?>
-<form class="manage-form" action="<?php echo $url ?>" method="post" id="save">
+<form class="manage-form" action="<?php echo $url ?>" method="post" class="save">
     <?php csrf_token(); ?>
     <input type="hidden" name="do" value="<?php echo $action; ?>">
     <input type="hidden" name="a" value="<?php echo $action; ?>">
diff --git a/include/staff/dynamic-list.inc.php b/include/staff/dynamic-list.inc.php
index a71079656404d42f7b509b72adfaf38c09c7dd2d..8fb39d2cf4333d88ca3a7e65452ba862c29e079d 100644
--- a/include/staff/dynamic-list.inc.php
+++ b/include/staff/dynamic-list.inc.php
@@ -19,7 +19,7 @@ if ($list) {
 $info=Format::htmlchars(($errors && $_POST) ? array_merge($info,$_POST) : $info);
 
 ?>
-<form action="" method="post" id="save">
+<form action="" method="post" class="save">
     <?php csrf_token(); ?>
     <input type="hidden" name="do" value="<?php echo $action; ?>">
     <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
@@ -257,7 +257,7 @@ $(function() {
     $('#items').on('click', 'a.items-action', function(e) {
         e.preventDefault();
         var ids = [];
-        $('form#save :checkbox.mass:checked').each(function() {
+        $('form.save :checkbox.mass:checked').each(function() {
             ids.push($(this).val());
         });
         if (ids.length && confirm(__('You sure?'))) {
diff --git a/include/staff/email.inc.php b/include/staff/email.inc.php
index 953da7f55ccbdc324d09f5f2f08fd56b4dd2b462..3653f06a7949bacc7d92d1b32a911c075abe07c0 100644
--- a/include/staff/email.inc.php
+++ b/include/staff/email.inc.php
@@ -39,7 +39,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
     — <?php echo $info['email']; ?></small>
     <?php } ?>
 </h2>
-<form action="emails.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
+<form action="emails.php?<?php echo Http::build_query($qs); ?>" method="post" class="save">
  <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
diff --git a/include/staff/faq-categories.inc.php b/include/staff/faq-categories.inc.php
index e90f06cd88017ce603f952c76eebf535c561ff6c..4c484822751eeb0a6b8e3f5ad8ce59562ad523b6 100644
--- a/include/staff/faq-categories.inc.php
+++ b/include/staff/faq-categories.inc.php
@@ -140,8 +140,7 @@ if($_REQUEST['q'] || $_REQUEST['cid'] || $_REQUEST['topicId']) { //Search.
     }
 } else { //Category Listing.
     $categories = Category::objects()
-        ->annotate(array('faq_count'=>SqlAggregate::COUNT('faqs')))
-        ->all();
+        ->annotate(array('faq_count'=>SqlAggregate::COUNT('faqs')));
 
     if (count($categories)) {
         $categories->sort(function($a) { return $a->getLocalName(); });
diff --git a/include/staff/faq.inc.php b/include/staff/faq.inc.php
index d75958fdadd7dd97b4eed2fdd0c5d613fa5f8155..4579deb8d34ca38484835ec6bb33d178721ddbda 100644
--- a/include/staff/faq.inc.php
+++ b/include/staff/faq.inc.php
@@ -41,7 +41,7 @@ if($faq){
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 $qstr = Http::build_query($qs);
 ?>
-<form action="faq.php?<?php echo $qstr; ?>" method="post" id="save" enctype="multipart/form-data">
+<form action="faq.php?<?php echo $qstr; ?>" method="post" class="save" enctype="multipart/form-data">
  <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
diff --git a/include/staff/filter.inc.php b/include/staff/filter.inc.php
index 4175f2b3b2ff35df8fcefc5b9d243996454a476e..2330fc47dc4ebeece8aa04e8365c71bb30bfb186 100644
--- a/include/staff/filter.inc.php
+++ b/include/staff/filter.inc.php
@@ -23,7 +23,7 @@ if($filter && $_REQUEST['a']!='add'){
 }
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
-<form action="filters.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
+<form action="filters.php?<?php echo Http::build_query($qs); ?>" method="post" class="save">
     <?php csrf_token(); ?>
     <input type="hidden" name="do" value="<?php echo $action; ?>">
     <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
diff --git a/include/staff/header.inc.php b/include/staff/header.inc.php
index 13a122c54df8a1fb40a03435e431b068d9fd05bd..b89c16ab49c93c57bfa790a1d2153cf1a77b2e6b 100644
--- a/include/staff/header.inc.php
+++ b/include/staff/header.inc.php
@@ -1,5 +1,9 @@
 <?php
 header("Content-Type: text/html; charset=UTF-8");
+
+$title = ($ost && ($title=$ost->getPageTitle()))
+    ? $title : ('osTicket :: '.__('Staff Control Panel'));
+
 if (!isset($_SERVER['HTTP_X_PJAX'])) { ?>
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
 <html<?php
@@ -17,7 +21,7 @@ if ($lang) {
     <meta http-equiv="cache-control" content="no-cache" />
     <meta http-equiv="pragma" content="no-cache" />
     <meta http-equiv="x-pjax-version" content="<?php echo GIT_VERSION; ?>">
-    <title><?php echo ($ost && ($title=$ost->getPageTitle()))?$title:'osTicket :: '.__('Staff Control Panel'); ?></title>
+    <title><?php echo Format::htmlchars($title); ?></title>
     <!--[if IE]>
     <style type="text/css">
         .tip_shadow { display:block !important; }
diff --git a/include/staff/helptopic.inc.php b/include/staff/helptopic.inc.php
index a5a2c31805f760bbeae7aacc0340b9bb8984ec7c..8cb90850d546d9080495833ea95de0d1f5376f1a 100644
--- a/include/staff/helptopic.inc.php
+++ b/include/staff/helptopic.inc.php
@@ -35,7 +35,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
     <li><a href="#forms"><i class="icon-paste"></i> <?php echo __('Forms'); ?></a></li>
 </ul>
 
-<form action="helptopics.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
+<form action="helptopics.php?<?php echo Http::build_query($qs); ?>" method="post" class="save">
  <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
diff --git a/include/staff/helptopics.inc.php b/include/staff/helptopics.inc.php
index d356542c4a0d1f1165f76cab2a29e0ae31c955ab..0b5c58580c22ffdb3c7774db0ac170a904accf57 100644
--- a/include/staff/helptopics.inc.php
+++ b/include/staff/helptopics.inc.php
@@ -147,7 +147,7 @@ $order_by = 'sort';
                 <td><?php echo $priority; ?></td>
                 <td><a href="departments.php?id=<?php echo $deptId;
                 ?>"><?php echo $dept; ?></a></td>
-                <td>&nbsp;<?php echo Format::datetime($team->updated); ?></td>
+                <td>&nbsp;<?php echo Format::datetime($topic->updated); ?></td>
             </tr>
             <?php
             } //end of foreach.
diff --git a/include/staff/login.header.php b/include/staff/login.header.php
index d4068027840b811e2641f4870e6cd3927603e4f9..4460229c1acb8c2814128e343c9d0e861048abcc 100644
--- a/include/staff/login.header.php
+++ b/include/staff/login.header.php
@@ -12,7 +12,7 @@ defined('OSTSCPINC') or die('Invalid path');
     <meta name="robots" content="noindex" />
     <meta http-equiv="cache-control" content="no-cache" />
     <meta http-equiv="pragma" content="no-cache" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
     <script type="text/javascript" src="<?php echo ROOT_PATH; ?>js/jquery-1.11.2.min.js"></script>
     <script type="text/javascript">
         $(document).ready(function() {
diff --git a/include/staff/page.inc.php b/include/staff/page.inc.php
index 97cb838e50a13c9739e1c020aced734c17ecd4ef..6ecd1e44397f4296a9994e2ce2acf503b278a94e 100644
--- a/include/staff/page.inc.php
+++ b/include/staff/page.inc.php
@@ -37,7 +37,7 @@ if($page && $_REQUEST['a']!='add'){
 }
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
-<form action="pages.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
+<form action="pages.php?<?php echo Http::build_query($qs); ?>" method="post" class="save">
  <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
diff --git a/include/staff/plugin.inc.php b/include/staff/plugin.inc.php
index 6ab5b3c284d7c1eedf88a477a17cc931c9f05a70..5f9c35416f9e4eed86bcb1ae36b44517d3ddff60 100644
--- a/include/staff/plugin.inc.php
+++ b/include/staff/plugin.inc.php
@@ -18,7 +18,7 @@ if($plugin && $_REQUEST['a']!='add') {
 $info = Format::htmlchars(($errors && $_POST) ? $_POST : $info);
 ?>
 
-<form action="?<?php echo Http::build_query(array('id' => $_REQUEST['id'])); ?>" method="post" id="save">
+<form action="?<?php echo Http::build_query(array('id' => $_REQUEST['id'])); ?>" method="post" class="save">
     <?php csrf_token(); ?>
     <input type="hidden" name="do" value="<?php echo $action; ?>">
     <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
diff --git a/include/staff/profile.inc.php b/include/staff/profile.inc.php
index 5383a8c9893c1c9a62a79b489f964e6796c58ebd..627842f6942e7d11339107507d45203bc84f4535 100644
--- a/include/staff/profile.inc.php
+++ b/include/staff/profile.inc.php
@@ -2,7 +2,7 @@
 if(!defined('OSTSTAFFINC') || !$staff || !$thisstaff) die('Access Denied');
 ?>
 
-<form action="profile.php" method="post" id="save" autocomplete="off">
+<form action="profile.php" method="post" class="save" autocomplete="off">
  <?php csrf_token(); ?>
  <input type="hidden" name="do" value="update">
  <input type="hidden" name="id" value="<?php echo $staff->getId(); ?>">
diff --git a/include/staff/role.inc.php b/include/staff/role.inc.php
index 9d82a8a318275582b0d1cf281c7ecd47242321a6..5f05c6d7943e09bc72804834ecaab312d40050e6 100644
--- a/include/staff/role.inc.php
+++ b/include/staff/role.inc.php
@@ -18,7 +18,7 @@ if ($role) {
 $info = Format::htmlchars(($errors && $_POST) ? array_merge($info, $_POST) : $info);
 
 ?>
-<form action="" method="post" id="save">
+<form action="" method="post" class="save">
     <?php csrf_token(); ?>
     <input type="hidden" name="do" value="<?php echo $action; ?>">
     <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
diff --git a/include/staff/settings-agents.inc.php b/include/staff/settings-agents.inc.php
index 2a06676f0bc6d82355ebaa84a78ea42067933085..310a6fbfcbbdd0c53e67d6a71c6ebd7edb2e1eaf 100644
--- a/include/staff/settings-agents.inc.php
+++ b/include/staff/settings-agents.inc.php
@@ -3,7 +3,7 @@ if (!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin() || !$config
 
 ?>
 <h2><?php echo __('Agents Settings'); ?></h2>
-<form action="settings.php?t=agents" method="post" id="save">
+<form action="settings.php?t=agents" method="post" class="save">
     <?php csrf_token(); ?>
     <input type="hidden" name="t" value="agents" >
     <ul class="tabs" id="agents-tabs">
diff --git a/include/staff/settings-emails.inc.php b/include/staff/settings-emails.inc.php
index eddfb56a3340d923c50bd883fcfe2f39b399504e..aece5823459b9ecf0aeb3bd2b8c565d04619fe4f 100644
--- a/include/staff/settings-emails.inc.php
+++ b/include/staff/settings-emails.inc.php
@@ -2,7 +2,7 @@
 if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin() || !$config) die('Access Denied');
 ?>
 <h2><?php echo __('Email Settings and Options');?></h2>
-<form action="emailsettings.php" method="post" id="save">
+<form action="emailsettings.php" method="post" class="save">
 <?php csrf_token(); ?>
 <input type="hidden" name="t" value="emails" >
 <table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2">
diff --git a/include/staff/settings-kb.inc.php b/include/staff/settings-kb.inc.php
index 2f7fa6762f54a60089e27ffc0c1f5d6d9d08b49d..0fe2de9d274348fe0d59890d703eead332663428 100644
--- a/include/staff/settings-kb.inc.php
+++ b/include/staff/settings-kb.inc.php
@@ -2,7 +2,7 @@
 if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin() || !$config) die('Access Denied');
 ?>
 <h2><?php echo __('Knowledge Base Settings and Options');?></h2>
-<form action="settings.php?t=kb" method="post" id="save">
+<form action="settings.php?t=kb" method="post" class="save">
 <?php csrf_token(); ?>
 <input type="hidden" name="t" value="kb" >
 <table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2">
diff --git a/include/staff/settings-pages.inc.php b/include/staff/settings-pages.inc.php
index f3702000368d23ea8cc8ef02201641aaa8029326..e7f37590e2edd2895474bb4b2d2f94f7c35ad2bd 100644
--- a/include/staff/settings-pages.inc.php
+++ b/include/staff/settings-pages.inc.php
@@ -3,7 +3,7 @@ if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin() || !$config)
 $pages = Page::getPages();
 ?>
 <h2><?php echo __('Company Profile'); ?></h2>
-<form action="settings.php?t=pages" method="post" id="save"
+<form action="settings.php?t=pages" method="post" class="save"
     enctype="multipart/form-data">
 <?php csrf_token(); ?>
 
diff --git a/include/staff/settings-system.inc.php b/include/staff/settings-system.inc.php
index 6d03642201a509181a3d623691e88806298213ae..22502ed5e54dde3ae77d17c0c8aa15f4c7204b4b 100644
--- a/include/staff/settings-system.inc.php
+++ b/include/staff/settings-system.inc.php
@@ -4,7 +4,7 @@ if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin() || !$config)
 $gmtime = Misc::gmtime();
 ?>
 <h2><?php echo __('System Settings and Preferences');?> <small>— <span class="ltr">osTicket (<?php echo $cfg->getVersion(); ?>)</span></small></h2>
-<form action="settings.php?t=system" method="post" id="save">
+<form action="settings.php?t=system" method="post" class="save">
 <?php csrf_token(); ?>
 <input type="hidden" name="t" value="system" >
 <table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2">
diff --git a/include/staff/settings-tasks.inc.php b/include/staff/settings-tasks.inc.php
index e06a96b5d1a984536c7263e93d38996132efe13d..d5a51f034161885ff7f29da5e7bf40bc908afd30 100644
--- a/include/staff/settings-tasks.inc.php
+++ b/include/staff/settings-tasks.inc.php
@@ -4,7 +4,7 @@ if(!($maxfileuploads=ini_get('max_file_uploads')))
     $maxfileuploads=DEFAULT_MAX_FILE_UPLOADS;
 ?>
 <h2><?php echo __('Task Settings and Options');?></h2>
-<form action="settings.php?t=tasks" method="post" id="save">
+<form action="settings.php?t=tasks" method="post" class="save">
 <?php csrf_token(); ?>
 <input type="hidden" name="t" value="tasks" >
 
diff --git a/include/staff/settings-tickets.inc.php b/include/staff/settings-tickets.inc.php
index 59570b4423a44d7f95f435177b84044b2b7ef4f3..8ec82503174c174509d51d3a923240dee7b4b1a2 100644
--- a/include/staff/settings-tickets.inc.php
+++ b/include/staff/settings-tickets.inc.php
@@ -4,7 +4,7 @@ if(!($maxfileuploads=ini_get('max_file_uploads')))
     $maxfileuploads=DEFAULT_MAX_FILE_UPLOADS;
 ?>
 <h2><?php echo __('Ticket Settings and Options');?></h2>
-<form action="settings.php?t=tickets" method="post" id="save">
+<form action="settings.php?t=tickets" method="post" class="save">
 <?php csrf_token(); ?>
 <input type="hidden" name="t" value="tickets" >
 
diff --git a/include/staff/settings-users.inc.php b/include/staff/settings-users.inc.php
index 4096ccbd921cc483729dc0534dad5be2787190a8..1ef385bf96ac456bdc8367995e454fee800168b4 100644
--- a/include/staff/settings-users.inc.php
+++ b/include/staff/settings-users.inc.php
@@ -3,7 +3,7 @@ if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin() || !$config)
 
 ?>
 <h2><?php echo __('Users Settings'); ?></h2>
-<form action="settings.php?t=users" method="post" id="save">
+<form action="settings.php?t=users" method="post" class="save">
 <?php csrf_token(); ?>
 <input type="hidden" name="t" value="users" >
 <ul class="tabs" id="users-tabs">
diff --git a/include/staff/slaplan.inc.php b/include/staff/slaplan.inc.php
index beba3be42ae2971bc44f7d4ce6f4502b362e1148..bc775ba57957b1e51a04c2fb5b000949d4785a04 100644
--- a/include/staff/slaplan.inc.php
+++ b/include/staff/slaplan.inc.php
@@ -20,7 +20,7 @@ if($sla && $_REQUEST['a']!='add'){
 }
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
-<form action="slas.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
+<form action="slas.php?<?php echo Http::build_query($qs); ?>" method="post" class="save">
  <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
diff --git a/include/staff/staff.inc.php b/include/staff/staff.inc.php
index c063948b75a68ed6e7ae6c9c4cac1adc8f1f410c..ff37fa8fc17671947468c6f1764bbf37930ee97b 100644
--- a/include/staff/staff.inc.php
+++ b/include/staff/staff.inc.php
@@ -35,7 +35,7 @@ else {
 }
 ?>
 
-<form action="staff.php?<?php echo Http::build_query($qs); ?>" method="post" id="save" autocomplete="off">
+<form action="staff.php?<?php echo Http::build_query($qs); ?>" method="post" class="save" autocomplete="off">
   <?php csrf_token(); ?>
   <input type="hidden" name="do" value="<?php echo $action; ?>">
   <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
@@ -518,6 +518,7 @@ $('#join_team').find('button').on('click', function() {
 
 <?php
 foreach ($staff->dept_access as $dept_access) {
+  if (!$dept_access->dept_id) continue;
   echo sprintf('addAccess(%d, %s, %d, %d, %s);', $dept_access->dept_id,
     JsonDataEncoder::encode($dept_access->dept->getName()),
     $dept_access->role_id,
diff --git a/include/staff/staffmembers.inc.php b/include/staff/staffmembers.inc.php
index 7ddba38eab8213491443aeccdf489eeb7b62ad88..97f7c1265249a845d5bfb49d3705e66638e44569 100644
--- a/include/staff/staffmembers.inc.php
+++ b/include/staff/staffmembers.inc.php
@@ -16,12 +16,6 @@ $sortOptions = array(
 $orderWays = array('DESC'=>'DESC', 'ASC'=>'ASC');
 $sort = ($_REQUEST['sort'] && $sortOptions[strtolower($_REQUEST['sort'])]) ? strtolower($_REQUEST['sort']) : 'name';
 
-if ($sort && $sortOptions[$sort]) {
-    $order_column = $sortOptions[$sort];
-}
-
-$order_column = $order_column ? $order_column : array('firstname', 'lastname');
-
 switch ($cfg->getAgentNameFormat()) {
 case 'last':
 case 'lastfirst':
@@ -31,6 +25,12 @@ case 'legal':
 // Otherwise leave unchanged
 }
 
+if ($sort && $sortOptions[$sort]) {
+    $order_column = $sortOptions[$sort];
+}
+
+$order_column = $order_column ?: array('firstname', 'lastname');
+
 if ($_REQUEST['order'] && isset($orderWays[strtoupper($_REQUEST['order'])])) {
     $order = $orderWays[strtoupper($_REQUEST['order'])];
 } else {
diff --git a/include/staff/syslogs.inc.php b/include/staff/syslogs.inc.php
index 0d3f05e216a6e898f93b2a1134f497a2746ee6cf..9d4d43df1dbd020a61be1defc16109591bff1db3 100644
--- a/include/staff/syslogs.inc.php
+++ b/include/staff/syslogs.inc.php
@@ -156,7 +156,7 @@ else
                 <td>&nbsp;<a class="tip" href="#log/<?php echo $row['log_id']; ?>"><?php echo Format::htmlchars($row['title']); ?></a></td>
                 <td><?php echo $row['log_type']; ?></td>
                 <td>&nbsp;<?php echo Format::daydatetime($row['created']); ?></td>
-                <td><?php echo $row['ip_address']; ?></td>
+                <td><?php echo Format::htmlchars($row['ip_address']); ?></td>
             </tr>
             <?php
             } //end of while.
diff --git a/include/staff/team.inc.php b/include/staff/team.inc.php
index 600ea6a5826062b2c31de4550d505747ca069c76..254d1559d6407d5e15d522185e2c62778ff567f4 100644
--- a/include/staff/team.inc.php
+++ b/include/staff/team.inc.php
@@ -23,7 +23,7 @@ if ($team && $_REQUEST['a']!='add') {
 
 $info = $team->getInfo();
 ?>
-<form action="teams.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
+<form action="teams.php?<?php echo Http::build_query($qs); ?>" method="post" class="save">
  <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
diff --git a/include/staff/template.inc.php b/include/staff/template.inc.php
index c8a91cace854b47634bf2563e481afcd22a46eec..0ff7ff3d9e95c0bfd59708e17dc2d4a274dc312e 100644
--- a/include/staff/template.inc.php
+++ b/include/staff/template.inc.php
@@ -19,7 +19,7 @@ if($template && $_REQUEST['a']!='add'){
 }
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
-<form action="templates.php?<?php echo Http::build_query($qs); ?>" method="post" id="save">
+<form action="templates.php?<?php echo Http::build_query($qs); ?>" method="post" class="save">
  <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
diff --git a/include/staff/templates/task-view.tmpl.php b/include/staff/templates/task-view.tmpl.php
index e2e26b7cc52c814c2e8f213c61d3a3df4183adc3..b2dff125312309c5493da4ec93d4edac0edd78ce 100644
--- a/include/staff/templates/task-view.tmpl.php
+++ b/include/staff/templates/task-view.tmpl.php
@@ -469,7 +469,7 @@ else
     </ul>
     <?php
     if ($role->hasPerm(TaskModel::PERM_REPLY)) { ?>
-    <form id="task_reply" class="tab_content spellcheck"
+    <form id="task_reply" class="tab_content spellcheck save"
         action="<?php echo $action; ?>"
         name="task_reply" method="post" enctype="multipart/form-data">
         <?php csrf_token(); ?>
@@ -559,7 +559,7 @@ else
     } ?>
     <form id="task_note"
         action="<?php echo $action; ?>"
-        class="tab_content spellcheck <?php
+        class="tab_content spellcheck save <?php
             echo $role->hasPerm(TaskModel::PERM_REPLY) ? 'hidden' : ''; ?>"
         name="task_note"
         method="post" enctype="multipart/form-data">
diff --git a/include/staff/ticket-edit.inc.php b/include/staff/ticket-edit.inc.php
index 37697ea8c5059688306ceef2b077df57e1f1bf13..e15e8554d3d67afeea3ed47de83429638524dfbd 100644
--- a/include/staff/ticket-edit.inc.php
+++ b/include/staff/ticket-edit.inc.php
@@ -10,7 +10,7 @@ if ($_POST)
     // timezone)
     $info['duedate'] = Format::date(strtotime($info['duedate']), false, false, 'UTC');
 ?>
-<form action="tickets.php?id=<?php echo $ticket->getId(); ?>&a=edit" method="post" id="save"  enctype="multipart/form-data">
+<form action="tickets.php?id=<?php echo $ticket->getId(); ?>&a=edit" method="post" class="save"  enctype="multipart/form-data">
     <?php csrf_token(); ?>
     <input type="hidden" name="do" value="update">
     <input type="hidden" name="a" value="edit">
diff --git a/include/staff/ticket-open.inc.php b/include/staff/ticket-open.inc.php
index 5319cb1afee69d3bad59fcf55e92b6b1385f86fa..6d383e580aa55714518ab59a7e6707f9b1402940 100644
--- a/include/staff/ticket-open.inc.php
+++ b/include/staff/ticket-open.inc.php
@@ -25,7 +25,7 @@ if ($info['topicId'] && ($topic=Topic::lookup($info['topicId']))) {
 if ($_POST)
     $info['duedate'] = Format::date(strtotime($info['duedate']), false, false, 'UTC');
 ?>
-<form action="tickets.php?a=open" method="post" id="save"  enctype="multipart/form-data">
+<form action="tickets.php?a=open" method="post" class="save"  enctype="multipart/form-data">
  <?php csrf_token(); ?>
  <input type="hidden" name="do" value="create">
  <input type="hidden" name="a" value="open">
diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php
index 43097ab357e17b35f6a75b561a6a1d348739d804..ba3e0a468006f2caf6c66c1520212ae57d36ec6d 100644
--- a/include/staff/ticket-view.inc.php
+++ b/include/staff/ticket-view.inc.php
@@ -356,7 +356,7 @@ if($ticket->isOverdue())
                         echo Format::htmlchars($ticket->getSource());
 
                         if (!strcasecmp($ticket->getSource(), 'Web') && $ticket->getIP())
-                            echo '&nbsp;&nbsp; <span class="faded">('.$ticket->getIP().')</span>';
+                            echo '&nbsp;&nbsp; <span class="faded">('.Format::htmlchars($ticket->getIP()).')</span>';
                         ?>
                     </td>
                 </tr>
@@ -537,7 +537,7 @@ if ($errors['err'] && isset($_POST['a'])) {
     </ul>
     <?php
     if ($role->hasPerm(TicketModel::PERM_REPLY)) { ?>
-    <form id="reply" class="tab_content spellcheck exclusive"
+    <form id="reply" class="tab_content spellcheck exclusive save"
         data-lock-object-id="ticket/<?php echo $ticket->getId(); ?>"
         data-lock-id="<?php echo $mylock ? $mylock->getId() : ''; ?>"
         action="tickets.php?id=<?php
@@ -734,7 +734,7 @@ if ($errors['err'] && isset($_POST['a'])) {
     </form>
     <?php
     } ?>
-    <form id="note" class="hidden tab_content spellcheck exclusive"
+    <form id="note" class="hidden tab_content spellcheck exclusive save"
         data-lock-object-id="ticket/<?php echo $ticket->getId(); ?>"
         data-lock-id="<?php echo $mylock ? $mylock->getId() : ''; ?>"
         action="tickets.php?id=<?php echo $ticket->getId(); ?>#note"
diff --git a/include/staff/tpl.inc.php b/include/staff/tpl.inc.php
index 10fc3e70bb5ae13933389891cceab34a52173f39..650591ec0828a2ca2f196eb5cb5954df7f3dde1c 100644
--- a/include/staff/tpl.inc.php
+++ b/include/staff/tpl.inc.php
@@ -76,7 +76,7 @@ $tpl=$msgtemplates[$selected];
     <input type="hidden" name="tpl_id" value="<?php echo $tpl_id; ?>">
 </form>
 <hr/>
-<form action="templates.php?id=<?php echo $id; ?>&amp;a=manage" method="post" id="save">
+<form action="templates.php?id=<?php echo $id; ?>&amp;a=manage" method="post" class="save">
 <?php csrf_token(); ?>
 <?php foreach ($extras as $k=>$v) { ?>
     <input type="hidden" name="<?php echo $k; ?>" value="<?php echo Format::htmlchars($v); ?>" />
diff --git a/include/upgrader/streams/core/8f99b8bf-03ff59bf.task.php b/include/upgrader/streams/core/8f99b8bf-03ff59bf.task.php
index cd41e131bdc7617503aa789d731e538ad0fb7db5..1e323d52fa15a984c2e4ba3749cd8a6e3d200b97 100644
--- a/include/upgrader/streams/core/8f99b8bf-03ff59bf.task.php
+++ b/include/upgrader/streams/core/8f99b8bf-03ff59bf.task.php
@@ -13,7 +13,7 @@ class SequenceLoader extends MigrationTask {
         $i18n = new Internationalization($cfg->get('system_language', 'en_US'));
         $sequences = $i18n->getTemplate('sequence.yaml')->getData();
         foreach ($sequences as $s) {
-            Sequence::create($s)->save();
+            Sequence::__create($s);
         }
         db_query('UPDATE '.SEQUENCE_TABLE.' SET `next`= '
             .'(SELECT MAX(ticket_id)+1 FROM '.TICKET_TABLE.') '
diff --git a/index.php b/index.php
index 6c9558fa930d71173e59645febce619cf38651af..68062b124c00df15c392dd9ae2c8ee3ac9a4c356 100644
--- a/index.php
+++ b/index.php
@@ -28,8 +28,8 @@ if ($cfg && $cfg->isKnowledgebaseEnabled()) { ?>
 <div class="search-form">
     <form method="get" action="kb/faq.php">
     <input type="hidden" name="a" value="search"/>
-    <input type="text" name="q" class="search" placeholder="Search our knowledge base"/>
-    <button type="submit" class="green button">Search</button>
+    <input type="text" name="q" class="search" placeholder="<?php echo __('Search our knowledge base'); ?>"/>
+    <button type="submit" class="green button"><?php echo __('Search'); ?></button>
     </form>
 </div>
     <div class="thread-body">
@@ -53,7 +53,7 @@ if($cfg && $cfg->isKnowledgebaseEnabled()){
 <?php
 $cats = Category::getFeatured();
 if ($cats->all()) { ?>
-<h1>Featured Knowledge Base Articles</h1>
+<h1><?php echo __('Featured Knowledge Base Articles'); ?></h1>
 <?php
 }
 
diff --git a/login.php b/login.php
index c84d06cd87e67bf2e1e01b884081002a094033d0..5c4a713124bc6b55175f48d9f2926e4676f631ec 100644
--- a/login.php
+++ b/login.php
@@ -86,7 +86,7 @@ elseif ($_POST && isset($_POST['lticket'])) {
             Http::redirect('tickets.php');
 
         // This will succeed as it is checked in the authentication backend
-        $ticket = Ticket::lookupByNumber($_POST['lticket']);
+        $ticket = Ticket::lookupByNumber($_POST['lticket'], $_POST['lemail']);
 
         // We're using authentication backend so we can guard aganist brute
         // force attempts (which doesn't buy much since the link is emailed)
diff --git a/main.inc.php b/main.inc.php
index 026e440ca84cc904d8a5ebcf8e6b5101cd81d41e..e92ec4a71d3e59876361fba0aa8446328b383779 100644
--- a/main.inc.php
+++ b/main.inc.php
@@ -27,6 +27,9 @@ Bootstrap::i18n_prep();
 Bootstrap::loadCode();
 Bootstrap::connect();
 
+#Global override
+$_SERVER['REMOTE_ADDR'] = osTicket::get_client_ip();
+
 if(!($ost=osTicket::start()) || !($cfg = $ost->getConfig()))
 Bootstrap::croak(__('Unable to load config info from DB. Get tech support.'));
 
diff --git a/scp/emailtest.php b/scp/emailtest.php
index 682749760bc3ce8264b52087a3538d2618c45148..ae8d68579d88768ee3034c856d89ace84c5b6283 100644
--- a/scp/emailtest.php
+++ b/scp/emailtest.php
@@ -55,7 +55,7 @@ require(STAFFINC_DIR.'header.inc.php');
 
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
-<form action="emailtest.php" method="post" id="save">
+<form action="emailtest.php" method="post" class="save">
  <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <h2><?php echo __('Test Outgoing Email');?></h2>
diff --git a/scp/js/scp.js b/scp/js/scp.js
index 3c04b4a9cb6e17d33fd1ea22841433c1c5aaabbc..ae2512f63f921854e78ec117e9061d2bfe5eaadf 100644
--- a/scp/js/scp.js
+++ b/scp/js/scp.js
@@ -146,11 +146,11 @@ var scp_prep = function() {
         }
     };
 
-    $("form#save").on('change', ':input[name], :button[name]', function() {
+    $("form.save").on('change', ':input[name], :button[name]', function() {
         if (!$(this).is('.nowarn')) warnOnLeave($(this));
     });
 
-    $("form#save").on('click', ':input[type=reset], :button[type=reset]', function() {
+    $("form.save").on('click', ':input[type=reset], :button[type=reset]', function() {
         var fObj = $(this).closest('form');
         if(fObj.data('changed')){
             $('input[type=submit], button[type=submit]', fObj).removeClass('save pending');
@@ -161,7 +161,7 @@ var scp_prep = function() {
         }
     });
 
-    $('form#save, form:has(table.list)').submit(function() {
+    $('form.save, form:has(table.list)').submit(function() {
         $(window).unbind('beforeunload');
         $('#overlay, #loading').show();
         return true;
diff --git a/scp/js/upgrader.js b/scp/js/upgrader.js
index a10c02626b92fcb6a87680bcabe9c699a627d9a6..831337926e0689f31f1389d7db96a968da89729b 100644
--- a/scp/js/upgrader.js
+++ b/scp/js/upgrader.js
@@ -27,6 +27,13 @@ jQuery(function($) {
       });
 
     function autoUpgrade(url, data) {
+
+        if (!$.isFunction('__')) {
+          function __(s) {
+                return s;
+          }
+        }
+
         function _lp(count) {
             $.ajax({
                 type: 'POST',
diff --git a/setup/doc/api/tickets.md b/setup/doc/api/tickets.md
index 8965e76109cafd1a0133ef6ab4ee3d3344eb5b57..a3ba24ef7d919e6ca1b553021556f40e4e0f2999 100644
--- a/setup/doc/api/tickets.md
+++ b/setup/doc/api/tickets.md
@@ -36,6 +36,7 @@ request content.
                      following fields (_please refer to the format-specific examples below_):
     *   __name__:     *required* name of the file to be attached. Multiple files
                       with the same name are allowable
+    *   __data__:     *required* contents of the file to be attached. 
     *   __type__:     Mime type of the file. Default is `text/plain`
     *   __encoding__: Set to `base64` if content is base64 encoded
 
diff --git a/setup/test/tests/test.validation.php b/setup/test/tests/test.validation.php
index bce9fe85505d08e41251fc127e230bba9f775394..0297d51d7d61535f82e27548af169aa7222bb46d 100644
--- a/setup/test/tests/test.validation.php
+++ b/setup/test/tests/test.validation.php
@@ -54,6 +54,19 @@ class TestValidation extends Test {
         #$this->assert(Validator::is_email('δοκιμή@παράδειγμα.δοκιμή'));
         #$this->assert(Validator::is_email('甲斐@黒川.日本'));
     }
+
+    function testIPAddresses() {
+
+        // Validate IP Addreses
+        $this->assert(Validator::is_ip('127.0.0.1'));
+        $this->assert(Validator::is_ip('192.168.129.74'));
+
+        // Test IP check
+        $this->assert(Validator::check_ip('127.0.0.1', '127.0.0.0/24'));
+        $this->assert(Validator::check_ip('192.168.129.42',
+                    ['127.0.0.0/24', '192.168.129.0/24']));
+        $this->assert(!Validator::check_ip('10.0.5.15', '127.0.0.0/24'));
+    }
 }
 return 'TestValidation';
 ?>