diff --git a/README.md b/README.md
index 4f820dba8f8cef3a1e01289b326d334b03753788..c6d45adbddc61bb032759f4662529faeb60452f9 100644
--- a/README.md
+++ b/README.md
@@ -51,6 +51,11 @@ osTicket-1.7, visit the /scp page of you ticketing system. The upgrader will
 be presented and will walk you through the rest of the process. (The couple
 clicks needed to go through the process are pretty boring to describe).
 
+**WARNING**: If you are upgrading from osTicket 1.6, please ensure that all
+    your files in your upload folder are both readable and writable to your
+    http server software. Unreadable files will not be migrated to the
+    database during the upgrade and will be effectively lost.
+
 View the UPGRADING.txt file for other todo items to complete your upgrade.
 
 Help
@@ -86,4 +91,5 @@ osTicket is supported by several magical open source projects including:
   * [PEAR/Net_Socket](http://pear.php.net/package/Net_Socket)
   * [PEAR/Serivces_JSON](http://pear.php.net/package/Services_JSON)
   * [phplint](http://antirez.com/page/phplint.html)
+  * [phpseclib](http://phpseclib.sourceforge.net/)
   * [Spyc](http://github.com/mustangostang/spyc)
diff --git a/WHATSNEW.md b/WHATSNEW.md
index 752e61fc94d82555e76d0ad61a7d3ea927871bca..507b1c521cec807155a19370ab14b518eb902b9c 100644
--- a/WHATSNEW.md
+++ b/WHATSNEW.md
@@ -1,3 +1,72 @@
+osTicket v1.7.1
+===============
+### Bugfixes
+  * Properly reject attachments submitted via the API (#668)
+  * Correctly support the "Use Reply-To" in ticket filters (#669)
+  * Don't log users out after changing username or email address (#684)
+  * Don't leak private FAQ article titles (#683)
+
+osTicket v1.7.1-rc1
+===================
+### Enhancements
+  * Custom logos and site pages (#604, #632, #616)
+  * Password reset link (#638)
+  * Export and import feature. Useful for migrations and backups. (#626)
+  * Use your email address as your username for logins (#631)
+  * SLA's can be marked *transient*. Tickets with a transient SLA will
+    change to the SLA of the new department or help-topic when transferred
+    or edited.
+  * Support installation on MySQL and MariaDB clusters. Use default storage
+    engine and don't assume predictable auto-increment values (#568, #621)
+
+### Geeky Stuff
+  * mysqli support for PHP5+
+  * SSL support for database connections
+  * Namespaced configuration. This greatly simplifies the process of adding
+  * new configurable item (#564)
+  * Add signals API. A simple event hooking mechanism to allow for
+  * extensibility (#577)
+  * Add deployment command-line script (#586)
+  * Allow XHTML editing in the nicEditor (#615)
+  * Allow parallel database migration streams (#563) -- paves the way for
+    *extensions*
+  * Use row-based email templates (#604) -- simplifies the process of adding
+    new email message templates (think *extensions*)
+  * Support fetching from email boxes with aliased email addresses (#663)
+  * Introduce new crypto library that provides failsafe encryption for email
+    passwords (#651)
+
+### Bugfixes
+  * Several typos in code and messages (#617, #618, #644, #660)
+  * Fix several upgrader bugs (#548, #619)
+  * Fix install fail on some Windows platforms (#570)
+  * Fix several issues in the command-line management (#580)
+  * Make room for command-line installation of osTicket (#581)
+  * *regression* Fix corrupted attachment downloads (#579, #583)
+  * Fix truncated attachment downloads when `zlib.output_compression` is
+    enabled (#596)
+  * Disable cron activities when upgrade is pending (#594)
+  * Provide failsafe encoding for improperly-formatted emails (#601)
+  * Fix corrupted email attachments processed via `pipe.php` (#607)
+  * Fix discarding of poorly encoded base64 emails (#624)
+  * Support MariaDB 10.0+ (#630)
+  * Properly trim ticket email and name fields (#600)
+  * Fix truncated text from text/plain emails and web interface posts (#652)
+  * Add **Assigned To** and other fields to ticket view export (#646)
+  * *regression* Fix attachment migration (#648)
+  * Display correct staff notes (#588)
+  * Display correct auto-response email for departments (#575)
+  * Fix login form ("Authentication Required") loop (#653)
+  * Ensure email message-id is fetched correctly (#664)
+  * Ensure X-Forwarded-For header does not have leading or trailing
+    whitespace (#665)
+
+### Performance
+  * Only fetch configuration for multifile upload if necessary (#637)
+  * Don't use sessions on the API (#623)
+  * *regression* Avoid an extra query per request to fetch schema signature
+    (#658)
+
 New stuff in 1.7.0
 ====================
    * Bug fixes from rc6
diff --git a/bootstrap.php b/bootstrap.php
index cedc9436f86d5f3e7d210f42ff4fba836ebaa2ca..6555f9049273110c43f1d34b76b124566f2660cf 100644
--- a/bootstrap.php
+++ b/bootstrap.php
@@ -230,8 +230,9 @@ define('DEFAULT_PRIORITY_ID',1);
 
 define('EXT_TICKET_ID_LEN',6); //Ticket create. when you start getting collisions. Applies only on random ticket ids.
 
-#Global overwrite
-if($_SERVER['HTTP_X_FORWARDED_FOR']) //Can contain multiple IPs - use the last one.
-    $_SERVER['REMOTE_ADDR'] =  array_pop(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']));
-
+#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/include/api.tickets.php b/include/api.tickets.php
index f7b8ce357ea62e964af7a31f72b5b79fcf00cfc3..59f6c6f5a8b5fbb093fdd59ac97e675dde964639 100644
--- a/include/api.tickets.php
+++ b/include/api.tickets.php
@@ -19,7 +19,8 @@ class TicketApiController extends ApiController {
         );
 
         if(!strcasecmp($format, 'email'))
-            $supported = array_merge($supported, array('header', 'mid', 'emailId', 'ticketId'));
+            $supported = array_merge($supported, array('header', 'mid',
+                'emailId', 'ticketId', 'reply-to', 'reply-to-name'));
 
         return $supported;
     }
@@ -42,7 +43,7 @@ class TicketApiController extends ApiController {
         if($data['attachments'] && is_array($data['attachments'])) {
             foreach($data['attachments'] as &$attachment) {
                 if(!$ost->isFileTypeAllowed($attachment))
-                    $data['error'] = 'Invalid file type (ext) for '.Format::htmlchars($attachment['name']);
+                    $attachment['error'] = 'Invalid file type (ext) for '.Format::htmlchars($attachment['name']);
                 elseif ($attachment['encoding'] && !strcasecmp($attachment['encoding'], 'base64')) {
                     if(!($attachment['data'] = base64_decode($attachment['data'], true)))
                         $attachment['error'] = sprintf('%s: Poorly encoded base64 data', Format::htmlchars($attachment['name']));
@@ -112,6 +113,10 @@ class TicketApiController extends ApiController {
                 return $ticket;
         }
 
+        if (($thread = ThreadEntry::lookupByEmailHeaders($data))
+                && $thread->postEmail($data)) {
+            return true;
+        }
         return $this->createTicket($data);
     }
 
diff --git a/include/class.api.php b/include/class.api.php
index b254d6ce610d72fcce57ad26851f47be216aa881..3d61f6031d84ca49f62158bf254233ea86b078b1 100644
--- a/include/class.api.php
+++ b/include/class.api.php
@@ -423,11 +423,6 @@ class ApiEmailDataParser extends EmailDataParser {
         if(!$data['emailId'])
             $data['emailId'] = $cfg->getDefaultEmailId();
 
-        if($data['email'] && preg_match ('[[#][0-9]{1,10}]', $data['subject'], $matches)) {
-            if(($tid=Ticket::getIdByExtId(trim(preg_replace('/[^0-9]/', '', $matches[0])), $data['email'])))
-                $data['ticketId'] = $tid;
-        }
-
         if(!$cfg->useEmailPriority())
             unset($data['priorityId']);
 
diff --git a/include/class.csrf.php b/include/class.csrf.php
index 806217284b4ca7f381d37496fb763462fedbe0d1..cdd04a29258c9c7daa4056b6a886e32a52ce096e 100644
--- a/include/class.csrf.php
+++ b/include/class.csrf.php
@@ -53,16 +53,11 @@ Class CSRF {
         return $this->name;
     }
 
-    function getToken($len=32) {
+    function getToken() {
 
         if(!$this->csrf['token'] || $this->isExpired()) {
 
-            $len = $len>8?$len:32;
-            $r = '';
-            for ($i = 0; $i <= $len; $i++)
-                $r .= chr(mt_rand(0, 255));
-        
-            $this->csrf['token'] = base64_encode(sha1(session_id().$r.SECRET_SALT));
+            $this->csrf['token'] = sha1(session_id().Crypto::randcode(16).SECRET_SALT);
             $this->csrf['time'] = time();
         } else {
             //Reset the timer
diff --git a/include/class.email.php b/include/class.email.php
index a55a0e3e478733e3c277ab8b19083fa857b2b154..9f7ea95b0c76ceac926d5bdedea534afc1830ea4 100644
--- a/include/class.email.php
+++ b/include/class.email.php
@@ -245,6 +245,11 @@ class Email {
 
             if(!$id && !$vars['passwd'])
                 $errors['passwd']='Password required';
+            elseif($vars['passwd']
+                    && $vars['userid']
+                    && !Crypto::encrypt($vars['passwd'], SECRET_SALT, $vars['userid'])
+                    )
+                $errors['passwd'] = 'Unable to encrypt password - get technical support';
         }
 
         if($vars['mail_active']) {
diff --git a/include/class.filter.php b/include/class.filter.php
index 5ee3f1bcaa39b854c9db900247d7a886aa45be6c..25c51603db2d88f9b114e88501a5d598b7092f73 100644
--- a/include/class.filter.php
+++ b/include/class.filter.php
@@ -652,8 +652,10 @@ class TicketFilter {
                      'subject'   => $vars['subject'],
                      'name'      => $vars['name'],
                      'body'      => $vars['message'],
-                     'emailId'   => $vars['emailId'])
-                 ));
+                     'emailId'   => $vars['emailId'],
+                     'reply-to'  => @$vars['reply-to'],
+                     'reply-to-name' => @$vars['reply-to-name'],
+                 )));
 
          //Init filters.
         $this->build();
diff --git a/include/class.mailer.php b/include/class.mailer.php
index b4ec97c243718f1b86b3a669c8bc901a6c947096..d291effb228bf81cc5b7cae62e58b03dcce37bc9 100644
--- a/include/class.mailer.php
+++ b/include/class.mailer.php
@@ -2,7 +2,7 @@
 /*********************************************************************
     class.mailer.php
 
-    osTicket mailer 
+    osTicket mailer
 
     It's mainly PEAR MAIL wrapper for now (more improvements planned).
 
@@ -27,10 +27,10 @@ class Mailer {
 
     var $smtp = array();
     var $eol="\n";
-    
+
     function Mailer($email=null, $options=null) {
         global $cfg;
-       
+
         if(is_object($email) && $email->isSMTPEnabled() && ($info=$email->getSMTPInfo())) { //is SMTP enabled for the current email?
             $this->smtp = $info;
         } elseif($cfg && ($e=$cfg->getDefaultSMTPEmail()) && $e->isSMTPEnabled()) { //What about global SMTP setting?
@@ -54,7 +54,7 @@ class Mailer {
     function getEmail() {
         return $this->email;
     }
-    
+
     function getSMTPInfo() {
         return $this->smtp;
     }
@@ -117,12 +117,24 @@ class Mailer {
                     'X-Auto-Response-Suppress' => 'ALL, AutoReply',
                     'Auto-Submitted' => 'auto-replied');
 
-            if($options['bulk']) 
+            if($options['bulk'])
                 $headers+= array('Precedence' => 'bulk');
             else
                 $headers+= array('Precedence' => 'auto_reply');
         }
 
+        if ($options) {
+            if (isset($options['replyto']))
+                $headers += array('In-Reply-To' => $options['replyto']);
+            if (isset($options['references'])) {
+                if (is_array($options['references']))
+                    $headers += array('References' =>
+                        implode(' ', $options['references']));
+                else
+                    $headers += array('References' => $options['references']);
+            }
+        }
+
         $mime = new Mail_mime();
         $mime->setTXTBody($body);
         //XXX: Attachments
@@ -134,7 +146,7 @@ class Mailer {
                     $mime->addAttachment($attachment['file'],$attachment['type'],$attachment['name']);
             }
         }
-        
+
         //Desired encodings...
         $encodings=array(
                 'head_encoding' => 'quoted-printable',
@@ -176,7 +188,7 @@ class Mailer {
 
     function logError($error) {
         global $ost;
-        //NOTE: Admin alert overwrite - don't email when having email trouble!
+        //NOTE: Admin alert override - don't email when having email trouble!
         $ost->logError('Mailer Error', $error, false);
     }
 
diff --git a/include/class.mailfetch.php b/include/class.mailfetch.php
index 53fce8bd340308a0627ff76a7b7e487554ac621e..57d828274c01594cc6c1e5487c782817add9012a 100644
--- a/include/class.mailfetch.php
+++ b/include/class.mailfetch.php
@@ -229,11 +229,43 @@ class MailFetcher {
         $sender=$headerinfo->from[0];
         //Just what we need...
         $header=array('name'  =>@$sender->personal,
-                      'email' =>(strtolower($sender->mailbox).'@'.$sender->host),
+                      'email'  => trim(strtolower($sender->mailbox).'@'.$sender->host),
                       'subject'=>@$headerinfo->subject,
-                      'mid'    =>$headerinfo->message_id
+                      'mid'    => trim(@$headerinfo->message_id),
+                      'header' => $this->getHeader($mid),
+                      'in-reply-to' => $headerinfo->in_reply_to,
+                      'references' => $headerinfo->references,
                       );
 
+        if ($replyto = $headerinfo->reply_to) {
+            $header['reply-to'] = $replyto[0]->mailbox.'@'.$replyto[0]->host;
+            $header['reply-to-name'] = $replyto[0]->personal;
+        }
+
+        //Try to determine target email - useful when fetched inbox has
+        // aliases that are independent emails within osTicket.
+        $emailId = 0;
+        $tolist = array();
+        if($headerinfo->to)
+            $tolist = array_merge($tolist, $headerinfo->to);
+        if($headerinfo->cc)
+            $tolist = array_merge($tolist, $headerinfo->cc);
+        if($headerinfo->bcc)
+            $tolist = array_merge($tolist, $headerinfo->bcc);
+
+        foreach($tolist as $addr)
+            if(($emailId=Email::getIdByEmail(strtolower($addr->mailbox).'@'.$addr->host)))
+                break;
+
+        $header['emailId'] = $emailId;
+
+        // Ensure we have a message-id. If unable to read it out of the
+        // email, use the hash of the entire email headers
+        if (!$header['mid'] && $header['header'])
+            if (!($header['mid'] = Mail_Parse::findHeaderEntry($header['header'],
+                    'message-id')))
+                $header['mid'] = '<' . md5($header['header']) . '@local>';
+
         return $header;
     }
 
@@ -363,10 +395,6 @@ class MailFetcher {
         if(!($mailinfo = $this->getHeaderInfo($mid)))
             return false;
 
-        //Make sure the email is NOT already fetched... (undeleted emails)
-        if($mailinfo['mid'] && ($id=Ticket::getIdByMessageId(trim($mailinfo['mid']), $mailinfo['email'])))
-            return true; //Reporting success so the email can be moved or deleted.
-
 	    //Is the email address banned?
         if($mailinfo['email'] && TicketFilter::isBanned($mailinfo['email'])) {
 	        //We need to let admin know...
@@ -374,15 +402,11 @@ class MailFetcher {
 	        return true; //Report success (moved or delete)
         }
 
-        $emailId = $this->getEmailId();
-        $vars = array();
-        $vars['email']=$mailinfo['email'];
+        $vars = $mailinfo;
         $vars['name']=$this->mime_decode($mailinfo['name']);
         $vars['subject']=$mailinfo['subject']?$this->mime_decode($mailinfo['subject']):'[No Subject]';
         $vars['message']=Format::stripEmptyLines($this->getBody($mid));
-        $vars['header']=$this->getHeader($mid);
-        $vars['emailId']=$emailId?$emailId:$ost->getConfig()->getDefaultEmailId(); //ok to default?
-        $vars['mid']=$mailinfo['mid'];
+        $vars['emailId']=$mailinfo['emailId']?$mailinfo['emailId']:$this->getEmailId();
 
         //Missing FROM name  - use email address.
         if(!$vars['name'])
@@ -397,19 +421,15 @@ class MailFetcher {
 
         $ticket=null;
         $newticket=true;
-        //Check the subject line for possible ID.
-        if($vars['subject'] && preg_match ("[[#][0-9]{1,10}]", $vars['subject'], $regs)) {
-            $tid=trim(preg_replace("/[^0-9]/", "", $regs[0]));
-            //Allow mismatched emails?? For now NO.
-            if(!($ticket=Ticket::lookupByExtId($tid, $vars['email'])))
-                $ticket=null;
-        }
 
         $errors=array();
-        if($ticket) {
-            if(!($message=$ticket->postMessage($vars, 'Email')))
-                return false;
-
+        if (($thread = ThreadEntry::lookupByEmailHeaders($vars))
+                && ($message = $thread->postEmail($vars))) {
+            if ($message === true)
+                // Email has been processed previously
+                return true;
+            elseif ($message)
+                $ticket = $message->getTicket();
         } elseif (($ticket=Ticket::create($vars, $errors, 'Email'))) {
             $message = $ticket->getLastMessage();
         } else {
diff --git a/include/class.mailparse.php b/include/class.mailparse.php
index 822d3f5ed58b21009be467ae116e0d5f34103f13..d224b9fe739a2f1db30cef8713cbe0ef4737d38b 100644
--- a/include/class.mailparse.php
+++ b/include/class.mailparse.php
@@ -106,6 +106,15 @@ class Mail_Parse {
         return $array;
     }
 
+    /* static */
+    function findHeaderEntry($headers, $name) {
+        if (!is_array($headers))
+            $headers = self::splitHeaders($headers);
+        foreach ($headers as $key=>$val)
+            if (strcasecmp($key, $name) === 0)
+                return $val;
+        return false;
+    }
 
     function getStruct(){
         return $this->struct;
@@ -143,6 +152,10 @@ class Mail_Parse {
         return $this->struct->headers['subject'];
     }
 
+    function getReplyTo() {
+        return Mail_Parse::parseAddressList($this->struct->headers['reply-to']);
+    }
+
     function getBody(){
 
         $body='';
@@ -328,6 +341,13 @@ class EmailDataParser {
         $data['priorityId'] = $parser->getPriority();
         $data['emailId'] = $emailId;
 
+        if ($replyto = $parser->getReplyTo()) {
+            $replyto = $replyto[0];
+            $data['reply-to'] = $replyto->mailbox.'@'.$replyto->host;
+            if ($replyto->personal)
+                $data['reply-to-name'] = trim($replyto->personal, " \t\n\r\0\x0B\x22");
+        }
+
         if($cfg && $cfg->allowEmailAttachments())
             $data['attachments'] = $parser->getAttachments();
 
diff --git a/include/class.osticket.php b/include/class.osticket.php
index 7d75834d414e13be63e155548d118b6d6b2a701e..8755d3278fda537bd02e4454251b35a1dcbc1e58 100644
--- a/include/class.osticket.php
+++ b/include/class.osticket.php
@@ -375,7 +375,7 @@ class osTicket {
         if(!($ost = new osTicket()))
             return null;
 
-        //Set default time zone... user/staff settting will overwrite it (on login).
+        //Set default time zone... user/staff settting will override it (on login).
         $_SESSION['TZ_OFFSET'] = $ost->getConfig()->getTZoffset();
         $_SESSION['TZ_DST'] = $ost->getConfig()->observeDaylightSaving();
 
diff --git a/include/class.setup.php b/include/class.setup.php
index dfb348c8919ac8be8fa58df0d5d0bf29cd19db8f..4b73c257e4922dffc3ee4c8d60035f9c20d55473 100644
--- a/include/class.setup.php
+++ b/include/class.setup.php
@@ -30,7 +30,7 @@ Class SetupWizard {
 
     function SetupWizard(){
         $this->errors=array();
-        $this->version_verbose = ('osTicket v'. strtoupper(THIS_VERSION));
+        $this->version_verbose = ('osTicket '. strtoupper(THIS_VERSION));
 
     }
 
diff --git a/include/class.staff.php b/include/class.staff.php
index 4e375bb10ec473aeb68776a4d08993ff5447770e..e0220120c0ca497bc12482296d6e08ffe84c257f 100644
--- a/include/class.staff.php
+++ b/include/class.staff.php
@@ -657,7 +657,7 @@ class Staff {
         db_query($sql);
         //Now set session crap and lets roll baby!
         $_SESSION['_staff'] = array(); //clear.
-        $_SESSION['_staff']['userID'] = $username;
+        $_SESSION['_staff']['userID'] = $user->getId();
         $user->refreshSession(); //set the hash.
         $_SESSION['TZ_OFFSET'] = $user->getTZoffset();
         $_SESSION['TZ_DST'] = $user->observeDaylight();
@@ -742,8 +742,9 @@ class Staff {
         if(!$vars['lastname'])
             $errors['lastname']='Last name required';
 
-        if(!$vars['username'] || strlen($vars['username'])<2)
-            $errors['username']='Username required';
+        $error = '';
+        if(!$vars['username'] || !Validator::is_username($vars['username'], $error))
+            $errors['username']=($error) ? $error : 'Username required';
         elseif(($uid=Staff::getIdByUsername($vars['username'])) && $uid!=$id)
             $errors['username']='Username already in use';
 
diff --git a/include/class.thread.php b/include/class.thread.php
index 9b4853a420b77b67d74a51bebad8875065f349b3..d0260be905d6b1715fe10eceb5b7fcece5be7fc7 100644
--- a/include/class.thread.php
+++ b/include/class.thread.php
@@ -189,6 +189,14 @@ class Thread {
 
     function delete() {
 
+        /* XXX: Leave this out until TICKET_EMAIL_INFO_TABLE has a primary
+         *      key
+        $sql = 'DELETE mid.* FROM '.TICKET_EMAIL_INFO_TABLE.' mid
+            INNER JOIN '.TICKET_THREAD_TABLE.' thread ON (thread.id = mid.message_id)
+            WHERE thread.ticket_id = '.db_input($this->getTicketId());
+        db_query($sql);
+         */
+
         $res=db_query('DELETE FROM '.TICKET_THREAD_TABLE.' WHERE ticket_id='.db_input($this->getTicketId()));
         if(!$res || !db_affected_rows())
             return false;
@@ -230,7 +238,7 @@ Class ThreadEntry {
         if(!$id && !($id=$this->getId()))
             return false;
 
-        $sql='SELECT thread.*, info.* '
+        $sql='SELECT thread.*, info.email_mid '
             .' ,count(DISTINCT attach.attach_id) as attachments '
             .' FROM '.TICKET_THREAD_TABLE.' thread '
             .' LEFT JOIN '.TICKET_EMAIL_INFO_TABLE.' info
@@ -309,6 +317,10 @@ Class ThreadEntry {
         return $this->ht['ticket_id'];
     }
 
+    function getEmailMessageId() {
+        return $this->ht['email_mid'];
+    }
+
     function getTicket() {
 
         if(!$this->ticket && $this->getTicketId())
@@ -471,7 +483,76 @@ Class ThreadEntry {
 
         return $str;
     }
+    /**
+     * postEmail
+     *
+     * After some security and sanity checks, attaches the body and subject
+     * of the message in reply to this thread item
+     *
+     * Parameters:
+     * mailinfo - (array) of information about the email, with at least the
+     *          following keys
+     *      - mid - (string) email message-id
+     *      - name - (string) personal name of email originator
+     *      - email - (string<email>) originating email address
+     *      - subject - (string) email subject line (decoded)
+     *      - body - (string) email message body (decoded)
+     */
+    function postEmail($mailinfo) {
+        // +==================+===================+=============+
+        // | Orig Thread-Type | Reply Thread-Type | Requires    |
+        // +==================+===================+=============+
+        // | *                | Message (M)       | From: Owner |
+        // | *                | Note (N)          | From: Staff |
+        // | Response (R)     | Message (M)       |             |
+        // | Message (M)      | Response (R)      | From: Staff |
+        // +------------------+-------------------+-------------+
+
+        if (!$ticket = $this->getTicket())
+            // Kind of hard to continue a discussion without a ticket ...
+            return false;
 
+        // Make sure the email is NOT already fetched... (undeleted emails)
+        elseif ($this->getEmailMessageId() == $mailinfo['mid'])
+            // Reporting success so the email can be moved or deleted.
+            return true;
+
+        $vars = array(
+            'mid' =>    $mailinfo['mid'],
+            'ticketId' => $ticket->getId(),
+            'poster' => $mailinfo['name'],
+            'origin' => 'Email',
+            'source' => 'Email',
+            'ip' =>     '',
+            'reply_to' => $this,
+        );
+
+        $body = $mailinfo['message'];
+
+        // Disambiguate if the user happens also to be a staff member of the
+        // system. The current ticket owner should _always_ post messages
+        // instead of notes or responses
+        if ($mailinfo['email'] == $ticket->getEmail()) {
+            $vars['message'] = $body;
+            return $ticket->postMessage($vars, 'Email');
+        }
+        elseif ($staff_id = Staff::getIdByEmail($mailinfo['email'])) {
+            $vars['staffId'] = $staff_id;
+            $poster = Staff::lookup($staff_id);
+            $errors = array();
+            $vars['note'] = $body;
+            return $ticket->postNote($vars, $errors, $poster);
+        }
+        // TODO: Consider security constraints
+        else {
+            $vars['message'] = sprintf("Received From: %s\n\n%s",
+                $mailinfo['email'], $body);
+            return $ticket->postMessage($vars, 'Email');
+        }
+        // Currently impossible, but indicate that this thread object could
+        // not append the incoming email.
+        return false;
+    }
 
     /* Returns file names with id as key */
     function getFiles() {
@@ -495,8 +576,11 @@ Class ThreadEntry {
 
         $sql='INSERT INTO '.TICKET_EMAIL_INFO_TABLE
             .' SET message_id='.db_input($this->getId()) //TODO: change it to thread_id
-            .', email_mid='.db_input($vars['mid']) //TODO: change it to mid.
-            .', headers='.db_input($vars['header']);
+            .', email_mid='.db_input($vars['mid']); //TODO: change it to mid.
+        if (isset($vars['header']))
+            $sql .= ', headers='.db_input($vars['header']);
+
+        $this->ht['email_mid'] = $vars['mid'];
 
         return db_query($sql)?db_insert_id():0;
     }
@@ -544,8 +628,56 @@ Class ThreadEntry {
                 )?$e:null;
     }
 
+    /**
+     * Parameters:
+     * mailinfo (hash<String>) email header information. Must include keys
+     *  - "mid" => Message-Id header of incoming mail
+     *  - "in-reply-to" => Message-Id the email is a direct response to
+     *  - "references" => List of Message-Id's the email is in response
+     *  - "subject" => Find external ticket number in the subject line
+     */
+    function lookupByEmailHeaders($mailinfo) {
+        // Search for messages using the References header, then the
+        // in-reply-to header
+        $search = 'SELECT message_id FROM '.TICKET_EMAIL_INFO_TABLE
+               . ' WHERE email_mid=%s ORDER BY message_id DESC';
+
+        if ($id = db_result(db_query(
+                sprintf($search, db_input($mailinfo['mid'])))))
+            return ThreadEntry::lookup($id);
+
+        foreach (array('mid', 'in-reply-to', 'references') as $header) {
+            $matches = array();
+            if (!isset($mailinfo[$header]) || !$mailinfo[$header])
+                continue;
+            // Header may have multiple entries (usually separated by
+            // semi-colons (;))
+            elseif (!preg_match_all('/<[^>@]+@[^>]+>/', $mailinfo[$header],
+                        $matches))
+                continue;
+
+            foreach ($matches[0] as $mid) {
+                $res = db_query(sprintf($search, db_input($mid)));
+                while (list($id) = db_fetch_row($res)) {
+                    if ($t = ThreadEntry::lookup($id))
+                        return $t;
+                }
+            }
+        }
+
+        // Search for ticket by the [#123456] in the subject line
+        $subject = $mailinfo['subject'];
+        $match = array();
+        if ($subject && preg_match("/\[#([0-9]{1,10})\]/", $subject, $match))
+            // Return last message for the thread
+            return Message::lastByExtTicketId((int)$match[1]);
+
+        return null;
+    }
+
     //new entry ... we're trusting the caller to check validity of the data.
     function create($vars) {
+        global $cfg;
 
         //Must have...
         if(!$vars['ticketId'] || !$vars['type'] || !in_array($vars['type'], array('M','R','N')))
@@ -562,6 +694,12 @@ Class ThreadEntry {
 
         if(isset($vars['pid']))
             $sql.=' ,pid='.db_input($vars['pid']);
+        // Check if 'reply_to' is in the $vars as the previous ThreadEntry
+        // instance. If the body of the previous message is found in the new
+        // body, strip it out.
+        elseif (isset($vars['reply_to'])
+                && $vars['reply_to'] instanceof ThreadEntry)
+            $sql.=' ,pid='.db_input($vars['reply_to']->getId());
 
         if($vars['ip_address'])
             $sql.=' ,ip_address='.db_input($vars['ip_address']);
@@ -584,6 +722,12 @@ Class ThreadEntry {
         if($vars['cannedattachments'] && is_array($vars['cannedattachments']))
             $entry->saveAttachments($vars['cannedattachments']);
 
+        // Email message id (required for all thread posts)
+        if (!isset($vars['mid']))
+            $vars['mid'] = sprintf('<%s@%s>', Misc::randCode(24),
+                substr(md5($cfg->getUrl()), -10));
+        $entry->saveEmailInfo($vars);
+
         return $entry;
     }
 
@@ -630,6 +774,17 @@ class Message extends ThreadEntry {
                 && $m->getId()==$id
                 )?$m:null;
     }
+
+    function lastByExtTicketId($ticketId) {
+        $sql = 'SELECT thread.id FROM '.TICKET_THREAD_TABLE
+            .' thread JOIN '.TICKET_TABLE.' ticket ON (ticket.ticket_id = thread.ticket_id)
+                WHERE thread_type=\'M\' AND ticket.ticketID = '.db_input($ticketId)
+            .' ORDER BY thread.id DESC LIMIT 1';
+        if (($res = db_query($sql)) && (list($id) = db_fetch_row($res)))
+            return Message::lookup($id);
+        else
+            return null;
+    }
 }
 
 /* Response - Ticket thread entry of type response */
diff --git a/include/class.ticket.php b/include/class.ticket.php
index 2c6f52676d10dacf0b34f505797b9ebf6e0d6388..85b7e3b3820d447ba02c810fdbf975e899887022 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -597,7 +597,7 @@ class Ticket {
      */
     function selectSLAId($trump=null) {
         global $cfg;
-        # XXX Should the SLA be overwritten if it was originally set via an
+        # XXX Should the SLA be overridden if it was originally set via an
         #     email filter? This method doesn't consider such a case
         if ($trump && is_numeric($trump)) {
             $slaId = $trump;
@@ -733,6 +733,8 @@ class Ticket {
         if(!$dept || !($email=$dept->getAutoRespEmail()))
             $email =$cfg->getDefaultEmail();
 
+        $options = array('references'=>$message->getEmailMessageId());
+
         //Send auto response - if enabled.
         if($autorespond && $email && $cfg->autoRespONNewTicket()
                 && $dept->autoRespONNewTicket()
@@ -746,7 +748,8 @@ class Ticket {
             if($cfg->stripQuotedReply() && ($tag=$cfg->getReplySeparator()))
                 $msg['body'] ="\n$tag\n\n".$msg['body'];
 
-            $email->sendAutoReply($this->getEmail(), $msg['subj'], $msg['body']);
+            $email->sendAutoReply($this->getEmail(), $msg['subj'],
+                $msg['body'], null, $options);
         }
 
         if(!($email=$cfg->getAlertEmail()))
@@ -763,7 +766,8 @@ class Ticket {
             //Alert admin??
             if($cfg->alertAdminONNewTicket()) {
                 $alert = str_replace('%{recipient}', 'Admin', $msg['body']);
-                $email->sendAlert($cfg->getAdminEmail(), $msg['subj'], $alert);
+                $email->sendAlert($cfg->getAdminEmail(), $msg['subj'],
+                    $alert, null, $options);
                 $sentlist[]=$cfg->getAdminEmail();
             }
 
@@ -779,7 +783,8 @@ class Ticket {
             foreach( $recipients as $k=>$staff) {
                 if(!is_object($staff) || !$staff->isAvailable() || in_array($staff->getEmail(), $sentlist)) continue;
                 $alert = str_replace('%{recipient}', $staff->getFirstName(), $msg['body']);
-                $email->sendAlert($staff->getEmail(), $msg['subj'], $alert);
+                $email->sendAlert($staff->getEmail(), $msg['subj'], $alert,
+                    null, $options);
                 $sentlist[] = $staff->getEmail();
             }
 
@@ -831,7 +836,7 @@ class Ticket {
         db_query('UPDATE '.TICKET_TABLE.' SET isanswered=1,lastresponse=NOW(), updated=NOW() WHERE ticket_id='.db_input($this->getId()));
     }
 
-    function onMessage($autorespond=true, $alert=true) {
+    function onMessage($autorespond=true, $message=null) {
         global $cfg;
 
         db_query('UPDATE '.TICKET_TABLE.' SET isanswered=0,lastmessage=NOW() WHERE ticket_id='.db_input($this->getId()));
@@ -875,7 +880,11 @@ class Ticket {
             if($cfg->stripQuotedReply() && ($tag=$cfg->getReplySeparator()))
                 $msg['body'] ="\n$tag\n\n".$msg['body'];
 
-            $email->sendAutoReply($this->getEmail(), $msg['subj'], $msg['body']);
+            if (!$message)
+                $message = $this->getLastMessage();
+            $options = array('references' => $message->getEmailMessageId());
+            $email->sendAutoReply($this->getEmail(), $msg['subj'], $msg['body'],
+                null, $options);
         }
     }
 
@@ -893,7 +902,8 @@ class Ticket {
         $assigner = $thisstaff?$thisstaff:'SYSTEM (Auto Assignment)';
 
         //Log an internal note - no alerts on the internal note.
-        $this->logNote('Ticket Assigned to '.$assignee->getName(), $comments, $assigner, false);
+        $note = $this->logNote('Ticket Assigned to '.$assignee->getName(),
+            $comments, $assigner, false);
 
         //See if we need to send alerts
         if(!$alert || !$cfg->alertONAssignment()) return true; //No alerts!
@@ -931,10 +941,12 @@ class Ticket {
 
             //Send the alerts.
             $sentlist=array();
+            $options = array('references' => $note->getEmailMessageId());
             foreach( $recipients as $k=>$staff) {
                 if(!is_object($staff) || !$staff->isAvailable() || in_array($staff->getEmail(), $sentlist)) continue;
                 $alert = str_replace('%{recipient}', $staff->getFirstName(), $msg['body']);
-                $email->sendAlert($staff->getEmail(), $msg['subj'], $alert);
+                $email->sendAlert($staff->getEmail(), $msg['subj'], $alert,
+                    null, $options);
                 $sentlist[] = $staff->getEmail();
             }
         }
@@ -1140,7 +1152,7 @@ class Ticket {
         /*** log the transfer comments as internal note - with alerts disabled - ***/
         $title='Ticket transfered from '.$currentDept.' to '.$this->getDeptName();
         $comments=$comments?$comments:$title;
-        $this->logNote($title, $comments, $thisstaff, false);
+        $note = $this->logNote($title, $comments, $thisstaff, false);
 
         $this->logEvent('transferred');
 
@@ -1180,10 +1192,12 @@ class Ticket {
                 $recipients[]= $manager;
 
             $sentlist=array();
+            $options = array('references' => $note->getEmailMessageId());
             foreach( $recipients as $k=>$staff) {
                 if(!is_object($staff) || !$staff->isAvailable() || in_array($staff->getEmail(), $sentlist)) continue;
                 $alert = str_replace('%{recipient}', $staff->getFirstName(), $msg['body']);
-                $email->sendAlert($staff->getEmail(), $msg['subj'], $alert);
+                $email->sendAlert($staff->getEmail(), $msg['subj'], $alert,
+                    null, $options);
                 $sentlist[] = $staff->getEmail();
             }
          }
@@ -1279,7 +1293,7 @@ class Ticket {
             if(list($msg) = split($tag, $vars['message']))
                 $vars['message'] = $msg;
 
-        if($vars['ip'])
+        if(isset($vars['ip']))
             $vars['ip_address'] = $vars['ip'];
         elseif(!$vars['ip_address'] && $_SERVER['REMOTE_ADDR'])
             $vars['ip_address'] = $_SERVER['REMOTE_ADDR'];
@@ -1290,16 +1304,13 @@ class Ticket {
 
         $this->setLastMsgId($message->getId());
 
-        if (isset($vars['mid']))
-            $message->saveEmailInfo($vars);
-
         if(!$alerts) return $message; //Our work is done...
 
         $autorespond = true;
         if ($autorespond && $message->isAutoResponse())
             $autorespond=false;
 
-        $this->onMessage($autorespond); //must be called b4 sending alerts to staff.
+        $this->onMessage($autorespond, $message); //must be called b4 sending alerts to staff.
 
         $dept = $this->getDept();
 
@@ -1330,10 +1341,12 @@ class Ticket {
                 $recipients[]=$manager;
 
             $sentlist=array(); //I know it sucks...but..it works.
+            $options = array('references'=>$message->getEmailMessageId());
             foreach( $recipients as $k=>$staff) {
                 if(!$staff || !$staff->getEmail() || !$staff->isAvailable() || in_array($staff->getEmail(), $sentlist)) continue;
                 $alert = str_replace('%{recipient}', $staff->getFirstName(), $msg['body']);
-                $email->sendAlert($staff->getEmail(), $msg['subj'], $alert);
+                $email->sendAlert($staff->getEmail(), $msg['subj'], $alert,
+                    null, $options);
                 $sentlist[] = $staff->getEmail();
             }
         }
@@ -1386,7 +1399,9 @@ class Ticket {
                 $msg['body'] ="\n$tag\n\n".$msg['body'];
 
             $attachments =($cfg->emailAttachments() && $files)?$response->getAttachments():array();
-            $email->sendAutoReply($this->getEmail(), $msg['subj'], $msg['body'], $attachments);
+            $options = array('references' => $response->getEmailMessageId());
+            $email->sendAutoReply($this->getEmail(), $msg['subj'], $msg['body'], $attachments,
+                $options);
         }
 
         return $response;
@@ -1441,8 +1456,10 @@ class Ticket {
 
             //Set attachments if emailing.
             $attachments = $cfg->emailAttachments()?$response->getAttachments():array();
+            $options = array('references' => $response->getEmailMessageId());
             //TODO: setup  5 param (options... e.g mid trackable on replies)
-            $email->send($this->getEmail(), $msg['subj'], $msg['body'], $attachments);
+            $email->send($this->getEmail(), $msg['subj'], $msg['body'], $attachments,
+                $options);
         }
 
         return $response;
@@ -1551,6 +1568,7 @@ class Ticket {
                 $recipients[]=$dept->getManager();
 
             $attachments = $note->getAttachments();
+            $options = array('references' => $note->getEmailMessageId());
             $sentlist=array();
             foreach( $recipients as $k=>$staff) {
                 if(!is_object($staff)
@@ -1559,7 +1577,8 @@ class Ticket {
                         || $note->getStaffId() == $staff->getId())  //No need to alert the poster!
                     continue;
                 $alert = str_replace('%{recipient}', $staff->getFirstName(), $msg['body']);
-                $email->sendAlert($staff->getEmail(), $msg['subj'], $alert, $attachments);
+                $email->sendAlert($staff->getEmail(), $msg['subj'], $alert, $attachments,
+                    $options);
                 $sentlist[] = $staff->getEmail();
             }
         }
@@ -1815,7 +1834,7 @@ class Ticket {
     /*
      * The mother of all functions...You break it you fix it!
      *
-     *  $autorespond and $alertstaff overwrites config settings...
+     *  $autorespond and $alertstaff overrides config settings...
      */
     function create($vars, &$errors, $origin, $autorespond=true, $alertstaff=true) {
         global $ost, $cfg, $thisclient, $_FILES;
@@ -1928,7 +1947,7 @@ class Ticket {
         $priorityId=$vars['priorityId'];
         $source=ucfirst($vars['source']);
         $topic=NULL;
-        // Intenal mapping magic...see if we need to overwrite anything
+        // Intenal mapping magic...see if we need to override anything
         if(isset($vars['topicId']) && ($topic=Topic::lookup($vars['topicId']))) { //Ticket created via web by user/or staff
             $deptId=$deptId?$deptId:$topic->getDeptId();
             $priorityId=$priorityId?$priorityId:$topic->getPriorityId();
@@ -2010,7 +2029,7 @@ class Ticket {
             $ticket->assignToTeam($vars['teamId'], 'Auto Assignment');
 
         /**********   double check auto-response  ************/
-        //Overwrite auto responder if the FROM email is one of the internal emails...loop control.
+        //Override auto responder if the FROM email is one of the internal emails...loop control.
         if($autorespond && (Email::getIdByEmail($ticket->getEmail())))
             $autorespond=false;
 
@@ -2128,7 +2147,12 @@ class Ticket {
                 $msg['body'] ="\n$tag\n\n".$msg['body'];
 
             $attachments =($cfg->emailAttachments() && $response)?$response->getAttachments():array();
-            $email->send($ticket->getEmail(), $msg['subj'], $msg['body'], $attachments);
+            $references = $ticket->getLastMessage()->getEmailMessageId();
+            if (isset($response))
+                $references = array($response->getEmailMessageId(), $references);
+            $options = array('references' => $references);
+            $email->send($ticket->getEmail(), $msg['subj'], $msg['body'], $attachments,
+                $options);
         }
 
         return $ticket;
diff --git a/include/class.upgrader.php b/include/class.upgrader.php
index d0f20004086d0e09474681e13ddb57e79f112765..b71a3ff6bc4c121c52acef36ed2bc4a229e0c7b0 100644
--- a/include/class.upgrader.php
+++ b/include/class.upgrader.php
@@ -72,6 +72,35 @@ class Upgrader {
 
     function setState($state) {
         $this->state = $state;
+        if ($state == 'done')
+            $this->createUpgradedTicket();
+    }
+
+    function createUpgradedTicket() {
+        global $cfg;
+
+        //Create a ticket to make the system warm and happy.
+        $dept_id = $cfg->getDefaultDeptId();
+        $prio_id = $cfg->getDefaultPriorityId();
+        $sql='INSERT INTO '.TICKET_TABLE.' SET created=NOW(), status="open", source="Web" '
+            ." ,priority_id=$prio_id, dept_id=$dept_id, topic_id=0 "
+            .' ,ticketID='.db_input(Misc::randNumber(6))
+            .' ,email="support@osticket.com" '
+            .' ,name="osTicket Support" '
+            .' ,subject="osTicket Upgraded!"';
+
+        if(db_query($sql, false) && ($tid=db_insert_id())) {
+            if(!($msg=file_get_contents(UPGRADE_DIR.'msg/upgraded.txt')))
+                $msg='Congratulations and Thank you for choosing osTicket!';
+
+            $sql='INSERT INTO '.TICKET_THREAD_TABLE.' SET created=NOW()'
+                .', source="Web" '
+                .', thread_type="M" '
+                .', ticket_id='.db_input($tid)
+                .', title='.db_input('osTicket Upgraded')
+                .', body='.db_input($msg);
+            db_query($sql, false);
+        }
     }
 
     function getMode() {
diff --git a/include/class.usersession.php b/include/class.usersession.php
index 5e10df43f2d1e3c6b028b788980543b121ca8aca..b596934cf0da76c95f681899935672f04aac3f74 100644
--- a/include/class.usersession.php
+++ b/include/class.usersession.php
@@ -147,7 +147,7 @@ class StaffSession extends Staff {
     
     function StaffSession($var){
         parent::Staff($var);
-        $this->session= new UserSession($var);
+        $this->session= new UserSession($this->getId());
     }
 
     function isValid(){
diff --git a/include/class.validator.php b/include/class.validator.php
index e8bf851a55f76dbc96f6e0d248e9866d180f0b03..f01bcb38ca85f799c9a7d8a187624907228d8941 100644
--- a/include/class.validator.php
+++ b/include/class.validator.php
@@ -111,8 +111,9 @@ class Validator {
                     $this->errors[$k]=$field['error'].' (5 chars min)';
                 break;
             case 'username':
-                if(strlen($this->input[$k])<2)
-                    $this->errors[$k]=$field['error'].' (2 chars min)';
+                $error = '';
+                if (!$this->is_username($this->input[$k], $error))
+                    $this->errors[$k]=$field['error'].": $error";
                 break;
             case 'zipcode':
                 if(!is_numeric($this->input[$k]) || (strlen($this->input[$k])!=5))
@@ -169,6 +170,14 @@ class Validator {
         return false;
     }
 
+    function is_username($username, &$error='') {
+        if (strlen($username)<2)
+            $error = 'At least two (2) characters';
+        elseif (!preg_match('/^[\w._-]+$/', $username))
+            $error = 'Username contains invalid characters';
+        return $error == '';
+    }
+
     function process($fields,$vars,&$errors){
 
         $val = new Validator();
diff --git a/include/class.variable.php b/include/class.variable.php
index ce82dc868dc72219f14a4bfcfc78cb1e9b551f63..3a71bd66de4239c47439cbd196061d1557ebf0f6 100644
--- a/include/class.variable.php
+++ b/include/class.variable.php
@@ -2,8 +2,8 @@
 /*********************************************************************
     class.variable.php
 
-    Variable replacer 
-    
+    Variable replacer
+
     Used to parse, resolve and replace variables.
 
     Peter Rotich <peter@osticket.com>
@@ -42,17 +42,17 @@ class VariableReplacer {
     function getErrors() {
         return $this->errors;
     }
-    
+
     function getObj($tag) {
         return @$this->objects[$tag];
     }
 
     function assign($var, $val='') {
-        
+
         if($val && is_object($val)) {
             $this->objects[$var] = $val;
         } elseif($var && is_array($var)) {
-            foreach($var as $k => $v) 
+            foreach($var as $k => $v)
                 $this->assign($k, $v);
         } elseif($var) {
             $this->variables[$var] = $val;
@@ -74,7 +74,7 @@ class VariableReplacer {
 
             return $this->getVar($rv, $part);
         }
-       
+
         if(!$var || !is_callable(array($obj, 'getVar')))
             return "";
 
@@ -84,9 +84,9 @@ class VariableReplacer {
 
         if(!is_object($rv))
             return $rv;
-            
+
         list(, $part) = explode('.', $var, 2);
-        
+
         return $this->getVar($rv, $part);
     }
 
@@ -110,7 +110,7 @@ class VariableReplacer {
         $parts = explode('.', $var, 2);
         if($parts && ($obj=$this->getObj($parts[0])))
             return $this->getVar($obj, $parts[1]);
-        elseif($parts[0] && @isset($this->variables[$parts[0]])) //root overwrite
+        elseif($parts[0] && @isset($this->variables[$parts[0]])) //root override
             return $this->variables[$parts[0]];
 
         //Unknown object or variable - leavig it alone.
diff --git a/include/client/knowledgebase.inc.php b/include/client/knowledgebase.inc.php
index 2c34a9d82027044d1b824fc68a9e4f690e0a544f..4d75bcba5be080eb463695fb8508d425ee11d608 100644
--- a/include/client/knowledgebase.inc.php
+++ b/include/client/knowledgebase.inc.php
@@ -61,18 +61,18 @@ if($_REQUEST['q'] || $_REQUEST['cid'] || $_REQUEST['topicId']) { //Search.
         .' LEFT JOIN '.FAQ_CATEGORY_TABLE.' cat ON(cat.category_id=faq.category_id) '
         .' LEFT JOIN '.FAQ_TOPIC_TABLE.' ft ON(ft.faq_id=faq.faq_id) '
         .' WHERE faq.ispublished=1 AND cat.ispublic=1';
-    
+
     if($_REQUEST['cid'])
         $sql.=' AND faq.category_id='.db_input($_REQUEST['cid']);
-    
+
     if($_REQUEST['topicId'])
         $sql.=' AND ft.topic_id='.db_input($_REQUEST['topicId']);
 
 
     if($_REQUEST['q']) {
-        $sql.=" AND question LIKE ('%".db_input($_REQUEST['q'],false)."%') 
-                 OR answer LIKE ('%".db_input($_REQUEST['q'],false)."%') 
-                 OR keywords LIKE ('%".db_input($_REQUEST['q'],false)."%')";
+        $sql.=" AND (question LIKE ('%".db_input($_REQUEST['q'],false)."%')
+                 OR answer LIKE ('%".db_input($_REQUEST['q'],false)."%')
+                 OR keywords LIKE ('%".db_input($_REQUEST['q'],false)."%'))";
     }
 
     $sql.=' GROUP BY faq.faq_id';
diff --git a/include/index.html b/include/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..c4c9a988e260cbb934d504315ea7bb67d5a0935b
--- /dev/null
+++ b/include/index.html
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html version="-//W3C//DTD XHTML 1.1//EN" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<link rel="stylesheet" type="text/css" href="/s/d16ebb.css" title="Default"/>
+<title>xkcd: Monster</title>
+<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
+<link rel="shortcut icon" href="/s/919f27.ico" type="image/x-icon"/>
+<link rel="icon" href="/s/919f27.ico" type="image/x-icon"/>
+<link rel="alternate" type="application/atom+xml" title="Atom 1.0" href="/atom.xml"/>
+<link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="/rss.xml"/>
+<link rel="apple-touch-icon-precomposed" href="/s/d9522a.png" />
+<script type="text/javascript">
+  var _gaq = _gaq || [];
+  _gaq.push(['_setAccount', 'UA-25700708-7']);
+  _gaq.push(['_setDomainName', 'xkcd.com']);
+  _gaq.push(['_setAllowLinker', true]);
+  _gaq.push(['_trackPageview']);
+
+  (function() {
+    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+  })();
+</script>
+
+</head>
+<body>
+<div id="topContainer">
+<div id="topLeft">
+<ul>
+<li><a href="/archive">Archive</a></li>
+<li><a href="http://what-if.xkcd.com">What If?</a></li>
+<li><a href="http://blag.xkcd.com">Blag</a></li>
+<li><a href="http://store.xkcd.com/">Store</a></li>
+<li><a rel="author" href="/about">About</a></li>
+</ul>
+</div>
+<div id="topRight">
+<div id="masthead">
+<span><a href="/"><img src="http://imgs.xkcd.com/static/terrible_small_logo.png" alt="xkcd.com logo" height="83" width="185"/></a></span>
+<span id="slogan">A webcomic of romance,<br/> sarcasm, math, and language.</span>
+</div>
+<div id="news">
+You can get the Subways comic as a <a href="http://store-xkcd-com.myshopify.com/products/subways">poster</a>!
+</div>
+</div>
+<div id="bgLeft" class="bg box"></div>
+<div id="bgRight" class="bg box"></div>
+</div>
+<div id="middleContainer" class="box">
+
+<div id="ctitle">Monster</div>
+<ul class="comicNav">
+<li><a href="/1/">|&lt;</a></li>
+<li><a rel="prev" href="/1256/" accesskey="p">&lt; Prev</a></li>
+<li><a href="http://dynamic.xkcd.com/random/comic/">Random</a></li>
+<li><a rel="next" href="#" accesskey="n">Next &gt;</a></li>
+<li><a href="/">&gt;|</a></li>
+</ul>
+<div id="comic">
+<img src="http://imgs.xkcd.com/comics/monster.png" title="It was finally destroyed with a nuclear weapon carrying the destructive energy of the Hiroshima bomb." alt="Monster" />
+</div>
+<ul class="comicNav">
+<li><a href="/1/">|&lt;</a></li>
+<li><a rel="prev" href="/1256/" accesskey="p">&lt; Prev</a></li>
+<li><a href="http://dynamic.xkcd.com/random/comic/">Random</a></li>
+<li><a rel="next" href="#" accesskey="n">Next &gt;</a></li>
+<li><a href="/">&gt;|</a></li>
+</ul>
+<br />
+Permanent link to this comic: http://xkcd.com/1257/<br />
+Image URL (for hotlinking/embedding): http://imgs.xkcd.com/comics/monster.png
+<div id="transcript" style="display: none"></div>
+</div>
+<div id="bottom" class="box">
+<img src="http://imgs.xkcd.com/s/a899e84.jpg" width="520" height="100" alt="Selected Comics" usemap="#comicmap"/>
+<map id="comicmap" name="comicmap">
+<!-- http://code.google.com/p/chromium/issues/detail?id=108489 Might be MIME dependent. -->
+<area shape="rect" coords="0,0,100,100" href="/150/" alt="Grownups"/>
+<area shape="rect" coords="104,0,204,100" href="/730/" alt="Circuit Diagram"/>
+<area shape="rect" coords="208,0,308,100" href="/162/" alt="Angular Momentum"/>
+<area shape="rect" coords="312,0,412,100" href="/688/" alt="Self-Description"/>
+<area shape="rect" coords="416,0,520,100" href="/556/" alt="Alternative Energy Revolution"/>
+</map>
+<div>
+Search comic titles and transcripts:
+<script type="text/javascript" src="//www.google.com/jsapi"></script>
+<script type="text/javascript">google.load('search', '1');google.setOnLoadCallback(function() {google.search.CustomSearchControl.attachAutoCompletion('012652707207066138651:zudjtuwe28q',document.getElementById('q'),'cse-search-box');});</script>
+<form action="//www.google.com/cse" id="cse-search-box">
+<div>
+<input type="hidden" name="cx" value="012652707207066138651:zudjtuwe28q"/>
+<input type="hidden" name="ie" value="UTF-8"/>
+<input type="text" name="q" id="q" size="31"/>
+<input type="submit" name="sa" value="Search"/>
+</div>
+</form>
+<script type="text/javascript" src="//www.google.com/cse/brand?form=cse-search-box&amp;lang=en"></script>
+<a href="/rss.xml">RSS Feed</a> - <a href="/atom.xml">Atom Feed</a>
+</div>
+<br />
+<div id="comicLinks">
+Comics I enjoy:<br/>
+        <a href="http://threewordphrase.com/">Three Word Phrase</a>,
+        <a href="http://oglaf.com/">Oglaf</a> (nsfw),
+        <a href="http://www.smbc-comics.com/">SMBC</a>,
+        <a href="http://www.qwantz.com">Dinosaur Comics</a>,
+        <a href="http://www.asofterworld.com">A Softer World</a>,
+        <a href="http://buttersafe.com/">Buttersafe</a>,
+        <a href="http://pbfcomics.com/">Perry Bible Fellowship</a>,
+        <a href="http://questionablecontent.net/">Questionable Content</a>,
+        <a href="http://www.buttercupfestival.com/">Buttercup Festival</a>
+</div>
+<p>Warning: this comic occasionally contains strong language (which may be unsuitable for children), unusual humor (which may be unsuitable for adults), and advanced mathematics (which may be unsuitable for liberal-arts majors).</p>
+<div id="footnote">BTC 1NfBXWqseXc9rCBc3Cbbu6HjxYssFUgkH6<br />We did not invent the algorithm. The algorithm consistently finds Jesus. The algorithm killed Jeeves. <br/>The algorithm is banned in China. The algorithm is from Jersey. The algorithm constantly finds Jesus.<br/>This is not the algorithm. This is close.</div>
+<div id="licenseText">
+<p>
+This work is licensed under a
+<a href="http://creativecommons.org/licenses/by-nc/2.5/">Creative Commons Attribution-NonCommercial 2.5 License</a>.
+</p><p>
+This means you're free to copy and share these comics (but not to sell them). <a rel="license" href="/license.html">More details</a>.</p>
+</div>
+</div>
+</body>
+<!-- Layout by Ian Clasbey, davean, and chromakode -->
+</html>
+
diff --git a/include/staff/department.inc.php b/include/staff/department.inc.php
index ab22f94ec3074e88c37c8ef509336dbf192bf611..b43806b0b99bd65ec8be77b68b2db7e803ab410b 100644
--- a/include/staff/department.inc.php
+++ b/include/staff/department.inc.php
@@ -158,7 +158,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
         </tr>
         <tr>
             <th colspan="2">
-                <em><strong>Auto Response Settings</strong>: Overwrite global auto-response settings for tickets routed to the Dept.</em>
+                <em><strong>Auto Response Settings</strong>: Override global auto-response settings for tickets routed to the Dept.</em>
             </th>
         </tr>
         <tr>
diff --git a/include/staff/email.inc.php b/include/staff/email.inc.php
index 5e2935e06a02157c4cc7f62e45a38eb4af87326d..58ecb35a8cd6b1cad83377fdfbf68a6f8541fbc9 100644
--- a/include/staff/email.inc.php
+++ b/include/staff/email.inc.php
@@ -40,7 +40,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
         <tr>
             <th colspan="2">
                 <h4><?php echo $title; ?></h4>
-                <em><strong>Email Information</strong>: Login details are optional BUT required when IMAP/POP or SMTP are enabled.</em>
+                <em><strong>Email Information &amp; Settings</strong></em>
             </th>
         </tr>
     </thead>
@@ -65,7 +65,62 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
         </tr>
         <tr>
             <td width="180">
-                Login Username
+                New Ticket Priority
+            </td>
+            <td>
+                <select name="priority_id">
+                    <option value="">&mdash; Select Priority &mdash;</option>
+                    <?php
+                    $sql='SELECT priority_id,priority_desc FROM '.PRIORITY_TABLE.' pri ORDER by priority_urgency DESC';
+                    if(($res=db_query($sql)) && db_num_rows($res)){
+                        while(list($id,$name)=db_fetch_row($res)){
+                            $selected=($info['priority_id'] && $id==$info['priority_id'])?'selected="selected"':'';
+                            echo sprintf('<option value="%d" %s>%s</option>',$id,$selected,$name);
+                        }
+                    }
+                    ?>
+                </select>
+                &nbsp;<span class="error"><?php echo $errors['priority_id']; ?></span>
+            </td>
+        </tr>
+        <tr>
+            <td width="180">
+                New Ticket Dept.
+            </td>
+            <td>
+                <select name="dept_id">
+                    <option value="">&mdash; Select Department &mdash;</option>
+                    <?php
+                    $sql='SELECT dept_id,dept_name FROM '.DEPT_TABLE.' dept ORDER by dept_name';
+                    if(($res=db_query($sql)) && db_num_rows($res)){
+                        while(list($id,$name)=db_fetch_row($res)){
+                            $selected=($info['dept_id'] && $id==$info['dept_id'])?'selected="selected"':'';
+                            echo sprintf('<option value="%d" %s>%s</option>',$id,$selected,$name);
+                        }
+                    }
+                    ?>
+                </select>
+                &nbsp;<span class="error"><?php echo $errors['dept_id']; ?></span>
+            </td>
+        </tr>
+        <tr>
+            <td width="180">
+                Auto-response
+            </td>
+            <td>
+                <input type="checkbox" name="noautoresp" value="1" <?php echo $info['noautoresp']?'checked="checked"':''; ?> >
+                <strong>Disable</strong> new ticket auto-response for this
+                email. Override global and dept. settings.
+            </td>
+        </tr>
+        <tr>
+            <th colspan="2">
+                <em><strong>Login Information:</strong>: Optional BUT required when IMAP/POP or SMTP (with auth.) are enabled.</em>
+            </th>
+        </tr>
+        <tr>
+            <td width="180">
+                Username
             </td>
             <td>
                 <input type="text" size="35" name="userid" value="<?php echo $info['userid']; ?>">
@@ -74,7 +129,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
         </tr>
         <tr>
             <td width="180">
-                Login Password
+               Password
             </td>
             <td>
                 <input type="password" size="35" name="passwd" value="<?php echo $info['passwd']; ?>">
@@ -137,55 +192,6 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                 &nbsp;<font class="error">&nbsp;<?php echo $errors['mail_fetchmax']; ?></font>
             </td>
         </tr>
-        <tr>
-            <td width="180">
-                New Ticket Priority:
-            </td>
-            <td>
-                <select name="priority_id">
-                    <option value="">&mdash; Select Priority &mdash;</option>
-                    <?php
-                    $sql='SELECT priority_id,priority_desc FROM '.PRIORITY_TABLE.' pri ORDER by priority_urgency DESC';
-                    if(($res=db_query($sql)) && db_num_rows($res)){
-                        while(list($id,$name)=db_fetch_row($res)){
-                            $selected=($info['priority_id'] && $id==$info['priority_id'])?'selected="selected"':'';
-                            echo sprintf('<option value="%d" %s>%s</option>',$id,$selected,$name);
-                        }
-                    }
-                    ?>
-                </select>
-                &nbsp;<span class="error"><?php echo $errors['priority_id']; ?></span>
-            </td>
-        </tr>
-        <tr>
-            <td width="180">
-                New Ticket Dept.
-            </td>
-            <td>
-                <select name="dept_id">
-                    <option value="">&mdash; Select Department &mdash;</option>
-                    <?php
-                    $sql='SELECT dept_id,dept_name FROM '.DEPT_TABLE.' dept ORDER by dept_name';
-                    if(($res=db_query($sql)) && db_num_rows($res)){
-                        while(list($id,$name)=db_fetch_row($res)){
-                            $selected=($info['dept_id'] && $id==$info['dept_id'])?'selected="selected"':'';
-                            echo sprintf('<option value="%d" %s>%s</option>',$id,$selected,$name);
-                        }
-                    }
-                    ?>
-                </select>
-                &nbsp;<span class="error"><?php echo $errors['dept_id']; ?></span>
-            </td>
-        </tr>
-        <tr>
-            <td width="180">
-                Auto-response
-            </td>
-            <td>
-                <input type="checkbox" name="noautoresp" value="1" <?php echo $info['noautoresp']?'checked="checked"':''; ?> >
-                <strong>Disable</strong> new ticket auto-response for this email. Overwrite global and dept. settings.
-            </td>
-        </tr>
         <tr><td valign="top">Fetched Emails</td>
              <td>
                 <input type="radio" name="postfetch" value="archive" <?php echo ($info['postfetch']=='archive')? 'checked="checked"': ''; ?> >
diff --git a/include/staff/filter.inc.php b/include/staff/filter.inc.php
index 7ccecd79b85172ba7cda8e7d7b34fe179839ed71..d82c1ca85d2e2fd0998be5154a9de778dc996eeb 100644
--- a/include/staff/filter.inc.php
+++ b/include/staff/filter.inc.php
@@ -157,7 +157,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
         } ?>
         <tr>
             <th colspan="2">
-                <em><strong>Filter Actions</strong>: Can be overwriten by other filters depending on processing order.&nbsp;</em>
+                <em><strong>Filter Actions</strong>: Can be overridden by other filters depending on processing order.&nbsp;</em>
             </th>
         </tr>
         <tr>
@@ -184,7 +184,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
             </td>
             <td>
                 <input type="checkbox" name="disable_autoresponder" value="1" <?php echo $info['disable_autoresponder']?'checked="checked"':''; ?> >
-                    <strong>Disable</strong> auto-response. <em>(Overwrites Dept. settings)</em>
+                    <strong>Disable</strong> auto-response. <em>(Override Dept. settings)</em>
             </td>
         </tr>
         <tr>
@@ -249,7 +249,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                     ?>
                 </select>
                 &nbsp;<span class="error">*&nbsp;<?php echo $errors['priority_id']; ?></span>
-                <em>(Overwrites department's priority)</em>
+                <em>(Overrides department's priority)</em>
             </td>
         </tr>
         <tr>
@@ -269,7 +269,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                     ?>
                 </select>
                 &nbsp;<span class="error">&nbsp;<?php echo $errors['sla_id']; ?></span>
-                <em>(Overwrites department's SLA)</em>
+                <em>(Overrides department's SLA)</em>
             </td>
         </tr>
         <tr>
diff --git a/include/staff/helptopic.inc.php b/include/staff/helptopic.inc.php
index e54323ac491f61eb8ea4044440523369446ed5e0..5dafc452d1d05ac9531383ecc7e7a43d6939d65d 100644
--- a/include/staff/helptopic.inc.php
+++ b/include/staff/helptopic.inc.php
@@ -146,7 +146,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                     ?>
                 </select>
                 &nbsp;<span class="error">&nbsp;<?php echo $errors['sla_id']; ?></span>
-                <em>(Overwrites department's SLA)</em>
+                <em>(Overrides department's SLA)</em>
             </td>
         </tr>
         <tr>
@@ -166,7 +166,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                     }
                     ?>
                 </select>&nbsp;<font class="error"><?php echo $errors['page_id']; ?></font>
-                <em>(Overwrites global setting. Applies to web tickets only.)</em>
+                <em>(Overrides global setting. Applies to web tickets only.)</em>
             </td>
         </tr>
         <tr>
@@ -213,7 +213,8 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
             </td>
             <td>
                 <input type="checkbox" name="noautoresp" value="1" <?php echo $info['noautoresp']?'checked="checked"':''; ?> >
-                    <strong>Disable</strong> new ticket auto-response for this topic (Overwrites Dept. settings).
+                    <strong>Disable</strong> new ticket auto-response for
+                    this topic (Overrides Dept. settings).
             </td>
         </tr>
 
diff --git a/include/staff/login.header.php b/include/staff/login.header.php
index 679a509f96baa7f581bf8463048d3b642531d51a..cf6fbddba8533edba2f7c4c8d960df48007bcb66 100644
--- a/include/staff/login.header.php
+++ b/include/staff/login.header.php
@@ -5,6 +5,7 @@ defined('OSTSCPINC') or die('Invalid path');
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 <head>
     <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+    <meta http-equiv="refresh" content="7200" />
     <title>osTicket:: SCP Login</title>
     <link rel="stylesheet" href="css/login.css" type="text/css" />
     <meta name="robots" content="noindex" />
diff --git a/include/staff/login.tpl.php b/include/staff/login.tpl.php
index 6d5435732128d556219c0230bdfb66004bdc21e7..1f3bb55e0c1565f6d9b6908c7359018c56d1bdaa 100644
--- a/include/staff/login.tpl.php
+++ b/include/staff/login.tpl.php
@@ -9,7 +9,7 @@ $info = ($_POST && $errors)?Format::htmlchars($_POST):array();
         <?php csrf_token(); ?>
         <input type="hidden" name="do" value="scplogin">
         <fieldset>
-            <input type="text" name="userid" id="name" value="<?php echo $info['username']; ?>" placeholder="username" autocorrect="off" autocapitalize="off">
+            <input type="text" name="userid" id="name" value="<?php echo $info['userid']; ?>" placeholder="username" autocorrect="off" autocapitalize="off">
             <input type="password" name="passwd" id="pass" placeholder="password" autocorrect="off" autocapitalize="off">
         </fieldset>
         <?php if ($_SESSION['_staff']['strikes'] > 1 && $cfg->allowPasswordReset()) { ?>
diff --git a/include/staff/page.inc.php b/include/staff/page.inc.php
index 35881ee742046387c9dea3630fc771546232822b..ea9d2c639f848c0e83fa161782c48a4f5928b96c 100644
--- a/include/staff/page.inc.php
+++ b/include/staff/page.inc.php
@@ -29,7 +29,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
  <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
- <h2>Email Template</h2>
+ <h2>Site Pages</h2>
  <table class="form_table" width="940" border="0" cellspacing="0" cellpadding="2">
     <thead>
         <tr>
diff --git a/include/staff/settings-autoresp.inc.php b/include/staff/settings-autoresp.inc.php
index b5815915fc346bb97fbfa318db9416bda6bfccce..0ad893b3fb97c4515ca407e9318a164cdc37454e 100644
--- a/include/staff/settings-autoresp.inc.php
+++ b/include/staff/settings-autoresp.inc.php
@@ -28,7 +28,7 @@
                 <input type="radio" name="ticket_notice_active"  value="1"   <?php echo $config['ticket_notice_active']?'checked="checked"':''; ?> /><b>Enable</b>
                 <input type="radio" name="ticket_notice_active"  value="0"   <?php echo !$config['ticket_notice_active']?'checked="checked"':''; ?> />Disable
                  &nbsp;&nbsp;&nbsp;
-                 <em>(Notice sent when staff creates a ticket on behalf of the user (Staff can overwrite))</em>
+                 <em>(Notice sent when staff creates a ticket on behalf of the user (Staff can override))</em>
             </td>
         </tr>
         <tr>
diff --git a/include/staff/settings-emails.inc.php b/include/staff/settings-emails.inc.php
index b7175a06e6b9c5b6768690de5d233bdd6a43f5fc..e433cd7a2d9eb0d10243d886ce06e941d8dc7773 100644
--- a/include/staff/settings-emails.inc.php
+++ b/include/staff/settings-emails.inc.php
@@ -10,7 +10,7 @@ if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin() || !$config)
         <tr>
             <th colspan="2">
                 <h4>Email Settings</h4>
-                <em>Note that some of the global settings can be overwritten at department/email level.</em>
+                <em>Note that some of the global settings can be overridden at department/email level.</em>
             </th>
         </tr>
     </thead>
@@ -58,7 +58,7 @@ if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin() || !$config)
             <td>
                 <input type="text" size=40 name="admin_email" value="<?php echo $config['admin_email']; ?>">
                     &nbsp;<font class="error">*&nbsp;<?php echo $errors['admin_email']; ?></font>
-                &nbsp;&nbsp;<em>(System administrator's email)</em> 
+                &nbsp;&nbsp;<em>(System administrator's email)</em>
             </td>
         </tr>
         <tr><th colspan=2><em><strong>Incoming Emails</strong>: For mail fetcher (polling) to work you must set an external cron job or enable auto-cron polling</em></th>
diff --git a/include/staff/settings-system.inc.php b/include/staff/settings-system.inc.php
index 8915c8b4f87048d60cfba3a4d0fe3e2ca697dc62..8dd170e4161a97601b589017b4430ba8a15303ae 100644
--- a/include/staff/settings-system.inc.php
+++ b/include/staff/settings-system.inc.php
@@ -3,7 +3,7 @@ if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin() || !$config)
 
 $gmtime = Misc::gmtime();
 ?>
-<h2>System Settings and Preferences - <span>osTicket (v<?php echo $cfg->getVersion(); ?>)</span></h2>
+<h2>System Settings and Preferences - <span>osTicket (<?php echo $cfg->getVersion(); ?>)</span></h2>
 <form action="settings.php?t=system" method="post" id="save">
 <?php csrf_token(); ?>
 <input type="hidden" name="t" value="system" >
diff --git a/include/staff/settings-tickets.inc.php b/include/staff/settings-tickets.inc.php
index 4d3f47f6f90849c6b4b6ed313fa95bcb96df2cc4..0c29ca73a1c6bbc4d478e3e71433031ed2754c22 100644
--- a/include/staff/settings-tickets.inc.php
+++ b/include/staff/settings-tickets.inc.php
@@ -80,7 +80,7 @@ if(!($maxfileuploads=ini_get('max_file_uploads')))
                     <td width="180">Web Tickets Priority:</td>
                     <td>
                         <input type="checkbox" name="allow_priority_change" value="1" <?php echo $config['allow_priority_change'] ?'checked="checked"':''; ?>>
-                        <em>(Allow user to overwrite/set priority)</em>
+                        <em>(Allow user to override/set priority)</em>
                     </td>
                 </tr>
                 <tr>
diff --git a/include/staff/slaplan.inc.php b/include/staff/slaplan.inc.php
index 541050ce846f9a65ddcf35baf868f3e4436f5275..94f1fb1c61a9bf805758339f36d5885f003fa1ee 100644
--- a/include/staff/slaplan.inc.php
+++ b/include/staff/slaplan.inc.php
@@ -80,7 +80,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
             </td>
             <td>
                 <input type="checkbox" name="transient" value="1" <?php echo $info['transient']?'checked="checked"':''; ?> >
-                SLA can be overwritten on ticket transfer or help topic
+                SLA can be overridden on ticket transfer or help topic
                 change
             </td>
         </tr>
@@ -90,10 +90,10 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
             </td>
             <td>
                 <input type="checkbox" name="disable_overdue_alerts" value="1" <?php echo $info['disable_overdue_alerts']?'checked="checked"':''; ?> >
-                    <strong>Disable</strong> overdue alerts notices. <em>(Overwrite global setting)</em>
+                    <strong>Disable</strong> overdue alerts notices.
+                    <em>(Override global setting)</em>
             </td>
         </tr>
-
         <tr>
             <th colspan="2">
                 <em><strong>Admin Notes</strong>: Internal notes.&nbsp;</em>
diff --git a/include/staff/team.inc.php b/include/staff/team.inc.php
index 916582d8e7d95b4d5d188f0174aca1f3bd3411b8..4ca688ac5ae3702b80f2478e67c407330b809bf7 100644
--- a/include/staff/team.inc.php
+++ b/include/staff/team.inc.php
@@ -81,7 +81,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
             </td>
             <td>
                 <input type="checkbox" name="noalerts" value="1" <?php echo $info['noalerts']?'checked="checked"':''; ?> >
-                <strong>Disable</strong> assignment alerts for this team (<i>overwrite global settings.</i>)
+                <strong>Disable</strong> assignment alerts for this team (<i>override global settings.</i>)
             </td>
         </tr>
         <?php
@@ -97,8 +97,8 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                             <b><a href="staff.php?id=%d">%s</a></span></b>
                             &nbsp;<input type="checkbox" name="remove[]" value="%d"><i>Remove</i></td></tr>',
                           $staff->getId(),$staff->getName(),$staff->getId());
-               
-            
+
+
             }
         } ?>
         <tr>
diff --git a/include/staff/teams.inc.php b/include/staff/teams.inc.php
index 0d33d7dfb036bcbcae2e2c467ad65d07ca0d3d4b..9724714f71956fcdc0fb3ddb9f4cd5e3fb3a26f5 100644
--- a/include/staff/teams.inc.php
+++ b/include/staff/teams.inc.php
@@ -52,7 +52,7 @@ else
     <caption><?php echo $showing; ?></caption>
     <thead>
         <tr>
-            <th width="7px">&nbsp;</th>        
+            <th width="7px">&nbsp;</th>
             <th width="250"><a <?php echo $name_sort; ?> href="teams.php?<?php echo $qstr; ?>&sort=name">Team Name</a></th>
             <th width="80"><a  <?php echo $status_sort; ?> href="teams.php?<?php echo $qstr; ?>&sort=status">Status</a></th>
             <th width="80"><a  <?php echo $members_sort; ?>href="teams.php?<?php echo $qstr; ?>&sort=members">Members</a></th>
@@ -73,7 +73,7 @@ else
                 ?>
             <tr id="<?php echo $row['team_id']; ?>">
                 <td width=7px>
-                  <input type="checkbox" class="ckb" name="ids[]" value="<?php echo $row['team_id']; ?>" 
+                  <input type="checkbox" class="ckb" name="ids[]" value="<?php echo $row['team_id']; ?>"
                             <?php echo $sel?'checked="checked"':''; ?>> </td>
                 <td><a href="teams.php?id=<?php echo $row['team_id']; ?>"><?php echo $row['name']; ?></a> &nbsp;</td>
                 <td>&nbsp;<?php echo $row['isenabled']?'Active':'<b>Disabled</b>'; ?></td>
diff --git a/include/staff/ticket-edit.inc.php b/include/staff/ticket-edit.inc.php
index 5f5a0a4d2e2e86816e64039bfb6ede821f5379b5..93fc68bad4f957eb3044b503eb5dc0c6df8ae4d9 100644
--- a/include/staff/ticket-edit.inc.php
+++ b/include/staff/ticket-edit.inc.php
@@ -50,7 +50,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$ticket->getUpdateInfo());
         </tr>
         <tr>
             <th colspan="2">
-                <em><strong>Ticket Information</strong>: Due date overwrites SLA's grace period.</em>
+                <em><strong>Ticket Information</strong>: Due date overrides SLA's grace period.</em>
             </th>
         </tr>
         <tr>
@@ -146,7 +146,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$ticket->getUpdateInfo());
                 $min=$hr=null;
                 if($info['time'])
                     list($hr, $min)=explode(':', $info['time']);
-                    
+
                 echo Misc::timeDropdown($hr, $min, 'time');
                 ?>
                 &nbsp;<font class="error">&nbsp;<?php echo $errors['duedate']; ?>&nbsp;<?php echo $errors['time']; ?></font>
diff --git a/include/upgrader/msg/upgraded.txt b/include/upgrader/msg/upgraded.txt
new file mode 100644
index 0000000000000000000000000000000000000000..84554ec313eaad08b45fd64e7e7bfd781263bc50
--- /dev/null
+++ b/include/upgrader/msg/upgraded.txt
@@ -0,0 +1,11 @@
+osTicket upgraded successfully! Please refer to the Release Notes (http://osticket.com/wiki/Release_Notes) for more information about changes and new features.
+
+Be sure to join osTicket forum (http://osticket.com/forums) and our mailing list (http://osticket.com/updates) , if you haven't done so already,  to stay up to date on announcements, security updates and alerts! Your contribution to osTicket community will be appreciated!
+
+The osTicket team is committed to providing support to all users through our free online resources and a full range of commercial support packages and services. For more information, or to discuss your needs, please contact us today at http://osticket.com/support/. Any feedback will be appreciated!
+
+If managing and upgrading this osTicket installation is daunting, you can try osTicket as a hosted service at http://www.supportsystem.com/ -- no upgrading ever, and we can import your data!  With SupportSystem's turnkey infrastructure, you get osTicket at its best, leaving you free to focus on your customers without the burden of making sure the application is stable, maintained, and secure.
+
+-
+osTicket Team
+http://osticket.com/
diff --git a/main.inc.php b/main.inc.php
index ca636616bcaf6e18ed70104ceccdb1bd347abacb..5dd4109d3f6f4b940e95243cfba7901958f877fd 100644
--- a/main.inc.php
+++ b/main.inc.php
@@ -30,7 +30,7 @@
     $session = $ost->getSession();
 
     //System defaults we might want to make global//
-    #pagenation default - user can overwrite it!
+    #pagenation default - user can override it!
     define('DEFAULT_PAGE_LIMIT', $cfg->getPageSize()?$cfg->getPageSize():25);
 
     #Cleanup magic quotes crap.
diff --git a/scp/admin.inc.php b/scp/admin.inc.php
index 19d2d5fbcf97008b689ee6a07204c1780e3ad455..97dc168406af6c36909cdcfd135eca8947fc5624 100644
--- a/scp/admin.inc.php
+++ b/scp/admin.inc.php
@@ -34,11 +34,11 @@ if($ost->isUpgradePending()) {
         exit;
     }
 } else {
-    
+
     if(!strcasecmp(basename(CONFIG_FILE), 'settings.php')) {
         $sysnotice=sprintf('Please rename config file include/%s to include/ost-config.php to avoid possible conflicts',
                                 basename(CONFIG_FILE));
-        //Die gracefully - otherwise upgraded RC5 installations will die with confusing message. 
+        //Die gracefully - otherwise upgraded RC5 installations will die with confusing message.
         if(!strcasecmp(basename($_SERVER['SCRIPT_NAME']), 'settings.php'))
             die($sysnotice);
 
diff --git a/scp/js/ticket.js b/scp/js/ticket.js
index 56b02f20136a6218ee937c63de3705ccc8916285..ab83eab43ae8be4a65af0b15177d4ea93b9f5fe4 100644
--- a/scp/js/ticket.js
+++ b/scp/js/ticket.js
@@ -14,7 +14,7 @@
     vim: expandtab sw=4 ts=4 sts=4:
 **********************************************************************/
 var autoLock = {
-    
+
     addEvent: function(elm, evType, fn, useCapture) {
         if(elm.addEventListener) {
             elm.addEventListener(evType, fn, useCapture);
@@ -55,7 +55,7 @@ var autoLock = {
                 return "Any changes or info you've entered will be discarded!";
              });
         }
-        
+
         autoLock.lasteventTime=new Date().getTime();
     },
 
@@ -75,7 +75,7 @@ var autoLock = {
                     break;
                 case 'select-one':
                 case 'select-multiple':
-                    if(fObj.name!='reply') //Bug on double ajax call since select make it's own ajax call. TODO: fix it 
+                    if(fObj.name!='reply') //Bug on double ajax call since select make it's own ajax call. TODO: fix it
                         autoLock.addEvent(fObj[i],'change',autoLock.handleEvent,true);
                     break;
                 default:
@@ -98,8 +98,8 @@ var autoLock = {
 
         //make sure we are on ticket view page & locking is enabled!
         var fObj=$('form#note');
-        if(!fObj 
-                || !$(':input[name=id]',fObj).length 
+        if(!fObj
+                || !$(':input[name=id]',fObj).length
                 || !$(':input[name=locktime]',fObj).length
                 || $(':input[name=locktime]',fObj).val()==0) {
             return;
@@ -124,7 +124,7 @@ var autoLock = {
         autoLock.resetTimer();
         autoLock.addEvent(window,'unload',autoLock.releaseLock,true); //Release lock regardless of any activity.
     },
-          
+
 
     onSubmit: function(e) {
         if(e.type=='submit') { //Submit. double check!
@@ -146,8 +146,8 @@ var autoLock = {
         }
         return true;
     },
-    
-    acquireLock: function(e,warn) {      
+
+    acquireLock: function(e,warn) {
 
         if(!autoLock.tid) { return false; }
 
@@ -168,16 +168,16 @@ var autoLock = {
             .done(function() { })
             .fail(function() { });
         }
-   
+
         return autoLock.lockId;
     },
 
-    //Renewal only happens on form activity.. 
+    //Renewal only happens on form activity..
     renewLock: function(e) {
-        
+
         if(!autoLock.lockId) { return false; }
-        
-        var now= new Date().getTime(); 
+
+        var now= new Date().getTime();
         if(!autoLock.lastcheckTime || (now-autoLock.lastcheckTime)>=(autoLock.renewFreq*1000)){
             $.ajax({
                 type: 'POST',
@@ -191,8 +191,8 @@ var autoLock = {
             .done(function() {  })
             .fail(function() { });
         }
-    }, 
-     
+    },
+
     releaseLock: function(e) {
         if(!autoLock.tid) { return false; }
 
@@ -202,7 +202,7 @@ var autoLock = {
             data: 'delete',
             cache: false,
             success: function(){
-               
+
             }
         })
         .done(function() { })
@@ -211,15 +211,15 @@ var autoLock = {
 
     setLock: function(lock, action, warn) {
         var warn = warn || false;
-            
+
         if(!lock) return false;
 
         if(lock.id) {
             autoLock.renewFreq=lock.time?(lock.time/2):30;
             autoLock.lastcheckTime=new Date().getTime();
         }
-        autoLock.lockId=lock.id; //overwrite the lockid.
-        
+        autoLock.lockId=lock.id; //override the lockid.
+
         switch(action){
             case 'renew':
                 if(!lock.id && lock.retry) {
@@ -232,18 +232,18 @@ var autoLock = {
                     autoLock.lockAttempts++;
                     if(warn && (!lock.retry || autoLock.lockAttempts>=autoLock.maxattempts)) {
                         autoLock.retry=false;
-                        alert('Unable to lock the ticket. Someone else could be working on the same ticket.'); 
+                        alert('Unable to lock the ticket. Someone else could be working on the same ticket.');
                     }
-                }   
+                }
                 break;
         }
     },
-    
+
     discardWarning: function(e) {
         e.returnValue="Any changes or info you've entered will be discarded!";
     },
 
-    //TODO: Monitor events and elapsed time and warn user when the lock is about to expire. 
+    //TODO: Monitor events and elapsed time and warn user when the lock is about to expire.
     monitorEvents: function() {
        // warn user when lock is about to expire??;
         //autoLock.resetTimer();
@@ -252,7 +252,7 @@ var autoLock = {
     clearTimer: function() {
         clearTimeout(autoLock.timerId);
     },
-    
+
     resetTimer: function() {
         clearTimeout(autoLock.timerId);
         autoLock.timerId=setTimeout(function () { autoLock.monitorEvents() },30000);
@@ -283,7 +283,7 @@ jQuery(function($) {
     }
 
     $('#reply_tab').click(function() {
-       $(this).removeClass('tell'); 
+       $(this).removeClass('tell');
      });
 
     $('#note_tab').click(function() {
@@ -341,7 +341,7 @@ jQuery(function($) {
         $('.dialog#ticket-status').show();
         return false;
     });
-       
+
     //ticket actions confirmation - Delete + more
     $('a#ticket-delete, a#ticket-claim, #action-dropdown-more li a').click(function(e) {
         e.preventDefault();
diff --git a/scp/staff.inc.php b/scp/staff.inc.php
index 54ff91b9976bc4e3ddbc558e07d5f205c1ee2d06..0c835d46a780a5acf439af2268da039a73335905 100644
--- a/scp/staff.inc.php
+++ b/scp/staff.inc.php
@@ -58,7 +58,7 @@ if(!function_exists('staffLoginPage')) { //Ajax interface can pre-declare the fu
 
 $thisstaff = new StaffSession($_SESSION['_staff']['userID']); //Set staff object.
 //1) is the user Logged in for real && is staff.
-if(!$thisstaff || !is_object($thisstaff) || !$thisstaff->getId() || !$thisstaff->isValid()){
+if(!$thisstaff->getId() || !$thisstaff->isValid()){
     if (isset($_SESSION['_staff']['auth']['msg'])) {
         $msg = $_SESSION['_staff']['auth']['msg'];
         unset($_SESSION['_staff']['auth']['msg']);
diff --git a/setup/cli/package.php b/setup/cli/package.php
index f4c485b9a1a1f0bef448fea945c2b47df415912a..45fd517704822e7ae3e4c8d471bdb30b14d1e5ea 100755
--- a/setup/cli/package.php
+++ b/setup/cli/package.php
@@ -84,13 +84,15 @@ mkdir($stage_path . '/upload');
 
 # Load the root directory files
 package("*.php", 'upload/');
+package("web.config", 'upload/');
 
 # Load the client interface
 foreach (array('assets','css','images','js') as $dir)
     package("$dir/*", "upload/$dir", -1, "*less");
 
-# Load API
+# Load API and pages
 package('api/{,.}*', 'upload/api');
+package('pages/{,.}*', 'upload/pages');
 
 # Load the knowledgebase
 package("kb/*.php", "upload/kb");
diff --git a/setup/inc/msg/installed.txt b/setup/inc/msg/installed.txt
index 58bbeb5a0c6238df52c83fa91eeb701cdd00dbd5..5b598afdaec399b23c751177967dfc689814b201 100644
--- a/setup/inc/msg/installed.txt
+++ b/setup/inc/msg/installed.txt
@@ -1,9 +1,11 @@
 Thank you for choosing osTicket.
 
-Please make sure you join the osTicket forums at http://osticket.com/forums to stay up to date on the latest news, security alerts and updates. The osTicket forums are also a great place to get assistance, guidance, tips, and help from other osTicket users. In addition to the forums, the osTicket wiki provides a useful collection of educational materials, documentation, and notes from the community. We welcome your contributions to the osTicket community.
+Please make sure you join the osTicket forums (http://osticket.com/forums) and our mailing list (http://osticket.com/updates) to stay up to date on the latest news, security alerts and updates. The osTicket forums are also a great place to get assistance, guidance, tips, and help from other osTicket users. In addition to the forums, the osTicket wiki provides a useful collection of educational materials, documentation, and notes from the community. We welcome your contributions to the osTicket community.
 
 If you are looking for a greater level of support, we provide professional services and commercial support with guaranteed response times, and access to the core development team. We can also help customize osTicket or even add new features to the system to meet your unique needs.
 
+If the idea of managing and upgrading this osTicket installation is daunting, you can try osTicket as a hosted service at http://www.supportsystem.com/ -- no installation required and we can import your data!  With SupportSystem's turnkey infrastructure, you get osTicket at its best, leaving you free to focus on your customers without the burden of making sure the application is stable, maintained, and secure.
+
 Cheers,
 
 -
diff --git a/setup/inc/msg/upgraded.txt b/setup/inc/msg/upgraded.txt
deleted file mode 100644
index d88a29733659f1e9696a47338b89f7b7ccec1b97..0000000000000000000000000000000000000000
--- a/setup/inc/msg/upgraded.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-
-osTicket upgraded successfully! Please refer to the Release Notes (http://osticket.com/wiki/Release_Notes) for more information about changes and new features.
-
-Be sure to join osTicket forum (http://osticket.com/forums) and our mailing list (http://osticket.com/support/subscribe.php) , if you haven't done so already,  to stay up to date on announcements, security updates and alerts! Your contribution to osTicket community will be appreciated!
-
-The osTicket team is committed to providing support to all users through our free online resources and a full range of commercial support packages and services. For more information, or to discuss your needs, please contact us today at http://osticket.com/support/. Any feedback will be appreciated!
-
--
-osTicket Team
-http://osticket.com/
diff --git a/setup/install.php b/setup/install.php
index 497d37817faf22754c6af26468a56873190ca702..2bca44418e655637620993439f34ca1e0a0329f7 100644
--- a/setup/install.php
+++ b/setup/install.php
@@ -25,7 +25,7 @@ define('OSTICKET_CONFIGFILE','../include/ost-config.php'); //XXX: Make sure the
 $installer = new Installer(OSTICKET_CONFIGFILE); //Installer instance.
 $wizard=array();
 $wizard['title']='osTicket Installer';
-$wizard['tagline']='Installing osTicket v'.$installer->getVersionVerbose();
+$wizard['tagline']='Installing osTicket '.$installer->getVersionVerbose();
 $wizard['logo']='logo.png';
 $wizard['menu']=array('Installation Guide'=>'http://osticket.com/wiki/Installation',
         'Get Professional Help'=>'http://osticket.com/support');
@@ -85,17 +85,17 @@ switch(strtolower($_SESSION['ost_installer']['s'])) {
     case 'install':
         if(!$installer->config_exists()) {
             $inc='file-missing.inc.php';
-        } elseif(!($cFile=file_get_contents($installer->getConfigFile())) 
+        } elseif(!($cFile=file_get_contents($installer->getConfigFile()))
                 || preg_match("/define\('OSTINSTALLED',TRUE\)\;/i",$cFile)) { //osTicket already installed or empty config file?
             $inc='file-unclean.inc.php';
         } elseif(!$installer->config_writable()) { //writable config file??
             clearstatcache();
             $inc='file-perm.inc.php';
         } else { //Everything checked out show install form.
-            $inc='install.inc.php'; 
+            $inc='install.inc.php';
         }
         break;
-    case 'subscribe': //TODO: Prep for v1.7 RC1 
+    case 'subscribe': //TODO: Prep for v1.7 RC1
        $inc='subscribe.inc.php';
         break;
     case 'done':
@@ -105,10 +105,10 @@ switch(strtolower($_SESSION['ost_installer']['s'])) {
         break;
     default:
         //Fail IF any of the old config files exists.
-        if(file_exists(INCLUDE_DIR.'settings.php') 
+        if(file_exists(INCLUDE_DIR.'settings.php')
                 || file_exists(ROOT_DIR.'ostconfig.php')
-                || (file_exists(OSTICKET_CONFIGFILE) 
-                    && preg_match("/define\('OSTINSTALLED',TRUE\)\;/i", 
+                || (file_exists(OSTICKET_CONFIGFILE)
+                    && preg_match("/define\('OSTINSTALLED',TRUE\)\;/i",
                         file_get_contents(OSTICKET_CONFIGFILE)))
                 )
             $inc='file-unclean.inc.php';