diff --git a/.gitignore b/.gitignore
index 3303e4bdcbe10c755ed21dae59e9201c243983e0..2c0568a588f2c2759a62bc94151c0597f8c09abe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
 php53.cgi
 include/ost-config.php
 *.sw[a-z]
+.DS_Store
diff --git a/README.md b/README.md
index 34981849af1f420236229466374cba706e0351e3..4d97925949c0c7e4fff49c52ab5c8b445572f171 100644
--- a/README.md
+++ b/README.md
@@ -34,6 +34,25 @@ Follow the usual install instructions (beginning from Manual Installation
 above), except, don't delete the setup/ folder. For this reason, such an
 installation is not recommended for a public-facing support system.
 
+Upgrading
+---------
+osTicket supports upgrading from 1.6-rc1 and later versions. As with any
+upgrade, strongly consider a backup of your attachment files, database, and
+osTicket codebase before embarking on an upgrade.
+
+To trigger the update process, fetch the osTicket-1.7 tarball from either
+the osTicket [github](http://github.com/osTicket/osTicket-1.7) page or from
+the osTicket website. Extract the tarball into the folder of you osTicket
+codebase. This can also be accomplished with the zip file, and a FTP client
+can of course be used to upload the new source code to your server. 
+
+Any way you choose your adventure, when you have your codebase upgraded to
+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).
+
+View the UPGRADING.txt file for other todo items to complete your upgrade.
+
 Help
 ----
 Visit the [wiki](http://osticket.com/wiki/Home) or the
diff --git a/UPGRADING.txt b/UPGRADING.txt
new file mode 100644
index 0000000000000000000000000000000000000000..bdb477299beaf64ef7c96435116bf31d4c2ad6ec
--- /dev/null
+++ b/UPGRADING.txt
@@ -0,0 +1,90 @@
+Welcome to osTicket 1.7
+=======================
+Some tasks are better left to a system administrator rather than a mindless
+upgrade script. These are those remaining things that we'd rather you take
+care of:
+
+  * Verify that your attachments have been successfully migrated to the
+    database and removed from your server's filesystem. Once you're
+    comfortable that they're all migrated, and that the remaining files are
+    all failed uploads or orphans from deleted tickets, remove the folder
+    where attachments were uploaded to.
+
+  * Remove codebase files no longer utilized in osTicket 1.7. If you have
+    console access to your server, a codebase-cleanup.sh script is provided
+    for you in the setup/ folder to help you automatically take care of this.
+    Otherwise, you may safely remove the following files from your codebase if
+    they exist:
+
+    * Removed in osTicket-1.6-rc5
+      ostconfig.php
+
+    * Removed in osTicket-1.6.0
+      images/button.jpg
+      images/logo.jpg
+      images/new_ticket_title.jpg
+      images/ticket_status_title.jpg
+      include/settings.php
+
+    * Removed in osTicket-1.7.0
+      images/bg.gif
+      images/fibres.png
+      images/home.gif
+      images/icons
+      images/lipsum.png
+      images/logo2.jpg
+      images/logout.gif
+      images/my_tickets.gif
+      images/new_ticket.gif
+      images/new_ticket_icon.jpg
+      images/poweredby.jpg
+      images/rainbow.png
+      images/refresh_btn.gif
+      images/ticket_status.gif
+      images/ticket_status_icon.jpg
+      images/verticalbar.jpg
+      images/view_closed_btn.gif
+      images/view_open_btn.gif
+      include/class.msgtpl.php
+      include/class.sys.php
+      include/client/index.php
+      include/client/viewticket.inc.php
+      include/ost-config.sameple.php
+      include/staff/api.inc.php
+      include/staff/changepasswd.inc.php
+      include/staff/dept.inc.php
+      include/staff/depts.inc.php
+      include/staff/editticket.inc.php
+      include/staff/mypref.inc.php
+      include/staff/myprofile.inc.php
+      include/staff/newticket.inc.php
+      include/staff/premade.inc.php
+      include/staff/reply.inc.php
+      include/staff/smtp.inc.php
+      include/staff/viewticket.inc.php
+      scp/css/autosuggest_inquisitor.css
+      scp/css/datepicker.css
+      scp/css/main.css
+      scp/css/style.css
+      scp/css/tabs.css
+      scp/images/alert.png
+      scp/images/bg-login-box.gif
+      scp/images/icons/email_settings.gif
+      scp/images/logo-support.gif
+      scp/images/minus.gif
+      scp/images/ostlogo.jpg
+      scp/images/pagebg.jpg
+      scp/images/plus.gif
+      scp/images/refresh.gif
+      scp/images/tab.jpg
+      scp/images/view_closed.gif
+      scp/images/view_open.gif
+      scp/js/ajax.js
+      scp/js/autolock.js
+      scp/js/bsn.AutoSuggest_2.1.3.js
+      scp/js/calendar.js
+      scp/js/datepicker.js
+      scp/js/tabber.js
+
+  * Remove the setup/ folder. This contains code you won't need for a live
+    ticketing system.
diff --git a/WHATSNEW.md b/WHATSNEW.md
index 013fce7d70a0d3ea8fda4662f8d69da872771919..63abe0a617c3c5c558eda6c26dbc78c2d3dfebde 100644
--- a/WHATSNEW.md
+++ b/WHATSNEW.md
@@ -1,8 +1,19 @@
+New stuff in 1.7-rc1
+====================
+  * Upgrade support for osTicket 1.6-rc1 and later
+  * Multi-file upload support -- more than one file (configurable) can be
+    uploaded with new messages, replies, and internal notes via the web
+    interface
+  * Department/Group access feature allowing members of a group access to a
+    department. Staff members are members of a (primary) group, and that
+    group can be granted access to one or more departments, granting the
+    associated staff access to departments other than their primary
+    department.
+  * Email filters can specify a canned auto-response
+  * Support inline attachments for fetched email
+
 New stuff in 1.7-dpr4
 ======================
-
-Features
---------
   * Dashboard reports for ticket system activity and statistics
   * PDF print / export for tickets (staff pages only)
 
@@ -17,9 +28,6 @@ New stuff in 1.7-dpr3
 
 New stuff in 1.7-dpr2
 ======================
-
-Features
---------
   * Autocomplete for ticket search box (emails and ticket numbers typeahead)
   * Redesigned staff login page
   * Warning when leaving unsaved changes in admin and staff settings pages
@@ -29,25 +37,6 @@ Features
   * Preview ticket from the search results
   * Export tickets to CSV file
 
-Issues
-------
-  * (#1) Automatically cleanup orphaned attachments
-  * (#2) Reject ticket creation when a matching email filter has
-         'Reject email' set
-  * (#3) Ticket search results are properly paginated
-  * (#4) Make email filters editable
-  * (#5) Add .htaccess for API URLs rewrites
-  * (#6) Add utf-8 content type declaration for installer HTML output
-  * (#8) Fix installer for PHP settings with 'register_globals' enabled
-
-Outstanding
------------
-  * Implement the dashboard reports
-  * Advanced search form for ticket searches
-  * Multi-file upload for responses, notes, and new tickets
-  * PDF export for ticket thread
-  * Misc. improvements
-
 New Features in 1.7
 ===================
 Version 1.7 includes several new features
@@ -62,6 +51,7 @@ tickets:
   * To a specific department, staff member, and/or team
   * Automatically assign ticket priority and/or service-level-agreement
   * Disable ticket auto-responses
+  * Send automatic canned responses
 
 Canned Attachments
 ------------------
diff --git a/ajax.php b/ajax.php
new file mode 100644
index 0000000000000000000000000000000000000000..b40869292b81680ad136b9365793c616e0b0c3bb
--- /dev/null
+++ b/ajax.php
@@ -0,0 +1,34 @@
+<?php
+/*********************************************************************
+    ajax.php
+
+    Ajax utils for client interface.
+
+    Peter Rotich <peter@osticket.com>
+    Copyright (c)  2006-2012 osTicket
+    http://www.osticket.com
+
+    Released under the GNU General Public License WITHOUT ANY WARRANTY.
+    See LICENSE.TXT for details.
+
+    vim: expandtab sw=4 ts=4 sts=4:
+**********************************************************************/
+
+function clientLoginPage($msg='Unauthorized') {
+    Http::response(403,'Must login: '.Format::htmlchars($msg));
+    exit;
+}
+
+require('client.inc.php');
+
+if(!defined('INCLUDE_DIR'))	Http::response(500, 'Server configuration error');
+require_once INCLUDE_DIR.'/class.dispatcher.php';
+require_once INCLUDE_DIR.'/class.ajax.php';
+
+$dispatcher = patterns('',
+    url('^/config/', patterns('ajax.config.php:ConfigAjaxAPI',
+        url_get('^client', 'client')
+    ))
+);
+print $dispatcher->resolve($_SERVER['PATH_INFO']);
+?>
diff --git a/api/.htaccess b/api/.htaccess
index e230ac6e186f66ada37cca3809396e32b98473e1..e73e2eb3b9c3f1204223b4426274817c0200e279 100644
--- a/api/.htaccess
+++ b/api/.htaccess
@@ -1,4 +1,3 @@
-Options +FollowSymLinks
 RewriteEngine On
 
 RewriteBase /api/
diff --git a/api/pipe.php b/api/pipe.php
index b4e5e5ad5c247cb93de0dad36281651d2d2a365d..29dfcff1d1aa10a20386589927830ffed8211911 100644
--- a/api/pipe.php
+++ b/api/pipe.php
@@ -21,7 +21,7 @@ require_once(INCLUDE_DIR.'class.mailparse.php');
 require_once(INCLUDE_DIR.'class.email.php');
 
 //Make sure piping is enabled!
-if(!$cfg->enableEmailPiping())
+if(!$cfg->isEmailPipingEnabled())
     api_exit(EX_UNAVAILABLE,'Email piping not enabled - check MTA settings.');
 //Get the input
 $data=isset($_SERVER['HTTP_HOST'])?file_get_contents('php://input'):file_get_contents('php://stdin');
@@ -87,7 +87,7 @@ $var['emailId']=$emailId?$emailId:$cfg->getDefaultEmailId();
 $var['subject']=$subj?$subj:'[No Subject]';
 $var['message']=utf8_encode(Format::stripEmptyLines($body));
 $var['header']=$parser->getHeader();
-$var['pri']=$cfg->useEmailPriority()?$parser->getPriority():0;
+$var['priorityId']=$cfg->useEmailPriority()?$parser->getPriority():0;
 
 $ticket=null;
 if(preg_match ("[[#][0-9]{1,10}]",$var['subject'],$regs)) {
@@ -99,33 +99,25 @@ if(preg_match ("[[#][0-9]{1,10}]",$var['subject'],$regs)) {
 }        
 $errors=array();
 $msgid=0;
-if(!$ticket){ //New tickets...
-    # Apply filters against the new ticket
-    $ef = new EmailFilter($var); $ef->apply($var);
+if(!$ticket) { //New tickets...
     $ticket=Ticket::create($var,$errors,'email');
-    if(!is_object($ticket) || $errors){
+    if(!is_object($ticket) || $errors) {
         api_exit(EX_DATAERR,'Ticket create Failed '.implode("\n",$errors)."\n\n");
     }
+
     $msgid=$ticket->getLastMsgId();
-}else{
-    $message=$var['message'];
-    //Strip quoted reply...TODO: figure out how mail clients do it without special tag..
-    if($cfg->stripQuotedReply() && ($tag=$cfg->getReplySeparator()) && strpos($var['message'],$tag))
-        list($message)=split($tag,$var['message']);
+
+} else {
     //post message....postMessage does the cleanup.
-    if(!($msgid=$ticket->postMessage($message,'Email',$var['mid'],$var['header']))) {
-        api_exit(EX_DATAERR,"Unable to post message \n\n $message\n");
+    if(!($msgid=$ticket->postMessage($var['message'], 'Email',$var['mid'],$var['header']))) {
+        api_exit(EX_DATAERR, 'Unable to post message');
     }
 }
 //Ticket created...save attachments if enabled.
-if($cfg->allowEmailAttachments()) {                   
-    if($attachments=$parser->getAttachments()){
-        //print_r($attachments);
-        foreach($attachments as $k=>$attachment){
-            if($attachment['filename'] && $cfg->canUploadFileType($attachment['filename'])) {
-                $ticket->saveAttachment($attachment['filename'],$attachment['body'],$msgid,'M');
-            }
-        }
+if($cfg->allowEmailAttachments() && ($attachments=$parser->getAttachments())) {
+    foreach($attachments as $attachment) {
+        if($attachment['filename'] && $ost->isFileTypeAllowed($attachment['filename']))
+            $ticket->saveAttachment(array('name' => $attachment['filename'], 'data' => $attachment['body']), $msgid, 'M');
     }
 }
 api_exit(EX_SUCCESS);
diff --git a/assets/default/css/theme.css b/assets/default/css/theme.css
index 88c4898a80b62ae5be6ede550948a3e217fd3a8a..b59f6af8955857d2008dff647e8e4d83d4924e72 100644
--- a/assets/default/css/theme.css
+++ b/assets/default/css/theme.css
@@ -106,10 +106,12 @@ table {
   border-spacing: 0;
 }
 
-td {
+th, td {
   vertical-align: top;
 }
 
+th { text-align: left; font-weight: normal; }
+
 h1, h2, h3, h4, h5, h6, form, fieldset {
   margin: 0;
   padding: 0;
@@ -516,17 +518,23 @@ body {
   display: block;
   float: left;
 }
+
+#ticketForm div input[type=file] {
+  border: 0;
+}
+
 #ticketForm div select, #clientLogin div select {
   display: block;
   float: left;
 }
-#ticketForm div textarea, #clientLogin div textarea {
+#ticketForm td textarea, #clientLogin div textarea {
   width: 600px;
 }
-#ticketForm div em, #clientLogin div em {
+
+#ticketForm td em, #clientLogin div em {
   color: #777;
 }
-#ticketForm div .captcha, #clientLogin div .captcha {
+#ticketForm td .captcha, #clientLogin div .captcha {
   width: 88px;
   height: 31px;
   background: #000;
@@ -534,20 +542,33 @@ body {
   float: left;
   margin-right: 20px;
 }
-#ticketForm div label.inline, #clientLogin div label.inline {
+#ticketForm td label.inline, #clientLogin div label.inline {
   width: auto;
   padding: 0 10px;
 }
-#ticketForm div label.required, #clientLogin div label.required {
+
+#ticketTable table tr th { 
+  width: 160px;
+  font-weight: normal;
+  text-align: left;
+}
+
+#ticketForm table th.required, #ticketForm table td.required, #clientLogin div label.required {
   font-weight: bold;
+  text-align: left;
 }
-#ticketForm div.captchaRow, #clientLogin div.captchaRow {
+
+
+
+#ticketForm tr.captchaRow, #clientLogin div.captchaRow {
   line-height: 31px;
 }
-#ticketForm div.captchaRow input, #clientLogin div.captchaRow input {
+
+.captchaRow td input, #clientLogin div.captchaRow input {
   position: relative;
   top: 6px;
 }
+
 #ticketForm div.error input, #clientLogin div.error input {
   border: 1px solid #a00;
 }
@@ -797,6 +818,14 @@ a.refresh {
     font-family:helvetica, arial, sans-serif;
 }
 
+
+.uploads {
+    display:inline-block;
+    padding-right:20px;
+}
+
+.uploads label { padding:3px; padding-right:10px; width: auto !important }
+
 .button:hover                          { background-color: #111; color: #fff; }
 .button:active                         { top: 1px; box-shadow:none; -moz-box-shadow:none; -webkit-box-shadow:none; }
 .button, .button:visited,
diff --git a/client.inc.php b/client.inc.php
index 1908eaa1b5d5172fffaccfbee69f6f17e4871d1e..91956c0d7dfc36e5ffb374f0812cea2f9693c6b9 100644
--- a/client.inc.php
+++ b/client.inc.php
@@ -51,8 +51,17 @@ if($_SESSION['_client']['userID'] && $_SESSION['_client']['key'])
 if($thisclient && $thisclient->getId() && $thisclient->isValid()){
      $thisclient->refreshSession();
 }
+
+/******* CSRF Protectin *************/
+// Enforce CSRF protection for POSTS
+if ($_POST  && !$ost->checkCSRFToken()) {
+    @header('Location: index.php');
+    //just incase redirect fails
+    die('Action denied (400)!');
+}
+
 /* Client specific defaults */
-define('PAGE_LIMIT',DEFAULT_PAGE_LIMIT);
+define('PAGE_LIMIT', DEFAULT_PAGE_LIMIT);
 
 $nav = new UserNav($thisclient, 'home');
 ?>
diff --git a/include/ajax.config.php b/include/ajax.config.php
index fc9fb2c3fc8622108054052828b7e6bb9a42dcd6..feb1eb4b0646f75762c554e73e55b7d7701b9680 100644
--- a/include/ajax.config.php
+++ b/include/ajax.config.php
@@ -19,12 +19,26 @@ if(!defined('INCLUDE_DIR')) die('!');
 class ConfigAjaxAPI extends AjaxController {
 
     //config info UI might need.
-    function scp_ui() {
-        global $thisstaff, $cfg;
+    function scp() {
+        global $cfg;
+
+        $config=array(
+                      'lock_time'       => ($cfg->getLockTime()*3600),
+                      'file_types'      => $cfg->getAllowedFileTypes(),
+                      'max_file_size'   => (int) $cfg->getMaxFileSize(),
+                      'max_file_uploads'=> (int) $cfg->getStaffMaxFileUploads()
+                      );
+        return $this->json_encode($config);
+    }
+
+    function client() {
+        global $cfg;
 
-        $config=array('ticket_lock_time'=>($cfg->getLockTime()*3600),
-                      'max_attachments'=>$cfg->getMaxFileUploads(),
-                      'max_file_size'=>$cfg->getMaxFileSize());
+        $config=array(
+                      'file_types'      => $cfg->getAllowedFileTypes(),
+                      'max_file_size'   => (int) $cfg->getMaxFileSize(),
+                      'max_file_uploads'=> (int) $cfg->getClientMaxFileUploads()
+                      );
 
         return $this->json_encode($config);
     }
diff --git a/include/ajax.reports.php b/include/ajax.reports.php
index 8b09100225f0d875c93476253a7eab4ae81873b4..9d002eb52c698a6788e33635f5576c22560d93df 100644
--- a/include/ajax.reports.php
+++ b/include/ajax.reports.php
@@ -35,8 +35,12 @@ class OverviewReportAjaxAPI extends AjaxController {
     }
 
     function getData() {
-        $start = $this->get('start', strtotime('last month'));
-        $stop = $this->get('stop', time());
+        $start = $this->get('start', 'last month');
+        $stop = $this->get('stop', 'now');
+        if (substr($stop, 0, 1) == '+')
+            $stop = $start . $stop;
+        $start = 'FROM_UNIXTIME('.strtotime($start).')';
+        $stop = 'FROM_UNIXTIME('.strtotime($stop).')';
 
         $groups = array(
             "dept" => array(
@@ -67,45 +71,51 @@ class OverviewReportAjaxAPI extends AjaxController {
         $info = $groups[$group];
         # XXX: Die if $group not in $groups
 
-        $res = db_query(
-            'SELECT ' . $info['fields'] . ','
-                .'(SELECT COUNT(A1.ticket_id) FROM '.TICKET_TABLE
-                    .' A1 WHERE A1.'.$info['pk'].' = T1.'.$info['pk']
-                    .'   AND A1.status=\'open\') AS Open,'
-                .'(SELECT COUNT(A1.ticket_id) FROM '.TICKET_TABLE
-                    .' A1 WHERE A1.'.$info['pk'].' = T1.'.$info['pk']
-                    .'   AND (A1.staff_id > 0 OR A1.team_id > 0)'
-                    .'   AND A1.status=\'open\') AS Assigned,'
-                .'(SELECT COUNT(A1.ticket_id) FROM '.TICKET_TABLE
-                    .' A1 WHERE A1.'.$info['pk'].' = T1.'.$info['pk']
-                    .'   AND (A1.staff_id = 0 AND A1.team_id = 0)'
-                    .'   AND A1.status=\'open\') AS Unassigned,'
-                .'(SELECT COUNT(A1.ticket_id) FROM '.TICKET_TABLE
-                    .' A1 WHERE A1.'.$info['pk'].' = T1.'.$info['pk']
-                    .'   AND A1.isanswered = 0'
-                    .'   AND A1.status=\'open\') AS Unanswered,'
-                .'(SELECT COUNT(A1.ticket_id) FROM '.TICKET_TABLE
-                    .' A1 WHERE A1.'.$info['pk'].' = T1.'.$info['pk']
-                    .'   AND A1.isoverdue = 1'
-                    .'   AND A1.status=\'open\') AS Overdue,'
-                .'(SELECT COUNT(A1.ticket_id) FROM '.TICKET_TABLE
-                    .' A1 WHERE A1.'.$info['pk'].' = T1.'.$info['pk']
-                    .'   AND A1.status=\'closed\') AS Closed,'
-                .'(SELECT COUNT(A1.ticket_id) FROM '.TICKET_TABLE
-                    .' A1 WHERE A1.'.$info['pk'].' = T1.'.$info['pk']
-                    .'   AND A1.reopened is not null) AS Reopened,'
-                .'(SELECT FORMAT(AVG(DATEDIFF(A1.closed, A1.created)),1) FROM '.TICKET_TABLE
-                    .' A1 WHERE A1.'.$info['pk'].' = T1.'.$info['pk']
-                    .'   AND A1.status=\'closed\') AS ServiceTime'
-            .' FROM ' . $info['table'] . ' T1'
+        $queries=array(
+            array(5, 'SELECT '.$info['fields'].',
+                COUNT(*)-COUNT(NULLIF(A1.state, "created")) AS Opened,
+                COUNT(*)-COUNT(NULLIF(A1.state, "assigned")) AS Assigned,
+                COUNT(*)-COUNT(NULLIF(A1.state, "overdue")) AS Overdue,
+                COUNT(*)-COUNT(NULLIF(A1.state, "closed")) AS Closed,
+                COUNT(*)-COUNT(NULLIF(A1.state, "reopened")) AS Reopened
+            FROM '.$info['table'].' T1 LEFT JOIN '.TICKET_TABLE.' T2 USING ('.$info['pk'].')
+                LEFT JOIN '.TICKET_EVENT_TABLE.' A1 USING (ticket_id)
+            WHERE A1.timestamp BETWEEN '.$start.' AND '.$stop.'
+            GROUP BY '.$info['fields'].'
+            ORDER BY '.$info['fields']),
+
+            array(1, 'SELECT '.$info['fields'].',
+                FORMAT(AVG(DATEDIFF(T2.closed, T2.created)),1) AS ServiceTime
+            FROM '.$info['table'].' T1 LEFT JOIN '.TICKET_TABLE.' T2 USING ('.$info['pk'].')
+            WHERE T2.closed BETWEEN '.$start.' AND '.$stop.'
+            GROUP BY '.$info['fields'].'
+            ORDER BY '.$info['fields']),
+
+            array(1, 'SELECT '.$info['fields'].',
+                FORMAT(AVG(DATEDIFF(B2.created, B1.created)),1) AS ResponseTime
+            FROM '.$info['table'].' T1 LEFT JOIN '.TICKET_TABLE.' T2 USING ('.$info['pk'].')
+                LEFT JOIN '.TICKET_THREAD_TABLE.' B2 ON (B2.ticket_id = T2.ticket_id
+                    AND B2.thread_type="R")
+                LEFT JOIN '.TICKET_THREAD_TABLE.' B1 ON (B2.pid = B1.id)
+            WHERE B1.created BETWEEN '.$start.' AND '.$stop.'
+            GROUP BY '.$info['fields'].'
+            ORDER BY '.$info['fields'])
         );
         $rows = array();
-        while ($row = db_fetch_row($res)) {
-            $rows[] = $row;
+        foreach ($queries as $q) {
+            list($c, $sql) = $q;
+            $res = db_query($sql);
+            $i = 0;
+            while ($row = db_fetch_row($res)) {
+                if (count($rows) <= $i)
+                    $rows[] = array_slice($row, 0, count($row) - $c);
+                $rows[$i] = array_merge($rows[$i], array_slice($row, -$c));
+                $i++;
+            }
         }
         return array("columns" => array_merge($info['headers'],
-                        array('Open','Assigned','Unassigned','Unanswered',
-                              'Overdue','Closed','Reopened','Service Time')),
+                        array('Open','Assigned','Overdue','Closed','Reopened',
+                              'Service Time','Response Time')),
                      "data" => $rows);
     }
 
diff --git a/include/ajax.tickets.php b/include/ajax.tickets.php
index f67581005194848131dbaf1c709b8c238c8e404a..b402d6efce3e5914ba2c3cec2471b2d534312cbc 100644
--- a/include/ajax.tickets.php
+++ b/include/ajax.tickets.php
@@ -180,7 +180,7 @@ class TicketsAjaxAPI extends AjaxController {
 
     function acquireLock($tid) {
         global $cfg,$thisstaff;
-        
+
         if(!$tid or !is_numeric($tid) or !$thisstaff or !$cfg) 
             return 0;
        
diff --git a/include/ajax.upgrader.php b/include/ajax.upgrader.php
new file mode 100644
index 0000000000000000000000000000000000000000..b04dfca4f3f429ef73536fccc9929fda33e797c2
--- /dev/null
+++ b/include/ajax.upgrader.php
@@ -0,0 +1,73 @@
+<?php
+/*********************************************************************
+    ajax.upgrader.php
+
+    AJAX interface for Upgrader
+
+    Peter Rotich <peter@osticket.com>
+    Copyright (c)  2006-2012 osTicket
+    http://www.osticket.com
+
+    Released under the GNU General Public License WITHOUT ANY WARRANTY.
+    See LICENSE.TXT for details.
+
+    vim: expandtab sw=4 ts=4 sts=4:
+**********************************************************************/
+
+if(!defined('INCLUDE_DIR')) die('403');
+require_once INCLUDE_DIR.'class.upgrader.php';
+
+class UpgraderAjaxAPI extends AjaxController {
+
+    function upgrade() {
+        global $thisstaff, $ost;
+
+        if(!$thisstaff or !$thisstaff->isAdmin() or !$ost)
+            Http::response(403, 'Access Denied');
+
+        $upgrader = new Upgrader($ost->getDBSignature(), TABLE_PREFIX, SQL_DIR);
+
+        //Just report the next action on the first call.
+        if(!$_SESSION['ost_upgrader'] || !$_SESSION['ost_upgrader'][$upgrader->getShash()]['progress']) {
+            $_SESSION['ost_upgrader'][$upgrader->getShash()]['progress'] = $upgrader->getNextAction();
+            Http::response(200, $upgrader->getNextAction());
+            exit;
+        }
+
+        if($upgrader->isAborted()) {
+            Http::response(416, "We have a problem ... wait a sec.");
+            exit;
+        }
+
+        if($upgrader->getNumPendingTasks() && $upgrader->doTasks()) {
+            //More pending tasks - doTasks returns the number of pending tasks
+            Http::response(200, $upgrader->getNextAction());
+            exit;
+        } elseif($ost->isUpgradePending()) {
+            if($upgrader->isUpgradable()) {
+                $version = $upgrader->getNextVersion();
+                if($upgrader->upgrade()) {
+                    //We're simply reporting progress here - call back will report next action'
+                    Http::response(200, "Upgraded to $version ... post-upgrade checks!");
+                    exit;
+                }
+            } else { 
+                //Abort: Upgrade pending but NOT upgradable - invalid or wrong hash.
+                $upgrader->abort(sprintf('Upgrade Failed: Invalid or wrong hash [%s]',$ost->getDBSignature()));
+            }
+        } elseif(!$ost->isUpgradePending()) {
+            $upgrader->setState('done');
+            session_write_close();
+            Http::response(201, "We're done!");
+            exit;
+        }
+
+        if($upgrader->isAborted() || $upgrader->getErrors()) {
+            Http::response(416, "We have a problem ... wait a sec.");
+            exit;
+        }
+
+        Http::response(200, $upgrader->getNextAction());
+    }
+}
+?>
diff --git a/include/api.ticket.php b/include/api.ticket.php
index d767e2128ba2ee4f60abcc44f2fc10b2f4af1a23..4fcae4b183925dfe32bb91c95275a986fc492ea6 100644
--- a/include/api.ticket.php
+++ b/include/api.ticket.php
@@ -10,7 +10,7 @@ class TicketController extends ApiController {
     # so that all supported input formats should be supported
     function getRequestStructure($format) {
         $supported = array(
-            "alert", "autorespond", "source",
+            "alert", "autorespond", "source", "topicId",
             "name", "email", "subject", "phone", "phone_ext",
             "attachments" => array("*" => 
                 array("name", "type", "data", "encoding")
@@ -33,8 +33,10 @@ class TicketController extends ApiController {
         $autorespond = $data['autorespond'] ? $data['autorespond'] : true;
         $source = $data['source'] ? $data['source'] : 'API';
 
-        # TODO: Handle attachment encoding (base64)
-        foreach ($data["attachments"] as $filename=>&$info) {
+        $attachments = $data['attachments'] ? $data['attachments'] : array();
+
+		# TODO: Handle attachment encoding (base64)
+        foreach ($attachments as $filename=>&$info) {
             if ($info["encoding"] == "base64") {
                 # XXX: May fail on large inputs. See
                 #      http://us.php.net/manual/en/function.base64-decode.php#105512
@@ -60,7 +62,7 @@ class TicketController extends ApiController {
         }
 
         # Save attachment(s)
-        foreach ($data["attachments"] as &$info)
+        foreach ($attachments as &$info)
             $ticket->saveAttachment($info, $ticket->getLastMsgId(), "M");
 
         # All done. Return HTTP/201 --> Created
diff --git a/include/class.ajax.php b/include/class.ajax.php
index 0240d91f83521393f31f73261562e1367b89e618..5bd26a67e13812966bd90164462c37083f52cd5f 100644
--- a/include/class.ajax.php
+++ b/include/class.ajax.php
@@ -26,11 +26,7 @@ require_once (INCLUDE_DIR.'class.api.php');
  */
 class AjaxController extends ApiController {
     function AjaxController() {
-        # Security checks first
-        # --> It is assumed that all AJAX calls will require a login. And
-        #     for now, since client logins are not yet supported, a staff
-        #     login will be required for AJAX calls.
-        $this->staffOnly();
+    
     }
     function staffOnly() {
         global $thisstaff;
diff --git a/include/class.canned.php b/include/class.canned.php
index 09a3877ada46bb507b649e65294bc6c0430399dd..399b490d3a9cf3c1832fc4892c66ccd4aed06f6f 100644
--- a/include/class.canned.php
+++ b/include/class.canned.php
@@ -31,9 +31,11 @@ class Canned {
         if(!$id && !($id=$this->getId()))
             return false;
 
-        $sql='SELECT canned.*, count(attach.file_id) as attachments '
+        $sql='SELECT canned.*, count(attach.file_id) as attachments, '
+            .' count(filter.id) as filters '
             .' FROM '.CANNED_TABLE.' canned '
             .' LEFT JOIN '.CANNED_ATTACHMENT_TABLE.' attach ON (attach.canned_id=canned.canned_id) ' 
+            .' LEFT JOIN '.EMAIL_FILTER_TABLE.' filter ON (canned.canned_id = filter.canned_response_id) '
             .' WHERE canned.canned_id='.db_input($id);
         if(!($res=db_query($sql)) ||  !db_num_rows($res))
             return false;
@@ -62,6 +64,9 @@ class Canned {
         return $this->isEnabled();
     }
 
+    function getNumFilters() {
+        return $this->ht['filters'];
+    }
     
     function getTitle() {
         return $this->ht['title'];
@@ -91,6 +96,19 @@ class Canned {
         return $this->getHashtable();
     }
 
+    function getFilters() {
+        if (!$this->_filters) {
+            $this->_filters = array();
+            $res = db_query(
+                  'SELECT name FROM '.EMAIL_FILTER_TABLE
+                .' WHERE canned_response_id = '.db_input($this->getId())
+                .' ORDER BY name');
+            while ($row = db_fetch_row($res))
+                $this->_filters[] = $row[0];
+        }
+        return $this->_filters;
+    }
+
     function update($vars, &$errors) {
 
         if(!$this->save($this->getId(),$vars,$errors))
@@ -168,6 +186,7 @@ class Canned {
     }
 
     function delete(){
+        if ($this->getNumFilters() > 0) return false;
 
         $sql='DELETE FROM '.CANNED_TABLE.' WHERE canned_id='.db_input($this->getId()).' LIMIT 1';
         if(db_query($sql) && ($num=db_affected_rows())) {
diff --git a/include/class.config.php b/include/class.config.php
index cb7cd40aed575013ee1db136d15037438d6b34fb..cc9b497682097d0e622dbbd410b0a4f5b0fae601 100644
--- a/include/class.config.php
+++ b/include/class.config.php
@@ -77,12 +77,18 @@ class Config {
         return THIS_VERSION;
     }
 
+    //Used to detect version prior to 1.7 (useful during upgrade)
+    function getDBVersion() {
+        return $this->config['ostversion'];
+    }
+
     function getSchemaSignature() {
 
         if($this->config['schema_signature'])
             return $this->config['schema_signature'];
-        elseif($this->config['ostversion']) //old version 1.6 st.
-            return md5(strtoupper($this->config['ostversion']));
+
+        if($this->config['ostversion']) //old version 1.6 RC[1-5]-ST
+            return md5(strtoupper(trim($this->config['ostversion'])));
 
         return null;
     }
@@ -289,10 +295,15 @@ class Config {
         return $this->config['max_file_size'];
     }
 
-    function getMaxFileUploads() {
+    function getStaffMaxFileUploads() {
         return $this->config['max_staff_file_uploads'];
     }
 
+    function getClientMaxFileUploads() {
+        //TODO: change max_user_file_uploads to max_client_file_uploads
+        return $this->config['max_user_file_uploads'];
+    }
+
     function getLogLevel() {
         return $this->config['log_level'];
     }
@@ -309,23 +320,23 @@ class Config {
         return ($this->config['clickable_urls']);
     }
         
-    function canFetchMail() {
-        return ($this->config['enable_mail_polling']);
-    }
-
     function enableStaffIPBinding() {
         return ($this->config['staff_ip_binding']);
     }
 
-    function enableCaptcha() {
+    function isCaptchaEnabled() {
         return (extension_loaded('gd') && function_exists('gd_info') && $this->config['enable_captcha']);
     }
 
-    function enableAutoCron() {
+    function isAutoCronEnabled() {
         return ($this->config['enable_auto_cron']);
     }
+
+    function isEmailPollingEnabled() {
+        return ($this->config['enable_mail_polling']);
+    }
         
-    function enableEmailPiping() {
+    function isEmailPipingEnabled() {
         return ($this->config['enable_email_piping']);
     }
 
@@ -503,6 +514,9 @@ class Config {
     
 
     /* Attachments */
+    function getAllowedFileTypes() {
+        return trim($this->config['allowed_filetypes']);
+    }
 
     function emailAttachments() {
         return ($this->config['email_attachments']);
@@ -524,22 +538,11 @@ class Config {
         return ($this->allowAttachments() && $this->config['allow_email_attachments']);
     }
 
+    /* Needed by upgrader on 1.6 and older releases upgrade - not not remove */
     function getUploadDir() {
         return $this->config['upload_dir'];
     }
     
-    //simply checking if destination dir is usable..nothing to do with permission to upload!
-    function canUploadFiles() {   
-        $dir=$this->config['upload_dir'];
-        return ($dir && is_writable($dir))?TRUE:FALSE;
-    }
-
-    function canUploadFileType($filename) {       
-        $ext = strtolower(preg_replace("/.*\.(.{3,4})$/", "$1", $filename));
-        $allowed=$this->config['allowed_filetypes']?array_map('trim',explode(',',strtolower($this->config['allowed_filetypes']))):null;
-        return ($ext && is_array($allowed) && (in_array(".$ext",$allowed) || in_array(".*",$allowed)))?TRUE:FALSE;
-    }
-
     function updateSettings($vars,&$errors) {
 
         if(!$vars || $errors)
@@ -730,10 +733,10 @@ class Config {
                 $maxfileuploads=DEFAULT_MAX_FILE_UPLOADS;
 
             if(!$vars['max_user_file_uploads'] || $vars['max_user_file_uploads']>$maxfileuploads)
-                $errors['max_user_file_uploads']='Invalid selection';
+                $errors['max_user_file_uploads']='Invalid selection. Must be less than '.$maxfileuploads;
 
             if(!$vars['max_staff_file_uploads'] || $vars['max_staff_file_uploads']>$maxfileuploads)
-                $errors['max_staff_file_uploads']='Invalid selection';
+                $errors['max_staff_file_uploads']='Invalid selection. Must be less than '.$maxfileuploads;
         }
 
         if($errors) return false;
diff --git a/include/class.cron.php b/include/class.cron.php
index c8e3a81def985b99eb0f21eaea8751362e1ced05..15ca7078b27785b6721b0a9f04b2d4b84eb28c9c 100644
--- a/include/class.cron.php
+++ b/include/class.cron.php
@@ -20,7 +20,7 @@ class Cron {
 
     function MailFetcher() {
         require_once(INCLUDE_DIR.'class.mailfetch.php');
-        MailFetcher::fetchMail(); //Fetch mail..frequency is limited by email account setting.
+        MailFetcher::run(); //Fetch mail..frequency is limited by email account setting.
     }
 
     function TicketMonitor() {
diff --git a/include/class.csrf.php b/include/class.csrf.php
new file mode 100644
index 0000000000000000000000000000000000000000..bfa792901167b58892e88e805728e9d72a337df7
--- /dev/null
+++ b/include/class.csrf.php
@@ -0,0 +1,93 @@
+<?php
+/*********************************************************************
+    class.csrf.php
+
+    Provides mechanisms to protect against cross-site request forgery
+    attacks. This is accomplished by using a token that is not stored in a
+    session, but required to make changes to the system.
+
+    This can be accomplished by emitting a hidden field in a form, or
+    sending a separate header (X-CSRFToken) when forms are submitted (e.g Ajax).
+
+    This technique is based on the protection mechanism in the Django
+    project, detailed at and thanks to
+    https://docs.djangoproject.com/en/dev/ref/contrib/csrf/.
+
+    * TIMEOUT
+    Token can be expired after X seconds of inactivity (timeout) independent of the session.
+    
+
+    Jared Hancock 
+    Copyright (c)  2006-2012 osTicket
+    http://www.osticket.com
+
+    Released under the GNU General Public License WITHOUT ANY WARRANTY.
+    See LICENSE.TXT for details.
+
+    vim: expandtab sw=4 ts=4 sts=4:
+**********************************************************************/
+
+Class CSRF {
+
+    var $name;
+    var $timeout;
+
+    var $csrf;
+
+    function CSRF($name='__CSRFToken__', $timeout=0) {
+
+        $this->name = $name;
+        $this->timeout = $timeout;
+        $this->csrf = &$_SESSION['csrf'];
+    }
+
+    function reset() {
+        $this->csrf = array();
+    }
+
+    function isExpired() {
+       return ($this->timeout && (time()-$this->csrf['time'])>$this->timeout);
+    }
+
+    function getTokenName() {
+        return $this->name;
+    }
+
+    function getToken($len=32) {
+
+        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['time'] = time();
+        } else {
+            //Reset the timer
+            $this->csrf['time'] = time();
+        }
+
+        return $this->csrf['token'];
+    }
+
+    function validateToken($token) {
+        return ($token && trim($token)==$this->getToken() && !$this->isExpired());
+    }
+
+    function getFormInput($name='') {
+        if(!$name) $name = $this->name;
+
+        return sprintf('<input type="hidden" name="%s" value="%s" />', $name, $this->getToken());
+    }
+}
+
+/* global function to add hidden token input with to forms */
+function csrf_token() {
+    global $ost;
+
+    if($ost && $ost->getCSRF())
+        echo $ost->getCSRFFormInput();
+}
+?>
diff --git a/include/class.dept.php b/include/class.dept.php
index 5a2babdd3da4021a7b81c736a79210fdf11f1d97..5516646129b348de5eba208d005c8ab87d2f4145 100644
--- a/include/class.dept.php
+++ b/include/class.dept.php
@@ -19,6 +19,9 @@ class Dept {
     var $email;
     var $sla;
     var $manager; 
+    var $members;
+    var $groups;
+
     var $ht;
   
     function Dept($id){
@@ -47,7 +50,7 @@ class Dept {
         $this->id=$this->ht['dept_id'];
         $this->email=$this->sla=$this->manager=null;
         $this->getEmail(); //Auto load email struct.
-        $this->members=array();
+        $this->members=$this->groups=array();
 
         return true;
     }
@@ -81,30 +84,39 @@ class Dept {
         return $this->ht['users'];
     }
 
-    function getNumMembers(){
-        return $this->getNumStaff();
-    }
-
+     
     function getNumUsers(){
         return $this->getNumStaff();
     }
 
-    function getAvailableMembers(){
-
-        if(!$this->members && $this->getNumStaff()){
-            $sql='SELECT m.staff_id FROM '.STAFF_TABLE.' m '
-                .'WHERE m.dept_id='.db_input($this->getId())
-                .' AND m.staff_id IS NOT NULL '
-                .'ORDER BY m.lastname, m.firstname';
-            if(($res=db_query($sql)) && db_num_rows($res)){
+    function getNumMembers(){
+        return count($this->getMembers());
+    }
+
+    function getMembers() {
+
+        if(!$this->members) {
+            $this->members = array();
+            $sql='SELECT DISTINCT s.staff_id FROM '.STAFF_TABLE.' s '
+                .' LEFT JOIN '.GROUP_DEPT_TABLE.' g ON(s.group_id=g.group_id) '
+                .' INNER JOIN '.DEPT_TABLE.' d 
+                       ON(d.dept_id=s.dept_id 
+                            OR d.manager_id=s.staff_id 
+                            OR (d.dept_id=g.dept_id AND d.group_membership=1)
+                        ) '
+                .' WHERE d.dept_id='.db_input($this->getId())
+                .' ORDER BY s.lastname, s.firstname';
+           
+            if(($res=db_query($sql)) && db_num_rows($res)) {
                 while(list($id)=db_fetch_row($res))
-                    if(($staff=Staff::lookup($id)) && $staff->isAvailable())
-                        $this->members[]= $staff;
+                    $this->members[] = Staff::lookup($id);
             }
         }
+
         return $this->members;
     }
 
+
     function getSLAId(){
         return $this->ht['sla_id'];
     }
@@ -179,6 +191,11 @@ class Dept {
     function noreplyAutoResp(){
          return ($this->ht['noreply_autoresp']);
     }
+
+
+    function isGroupMembershipEnabled() {
+        return ($this->ht['group_membership']);
+    }
    
     function getHashtable() {
         return $this->ht;
@@ -188,14 +205,53 @@ class Dept {
         return $this->getHashtable();
     }
 
-    function update($vars,&$errors){
 
-        if($this->save($this->getId(),$vars,$errors)) {
-            $this->reload();
-            return true;
+      
+    function getAllowedGroups() {
+
+        if($this->groups) return $this->groups;
+
+        $sql='SELECT group_id FROM '.GROUP_DEPT_TABLE
+            .' WHERE dept_id='.db_input($this->getId());
+
+        if(($res=db_query($sql)) && db_num_rows($res)) {
+            while(list($id)=db_fetch_row($res))
+                $this->groups[] = $id;
         }
 
-        return false;
+        return $this->groups;
+    }
+
+    function updateAllowedGroups($groups) {
+
+        if($groups && is_array($groups)) {
+            foreach($groups as $k=>$id) {
+                $sql='INSERT IGNORE INTO '.GROUP_DEPT_TABLE
+                    .' SET dept_id='.db_input($this->getId()).', group_id='.db_input($id);
+                db_query($sql);
+            }
+        }
+
+            
+        $sql='DELETE FROM '.GROUP_DEPT_TABLE.' WHERE dept_id='.db_input($this->getId());
+        if($groups && is_array($groups))  
+            $sql.=' AND group_id NOT IN('.implode(',', db_input($groups)).')';
+
+        db_query($sql);
+
+        return true;
+
+    }
+
+    function update($vars,&$errors){
+
+        if(!$this->save($this->getId(),$vars,$errors))
+            return false;
+
+        $this->updateAllowedGroups($vars['groups']);
+        $this->reload();
+        
+        return true;
     }
 
     function delete() {
@@ -214,7 +270,8 @@ class Dept {
             db_query('UPDATE '.STAFF_TABLE.' SET dept_id='.db_input($cfg->getDefaultDeptId()).' WHERE dept_id='.db_input($id));
             //make help topic using the dept default to default-dept.
             db_query('UPDATE '.TOPIC_TABLE.' SET dept_id='.db_input($cfg->getDefaultDeptId()).' WHERE dept_id='.db_input($id));
-            
+            //Delete group access
+            db_query('DELETE FROM '.GROUP_DEPT_TABLE.' WHERE dept_id='.db_input($id));
         }
 
         return $num;
@@ -267,7 +324,10 @@ class Dept {
     }
 
     function create($vars,&$errors) {
-        return Dept::save(0,$vars,$errors);
+        if(($id=self::save(0, $vars, $errors)) && ($dept=self::lookup($id)))
+            $dept->updateAllowedGroups($vars['groups']);
+
+        return $id;
     }
 
     function save($id,$vars,&$errors) {
@@ -305,6 +365,7 @@ class Dept {
             .' ,manager_id='.db_input($vars['manager_id']?$vars['manager_id']:0)
             .' ,dept_name='.db_input(Format::striptags($vars['name']))
             .' ,dept_signature='.db_input(Format::striptags($vars['signature']))
+            .' ,group_membership='.db_input(isset($vars['group_membership'])?1:0)
             .' ,ticket_auto_response='.db_input(isset($vars['ticket_auto_response'])?$vars['ticket_auto_response']:1)
             .' ,message_auto_response='.db_input(isset($vars['message_auto_response'])?$vars['message_auto_response']:1);
 
diff --git a/include/class.email.php b/include/class.email.php
index dba9a45d5d4c569c9a5e7b2c17c4254f12abdcee..e6b10c3892ece68f9d0410a77116f67cf7de61dd 100644
--- a/include/class.email.php
+++ b/include/class.email.php
@@ -98,6 +98,27 @@ class Email {
         return $this->getHashtable();
     }
 
+    function getMailAccountInfo() {
+
+        /*NOTE: Do not change any of the tags - otherwise mail fetching will fail */
+        $info = array(
+                //Mail server info
+                'host'  => $this->ht['mail_host'],
+                'port'  => $this->ht['mail_port'],
+                'protocol'  => $this->ht['mail_protocol'],
+                'encryption' => $this->ht['mail_encryption'],
+                'username'  => $this->ht['userid'],
+                'password' => Mcrypt::decrypt($this->ht['userpass'], SECRET_SALT),
+                //osTicket specific                
+                'email_id'  => $this->getId(), //Required for email routing to work.
+                'max_fetch' => $this->ht['mail_fetchmax'],
+                'delete_mail' => $this->ht['mail_delete'],
+                'archive_folder' => $this->ht['mail_archivefolder']
+                );
+
+        return $info;
+    }
+
     function isSMTPEnabled() {
         return $this->ht['smtp_active'];
     }
@@ -106,113 +127,39 @@ class Email {
         return ($this->ht['smtp_spoofing']);
     }
 
-    function getSMTPInfo($active=true) {
-        $info=array();
-        if(!$active || ($active && $this->isSMTPEnabled())) {
-
-            $info = array ('host' => $this->ht['smtp_host'],
-                           'port' => $this->ht['smtp_port'],
-                           'auth' => $this->ht['smtp_auth'],
-                           'username' => $this->ht['userid'],
-                           'password' =>Mcrypt::decrypt($this->ht['userpass'],SECRET_SALT)
-                           );
-        }
+    function getSMTPInfo() {
+            
+        $info = array (
+                'host' => $this->ht['smtp_host'],
+                'port' => $this->ht['smtp_port'],
+                'auth' => (bool) $this->ht['smtp_auth'],
+                'username' => $this->ht['userid'],
+                'password' => Mcrypt::decrypt($this->ht['userpass'], SECRET_SALT)
+                );
 
         return $info;
     }
 
     function send($to, $subject, $message, $attachments=null, $options=null) {
-        global $cfg, $ost;
-
-        //Get SMTP info IF enabled!
-        $smtp=array();
-        if($this->isSMTPEnabled() && ($info=$this->getSMTPInfo())) { //is SMTP enabled for the current email?
-            $smtp=$info;
-        }elseif($cfg && ($email=$cfg->getDefaultSMTPEmail()) && $email->isSMTPEnabled()) { //What about global SMTP setting?
-            if($email->allowSpoofing() && ($info=$email->getSMTPInfo())) //If spoofing is allowed..then continue.
-                $smtp=$info;
-            elseif($email->getId()!=$this->getId()) //No spoofing allowed. Send it via the default SMTP email.
-                return $email->send($to,$subject,$message,$attachments,$options);
-        }
-
-        //Get the goodies
-        require_once ('Mail.php'); // PEAR Mail package
-        require_once ('Mail/mime.php'); // PEAR Mail_Mime packge
-
-        //do some cleanup
-        $eol="\n";
-        $to=preg_replace("/(\r\n|\r|\n)/s",'', trim($to));
-        $subject=stripslashes(preg_replace("/(\r\n|\r|\n)/s",'', trim($subject)));
-        $body = stripslashes(preg_replace("/(\r\n|\r)/s", "\n", trim($message)));
-        $fromname=$this->getName();
-        $from =sprintf('"%s"<%s>',($fromname?$fromname:$this->getEmail()),$this->getEmail());
-        $headers = array ('From' => $from,
-                          'To' => $to,
-                          'Subject' => $subject,
-                          'Date'=>date('D, d M Y H:i:s O'),
-                          'Message-ID' =>'<'.Misc::randCode(6).''.time().'-'.$this->getEmail().'>',
-                          'X-Mailer' =>'osTicket v1.7',
-                          'Content-Type' => 'text/html; charset="UTF-8"'
-                          );
-
-        $mime = new Mail_mime();
-        $mime->setTXTBody($body);
-        //XXX: Attachments
-        if($attachments){
-            foreach($attachments as $attachment) {
-                if($attachment['file_id'] && ($file=AttachmentFile::lookup($attachment['file_id'])))
-                    $mime->addAttachment($file->getData(),$file->getType(), $file->getName(),false);
-                elseif($attachment['file'] &&  file_exists($attachment['file']) && is_readable($attachment['file']))
-                    $mime->addAttachment($attachment['file'],$attachment['type'],$attachment['name']);
-            }
-        }
-        
-        $options=array('head_encoding' => 'quoted-printable',
-                       'text_encoding' => 'quoted-printable',
-                       'html_encoding' => 'base64',
-                       'html_charset'  => 'utf-8',
-                       'text_charset'  => 'utf-8');
-        //encode the body
-        $body = $mime->get($options);
-        //encode the headers.
-        $headers = $mime->headers($headers);
-        if($smtp) { //Send via SMTP
-            $mail = mail::factory('smtp',
-                    array ('host' => $smtp['host'],
-                           'port' => $smtp['port'],
-                           'auth' => $smtp['auth']?true:false,
-                           'username' => $smtp['username'],
-                           'password' => $smtp['password'],
-                           'timeout'  =>20,
-                           'debug' => false,
-                           ));
-            $result = $mail->send($to, $headers, $body);
-            if(!PEAR::isError($result))
-                return true;
 
-            //SMTP failed - log error.
-            $alert=sprintf("Unable to email via %s:%d [%s]\n\n%s\n",$smtp['host'],$smtp['port'],$smtp['username'],$result->getMessage());
-            $ost->logError('SMTP Error', $alert, false); //NOTE: email alert overwrite - don't email when having email trouble.
-            //print_r($result);
-        }
 
-        //No SMTP or it failed....use php's native mail function.
-        $mail = mail::factory('mail');
-        return PEAR::isError($mail->send($to, $headers, $body))?false:true;
+        $mailer = new Mailer($this);
+        if($attachments)
+            $mailer->addAttachments($attachments);
 
+        return $mailer->send($to, $subject, $message, $options);
     }
 
-
     function update($vars,&$errors) {
         $vars=$vars;
         $vars['cpasswd']=$this->getPasswd(); //Current decrypted password.
 
-        if($this->save($this->getId(),$vars,$errors)) {
-            $this->reload();
-            return true;
-        }
+        if(!$this->save($this->getId(), $vars, $errors))
+            return false;
 
-        return false;
+        $this->reload();
+        
+        return true;
     }
 
 
@@ -235,42 +182,8 @@ class Email {
 
 
     /******* Static functions ************/
-
-    //sends emails using native php mail function Email::sendmail( ......);
-    //Don't use this function if you can help it.
-    function sendmail($to,$subject,$message,$from) {
-        
-        require_once ('Mail.php'); // PEAR Mail package
-        require_once ('Mail/mime.php'); // PEAR Mail_Mime packge
-        
-        $eol="\n";
-        $to=preg_replace("/(\r\n|\r|\n)/s",'', trim($to));
-        $subject=stripslashes(preg_replace("/(\r\n|\r|\n)/s",'', trim($subject)));
-        $body = stripslashes(preg_replace("/(\r\n|\r)/s", "\n", trim($message)));
-        $headers = array ('From' =>$from,
-                          'To' => $to,
-                          'Subject' => $subject,
-                          'Message-ID' =>'<'.Misc::randCode(10).''.time().'@osTicket>',
-                          'X-Mailer' =>'osTicket v 1.6',
-                          'Content-Type' => 'text/html; charset="UTF-8"'
-                          );
-        $mime = new Mail_mime();
-        $mime->setTXTBody($body);
-        $options=array('head_encoding' => 'quoted-printable',
-                       'text_encoding' => 'quoted-printable',
-                       'html_encoding' => 'base64',
-                       'html_charset'  => 'utf-8',
-                       'text_charset'  => 'utf-8');
-        //encode the body
-        $body = $mime->get($options);
-        //headers
-        $headers = $mime->headers($headers);
-        $mail = mail::factory('mail');
-        return PEAR::isError($mail->send($to, $headers, $body))?false:true;
-    }
-
-
-    function getIdByEmail($email) {
+    
+   function getIdByEmail($email) {
         
         $sql='SELECT email_id FROM '.EMAIL_TABLE.' WHERE email='.db_input($email);
         if(($res=db_query($sql)) && db_num_rows($res))   
@@ -341,11 +254,8 @@ class Email {
 
             if(!isset($vars['postfetch']))
                 $errors['postfetch']='Indicate what to do with fetched emails';
-            elseif(!strcasecmp($vars['postfetch'],'archive')) {
-                if(!$vars['mail_archivefolder'])
-                    $errors['postfetch']='Valid folder required';
-            }
-            
+            elseif(!strcasecmp($vars['postfetch'],'archive') && !$vars['mail_archivefolder'] )
+                $errors['postfetch']='Valid folder required';
         }
         
         if($vars['smtp_active']) {
@@ -370,10 +280,16 @@ class Email {
         
         $passwd=$vars['passwd']?$vars['passwd']:$vars['cpasswd'];
         if(!$errors && $vars['mail_active']) {
-           
             //note: password is unencrypted at this point...MailFetcher expect plain text.
-            $fetcher = new MailFetcher($vars['userid'],$passwd,$vars['mail_host'],$vars['mail_port'],
-                                            $vars['mail_protocol'],$vars['mail_encryption']);
+            $fetcher = new MailFetcher(
+                    array(
+                        'host'  => $vars['mail_host'],
+                        'port'  => $vars['mail_port'],
+                        'username'  => $vars['userid'],
+                        'password'  => $passwd,
+                        'protocol'  => $vars['mail_protocol'],
+                        'encryption' => $vars['mail_encryption'])
+                    );
             if(!$fetcher->connect()) {
                 $errors['err']='Invalid login. Check '.Format::htmlchars($vars['mail_protocol']).' settings';
                 $errors['mail']='<br>'.$fetcher->getLastError();
@@ -389,7 +305,7 @@ class Email {
             $smtp = mail::factory('smtp',
                     array ('host' => $vars['smtp_host'],
                            'port' => $vars['smtp_port'],
-                           'auth' => $vars['smtp_auth']?true:false,
+                           'auth' => (bool) $vars['smtp_auth'],
                            'username' =>$vars['userid'],
                            'password' =>$passwd,
                            'timeout'  =>20,
diff --git a/include/class.export.php b/include/class.export.php
index 7d6a7e7ec87b5939d8a7657370ea61626c06700c..a47a6f6f99c2eba77597694d22b2d69e1820407b 100644
--- a/include/class.export.php
+++ b/include/class.export.php
@@ -16,18 +16,18 @@
 
 class Export {
     
-    /* static */ function dumpQuery($sql, $headers, $how='csv') {
+    /* static */ function dumpQuery($sql, $headers, $how='csv', $filter=false) {
         $exporters = array(
             'csv' => CsvResultsExporter,
             'json' => JsonResultsExporter
         );
-        $exp = new $exporters[$how]($sql, $headers);
+        $exp = new $exporters[$how]($sql, $headers, $filter);
         return $exp->dump();
     }
 
     # XXX: Think about facilitated exporting. For instance, we might have a
     #      TicketExporter, which will know how to formulate or lookup a
-    #      formatl query (SQL), and cooperate with the output process to add
+    #      format query (SQL), and cooperate with the output process to add
     #      extra (recursive) information. In this funciton, the top-level
     #      SQL is exported, but for something like tickets, we will need to
     #      export attached messages, reponses, and notes, as well as
@@ -60,8 +60,11 @@ class Export {
 }
 
 class ResultSetExporter {
-    function ResultSetExporter($sql, $headers) {
+    function ResultSetExporter($sql, $headers, $filter=false) {
         $this->headers = array_values($headers);
+        if ($s = strpos(strtoupper($sql), ' LIMIT '))
+            $sql = substr($sql, 0, $s);
+        # TODO: If $filter, add different LIMIT clause to query
         $this->_res = db_query($sql);
         if ($row = db_fetch_array($this->_res)) {
             $query_fields = array_keys($row);
diff --git a/include/class.faq.php b/include/class.faq.php
index 78b1a799e021f46ed4f44ba159f98568328eb4cd..2197bbac102604d334d2f59b71d7658a3b18b39b 100644
--- a/include/class.faq.php
+++ b/include/class.faq.php
@@ -19,11 +19,11 @@ class FAQ {
 
     var $id;
     var $ht;
+
     var $category;
+    var $attachments;
 
     function FAQ($id) {
-
-
         $this->id=0;
         $this->ht = array();
         $this->load($id);
@@ -44,6 +44,7 @@ class FAQ {
         $this->ht = db_fetch_array($res);
         $this->ht['id'] = $this->id = $this->ht['faq_id'];
         $this->category = null;
+        $this->attachments = array();
 
         return true;
     }
@@ -134,7 +135,7 @@ class FAQ {
 
         if($ids) {
             $topics = $this->getHelpTopicsIds();
-            foreach($ids as $k=>$id) {
+            foreach($ids as $id) {
                 if($topics && in_array($id,$topics)) continue;
                 $sql='INSERT IGNORE INTO '.FAQ_TOPIC_TABLE
                     .' SET faq_id='.db_input($this->getId())
@@ -158,6 +159,20 @@ class FAQ {
             return false;
 
         $this->updateTopics($vars['topics']);
+                    
+        //Delete removed attachments.
+        $keepers = $vars['files']?$vars['files']:array();
+        if(($attachments = $this->getAttachments())) {
+            foreach($attachments as $file) {
+                if($file['id'] && !in_array($file['id'], $keepers))
+                    $this->deleteAttachment($file['id']);
+            }
+        }
+
+        //Upload new attachments IF any.
+        if($_FILES['attachments'] && ($files=Format::files($_FILES['attachments'])))
+            $this->uploadAttachments($files);
+
         $this->reload();
 
         return true;
@@ -261,10 +276,19 @@ class FAQ {
     /* ------------------> Static methods <--------------------- */
    
     function add($vars, &$errors) {
-        if(($id=self::create($vars, $errors)) && ($faq=self::lookup($id)))
+        if(!($id=self::create($vars, $errors)))
+            return false;
+
+        if(($faq=self::lookup($id))) {
             $faq->updateTopics($vars['topics']);
+               
+            if($_FILES['attachments'] && ($files=Format::files($_FILES['attachments'])))
+                $faq->uploadAttachments($files);
 
-        return$faq;
+            $faq->reload();
+        }
+            
+        return $faq;
     }
 
     function create($vars, &$errors) {   
diff --git a/include/class.file.php b/include/class.file.php
index b9bfbe1b7d2975ebdcc467bfb826ed35b8f1ec75..c27c9fdd07b5aa7477336c009af2fdb75605233c 100644
--- a/include/class.file.php
+++ b/include/class.file.php
@@ -141,7 +141,7 @@ class AttachmentFile {
     /* Function assumes the files types have been validated */
     function upload($file) {
         
-        if(!$file['name'] || !is_uploaded_file($file['tmp_name']))
+        if(!$file['name'] || $file['error'] || !is_uploaded_file($file['tmp_name']))
             return false;
 
         $info=array('type'=>$file['type'],
@@ -160,22 +160,27 @@ class AttachmentFile {
             $file['hash']=MD5(MD5($file['data']).time());
         if(!$file['size'])
             $file['size']=strlen($file['data']);
-
-
-        
-        //TODO: Do chunked INSERTs - 
-        if(($mps=db_get_variable('max_allowed_packet')) && $file['size']>($mps*0.7)) {
-            @db_set_variable('max_allowed_packet',$file['size']+$mps);
-        }
         
         $sql='INSERT INTO '.FILE_TABLE.' SET created=NOW() '
             .',type='.db_input($file['type'])
             .',size='.db_input($file['size'])
             .',name='.db_input($file['name'])
-            .',hash='.db_input($file['hash'])
-            .',filedata='.db_input($file['data']);
+            .',hash='.db_input($file['hash']);
+
+        if (!(db_query($sql) && ($id=db_insert_id())))
+            return false;
 
-        return db_query($sql)?db_insert_id():0;
+        foreach (str_split($file['data'], 1024*100) as $chunk) {
+            $sql='UPDATE '.FILE_TABLE
+                .' SET filedata = CONCAT(filedata,'.db_input($chunk).')'
+                .' WHERE id='.db_input($id);
+            if(!db_query($sql)) {
+                db_query('DELETE FROM '.FILE_TABLE.' WHERE id='.db_input($id).' LIMIT 1');
+                return false;
+            }
+        }
+
+        return $id;
     }
 
     /* Static functions */
diff --git a/include/class.filter.php b/include/class.filter.php
index 9c3065c10aba5aa1e359e4c36a67e4de83aec9fe..bc9b0847132aff00f794dd74abf6b2ec71379e35 100644
--- a/include/class.filter.php
+++ b/include/class.filter.php
@@ -71,6 +71,10 @@ class Filter {
         return $this->ht['execorder'];
     }
 
+    function getEmailId() {
+        return $this->ht['email_id'];
+    }
+
     function isActive(){
         return ($this->ht['isactive']);
     }
@@ -99,6 +103,10 @@ class Filter {
         return $this->ht['team_id'];
     }
 
+    function getCannedResponse() {
+        return $this->ht['canned_response_id'];
+    }
+
     function stopOnMatch(){
         return ($this->ht['stop_on_match']);
     }
@@ -212,11 +220,11 @@ class Filter {
      */
     function matches($email) {
         $what = array(
-            "email"     => $email['from'],
+            "email"     => $email['email'],
             "subject"   => $email['subject'],
             # XXX: Support reply-to too ?
             "name"      => $email['name'],
-            "body"      => $email['body']
+            "body"      => $email['message']
             # XXX: Support headers
         );
         $how = array(
@@ -227,6 +235,10 @@ class Filter {
             "dn_contain"=> array("strpos", false)
         );
         $match = false;
+        # Respect configured filter email-id
+        if ($email['emailId'] && $this->getEmailId()
+                && $this->getEmailId() != $email['emailId'])
+            return false;
         foreach ($this->getRules() as $rule) {
             list($func, $pos, $neg) = $how[$rule['h']];
             # TODO: convert $what and $rule['v'] to mb_strtoupper and do
@@ -274,6 +286,24 @@ class Filter {
             if ($email['reply-to-name']) 
                 $ticket['name'] = $email['reply-to-name'];
         }
+        if ($this->getCannedResponse())
+            $ticket['cannedResponseId'] = $this->getCannedResponse();
+    }
+    /* static */ function getSupportedMatches() {
+        return array(
+            'name'=>    "Sender's Name",
+            'email'=>   "Sender's Email",
+            'subject'=> 'Email Subject',
+            'body'=>    'Email Body/Text'
+        );
+    }
+    /* static */ function getSupportedMatchTypes() {
+        return array(
+            'equal'=>       'Equal',
+            'not_equal'=>   'Not Equal',
+            'contains'=>    'Contains',
+            'dn_contain'=>  'Does Not Contain'
+        );
     }
 
     function update($vars,&$errors){
@@ -395,6 +425,7 @@ class Filter {
              ',reject_email='.db_input(isset($vars['reject_email'])?1:0).
              ',use_replyto_email='.db_input(isset($vars['use_replyto_email'])?1:0).
              ',disable_autoresponder='.db_input(isset($vars['disable_autoresponder'])?1:0).
+             ',canned_response_id='.db_input($vars['canned_response_id']).
              ',notes='.db_input($vars['notes']);
        
 
@@ -560,7 +591,7 @@ class EmailFilter {
      * calls, etc).
      *
      * $email is an ARRAY, which has valid keys
-     *  *from - email address of sender
+     *  *email - email address of sender
      *   name - name of sender
      *   subject - subject line of the email
      *   email-id - id of osTicket email recipient address
@@ -579,8 +610,8 @@ class EmailFilter {
             $this->build($this->getAllActive());
         } else {
             $this->build(
-                $this->quickList($email['from'], $email['name'],
-                    $email['subject']));
+                $this->quickList($email['email'], $email['name'],
+                    $email['subject'], $email['emailId']));
         }
     }
     
diff --git a/include/class.format.php b/include/class.format.php
index 2c0993c459b108fdbd1bbf3394fb2e7f9ecdff95..9de1197edbb3d4272193f67af48826851f72296e 100644
--- a/include/class.format.php
+++ b/include/class.format.php
@@ -88,7 +88,12 @@ class Format {
     }
 
     function htmlchars($var) {
-        return is_array($var)?array_map(array('Format','htmlchars'),$var):htmlspecialchars($var,ENT_QUOTES);
+        $flags = ENT_COMPAT | ENT_QUOTES;
+        if (phpversion() >= '5.4.0')
+            $flags |= ENT_HTML401;
+        return is_array($var)
+            ? array_map(array('Format','htmlchars'),$var)
+            : htmlentities($var, $flags, 'UTF-8');
     }
 
     function input($var) {
@@ -114,7 +119,13 @@ class Format {
     }
 
     function striptags($var) {
-        return is_array($var)?array_map(array('Format','striptags'),$var):strip_tags(html_entity_decode($var)); //strip all tags ...no mercy!
+        $flags = ENT_COMPAT;
+        if (phpversion() >= '5.4.0')
+            $flags |= ENT_HTML401;
+        return is_array($var)
+            ? array_map(array('Format','striptags'),$var)
+              //strip all tags ...no mercy!
+            : strip_tags(html_entity_decode($var, $flags, 'UTF-8'));
     }
 
     //make urls clickable. Mainly for display 
diff --git a/include/class.group.php b/include/class.group.php
index 1b21dce29e4511b469c8dfb70386e7e940626d48..b13082be9f24301e12bf298cac0d043f86b7f8d1 100644
--- a/include/class.group.php
+++ b/include/class.group.php
@@ -19,13 +19,19 @@ class Group {
     var $id;
     var $ht;
 
+    var $members;
+    var $departments;
+
     function Group($id){
 
         $this->id=0;
         return $this->load($id);
     }
 
-    function load($id){
+    function load($id=0) {
+
+        if(!$id && !($id=$this->getId()))
+            return false;
 
         $sql='SELECT grp.*,grp.group_name as name, grp.group_enabled as isactive, count(staff.staff_id) as users '
             .'FROM '.GROUP_TABLE.' grp '
@@ -37,12 +43,13 @@ class Group {
         $this->ht=db_fetch_array($res);
         $this->id=$this->ht['group_id'];
         $this->members=array();
+        $this->departments = array();
 
         return $this->id;
     }
 
     function reload(){
-        return $this->load($this->getId());
+        return $this->load();
     }
 
     function getHashtable() {
@@ -73,17 +80,86 @@ class Group {
     function isActive(){
         return $this->isEnabled();
     }
+ 
+    //Get members of the group.
+    function getMembers() {
+
+        if(!$this->members && $this->getNumUsers()) {
+            $sql='SELECT staff_id FROM '.STAFF_TABLE
+                .' WHERE group_id='.db_input($this->getId())
+                .' ORDER BY lastname, firstname';
+            if(($res=db_query($sql)) && db_num_rows($res)) {
+                while(list($id)=db_fetch_row($res))
+                    if(($staff=Staff::lookup($id)))
+                        $this->members[]= $staff;
+            }
+        }
+
+        return $this->members;
+    }
 
+    //Get departments the group is allowed to access.
+    function getDepartments() {
 
+        if(!$this->departments) {
+            $sql='SELECT dept_id FROM '.GROUP_DEPT_TABLE
+                .' WHERE group_id='.db_input($this->getId());
+            if(($res=db_query($sql)) && db_num_rows($res)) {
+                while(list($id)=db_fetch_row($res))
+                    $this->departments[]= $id;
+            }
+        }
+
+        return $this->departments;
+    }
+
+        
+    function updateDeptAccess($depts) {
 
-    function update($vars,&$errors) {
 
-        if(Group::save($this->getId(),$vars,$errors)){
-            $this->reload();
-            return true;
+        if($depts && is_array($depts)) {
+            foreach($depts as $k=>$id) {
+                $sql='INSERT IGNORE INTO '.GROUP_DEPT_TABLE
+                    .' SET group_id='.db_input($this->getId())
+                    .', dept_id='.db_input($id);
+                db_query($sql);
+            }
         }
 
-        return false;
+        $sql='DELETE FROM '.GROUP_DEPT_TABLE.' WHERE group_id='.db_input($this->getId());
+        if($depts && is_array($depts)) // just inserted departments IF any.
+            $sql.=' AND dept_id NOT IN('.implode(',', db_input($depts)).')';
+
+        db_query($sql);
+
+        return true;
+    }
+
+    function update($vars,&$errors) {
+
+        if(!Group::save($this->getId(),$vars,$errors))
+            return false;
+
+        $this->updateDeptAccess($vars['depts']);
+        $this->reload();
+        
+        return true;
+    }
+
+    function delete() {
+
+        //Can't delete with members
+        if($this->getNumUsers())
+            return false;
+
+        $res = db_query('DELETE FROM '.GROUP_TABLE.' WHERE group_id='.db_input($this->getId()).' LIMIT 1');
+        if(!$res || !db_affected_rows($res))
+            return false;
+
+        //Remove dept access entry.
+        db_query('DELETE FROM '.GROUP_DEPT_TABLE.' WHERE group_id='.db_input($this->getId()));
+
+        return true;
     }
 
     /*** Static functions ***/
@@ -99,9 +175,11 @@ class Group {
         return ($id && is_numeric($id) && ($g= new Group($id)) && $g->getId()==$id)?$g:null;
     }
 
+    function create($vars, &$errors) { 
+        if(($id=self::save(0,$vars,$errors)) && ($group=self::lookup($id)))
+            $group->updateDeptAccess($vars['depts']);
 
-    function create($vars,&$errors) { 
-        return self::save(0,$vars,$errors);
+        return $id;
     }
 
     function save($id,$vars,&$errors) {
@@ -119,19 +197,19 @@ class Group {
         
         if($errors) return false;
             
-        $sql=' SET updated=NOW(), group_name='.db_input(Format::striptags($vars['name'])).
-             ', group_enabled='.db_input($vars['isactive']).
-             ', dept_access='.db_input($vars['depts']?implode(',',$vars['depts']):'').
-             ', can_create_tickets='.db_input($vars['can_create_tickets']).
-             ', can_delete_tickets='.db_input($vars['can_delete_tickets']).
-             ', can_edit_tickets='.db_input($vars['can_edit_tickets']).
-             ', can_assign_tickets='.db_input($vars['can_assign_tickets']).
-             ', can_transfer_tickets='.db_input($vars['can_transfer_tickets']).
-             ', can_close_tickets='.db_input($vars['can_close_tickets']).
-             ', can_ban_emails='.db_input($vars['can_ban_emails']).
-             ', can_manage_premade='.db_input($vars['can_manage_premade']).
-             ', can_manage_faq='.db_input($vars['can_manage_faq']).
-             ', notes='.db_input($vars['notes']);
+        $sql=' SET updated=NOW() '
+            .', group_name='.db_input(Format::striptags($vars['name']))
+            .', group_enabled='.db_input($vars['isactive'])
+            .', can_create_tickets='.db_input($vars['can_create_tickets'])
+            .', can_delete_tickets='.db_input($vars['can_delete_tickets'])
+            .', can_edit_tickets='.db_input($vars['can_edit_tickets'])
+            .', can_assign_tickets='.db_input($vars['can_assign_tickets'])
+            .', can_transfer_tickets='.db_input($vars['can_transfer_tickets'])
+            .', can_close_tickets='.db_input($vars['can_close_tickets'])
+            .', can_ban_emails='.db_input($vars['can_ban_emails'])
+            .', can_manage_premade='.db_input($vars['can_manage_premade'])
+            .', can_manage_faq='.db_input($vars['can_manage_faq'])
+            .', notes='.db_input($vars['notes']);
             
         if($id) {
             
diff --git a/include/class.mailer.php b/include/class.mailer.php
new file mode 100644
index 0000000000000000000000000000000000000000..a469d5528f6598489a8a8ecd63b795594f5db322
--- /dev/null
+++ b/include/class.mailer.php
@@ -0,0 +1,180 @@
+<?php
+/*********************************************************************
+    class.mailer.php
+
+    osTicket mailer 
+
+    It's mainly PEAR MAIL wrapper for now (more improvements planned).
+
+    Peter Rotich <peter@osticket.com>
+    Copyright (c)  2006-2012 osTicket
+    http://www.osticket.com
+
+    Released under the GNU General Public License WITHOUT ANY WARRANTY.
+    See LICENSE.TXT for details.
+
+    vim: expandtab sw=4 ts=4 sts=4:
+**********************************************************************/
+
+include_once(INCLUDE_DIR.'class.email.php');
+
+class Mailer {
+
+    var $email;
+
+    var $ht = array();
+    var $attachments = array();
+
+    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?
+            $this->smtp = $e->getSMTPInfo();
+            if(!$e->allowSpoofing() || !$email)
+                $email = $e;
+        } elseif(!$email && $cfg && ($e=$cfg->getDefaultEmail())) {
+            if($e->isSMTPEnabled() && ($info=$email->getSMTPInfo()))
+                $this->smtp = $info;
+            $email = $e;
+        }
+
+        $this->email = $email;
+        $this->attachments = array();
+    }
+
+    function getEOL() {
+        return $this->eol;
+    }
+
+    function getEmail() {
+        return $this->email;
+    }
+    
+    function getSMTPInfo() {
+        return $this->smtp;
+    }
+    /* FROM Address */
+    function setFromAddress($from) {
+        $this->ht['from'] = $from;
+    }
+
+    function getFromAddress() {
+
+        if(!$this->ht['from'] && $this->getEmail())
+            $this->ht['from'] =$this->getEmail()->getAddress();
+
+        return $this->ht['from'];
+    }
+
+    /* attachments */
+    function getAttachments() {
+        return $this->attachments;
+    }
+
+    function addAttachment($attachment) {
+        $this->attachments[] = $attachment;
+    }
+
+    function addAttachments($attachments) {
+        $this->attachments = array_merge($this->attachments, $attachments);
+    }
+
+    function send($to, $subject, $message, $options=null) {
+        global $ost;
+
+        //Get the goodies
+        require_once (PEAR_DIR.'Mail.php'); // PEAR Mail package
+        require_once (PEAR_DIR.'Mail/mime.php'); // PEAR Mail_Mime packge
+
+        //do some cleanup
+        $to=preg_replace("/(\r\n|\r|\n)/s",'', trim($to));
+        $subject=stripslashes(preg_replace("/(\r\n|\r|\n)/s",'', trim($subject)));
+        $body = stripslashes(preg_replace("/(\r\n|\r)/s", "\n", trim($message)));
+
+        /* Message ID - generated for each outgoing email */
+        $messageId = sprintf('<%s%d-%s>', Misc::randCode(6), time(),
+                ($this->getEmail()?$this->getEmail()->getEmail():'@osTicketMailer'));
+
+        $headers = array (
+                'From' => $this->getFromAddress(),
+                'To' => $to,
+                'Subject' => $subject,
+                'Date'=> date('D, d M Y H:i:s O'),
+                'Message-ID' => $messageId,
+                'X-Mailer' =>'osTicket Mailer',
+                'Content-Type' => 'text/html; charset="UTF-8"'
+                );
+
+        $mime = new Mail_mime();
+        $mime->setTXTBody($body);
+        //XXX: Attachments
+        if(($attachments=$this->getAttachments())) {
+            foreach($attachments as $attachment) {
+                if($attachment['file_id'] && ($file=AttachmentFile::lookup($attachment['file_id'])))
+                    $mime->addAttachment($file->getData(),$file->getType(), $file->getName(),false);
+                elseif($attachment['file'] &&  file_exists($attachment['file']) && is_readable($attachment['file']))
+                    $mime->addAttachment($attachment['file'],$attachment['type'],$attachment['name']);
+            }
+        }
+        
+        //Desired encodings...
+        $encodings=array(
+                'head_encoding' => 'quoted-printable',
+                'text_encoding' => 'quoted-printable',
+                'html_encoding' => 'base64',
+                'html_charset'  => 'utf-8',
+                'text_charset'  => 'utf-8',
+                'head_charset'  => 'utf-8'
+                );
+        //encode the body
+        $body = $mime->get($encodings);
+        //encode the headers.
+        $headers = $mime->headers($headers);
+        if(($smtp=$this->getSMTPInfo())) { //Send via SMTP
+            $mail = mail::factory('smtp',
+                    array ('host' => $smtp['host'],
+                           'port' => $smtp['port'],
+                           'auth' => $smtp['auth'],
+                           'username' => $smtp['username'],
+                           'password' => $smtp['password'],
+                           'timeout'  =>20,
+                           'debug' => false,
+                           ));
+
+            $result = $mail->send($to, $headers, $body);
+            if(!PEAR::isError($result))
+                return $messageId;
+
+            $alert=sprintf("Unable to email via SMTP:%s:%d [%s]\n\n%s\n",
+                    $smtp['host'], $smtp['port'], $smtp['username'], $result->getMessage());
+            $this->logError($alert);
+        }
+
+        //No SMTP or it failed....use php's native mail function.
+        $mail = mail::factory('mail');
+        return PEAR::isError($mail->send($to, $headers, $body))?false:$messageId;
+
+    }
+
+    function logError($error) {
+        global $ost;
+        //NOTE: Admin alert overwrite - don't email when having email trouble!
+        $ost->logError('Mailer Error', $error, false);
+    }
+
+    /******* Static functions ************/
+
+    //Emails using native php mail function - if DB connection doesn't exist.
+    //Don't use this function if you can help it.
+    function sendmail($to, $subject, $message, $from) {
+        $mailer = new Mailer();
+        $mailer->setFromAddress($from);
+        return $mailer->send($to, $subject, $message);
+    }
+}
+?>
diff --git a/include/class.mailfetch.php b/include/class.mailfetch.php
index a353b690be55c3f9cbd3740b6edcc7164dabc16e..fb8402169e83b39c258118329215d2459d7547a2 100644
--- a/include/class.mailfetch.php
+++ b/include/class.mailfetch.php
@@ -17,112 +17,161 @@
 require_once(INCLUDE_DIR.'class.mailparse.php');
 require_once(INCLUDE_DIR.'class.ticket.php');
 require_once(INCLUDE_DIR.'class.dept.php');
+require_once(INCLUDE_DIR.'class.email.php');
 require_once(INCLUDE_DIR.'class.filter.php');
 
 class MailFetcher {
-    var $hostname;
-    var $username;
-    var $password;
 
-    var $port;
-    var $protocol;
-    var $encryption;
+    var $ht;
 
     var $mbox;
+    var $srvstr;
 
-    var $charset= 'UTF-8';
+    var $charset = 'UTF-8';
+    var $encodings =array('UTF-8','WINDOWS-1251', 'ISO-8859-5', 'ISO-8859-1','KOI8-R');
     
-    function MailFetcher($username,$password,$hostname,$port,$protocol,$encryption='') {
+    function MailFetcher($email, $charset='UTF-8') {
 
-        if(!strcasecmp($protocol,'pop')) //force pop3
-            $protocol='pop3';
-
-        $this->hostname=$hostname;
-        $this->username=$username;
-        $this->password=$password;
-        $this->protocol=strtolower($protocol);
-        $this->port = $port;
-        $this->encryption = $encryption;
+        
+        if($email && is_numeric($email)) //email_id
+            $email=Email::lookup($email);
+
+        if(is_object($email))
+            $this->ht = $email->getMailAccountInfo();
+        elseif(is_array($email) && $email['host']) //hashtable of mail account info
+            $this->ht = $email; 
+        else
+            $this->ht = null;
+           
+        $this->charset = $charset;
+
+        if($this->ht) {
+            if(!strcasecmp($this->ht['protocol'],'pop')) //force pop3
+                $this->ht['protocol'] = 'pop3';
+            else
+                $this->ht['protocol'] = strtolower($this->ht['protocol']);
+
+            //Max fetch per poll
+            if(!$this->ht['max_fetch'] || !is_numeric($this->ht['max_fetch']))
+                $this->ht['max_fetch'] = 20;
+
+            //Mail server string
+            $this->srvstr=sprintf('{%s:%d/%s', $this->getHost(), $this->getPort(), $this->getProtocol());
+            if(!strcasecmp($this->getEncryption(), 'SSL'))
+                $this->srvstr.='/ssl';
+        
+            $this->srvstr.='/novalidate-cert}';
 
-        $this->serverstr=sprintf('{%s:%d/%s',$this->hostname,$this->port,strtolower($this->protocol));
-        if(!strcasecmp($this->encryption,'SSL')){
-            $this->serverstr.='/ssl';
         }
-        $this->serverstr.='/novalidate-cert}INBOX'; //add other flags here as needed.
 
-        //echo $this->serverstr;
-        //Charset to convert the mail to.
-        $this->charset='UTF-8';
         //Set timeouts 
-        if(function_exists('imap_timeout'))
-            imap_timeout(1,20); //Open timeout.
+        if(function_exists('imap_timeout')) imap_timeout(1,20);
+
+    }
+
+    function getEmailId() {
+        return $this->ht['email_id'];
+    }
+
+    function getHost() {
+        return $this->ht['host'];
+    }
+
+    function getPort() {
+        return $this->ht['port'];
+    }
+
+    function getProtocol() {
+        return $this->ht['protocol'];
+    }
+
+    function getEncryption() {
+        return $this->ht['encryption'];
+    }
+
+    function getUsername() {
+        return $this->ht['username'];
     }
     
+    function getPassword() {
+        return $this->ht['password'];
+    }
+
+    /* osTicket Settings */
+
+    function canDeleteEmails() {
+        return ($this->ht['delete_mail']);
+    }
+
+    function getMaxFetch() {
+        return $this->ht['max_fetch'];
+    }
+
+    function getArchiveFolder() {
+        return $this->ht['archive_folder'];
+    }
+
+    /* Core */
+    
     function connect() {
-        return $this->open()?true:false;
+        return ($this->mbox && $this->ping())?$this->mbox:$this->open();
     }
 
-    function open() {
-       
-        //echo $this->serverstr;
-        if($this->mbox && imap_ping($this->mbox))
-            return $this->mbox;
-            
-        $this->mbox =@imap_open($this->serverstr,$this->username,$this->password);
-        
+    function ping() {
+        return ($this->mbox && imap_ping($this->mbox));
+    }
+
+    /* Default folder is inbox - TODO: provide user an option to fetch from diff folder/label */
+    function open($box='INBOX') {
+      
+        if($this->mbox)
+           $this->close();
+
+        $this->mbox = imap_open($this->srvstr.$box, $this->getUsername(), $this->getPassword());
+
         return $this->mbox;
     }
 
-    function close() {
-        imap_close($this->mbox,CL_EXPUNGE);
+    function close($flag=CL_EXPUNGE) {
+        imap_close($this->mbox, $flag);
     }
 
-    function mailcount(){
+    function mailcount() {
         return count(imap_headers($this->mbox));
     }
 
     //Get mail boxes.
-    function getMailboxes(){
+    function getMailboxes() {
 
+        if(!($folders=imap_list($this->mbox, $this->srvstr, "*")) || !is_array($folders))
+            return null;
 
-        $mstr=sprintf('{%s:%d/%s',$this->hostname,$this->port,strtolower($this->protocol));
-        if(!strcasecmp($this->encryption,'SSL'))
-            $mstr.='/ssl';
-        $mstr.='/novalidate-cert}';
-        $list=array();
-        if(($folders=imap_listmailbox($this->mbox,$mstr,'*')) && is_array($folders)){
-            foreach($folders as $k=>$folder){
-                $list[]= str_replace($mstr, "", imap_utf7_decode(trim($folder)));
-            }
-        }
+        $list = array();
+        foreach($folders as $folder)
+            $list[]= str_replace($this->srvstr, '', imap_utf7_decode(trim($folder)));
 
         return $list;
     }
 
     //Create a folder.
-    function createMailbox($folder){
+    function createMailbox($folder) {
 
         if(!$folder) return false;
-
-        $mstr=sprintf('{%s:%d/%s',$this->hostname,$this->port,strtolower($this->protocol));
-        if(!strcasecmp($this->encryption,'SSL'))
-            $mstr.='/ssl';
-        $mstr.='/novalidate-cert}'.$folder;
             
-        return imap_createmailbox($this->mbox,imap_utf7_encode($mstr));
+        return imap_createmailbox($this->mbox, imap_utf7_encode($this->srvstr.trim($folder)));
     }
 
-    /* check if a folder exits - create on if requested */
-    function checkMailbox($folder,$create=false){
+    /* check if a folder exists - create one if requested */
+    function checkMailbox($folder, $create=false) {
 
-        if(($mailboxes=$this->getMailboxes()) && in_array($folder,$mailboxes))
+        if(($mailboxes=$this->getMailboxes()) && in_array(trim($folder), $mailboxes))
             return true;
 
         return ($create && $this->createMailbox($folder));
     }
 
 
-    function decode($encoding,$text) {
+    function decode($encoding, $text) {
 
         switch($encoding) {
             case 1:
@@ -145,14 +194,13 @@ class MailFetcher {
     }
 
     //Convert text to desired encoding..defaults to utf8
-    function mime_encode($text,$charset=null,$enc='utf-8') { //Thank in part to afterburner  
-                
-        $encodings=array('UTF-8','WINDOWS-1251', 'ISO-8859-5', 'ISO-8859-1','KOI8-R');
-        if(function_exists("iconv") and $text) {
+    function mime_encode($text, $charset=null, $enc='utf-8') { //Thank in part to afterburner  
+        
+        if(function_exists('iconv') and $text) {
             if($charset)
-                return iconv($charset,$enc.'//IGNORE',$text);
-            elseif(function_exists("mb_detect_encoding"))
-                return iconv(mb_detect_encoding($text,$encodings),$enc,$text);
+                return iconv($charset, $enc.'//IGNORE', $text);
+            elseif(function_exists('mb_detect_encoding'))
+                return iconv(mb_detect_encoding($text, $this->encodings), $enc, $text);
         }
 
         return utf8_encode($text);
@@ -161,15 +209,15 @@ class MailFetcher {
     //Generic decoder - mirrors imap_utf8
     function mime_decode($text) {
         
-        $a = imap_mime_header_decode($text);
         $str = '';
-        foreach ($a as $k => $part)
+        $parts = imap_mime_header_decode($text);
+        foreach ($parts as $part)
             $str.= $part->text;
         
         return $str?$str:imap_utf8($text);
     }
 
-    function getLastError(){
+    function getLastError() {
         return imap_last_error();
     }
 
@@ -183,67 +231,128 @@ class MailFetcher {
 
     function getHeaderInfo($mid) {
         
-        $headerinfo=imap_headerinfo($this->mbox,$mid);
-        $sender=$headerinfo->from[0];
+        if(!($headerinfo=imap_headerinfo($this->mbox, $mid)) || !$headerinfo->from)
+            return null;
 
-        //Parse what we need...
-        $header=array(
-                      'from'   =>array('name'  =>@$sender->personal,'email' =>strtolower($sender->mailbox).'@'.$sender->host),
+        $sender=$headerinfo->from[0];
+        //Just what we need...
+        $header=array('name'  =>@$sender->personal,
+                      'email' =>(strtolower($sender->mailbox).'@'.$sender->host),
                       'subject'=>@$headerinfo->subject,
-                      'mid'    =>$headerinfo->message_id);
+                      'mid'    =>$headerinfo->message_id
+                      );
+
         return $header;
     }
 
+    function getAttachment($part) {
+
+        if(!$part) return null;
+
+        if($part->ifdisposition && in_array(strtolower($part->disposition), array('attachment', 'inline')))
+            return $part->dparameters[0]->value;
+
+        if($part->ifparameters && $part->type == 5)
+            return $part->parameters[0]->value;
+
+
+        return null;
+    }
+
     //search for specific mime type parts....encoding is the desired encoding.
-    function getPart($mid,$mimeType,$encoding=false,$struct=null,$partNumber=false){
+    function getPart($mid, $mimeType, $encoding=false, $struct=null, $partNumber=false) {
           
         if(!$struct && $mid)
             $struct=@imap_fetchstructure($this->mbox, $mid);
+
         //Match the mime type.
-        if($struct && !$struct->ifdparameters && strcasecmp($mimeType,$this->getMimeType($struct))==0){
+        if($struct && !$struct->ifdparameters && strcasecmp($mimeType, $this->getMimeType($struct))==0) {
             $partNumber=$partNumber?$partNumber:1;
-            if(($text=imap_fetchbody($this->mbox, $mid, $partNumber))){
+            if(($text=imap_fetchbody($this->mbox, $mid, $partNumber))) {
                 if($struct->encoding==3 or $struct->encoding==4) //base64 and qp decode.
-                    $text=$this->decode($struct->encoding,$text);
+                    $text=$this->decode($struct->encoding, $text);
 
                 $charset=null;
                 if($encoding) { //Convert text to desired mime encoding...
-                    if($struct->ifparameters){
+                    if($struct->ifparameters) {
                         if(!strcasecmp($struct->parameters[0]->attribute,'CHARSET') && strcasecmp($struct->parameters[0]->value,'US-ASCII'))
                             $charset=trim($struct->parameters[0]->value);
                     }
-                    $text=$this->mime_encode($text,$charset,$encoding);
+                    $text=$this->mime_encode($text, $charset, $encoding);
                 }
                 return $text;
             }
         }
+
         //Do recursive search
         $text='';
-        if($struct && $struct->parts){
+        if($struct && $struct->parts) {
             while(list($i, $substruct) = each($struct->parts)) {
                 if($partNumber) 
                     $prefix = $partNumber . '.';
-                if(($result=$this->getPart($mid,$mimeType,$encoding,$substruct,$prefix.($i+1))))
+                if(($result=$this->getPart($mid, $mimeType, $encoding, $substruct, $prefix.($i+1))))
                     $text.=$result;
             }
         }
+
         return $text;
     }
 
-    function getHeader($mid){
+    /*
+     getAttachments
+
+     search and return a hashtable of attachments....
+     NOTE: We're not actually fetching the body of the attachment  - we'll do it on demand to save some memory.
+
+     */
+    function getAttachments($part, $index=0) {
+
+        if($part && !$part->parts) {
+            //Check if the part is an attachment.
+            $filename = '';
+            if($part->ifdisposition && in_array(strtolower($part->disposition), array('attachment', 'inline')))
+                $filename = $part->dparameters[0]->value;
+            elseif($part->ifparameters && $part->type == 5) //inline image without disposition.
+                $filename = $part->parameters[0]->value;
+
+            if($filename) {
+                return array(
+                        array(
+                            'name'  => $filename,
+                            'mime'  => $this->getMimeType($part),
+                            'encoding' => $part->encoding,
+                            'index' => ($index?$index:1)
+                            )
+                        );
+            }
+        }
+
+        //Recursive attachment search!
+        $attachments = array();
+        if($part && $part->parts) {
+            foreach($part->parts as $k=>$struct) {
+                if($index) $prefix = $index.'.';
+                $attachments = array_merge($attachments, $this->getAttachments($struct, $prefix.($k+1)));
+            }
+        }
+
+        return $attachments;
+    }
+
+    function getHeader($mid) {
         return imap_fetchheader($this->mbox, $mid,FT_PREFETCHTEXT);
     }
 
     
-    function getPriority($mid){
+    function getPriority($mid) {
         return Mail_Parse::parsePriority($this->getHeader($mid));
     }
 
     function getBody($mid) {
         
         $body ='';
-        if(!($body = $this->getPart($mid,'TEXT/PLAIN',$this->charset))) {
-            if(($body = $this->getPart($mid,'TEXT/HTML',$this->charset))) {
+        if(!($body = $this->getPart($mid,'TEXT/PLAIN', $this->charset))) {
+            if(($body = $this->getPart($mid,'TEXT/HTML', $this->charset))) {
                 //Convert tags of interest before we striptags
                 $body=str_replace("</DIV><DIV>", "\n", $body);
                 $body=str_replace(array("<br>", "<br />", "<BR>", "<BR />"), "\n", $body);
@@ -251,169 +360,201 @@ class MailFetcher {
                 $body=Format::striptags($body); //Strip tags??
             }
         }
+
         return $body;
     }
 
-    function createTicket($mid,$emailid=0){
-        global $cfg, $ost;
+    //email to ticket 
+    function createTicket($mid) { 
+        global $ost;
 
-        $mailinfo=$this->getHeaderInfo($mid);
+        if(!($mailinfo = $this->getHeaderInfo($mid)))
+            return false;
 
-        //Make sure the email is NOT one of the undeleted emails.
-        if($mailinfo['mid'] && ($id=Ticket::getIdByMessageId(trim($mailinfo['mid']),$mailinfo['from']['email']))){
-            //TODO: Move emails to a fetched folder when delete is false?? 
-            return true;
-        }
+        //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['from']['email'] && EmailFilter::isBanned($mailinfo['from']['email'])) {
+        if($mailinfo['email'] && EmailFilter::isBanned($mailinfo['email'])) {
 	        //We need to let admin know...
-            $ost->logWarning('Ticket denied', 'Banned email - '.$mailinfo['from']['email']);
-	        return true;
+            $ost->logWarning('Ticket denied', 'Banned email - '.$mailinfo['email']);
+	        return true; //Report success (moved or delete)
         }
-	
 
-        $var['name']=$this->mime_decode($mailinfo['from']['name']);
-        $var['email']=$mailinfo['from']['email'];
+        $emailId = $this->getEmailId();
+
+        $var['name']=$this->mime_decode($mailinfo['name']);
+        $var['email']=$mailinfo['email'];
         $var['subject']=$mailinfo['subject']?$this->mime_decode($mailinfo['subject']):'[No Subject]';
         $var['message']=Format::stripEmptyLines($this->getBody($mid));
         $var['header']=$this->getHeader($mid);
-        $var['emailId']=$emailid?$emailid:$cfg->getDefaultEmailId(); //ok to default?
+        $var['emailId']=$emailId?$emailId:$ost->getConfig()->getDefaultEmailId(); //ok to default?
         $var['name']=$var['name']?$var['name']:$var['email']; //No name? use email
         $var['mid']=$mailinfo['mid'];
 
-        if($cfg->useEmailPriority())
-            $var['pri']=$this->getPriority($mid);
+        if(!$var['message']) //An email with just attachments can have empty body.
+            $var['message'] = '(EMPTY)';
+
+        if($ost->getConfig()->useEmailPriority())
+            $var['priorityId']=$this->getPriority($mid);
        
         $ticket=null;
         $newticket=true;
         //Check the subject line for possible ID.
-        if(preg_match ("[[#][0-9]{1,10}]",$var['subject'],$regs)) {
-            $extid=trim(preg_replace("/[^0-9]/", "", $regs[0]));
-            $ticket= new Ticket(Ticket::getIdByExtId($extid));
+        if($var['subject'] && preg_match ("[[#][0-9]{1,10}]", $var['subject'], $regs)) {
+            $tid=trim(preg_replace("/[^0-9]/", "", $regs[0]));
             //Allow mismatched emails?? For now NO.
-            if(!$ticket || strcasecmp($ticket->getEmail(),$var['email']))
+            if(!($ticket=Ticket::lookupByExtId($tid)) || strcasecmp($ticket->getEmail(), $var['email']))
                 $ticket=null;
         }
         
         $errors=array();
-        if(!$ticket) {
-            # Apply email filters for the new ticket
-            $ef = new EmailFilter($var); $ef->apply($var);
-            if(!($ticket=Ticket::create($var,$errors,'Email')) || $errors)
-                return null;
-            $msgid=$ticket->getLastMsgId();
-        }else{
-            $message=$var['message'];
-            //Strip quoted reply...TODO: figure out how mail clients do it without special tag..
-            if($cfg->stripQuotedReply() && ($tag=$cfg->getReplySeparator()) && strpos($var['message'],$tag))
-                list($message)=split($tag,$var['message']);
-            $msgid=$ticket->postMessage($message,'Email',$var['mid'],$var['header']);
+        if($ticket) {
+            if(!($msgid=$ticket->postMessage($var['message'], 'Email', $var['mid'], $var['header'])))
+                return false;
+
+        } elseif (($ticket=Ticket::create($var, $errors, 'Email'))) {
+            $msgid = $ticket->getLastMsgId();
+        } else {
+            //TODO: Log error..
+            return null;
         }
-        //Save attachments if any.
-        if($msgid && $cfg->allowEmailAttachments()){
-            if(($struct = imap_fetchstructure($this->mbox,$mid)) && $struct->parts) {
-                if($ticket->getLastMsgId()!=$msgid)
-                    $ticket->setLastMsgId($msgid);
-                $this->saveAttachments($ticket,$mid,$struct);
 
+        //Save attachments if any.
+        if($msgid 
+                && $ost->getConfig()->allowEmailAttachments()
+                && ($struct = imap_fetchstructure($this->mbox, $mid)) 
+                && $struct->parts 
+                && ($attachments=$this->getAttachments($struct))) {
+                
+            //We're just checking the type of file - not size or number of attachments...
+            // Restrictions are mainly due to PHP file uploads limitations
+            foreach($attachments as $a ) {
+                if($ost->isFileTypeAllowed($a['name'], $a['mime'])) {
+                    $file = array(
+                            'name'  => $a['name'],
+                            'type'  => $a['mime'],
+                            'data'  => $this->decode($a['encoding'], imap_fetchbody($this->mbox, $mid, $a['index']))
+                            );
+                    $ticket->saveAttachment($file, $msgid, 'M');
+                } else {
+                    //This should be really a comment on message - NoT an internal note.
+                    //TODO: support comments on Messages and Responses.
+                    $error = sprintf('Attachment %s [%s] rejected because of file type', $a['name'], $a['mime']);
+                    $ticket->postNote('Email Attachment Rejected', $error, false);
+                    $ost->logDebug('Email Attachment Rejected (Ticket #'.$ticket->getExtId().')', $error);
+                }
             }
-        } 
+        }
+
         return $ticket;
     }
 
-    function saveAttachments($ticket,$mid,$part,$index=0) {
-        global $cfg;
 
-        if($part && $part->ifdparameters && ($filename=$part->dparameters[0]->value)){ //attachment
-            $index=$index?$index:1;
-            if($ticket && $cfg->canUploadFileType($filename) && $cfg->getMaxFileSize()>=$part->bytes) {
-                //extract the attachments...and do the magic.
-                $data=$this->decode($part->encoding, imap_fetchbody($this->mbox,$mid,$index));
-                $ticket->saveAttachment($filename,$data,$ticket->getLastMsgId(),'M');
-                return;
-            }
-            //TODO: Log failure??
-        }
+    function fetchEmails() {
 
-        //Recursive attachment search!
-        if($part && $part->parts) {
-            foreach($part->parts as $k=>$struct) {
-                if($index) $prefix = $index.'.';
-                $this->saveAttachments($ticket,$mid,$struct,$prefix.($k+1));
-            }
-        }
 
-    }
+        if(!$this->connect())
+            return false;
 
-    function fetchTickets($emailid,$max=20,$deletemsgs=false,$archivefolder){
+        $archiveFolder = $this->getArchiveFolder();
+        $delete = $this->canDeleteEmails();
+        $max = $this->getMaxFetch();
 
         $nummsgs=imap_num_msg($this->mbox);
         //echo "New Emails:  $nummsgs\n";
         $msgs=$errors=0;
-        for($i=$nummsgs; $i>0; $i--){ //process messages in reverse. Latest first. FILO.
-            if($this->createTicket($i,$emailid)){
-                imap_setflag_full($this->mbox, imap_uid($this->mbox,$i), "\\Seen", ST_UID); //IMAP only??
-                if((!$archivefolder || !imap_mail_move($this->mbox,$i,$archivefolder)) && $deletemsgs)
-                    imap_delete($this->mbox,$i);
+        for($i=$nummsgs; $i>0; $i--) { //process messages in reverse.
+            if($this->createTicket($i)) {
+
+                imap_setflag_full($this->mbox, imap_uid($this->mbox, $i), "\\Seen", ST_UID); //IMAP only??
+                if((!$archiveFolder || !imap_mail_move($this->mbox, $i, $archiveFolder)) && $delete)
+                    imap_delete($this->mbox, $i);
+
                 $msgs++;
                 $errors=0; //We are only interested in consecutive errors.
-            }else{
+            } else {
                 $errors++;
             }
-            if(($max && $msgs>=$max) || $errors>20)
+
+            if($max && ($msgs>=$max || $errors>($max*0.8)))
                 break;
         }
+
+        //Warn on excessive errors
+        if($errors>$msgs) {
+            $warn=sprintf('Excessive errors processing emails for %s/%s. Please manually check the inbox.',
+                    $this->getHost(), $this->getUsername());
+            $this->log($warn);
+        }
+
         @imap_expunge($this->mbox);
 
         return $msgs;
     }
 
-    function fetchMail(){
-        global $ost, $cfg;
+    function log($error) {
+        global $ost;
+        $ost->logWarning('Mail Fetcher', $error);
+    }
+
+    /*
+       MailFetcher::run()
+
+       Static function called to initiate email polling 
+     */
+    function run() {
+        global $ost;
       
-        if(!$cfg->canFetchMail())
+        if(!$ost->getConfig()->isEmailPollingEnabled())
             return;
 
         //We require imap ext to fetch emails via IMAP/POP3
+        //We check here just in case the extension gets disabled post email config...
         if(!function_exists('imap_open')) {
-            $msg='osTicket requires PHP IMAP extension enabled for IMAP/POP3 fetch to work!';
+            $msg='osTicket requires PHP IMAP extension enabled for IMAP/POP3 email fetch to work!';
             $ost->logWarning('Mail Fetch Error', $msg);
             return;
         }
 
-        $MAX_ERRORS=5; //Max errors before we start delayed fetch attempts - hardcoded for now.
+        //Hardcoded error control... 
+        $MAXERRORS = 5; //Max errors before we start delayed fetch attempts
+        $TIMEOUT = 10; //Timeout in minutes after max errors is reached.
 
-        $sql=' SELECT email_id,mail_host,mail_port,mail_protocol,mail_encryption,mail_delete,mail_archivefolder,mail_errors,userid,userpass FROM '.EMAIL_TABLE.
-             ' WHERE mail_active=1 AND (mail_errors<='.$MAX_ERRORS.' OR (TIME_TO_SEC(TIMEDIFF(NOW(),mail_lasterror))>5*60) )'.
-             ' AND (mail_lastfetch IS NULL OR TIME_TO_SEC(TIMEDIFF(NOW(),mail_lastfetch))>mail_fetchfreq*60) ';
-        //echo $sql;
-        if(!($accounts=db_query($sql)) || !db_num_rows($accounts))
-            return;
+        $sql=' SELECT email_id, mail_errors FROM '.EMAIL_TABLE
+            .' WHERE mail_active=1 '
+            .'  AND (mail_errors<='.$MAXERRORS.' OR (TIME_TO_SEC(TIMEDIFF(NOW(), mail_lasterror))>'.($TIMEOUT*60).') )'
+            .'  AND (mail_lastfetch IS NULL OR TIME_TO_SEC(TIMEDIFF(NOW(), mail_lastfetch))>mail_fetchfreq*60)'
+            .' ORDER BY mail_lastfetch DESC'
+            .' LIMIT 10'; //Processing up to 10 emails at a time.
+
+       // echo $sql;
+        if(!($res=db_query($sql)) || !db_num_rows($res))
+            return;  /* Failed query (get's logged) or nothing to do... */
 
         //TODO: Lock the table here??
-        while($row=db_fetch_array($accounts)) {
-            $fetcher = new MailFetcher($row['userid'], Mcrypt::decrypt($row['userpass'],SECRET_SALT),
-                                       $row['mail_host'],$row['mail_port'],$row['mail_protocol'],$row['mail_encryption']);
-            if($fetcher->connect()){   
-                $fetcher->fetchTickets($row['email_id'],$row['mail_fetchmax'],$row['mail_delete']?true:false,$row['mail_archivefolder']);
+
+        while(list($emailId, $errors)=db_fetch_row($res)) {
+            $fetcher = new MailFetcher($emailId);
+            if($fetcher->connect()) {
+                $fetcher->fetchEmails();
                 $fetcher->close();
-                db_query('UPDATE '.EMAIL_TABLE.' SET mail_errors=0, mail_lastfetch=NOW() WHERE email_id='.db_input($row['email_id']));
-            }else{
-                $errors=$row['mail_errors']+1;
-                db_query('UPDATE '.EMAIL_TABLE.' SET mail_errors=mail_errors+1, mail_lasterror=NOW() WHERE email_id='.db_input($row['email_id']));
-                if($errors>=$MAX_ERRORS){
+                db_query('UPDATE '.EMAIL_TABLE.' SET mail_errors=0, mail_lastfetch=NOW() WHERE email_id='.db_input($emailId));
+            } else {
+                db_query('UPDATE '.EMAIL_TABLE.' SET mail_errors=mail_errors+1, mail_lasterror=NOW() WHERE email_id='.db_input($emailId));
+                if(++$errors>=$MAXERRORS) {
                     //We've reached the MAX consecutive errors...will attempt logins at delayed intervals
-                    $msg="\nThe system is having trouble fetching emails from the following mail account: \n".
-                        "\nUser: ".$row['userid'].
-                        "\nHost: ".$row['mail_host'].
+                    $msg="\nosTicket is having trouble fetching emails from the following mail account: \n".
+                        "\nUser: ".$fetcher->getUsername().
+                        "\nHost: ".$fetcher->getHost().
                         "\nError: ".$fetcher->getLastError().
-                        "\n\n ".$errors.' consecutive errors. Maximum of '.$MAX_ERRORS. ' allowed'.
-                        "\n\n This could be connection issues related to the host. Next delayed login attempt in aprox. 10 minutes";
+                        "\n\n ".$errors.' consecutive errors. Maximum of '.$MAXERRORS. ' allowed'.
+                        "\n\n This could be connection issues related to the mail server. Next delayed login attempt in aprox. $TIMEOUT minutes";
                     $ost->alertAdmin('Mail Fetch Failure Alert', $msg, true);
                 }
             }
-        }
+        } //end while.
     }
 }
 ?>
diff --git a/include/class.mailparse.php b/include/class.mailparse.php
index f56006fa9c1e35c88d67165302a7797f43f562d7..8d162e52a6d9182b6cca5284ff061538b4124ff9 100644
--- a/include/class.mailparse.php
+++ b/include/class.mailparse.php
@@ -140,7 +140,7 @@ class Mail_Parse {
                 //Cleanup the html.
                 $body=str_replace("</DIV><DIV>", "\n", $body);                        
                 $body=str_replace(array("<br>", "<br />", "<BR>", "<BR />"), "\n", $body);
-                $body=Format::striptags($body);
+                $body=Format::striptags(Format::html($body));
             }
         }
         return $body;
diff --git a/include/class.migrater.php b/include/class.migrater.php
new file mode 100644
index 0000000000000000000000000000000000000000..04f38be2af9c46c7705591e550bb993096d723d2
--- /dev/null
+++ b/include/class.migrater.php
@@ -0,0 +1,288 @@
+<?php
+/*********************************************************************
+    class.migrater.php
+
+    Migration utils required by upgrader.
+    
+    Jared Hancock <jared@osticket.com>
+    Copyright (c)  2006-2012 osTicket
+    http://www.osticket.com
+
+    Released under the GNU General Public License WITHOUT ANY WARRANTY.
+    See LICENSE.TXT for details.
+
+    vim: expandtab sw=4 ts=4 sts=4:
+**********************************************************************/
+
+
+/*
+    DatabaseMigrater.
+
+    SQL database migrater. This provides the engine capable of rolling the
+    database for an osTicket installation forward (and perhaps even
+    backward) in time using a set of included migration scripts. Each script
+    will roll the database between two database checkpoints. Where possible,
+    the migrater will roll several checkpoint scripts into one to be applied
+    together.
+
+*/
+
+class DatabaseMigrater {
+
+    var $start;
+    var $end;
+    var $sqldir;
+
+    function DatabaseMigrater($start, $end, $sqldir) {
+       
+        $this->start = $start;
+        $this->end = $end;
+        $this->sqldir = $sqldir;
+       
+    }
+
+    function getPatches($stop=null) {
+
+        $start= $this->start;
+        $stop = $stop?$stop:$this->end;
+
+        $patches = array();
+        while (true) {
+            $next = glob($this->sqldir . substr($start, 0, 8)
+                         . '-*.patch.sql');
+            if (count($next) == 1) {
+                $patches[] = $next[0];
+                $start = substr(basename($next[0]), 9, 8);
+            } elseif (count($next) == 0) {
+                # There are no patches leaving the current signature. We
+                # have to assume that we've applied all the available
+                # patches.
+                break;
+            } else {
+                # Problem -- more than one patch exists from this snapshot.
+                # We probably need a graph approach to solve this.
+                break;
+            }
+
+            # Break if we've reached our target stop.
+            if(!$start || !strncasecmp($start, $stop, 8))
+                break;
+        }
+
+        return $patches;
+    }
+}
+
+
+/*
+    AttachmentMigrater
+
+    Attachment migration from file-based attachments in pre-1.7 to
+    database-backed attachments in osTicket v1.7. This class provides the
+    hardware to find and retrieve old attachments and move them into the new
+    database scheme with the data in the actual database.
+
+    Copyright (c)  2006-2012 osTicket
+    http://www.osticket.com
+
+    Released under the GNU General Public License WITHOUT ANY WARRANTY.
+    See LICENSE.TXT for details.
+
+    vim: expandtab sw=4 ts=4 sts=4:
+*/
+
+include_once(INCLUDE_DIR.'class.file.php');
+
+class AttachmentMigrater {
+
+
+    function AttachmentMigrater() {
+        $this->queue = &$_SESSION['ost_upgrader']['AttachmentMigrater']['queue'];
+        $this->skipList = &$_SESSION['ost_upgrader']['AttachmentMigrater']['skip'];
+        $this->errorList = array();
+    }
+
+
+    /**
+     * Process the migration for a unit of time. This will be used to
+     * overcome the execution time restriction of PHP. This instance can be
+     * stashed in a session and have this method called periodically to
+     * process another batch of attachments
+     *
+     * Returns:
+     * Number of pending attachments to migrate.
+     */
+    function do_batch($time=30, $max=0) {
+
+        if(!$this->queueAttachments($max) || !$this->getQueueLength())
+            return 0;
+
+        $count = 0;
+        $start = Misc::micro_time();
+        while ($this->getQueueLength() && (Misc::micro_time()-$start) < $time)
+            if($this->next() && $max && ++$count>=$max)
+                break;
+
+        return $this->queueAttachments($max);
+
+    }
+
+    function getSkipList() {
+        return $this->skipList;
+    }
+
+    function enqueue($fileinfo) {
+        $this->queue[] = $fileinfo;
+    }
+
+    function getQueue() {
+        return $this->queue;
+    }
+
+    function getQueueLength() { return count($this->queue); }
+    /**
+     * Processes the next item on the work queue. Emits a JSON messages to
+     * indicate current progress.
+     *
+     * Returns:
+     * TRUE/NULL if the migration was successful
+     */
+    function next() {
+        # Fetch next item -- use the last item so the array indices don't
+        # need to be recalculated for every shift() operation.
+        $info = array_pop($this->queue);
+        # Attach file to the ticket
+        if (!($info['data'] = @file_get_contents($info['path']))) {
+            # Continue with next file
+            return $this->skip($info['attachId'],
+                sprintf('%s: Cannot read file contents', $info['path']));
+        }
+        # Get the mime/type of each file
+        # XXX: Use finfo_buffer for PHP 5.3+
+        if(function_exists('mime_content_type')) { 
+            //XXX: function depreciated in newer versions of PHP!!!!!
+            $info['type'] = mime_content_type($info['path']);
+        } elseif (function_exists('finfo_file')) { // PHP 5.3.0+
+            $finfo = finfo_open(FILEINFO_MIME_TYPE);
+            $info['type'] = finfo_file($finfo, $info['path']);
+        }
+        # TODO: Add extension-based mime-type lookup
+
+        if (!($fileId = AttachmentFile::save($info))) {
+            return $this->skip($info['attachId'],
+                sprintf('%s: Unable to migrate attachment', $info['path']));
+        }
+        # Update the ATTACHMENT_TABLE record to set file_id
+        db_query('update '.TICKET_ATTACHMENT_TABLE
+                .' set file_id='.db_input($fileId)
+                .' where attach_id='.db_input($info['attachId']));
+        # Remove disk image of the file. If this fails, the migration for
+        # this file would not be retried, because the file_id in the
+        # TICKET_ATTACHMENT_TABLE has a nonzero value now
+        if (!@unlink($info['path'])) //XXX: what should we do on failure?
+            $this->error(
+                sprintf('%s: Unable to remove file from disk',
+                $info['path']));
+        # TODO: Log an internal note to the ticket?
+        return true;
+    }
+    /**
+     * From (class Ticket::fixAttachments), used to detect the locations of
+     * attachment files
+     */
+    /* static */ function queueAttachments($limit=0){
+        global $cfg, $ost;
+
+        # Since the queue is persistent - we want to make sure we get to empty 
+        # before we find more attachments.
+        if(($qc=$this->getQueueLength()))
+            return $qc;
+
+        $sql='SELECT attach_id, file_name, file_key, Ti.created'
+            .' FROM '.TICKET_ATTACHMENT_TABLE.' TA'
+            .' INNER JOIN '.TICKET_TABLE.' Ti ON (Ti.ticket_id=TA.ticket_id)'
+            .' WHERE NOT file_id ';
+
+        if(($skipList=$this->getSkipList()))
+            $sql.= ' AND attach_id NOT IN('.implode(',', db_input($skipList)).')';
+
+        if($limit && is_numeric($limit))
+            $sql.=' LIMIT '.$limit;
+
+        //XXX: Do a hard fail or error querying the database?
+        if(!($res=db_query($sql)))
+            return $this->error('Unable to query DB for attached files to migrate!');
+
+        $ost->logDebug('Found '.db_num_rows($res).' attachments to migrate');
+        if(!db_num_rows($res))
+            return 0;  //Nothing else to do!!
+
+        $dir=$cfg->getUploadDir();
+        if(!$dir || !is_dir($dir)) //XXX: Abort the upgrade??? Attachments are obviously critical!
+            return $this->error("Attachment directory [$dir] is invalid - aborting attachment migration");
+
+        //Clear queue
+        $this->queue = array();
+        while (list($id,$name,$key,$created)=db_fetch_row($res)) {
+            $month=date('my',strtotime($created));
+            $info=array(
+                'name'=>        $name,
+                'attachId'=>    $id,
+            );
+            $filename15=sprintf("%s/%s_%s",rtrim($dir,'/'),$key,$name);
+            $filename16=sprintf("%s/%s/%s_%s",rtrim($dir,'/'),$month,$key,$name); //new destination.
+            if (file_exists($filename15)) { 
+                $info['path'] = $filename15;
+            } elseif (file_exists($filename16)) {  
+                $info['path'] = $filename16;
+            } else {
+                # XXX Cannot find file for attachment
+                $this->skip($id,
+                        sprintf('%s: Unable to locate attachment file',
+                            $name));
+                # No need to further process this file
+                continue;
+            }
+            # TODO: Get the size and mime/type of each file.
+            #
+            # NOTE: If filesize() fails and file_get_contents() doesn't,
+            # then the AttachmentFile::save() method will automatically
+            # estimate the filesize based on the length of the string data
+            # received in $info['data'] -- ie. no need to do that here.
+            #
+            # NOTE: The size is done here because it should be quick to
+            # lookup out of file inode already loaded. The mime/type may
+            # take a while because it will require a second IO to read the
+            # file data.  To ensure this will finish before the
+            # max_execution_time, perform the type match in the ::next()
+            # method since the entire file content will be read there
+            # anyway.
+            $info['size'] = @filesize($info['path']);
+            # Coroutines would be nice ..
+            $this->enqueue($info);
+        }
+
+        return $this->queueAttachments($limit);
+    }
+
+    function skip($attachId, $error) {
+
+        $this->skipList[] = $attachId;
+
+        return $this->error($error." (ID #$attachId)");
+    }
+
+    function error($what) {
+        global $ost;
+
+        $this->errors++;
+        $this->errorList[] = $what;
+        $ost->logDebug('Upgrader: Attachment Migrater', $what);
+        # Assist in returning FALSE for inline returns with this method
+        return false;
+    }
+    function getErrors() {
+        return $this->errorList;
+    }
+}
+?>
diff --git a/include/class.misc.php b/include/class.misc.php
index 409e4bac6f84eee1c73b1d040eda18455c0f4954..9fd6744ba8913061a5e34c2b10bf705216d286fa 100644
--- a/include/class.misc.php
+++ b/include/class.misc.php
@@ -58,6 +58,13 @@ class Misc {
         return time()-date('Z');
     }
 
+    /* Needed because of PHP 4 support */
+    function micro_time() {
+        list($usec, $sec) = explode(" ", microtime());
+
+        return ((float)$usec + (float)$sec);
+    }
+
     //Current page
     function currentURL() {
         
diff --git a/include/class.nav.php b/include/class.nav.php
index ce3623d37acccb57d0eae500360a5579789683b5..a5ce84cb07affcec52e9ecec88460b790ece4fb6 100644
--- a/include/class.nav.php
+++ b/include/class.nav.php
@@ -181,7 +181,7 @@ class AdminNav extends StaffNav{
             $subnav=array();
             switch(strtolower($k)){
                 case 'dashboard':
-                    $subnav[]=array('desc'=>'System&nbsp;Logs','href'=>'syslogs.php','iconclass'=>'logs');
+                    $subnav[]=array('desc'=>'System&nbsp;Logs','href'=>'logs.php','iconclass'=>'logs');
                     break;
                 case 'settings':
                     $subnav[]=array('desc'=>'Settings&nbsp;&amp;&nbsp;Preferences','href'=>'settings.php','iconclass'=>'preferences');
diff --git a/include/class.osticket.php b/include/class.osticket.php
index 78e249d50436b451acabe7a90db69d578d502c2c..033ec0f82accf22a97b855b39c12c4166fe580af 100644
--- a/include/class.osticket.php
+++ b/include/class.osticket.php
@@ -19,6 +19,8 @@
 **********************************************************************/
 
 require_once(INCLUDE_DIR.'class.config.php'); //Config helper
+require_once(INCLUDE_DIR.'class.csrf.php'); //CSRF token class.
+
 define('LOG_WARN',LOG_WARNING);
 
 class osTicket {
@@ -32,10 +34,19 @@ class osTicket {
 
     var $config;
     var $session;
+    var $csrf;
 
     function osTicket($cfgId) {
+        
         $this->config = Config::lookup($cfgId);
-        $this->session = osTicketSession::start(SESSION_TTL); // start_session 
+
+        //DB based session storage was added starting with v1.7
+        if($this->config && !$this->getConfig()->getDBVersion())
+            $this->session = osTicketSession::start(SESSION_TTL); // start DB based session
+        else
+            session_start();
+
+        $this->csrf = new CSRF('__CSRFToken__');
     }
 
     function isSystemOnline() {
@@ -43,7 +54,7 @@ class osTicket {
     }
 
     function isUpgradePending() {
-        return (defined('SCHEMA_SIGNATURE') && strcasecmp($this->getConfig()->getSchemaSignature(), SCHEMA_SIGNATURE));
+        return (defined('SCHEMA_SIGNATURE') && strcasecmp($this->getDBSignature(), SCHEMA_SIGNATURE));
     }
 
     function getSession() {
@@ -59,6 +70,85 @@ class osTicket {
         return $this->getConfig()?$this->getConfig()->getId():0;
     }
 
+    function getDBSignature() {
+        return $this->getConfig()->getSchemaSignature();
+    }
+
+    function getVersion() {
+        return THIS_VERSION;
+    }
+
+    function getCSRF(){
+        return $this->csrf;
+    }
+
+    function getCSRFToken() {
+        return $this->getCSRF()->getToken();
+    }
+
+    function getCSRFFormInput() {
+        return $this->getCSRF()->getFormInput();
+    }
+
+    function validateCSRFToken($token) {
+        return ($token && $this->getCSRF()->validateToken($token));
+    }
+
+    function checkCSRFToken($name='') {
+
+        $name = $name?$name:$this->getCSRF()->getTokenName();
+        if(isset($_POST[$name]) && $this->validateCSRFToken($_POST[$name]))
+            return true;
+       
+        if(isset($_SERVER['HTTP_X_CSRFTOKEN']) && $this->validateCSRFToken($_SERVER['HTTP_X_CSRFTOKEN']))
+            return true;
+
+        $msg=sprintf('Invalid CSRF token [%s] on %s',
+                ($_POST[$name].''.$_SERVER['HTTP_X_CSRFTOKEN']), THISPAGE);
+        $this->logWarning('Invalid CSRF Token '.$name, $msg);
+
+        return false;
+    }
+    
+    function isFileTypeAllowed($file, $mimeType='') {
+       
+        if(!$file || !($allowedFileTypes=$this->getConfig()->getAllowedFileTypes()))
+            return false;
+
+        //Return true if all file types are allowed (.*)
+        if(trim($allowedFileTypes)=='.*') return true;
+
+        $allowed = array_map('trim', explode(',', strtolower($allowedFileTypes)));
+        $filename = is_array($file)?$file['name']:$file;
+
+        $ext = strtolower(preg_replace("/.*\.(.{3,4})$/", "$1", $filename));
+
+        //TODO: Check MIME type - file ext. shouldn't be solely trusted.
+
+        return ($ext && is_array($allowed) && in_array(".$ext", $allowed));
+    }
+
+    /* Function expects a well formatted array - see  Format::files()
+       It's up to the caller to reject the upload on error.
+     */
+    function validateFileUploads(&$files) {
+       
+        $errors=0;
+        foreach($files as &$file) {
+            if(!$this->isFileTypeAllowed($file))
+                $file['error']='Invalid file type for '.$file['name'];
+            elseif($file['size']>$this->getConfig()->getMaxFileSize())
+                $file['error']=sprintf('File (%s) is too big. Maximum of %s allowed',
+                        $file['name'], Format::file_size($this->getConfig()->getMaxFileSize()));
+            elseif(!$file['error'] && !is_uploaded_file($file['tmp_name']))
+                $file['error']='Invalid or bad upload POST';
+
+            if($file['error']) $errors++;
+        }
+
+        return (!$errors);
+    }
+
     function addExtraHeader($header) {
         $this->headers[md5($header)] = $header;
     }
@@ -122,6 +212,10 @@ class osTicket {
         if(!($to=$this->getConfig()->getAdminEmail()))
             $to=ADMIN_EMAIL;
 
+
+        //append URL to the message
+        $message.="\n\n".THISPAGE;
+
         //Try getting the alert email.
         $email=null;
         if(!($email=$this->getConfig()->getAlertEmail())) 
@@ -155,6 +249,14 @@ class osTicket {
         return $this->log(LOG_ERR, $title, $error, $alert);
     }
 
+    function logDBError($title, $error, $alert=true) {
+
+        if($alert && !$this->getConfig()->alertONSQLError())
+            $alert =false;
+
+        return $this->log(LOG_ERR, $title, $error, $alert);
+    }
+
     function log($priority, $title, $message, $alert=false) {
 
         //We are providing only 3 levels of logs. Windows style.
@@ -180,8 +282,8 @@ class osTicket {
         if($alert)
             $this->alertAdmin($title, $message);
 
-
-        if($this->getConfig()->getLogLevel()<$level)
+        //Logging everything during upgrade.
+        if($this->getConfig()->getLogLevel()<$level && !$this->isUpgradePending())
             return false;
 
         //Save log based on system log level settings.
diff --git a/include/class.ostsession.php b/include/class.ostsession.php
index 0bcd9449fb234c6b9a895da6b046527f7a7909a4..08cac02ce306f616ad0d6329e6a51436a78d9e7d 100644
--- a/include/class.ostsession.php
+++ b/include/class.ostsession.php
@@ -67,10 +67,13 @@ class osTicketSession {
     function write($id, $data){
         global $thisstaff;
 
+        $ttl = ($this && get_class($this) == 'osTicketSession') 
+            ? $this->getTTL() : SESSION_TTL;
+
         $sql='REPLACE INTO '.SESSION_TABLE.' SET session_updated=NOW() '.
              ',session_id='.db_input($id).
              ',session_data='.db_input($data).
-             ',session_expire=(NOW() + INTERVAL '.$this->getTTL().' SECOND)'.
+             ',session_expire=(NOW() + INTERVAL '.$ttl.' SECOND)'.
              ',user_id='.db_input($thisstaff?$thisstaff->getId():0).
              ',user_ip='.db_input($_SERVER['REMOTE_ADDR']).
              ',user_agent='.db_input($_SERVER['HTTP_USER_AGENT']);
diff --git a/include/class.pdf.php b/include/class.pdf.php
index 87e68a7d5277450dfb87eb7bfa54637449f1e105..2257dcc17aa6641fabeeac32a3fcecc28bd7b2c0 100644
--- a/include/class.pdf.php
+++ b/include/class.pdf.php
@@ -17,7 +17,6 @@
 define('THIS_DIR', str_replace('\\\\', '/', realpath(dirname(__FILE__))) . '/'); //Include path..
 define('FPDF_DIR', THIS_DIR . 'fpdf/');
 define('FPDF_FONTPATH', FPDF_DIR . 'font/'); //fonts directory.
-session_cache_limiter('private');
 require (FPDF_DIR . 'fpdf.php');
 
 class Ticket2PDF extends FPDF
@@ -29,10 +28,11 @@ class Ticket2PDF extends FPDF
 	
     var $ticket = null;
 
-	function Ticket2PDF($ticket, $notes=false) {
+	function Ticket2PDF($ticket, $psize='Letter', $notes=false) {
         global $thisstaff;
 
-        parent::FPDF('P', 'mm', $thisstaff->getDefaultPaperSize());
+
+        parent::FPDF('P', 'mm', $psize);
 
         $this->ticket = $ticket;
 
@@ -184,7 +184,7 @@ class Ticket2PDF extends FPDF
                         'R'=>array(255, 224, 179),
                         'N'=>array(250, 250, 210));
         //Get ticket thread
-        if(($entries = $ticket->getThreadWithNotes())) { 
+        if(($entries = $ticket->getThread(($this->includenotes)))) { 
             foreach($entries as $entry) {
 
                 $color = $colors[$entry['thread_type']];
diff --git a/setup/inc/class.setup.php b/include/class.setup.php
similarity index 92%
rename from setup/inc/class.setup.php
rename to include/class.setup.php
index 438eca54505302a30d6da9575067c90b296369dc..e566f2bf019ae55e913c0b1d460cb9389be1c0ac 100644
--- a/setup/inc/class.setup.php
+++ b/include/class.setup.php
@@ -21,14 +21,17 @@ Class SetupWizard {
                         'mysql' => '4.4');
 
     //Version info - same as the latest version.
-    var $version ='1.7-dpr3';
-    var $version_verbose='1.7 DPR 3';
+    
+    var $version =THIS_VERSION;
+    var $version_verbose = THIS_VERSION;
 
     //Errors
     var $errors=array();
 
     function SetupWizard(){
         $this->errors=array();
+        $this->version_verbose = ('osTicket v'. strtoupper(THIS_VERSION));
+
     }
 
     function load_sql_file($file, $prefix, $abort=true, $debug=false) {
@@ -55,6 +58,7 @@ Class SetupWizard {
 
         @mysql_query('SET SESSION SQL_MODE =""');
         foreach($statements as $k=>$sql) {
+            //Note that we're not using db_query - because we want to control how errors are reported.
             if(mysql_query($sql)) continue;
             $error = "[$sql] ".mysql_error();
             if($abort)
diff --git a/include/class.staff.php b/include/class.staff.php
index 2f5726d012d3e6f59e7b23faee48a54023766960..b607f6eac145aa7e7c13547218d936f7662ceb8a 100644
--- a/include/class.staff.php
+++ b/include/class.staff.php
@@ -13,6 +13,7 @@
 
     vim: expandtab sw=4 ts=4 sts=4:
 **********************************************************************/
+include_once(INCLUDE_DIR.'class.ticket.php');
 include_once(INCLUDE_DIR.'class.dept.php');
 include_once(INCLUDE_DIR.'class.team.php');
 include_once(INCLUDE_DIR.'class.group.php');
@@ -24,7 +25,10 @@ class Staff {
     var $id;
 
     var $dept;
+    var $departments;
+    var $group;
     var $teams;
+    var $timezone;
     var $stats;
     
     function Staff($var) {
@@ -37,13 +41,11 @@ class Staff {
         if(!$var && !($var=$this->getId()))
             return false;
 
-        $sql='SELECT staff.*, grp.*, tz.offset as tz_offset '
-            .' ,TIME_TO_SEC(TIMEDIFF(NOW(),IFNULL(staff.passwdreset,staff.created))) as passwd_change_sec '
+        $sql='SELECT staff.*, staff.created as added, grp.* '
             .' FROM '.STAFF_TABLE.' staff '
-            .' LEFT JOIN '.GROUP_TABLE.' grp ON(grp.group_id=staff.group_id) '
-            .' LEFT JOIN '.TIMEZONE_TABLE.' tz ON(tz.id=staff.timezone_id) ';
+            .' LEFT JOIN '.GROUP_TABLE.' grp ON(grp.group_id=staff.group_id) ';
 
-        $sql.=sprintf('WHERE %s=%s',is_numeric($var)?'staff_id':'username',db_input($var));
+        $sql.=sprintf(' WHERE %s=%s',is_numeric($var)?'staff_id':'username',db_input($var));
 
         if(!($res=db_query($sql)) || !db_num_rows($res))
             return NULL;
@@ -51,10 +53,18 @@ class Staff {
         
         $this->ht=db_fetch_array($res);
         $this->id  = $this->ht['staff_id'];
-        $this->teams =$this->ht['teams']=$this->getTeams();
+        $this->teams = $this->ht['teams'] = array();
+        $this->group = $this->dept = null;
+        $this->departments = $this->stats = array();
 
-        $this->teams=array();
-        $this->stats=array();
+        //WE have to patch info here to support upgrading from old versions.
+        if(($time=strtotime($this->ht['passwdreset']?$this->ht['passwdreset']:$this->ht['added'])))
+            $this->ht['passwd_change'] = time()-$time; //XXX: check timezone issues.
+
+        if($this->ht['timezone_id'])
+            $this->ht['tz_offset'] = Timezone::getOffsetById($this->ht['timezone_id']);
+        elseif($this->ht['timezone_offset'])
+            $this->ht['tz_offset'] = $this->ht['timezone_offset'];
 
         return ($this->id);
     }
@@ -96,7 +106,7 @@ class Staff {
     function isPasswdResetDue() {
         global $cfg;
         return ($cfg && $cfg->getPasswdResetPeriod() 
-                    && $this->ht['passwd_change_sec']>($cfg->getPasswdResetPeriod()*30*24*60*60));
+                    && $this->ht['passwd_change']>($cfg->getPasswdResetPeriod()*30*24*60*60));
     }
 
     function isPasswdChangeDue() {
@@ -147,10 +157,6 @@ class Staff {
         return $this->ht['lastname'];
     }
     
-    function getGroupId() {
-        return $this->ht['group_id'];
-    }
-
     function getSignature() {
         return $this->ht['signature'];
     }
@@ -167,13 +173,46 @@ class Staff {
         return ($this->ht['change_passwd']);
     }
 
+    function getDepartments() {
+
+        if($this->departments)
+            return $this->departments;
+
+        //Departments the staff is "allowed" to access...
+        // based on the group they belong to + user's primary dept + user's managed depts.
+        $sql='SELECT DISTINCT d.dept_id FROM '.STAFF_TABLE.' s '
+            .' LEFT JOIN '.GROUP_DEPT_TABLE.' g ON(s.group_id=g.group_id) '
+            .' INNER JOIN '.DEPT_TABLE.' d ON(d.dept_id=s.dept_id OR d.manager_id=s.staff_id OR d.dept_id=g.dept_id) '
+            .' WHERE s.staff_id='.db_input($this->getId());
+
+        $depts = array();
+        if(($res=db_query($sql)) && db_num_rows($res)) {
+            while(list($id)=db_fetch_row($res))
+                $depts[] = $id;
+        } else { //Neptune help us! (fallback)
+            $depts = array_merge($this->getGroup()->getDepartments(), array($this->getDeptId()));
+        }
+
+        $this->departments = array_filter(array_unique($depts));
+
+
+        return $this->departments;
+    }
+
     function getDepts() {
-        //Departments the user is allowed to access...based on the group they belong to + user's dept.
-        return array_filter(array_unique(array_merge(explode(',', $this->ht['dept_access']), array($this->dept_id)))); //Neptune help us
+        return $this->getDepartments();
+    }
+     
+    function getGroupId() {
+        return $this->ht['group_id'];
     }
 
-    function getDepartments() {
-        return $this->getDepts();
+    function getGroup() {
+     
+        if(!$this->group && $this->getGroupId())
+            $this->group = Group::lookup($this->getGroupId());
+
+        return $this->group;
     }
 
     function getDeptId() {
@@ -582,7 +621,7 @@ class Staff {
         if(!$vars['lastname'])
             $errors['lastname']='Last name required';
             
-        if(!$vars['username'] || strlen($vars['username'])<3)
+        if(!$vars['username'] || strlen($vars['username'])<2)
             $errors['username']='Username required';
         elseif(($uid=Staff::getIdByUsername($vars['username'])) && $uid!=$id)
             $errors['username']='Username already in-use';
diff --git a/include/class.team.php b/include/class.team.php
index 48d7b5655ee2066a73811cf76bd3663476b97a0c..cdf4cffcd3148fab082b2dd69f24733481aaeca0 100644
--- a/include/class.team.php
+++ b/include/class.team.php
@@ -80,6 +80,13 @@ class Team {
         return $this->members;
     }
 
+    function hasMember($staff) {
+        return db_count(
+             'SELECT COUNT(*) FROM '.TEAM_MEMBER_TABLE
+            .' WHERE team_id='.db_input($this->getId())
+            .'   AND staff_id='.db_input($staff->getId())) !== 0;
+    }
+
     function getLeadId(){
         return $this->ht['lead_id'];
     }
@@ -126,7 +133,9 @@ class Team {
         if($vars['remove']) {
             $sql='DELETE FROM '.TEAM_MEMBER_TABLE
                 .' WHERE team_id='.db_input($this->getId())
-                .' AND staff_id IN('.implode(',',$_POST['remove']).')';
+                .' AND staff_id IN ('
+                    .implode(',', array_map('db_input', $_POST['remove']))
+                .')';
             db_query($sql);
         }
 
diff --git a/include/class.ticket.php b/include/class.ticket.php
index 6b933239de4bcc181f82a2b88724789e3cc5454c..da45d51935322d606f6e6b60b102c6c63ea363b8 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -624,7 +624,7 @@ class Ticket{
             /* The has here can be changed  but must match validation in attachment.php */
             $hash=md5($attachment['file_id'].session_id().$attachment['file_hash']); 
             if($attachment['size'])
-                $size=sprintf('(<i>%s</i>)',Format::file_size($attachment['size']));
+                $size=sprintf('<em>(%s)</em>', Format::file_size($attachment['size']));
                 
             $str.=sprintf('<a class="Icon file" href="attachment.php?id=%d&h=%s" target="%s">%s</a>%s&nbsp;%s',
                     $attachment['attach_id'], $hash, $target, Format::htmlchars($attachment['name']), $size, $separator);
@@ -866,7 +866,7 @@ class Ticket{
               
             //Only alerts dept members if the ticket is NOT assigned.
             if($cfg->alertDeptMembersONNewTicket() && !$this->isAssigned()) {
-                if(($members=$dept->getAvailableMembers()))
+                if(($members=$dept->getMembers()))
                     $recipients=array_merge($recipients, $members);
             }
             
@@ -877,6 +877,7 @@ class Ticket{
                 if(!is_object($staff) || !$staff->isAvailable() || in_array($staff->getEmail(),$sentlist)) continue;
                 $alert = str_replace("%staff",$staff->getFirstName(),$body);
                 $email->send($staff->getEmail(),$subj,$alert);
+                $sentlist[] = $staff->getEmail();
             }
            
            
@@ -954,7 +955,7 @@ class Ticket{
         $this->reload();
 
 
-        if(!$dept && !($tpl = $dept->getTemplate()))
+        if(!$dept || !($tpl = $dept->getTemplate()))
             $tpl= $cfg->getDefaultTemplate();
        
         //If enabled...send confirmation to user. ( New Message AutoResponse)
@@ -995,7 +996,7 @@ class Ticket{
         $dept = $this->getDept();
 
         //Get template.
-        if(!$dept && !($tpl = $dept->getTemplate()))
+        if(!$dept || !($tpl = $dept->getTemplate()))
             $tpl= $cfg->getDefaultTemplate();
 
         //Email to use!
@@ -1029,8 +1030,8 @@ class Ticket{
                 if(!is_object($staff) || !$staff->isAvailable() || in_array($staff->getEmail(),$sentlist)) continue;
                 $alert = str_replace('%staff', $staff->getFirstName(), $body);
                 $email->send($staff->getEmail(), $subj, $alert);
+                $sentlist[] = $staff->getEmail();
             }
-            print_r($sentlist);
         }
 
         return true;
@@ -1072,7 +1073,7 @@ class Ticket{
                     $recipients=array_merge($recipients, $members);
             } elseif($cfg->alertDeptMembersONOverdueTicket() && !$this->isAssigned()) {
                 //Only alerts dept members if the ticket is NOT assigned.
-                if(($members=$dept->getAvailableMembers()))
+                if(($members=$dept->getMembers()))
                     $recipients=array_merge($recipients, $members);
             }
             //Always alert dept manager??
@@ -1084,6 +1085,7 @@ class Ticket{
                 if(!is_object($staff) || !$staff->isAvailable() || in_array($staff->getEmail(),$sentlist)) continue;
                 $alert = str_replace("%staff",$staff->getFirstName(),$body);
                 $email->send($staff->getEmail(),$subj,$alert);
+                $sentlist[] = $staff->getEmail();
             }
 
         }
@@ -1200,7 +1202,7 @@ class Ticket{
                     $recipients+=$members;
             } elseif($cfg->alertDeptMembersONTransfer() && !$this->isAssigned()) {
                 //Only alerts dept members if the ticket is NOT assigned.
-                if(($members=$dept->getAvailableMembers()))
+                if(($members=$dept->getMembers()))
                     $recipients+=$members;
             }
 
@@ -1213,6 +1215,7 @@ class Ticket{
                 if(!is_object($staff) || !$staff->isAvailable() || in_array($staff->getEmail(),$sentlist)) continue;
                 $alert = str_replace("%staff",$staff->getFirstName(),$body);
                 $email->send($staff->getEmail(),$subj,$alert);
+                $sentlist[] = $staff->getEmail();
             }
          }
 
@@ -1289,18 +1292,27 @@ class Ticket{
     }
 
     //Insert message from client
-    function postMessage($msg,$source='',$emsgid=null,$headers='',$newticket=false){
+    function postMessage($message,$source='',$emsgid=null,$headers='',$newticket=false){
         global $cfg;
        
         if(!$this->getId()) return 0;
-        
+
+
+            
+        //Strip quoted reply...on emailed replies
+        if(!strcasecmp($source, 'Email') 
+                && $cfg->stripQuotedReply() 
+                && ($tag=$cfg->getReplySeparator()) && strpos($msg, $tag))
+            list($msg)=split($tag, $msg);
+
+
         # XXX: Refuse auto-response messages? (via email) XXX: No - but kill our auto-responder.
 
         $sql='INSERT INTO '.TICKET_THREAD_TABLE.' SET created=NOW()'
             .' ,thread_type="M" '
             .' ,ticket_id='.db_input($this->getId())
             # XXX: Put Subject header into the 'title' field
-            .' ,body='.db_input(Format::striptags($msg)) //Tags/code stripped...meaning client can not send in code..etc
+            .' ,body='.db_input(Format::striptags($message)) //Tags/code stripped...meaning client can not send in code..etc
             .' ,source='.db_input($source?$source:$_SERVER['REMOTE_ADDR'])
             .' ,ip_address='.db_input($_SERVER['REMOTE_ADDR']);
     
@@ -1313,8 +1325,7 @@ class Ticket{
                 .' SET message_id='.db_input($msgid)
                 .', email_mid='.db_input($emsgid)
                 .', headers='.db_input($headers);
-
-            if (!db_query($sql)) return 0;
+            db_query($sql);
         }
 
         if($newticket) return $msgid; //Our work is done...
@@ -1333,13 +1344,12 @@ class Ticket{
         if(!($email=$cfg->getAlertEmail()))
             $email =$cfg->getDefaultEmail();
 
-
         //If enabled...send alert to staff (New Message Alert)
         if($cfg->alertONNewMessage() && $tpl && $email && ($msg=$tpl->getNewMessageAlertMsgTemplate())) {
 
             $body=$this->replaceTemplateVars($msg['body']);
             $subj=$this->replaceTemplateVars($msg['subj']);
-            $body = str_replace("%message", $msg,$body);
+            $body = str_replace("%message", $message,$body);
 
             //Build list of recipients and fire the alerts.
             $recipients=array();
@@ -1361,7 +1371,7 @@ class Ticket{
                 if(!$staff || !$staff->getEmail() || !$staff->isAvailable() && in_array($staff->getEmail(),$sentlist)) continue;
                 $alert = str_replace("%staff",$staff->getFirstName(),$body);
                 $email->send($staff->getEmail(),$subj,$alert);
-                $sentlist[]=$staff->getEmail();
+                $sentlist[] = $staff->getEmail();
             }
         }
         
@@ -1369,7 +1379,7 @@ class Ticket{
     }
 
     /* public */ 
-    function postReply($vars, $files, $errors, $alert = true) {
+    function postReply($vars, $errors, $alert = true) {
         global $thisstaff,$cfg;
 
         if(!$thisstaff || !$thisstaff->isStaff() || !$cfg) return 0;
@@ -1377,7 +1387,7 @@ class Ticket{
         if(!$vars['msgId'])
             $errors['msgId'] ='Missing messageId - internal error';
         if(!$vars['response'])
-            $errors['response'] = 'Resonse message required';
+            $errors['response'] = 'Response message required';
 
         if($errors) return 0;
 
@@ -1398,20 +1408,17 @@ class Ticket{
             $this->setStatus($vars['reply_ticket_status']);
 
         /* We can NOT recover from attachment related failures at this point */
-        //upload files.
-        $attachments = $uploads = array();
-        //Web based upload..
-        if($files && is_array($files) && ($files=Format::files($files)))
-            $attachments=array_merge($attachments,$files);
+        $attachments = array();
+        //Web based upload.. note that we're not "validating" attachments on response.
+        if($_FILES['attachments'] && ($files=Format::files($_FILES['attachments'])))
+            $attachments=$this->uploadAttachments($files, $respId, 'R');
 
         //Canned attachments...
-        if($vars['cannedattachments'] && is_array($vars['cannedattachments']))
-            $attachments=array_merge($attachments,$vars['cannedattachments']);
-
-        
-        //Upload attachments -ids used on outgoing emails are returned.
-        if($attachments)
-            $uploads = $this->uploadAttachments($attachments, $respId,'R');
+        if($vars['cannedattachments'] && is_array($vars['cannedattachments'])) {
+            foreach($vars['cannedattachments'] as $fileId)
+                if($fileId && $this->saveAttachment($fileId, $respId, 'R'))
+                    $attachments[] = $fileId;
+        }
 
         $this->onResponse(); //do house cleaning..
         $this->reload();
@@ -1445,7 +1452,7 @@ class Ticket{
                 $body ="\n$tag\n\n".$body;
 
             //Set attachments if emailing.
-            $attachments =($cfg->emailAttachments() && $uploads)?$this->getAttachments($respId,'R'):array();
+            $attachments =($cfg->emailAttachments() && $attachments)?$this->getAttachments($respId,'R'):array();
             //TODO: setup  5 param (options... e.g mid trackable on replies)
             $email->send($this->getEmail(), $subj, $body, $attachments);
         }
@@ -1494,14 +1501,16 @@ class Ticket{
     //Insert Internal Notes 
     function postNote($title,$note,$alert=true,$poster='') {        
         global $thisstaff,$cfg;
-
+		
+        $poster=($poster || !$thisstaff)?$poster:$thisstaff->getName();
+		
         $sql= 'INSERT INTO '.TICKET_THREAD_TABLE.' SET created=NOW() '.
                 ',thread_type="N"'.
                 ',ticket_id='.db_input($this->getId()).
                 ',title='.db_input(Format::striptags($title)).
                 ',body='.db_input(Format::striptags($note)).
                 ',staff_id='.db_input($thisstaff?$thisstaff->getId():0).
-                ',poster='.db_input(($poster || !$thisstaff)?$poster:$thisstaff->getName());
+                ',poster='.db_input($poster);
         //echo $sql;
         if(!db_query($sql) || !($id=db_insert_id()))
             return false;
@@ -1522,6 +1531,8 @@ class Ticket{
             $body=$this->replaceTemplateVars($msg['body']);
             $subj=$this->replaceTemplateVars($msg['subj']);
             $body = str_replace('%note',"$title\n\n$note",$body);
+            # TODO: Support a variable replacement of the staff writing the
+            #       note
 
             // Alert recipients    
             $recipients=array();
@@ -1544,7 +1555,7 @@ class Ticket{
                 if(in_array($staff->getEmail(),$sentlist) || ($thisstaff && $thisstaff->getId()==$staff->getId())) continue; 
                 $alert = str_replace('%staff',$staff->getFirstName(),$body);
                 $email->send($staff->getEmail(),$subj,$alert);
-                $sentlist[]=$staff->getEmail();
+                $sentlist[] = $staff->getEmail();
             }
         }
         
@@ -1552,23 +1563,40 @@ class Ticket{
     }
 
     //Print ticket... export the ticket thread as PDF.
-    function pdfExport() {
-        $pdf = new Ticket2PDF($this, true);
+    function pdfExport($psize='Letter', $notes=false) {
+        $pdf = new Ticket2PDF($this, $psize, $notes);
         $name='Ticket-'.$this->getExtId().'.pdf';
         $pdf->Output($name, 'I');
+        //Remember what the user selected - for autoselect on the next print.
+        $_SESSION['PAPER_SIZE'] = $psize;
         exit;
     }
 
     //online based attached files.
     function uploadAttachments($files, $refid, $type) {
+        global $ost;
 
         $uploaded=array();
         foreach($files as $file) {
-            if(($fileId=is_numeric($file)?$file:AttachmentFile::upload($file)) && is_numeric($fileId))
-                if($this->saveAttachment($fileId, $refid, $type))
-                    $uploaded[]=$fileId;
-        }
+            if(!$file['error'] 
+                    && ($id=AttachmentFile::upload($file)) 
+                    && $this->saveAttachment($id, $refid, $type))
+                $uploaded[]=$id;
+            elseif($file['error']!=UPLOAD_ERR_NO_FILE) { 
+                
+                // log file upload errors as interal notes + syslog debug.
+                if($file['error'] && gettype($file['error'])=='string')
+                    $error = $file['error'];
+                else
+                    $error ='Error #'.$file['error'];
 
+                $this->postNote('File Upload Error', $error, false);
+               
+                $ost->logDebug('File Upload Error (Ticket #'.$this->getExtId().')', $error);
+            }
+            
+        }
+        
         return $uploaded;
     }
 
@@ -1751,7 +1779,7 @@ class Ticket{
         global $cfg;
         
         /* Unknown or invalid staff */
-        if(!$staff || (!is_object($staff) && !($staff=Staff::lookup($staff))) || !$staff->isStaff())
+        if(!$staff || (!is_object($staff) && !($staff=Staff::lookup($staff))) || !$staff->isStaff() || $cfg->getDBVersion())
             return null;
 
 
@@ -1773,12 +1801,11 @@ class Ticket{
         if(($teams=$staff->getTeams()))
             $sql.=' OR ticket.team_id IN('.implode(',', array_filter($teams)).')';
 
-        if(!$staff->showAssignedOnly()) //Staff with limited access just see Assigned tickets.
-            $sql.=' OR ticket.dept_id IN('.implode(',',$staff->getDepts()).') ';
+        if(!$staff->showAssignedOnly() && ($depts=$staff->getDepts())) //Staff with limited access just see Assigned tickets.
+            $sql.=' OR ticket.dept_id IN('.implode(',', $depts).') ';
 
         $sql.=')';
 
-
         if(!$cfg || !($cfg->showAssignedTickets() || $staff->showAssignedTickets()))
             $sql.=' AND (ticket.staff_id=0 OR ticket.staff_id='.db_input($staff->getId()).') ';
 
@@ -1960,16 +1987,15 @@ class Ticket{
             return null;
 
         /* -------------------- POST CREATE ------------------------ */
-        $dept = $ticket->getDept();
-     
+        
         if(!$cfg->useRandomIds()){
             //Sequential ticketIDs support really..really suck arse.
             $extId=$id; //To make things really easy we are going to use autoincrement ticket_id.
             db_query('UPDATE '.TICKET_TABLE.' SET ticketID='.db_input($extId).' WHERE ticket_id='.$id.' LIMIT 1'); 
             //TODO: RETHING what happens if this fails?? [At the moment on failure random ID is used...making stuff usable]
-        }   
-
+        }
 
+        $dept = $ticket->getDept();
         //post the message.
         $msgid=$ticket->postMessage($vars['message'],$source,$vars['mid'],$vars['header'],true);
 
@@ -2004,8 +2030,26 @@ class Ticket{
             $autorespond=false;
         }
 
-        /***** See if we need to send some alerts ****/
+        if ($vars['cannedResponseId']
+                && ($canned = Canned::lookup($vars['cannedResponseId']))
+                && $canned->isEnabled()) {
+            $files = array();
+            foreach ($canned->getAttachments() as $file)
+                $files[] = $file['id'];
+            $ticket->postReply(
+                    array(
+                        'msgId'     => $msgid,
+                        'response'  =>
+                            $ticket->replaceTemplateVars($canned->getResponse()),
+                        'cannedattachments' => $files
+                    ),$errors, true);
+                    
+            // If a canned-response is immediately queued for this ticket,
+            // disable the autoresponse
+            $autorespond=false;
+        }
 
+        /***** See if we need to send some alerts ****/
         $ticket->onNewTicket($vars['message'], $autorespond, $alertstaff);
 
         /************ check if the user JUST reached the max. open tickets limit **********/
@@ -2023,7 +2067,7 @@ class Ticket{
         return $ticket;
     }
 
-    function open($vars, $files, &$errors) {
+    function open($vars, &$errors) {
         global $thisstaff,$cfg;
 
         if(!$thisstaff || !$thisstaff->canCreateTickets()) return false;
@@ -2045,7 +2089,7 @@ class Ticket{
         // post response - if any
         if($vars['response']) {
             $vars['response']=$ticket->replaceTemplateVars($vars['response']);
-            if(($respId=$ticket->postReply($vars,  $files, $errors, false))) {
+            if(($respId=$ticket->postReply($vars, $errors, false))) {
                 //Only state supported is closed on response
                 if(isset($vars['ticket_state']) && $thisstaff->canCloseTickets())
                     $ticket->setState($vars['ticket_state']);
diff --git a/include/class.timezone.php b/include/class.timezone.php
new file mode 100644
index 0000000000000000000000000000000000000000..cdff816345a2048b667b1385cdd73df35c500862
--- /dev/null
+++ b/include/class.timezone.php
@@ -0,0 +1,71 @@
+<?php
+/*********************************************************************
+    class.timezone.php
+
+    Time zone get utils.
+
+    Peter Rotich <peter@osticket.com>
+    Copyright (c)  2006-2012 osTicket
+    http://www.osticket.com
+
+    Released under the GNU General Public License WITHOUT ANY WARRANTY.
+    See LICENSE.TXT for details.
+
+    vim: expandtab sw=4 ts=4 sts=4:
+**********************************************************************/
+
+class Timezone {
+
+    var $id;
+    var $ht;
+
+    function Timezone($id){
+        $this->id=0;
+        return $this->load($id);
+    }
+
+    function load($id=0) {
+
+        if(!$id && !($id=$this->getId()))
+            return false;
+
+        $sql='SELECT * FROM '.TIMEZONE_TABLE.' WHERE id='.db_input($id);
+        if(!($res=db_query($sql)) || !db_num_rows($res))
+            return false;
+
+        $this->ht=db_fetch_array($res);
+        $this->id=$this->ht['id'];
+        
+        return $this->id;
+    }
+
+    function reload() {
+        return $this->load();
+    }
+
+    function getId() { 
+        return $this->id;
+    }
+        
+    function getOffset() {
+        return $this->ht['offset'];    
+    }
+
+    function getName() {
+        return $this->info['timezone'];
+    }
+
+    function getDesc() {
+        return $this->getName();
+    }
+
+    /* static functions */
+    function lookup($id) {
+        return ($id && is_numeric($id) && ($tz= new Timezone($id)) && $tz->getId()==$id)?$tz:null;
+    }
+
+    function getOffsetById($id) {
+        return ($tz=Timezone::lookup($id))?$tz->getOffset():0;
+    }
+}
+?>
diff --git a/setup/inc/class.upgrader.php b/include/class.upgrader.php
similarity index 57%
rename from setup/inc/class.upgrader.php
rename to include/class.upgrader.php
index 891d472d9264a78501bac8ec6d7a4d28abf8553c..7fa6c331ff542c44e7f4329c4e164f0848cf837e 100644
--- a/setup/inc/class.upgrader.php
+++ b/include/class.upgrader.php
@@ -14,8 +14,8 @@
     vim: expandtab sw=4 ts=4 sts=4:
 **********************************************************************/
 
-require_once INC_DIR.'class.setup.php';
-require_once INC_DIR.'class.migrater.php';
+require_once INCLUDE_DIR.'class.setup.php';
+require_once INCLUDE_DIR.'class.migrater.php';
 
 class Upgrader extends SetupWizard {
 
@@ -31,8 +31,12 @@ class Upgrader extends SetupWizard {
         $this->sqldir = $sqldir;
         $this->errors = array();
 
+        //Disable time limit if - safe mode is set.
+        if(!ini_get('safe_mode'))
+            set_time_limit(0);
+
         //Init persistent state of upgrade.
-        $this->state = &$_SESSION['ost_upgrader'][$this->getShash()]['state'];
+        $this->state = &$_SESSION['ost_upgrader']['state'];
 
         //Init the task Manager.
         if(!isset($_SESSION['ost_upgrader'][$this->getShash()]))
@@ -45,16 +49,29 @@ class Upgrader extends SetupWizard {
         $this->migrater = new DatabaseMigrater($this->signature, SCHEMA_SIGNATURE, $this->sqldir);
     }
 
-    function getStops() {
-        return array('7be60a84' => 'migrateAttachments2DB');
-    }
-
     function onError($error) {
-        global $ost;
+        global $ost, $thisstaff;
 
         $ost->logError('Upgrader Error', $error);
         $this->setError($error);
         $this->setState('aborted');
+
+        //Alert staff upgrading the system - if the email is not same as admin's
+        // admin gets alerted on error log (above)
+        if(!$thisstaff || !strcasecmp($thisstaff->getEmail(), $ost->getConfig()->getAdminEmail()))
+            return;
+
+        $email=null;
+        if(!($email=$ost->getConfig()->getAlertEmail()))
+            $email=$ost->getConfig()->getDefaultEmail(); //will take the default email.
+
+        $subject = 'Upgrader Error';
+        if($email) {
+            $email->send($thistaff->getEmail(), $subject, $error);
+        } else {//no luck - try the system mail.
+            Mailer::sendmail($thistaff->getEmail(), $subject, $error, sprintf('"osTicket Alerts"<%s>', $thistaff->getEmail()));
+        }
+
     }
 
     function isUpgradable() {
@@ -177,10 +194,14 @@ class Upgrader extends SetupWizard {
 
     function doTasks() {
 
+        global $ost;
         if(!($tasks=$this->getPendingTasks()))
             return true; //Nothing to do.
 
+        $ost->logDebug('Upgrader', sprintf('There are %d pending upgrade tasks', count($tasks)));
+        $start_time = Misc::micro_time();
         foreach($tasks as $k => $task) {
+            //TODO: check time used vs. max execution - break if need be
             if(call_user_func(array($this, $task['func']), $k)===0) {
                 $this->tasks[$k]['done'] = true;
             } else { //Task has pending items to process.
@@ -188,7 +209,7 @@ class Upgrader extends SetupWizard {
             }
         }
 
-        return (!$this->getPendingTasks());
+        return $this->getPendingTasks();
     }
     
     function upgrade() {
@@ -197,7 +218,12 @@ class Upgrader extends SetupWizard {
         if($this->getPendingTasks() || !($patches=$this->getPatches()))
             return false;
 
+        $start_time = Misc::micro_time();
+        if(!($max_time = ini_get('max_execution_time')))
+            $max_time = 300; //Apache/IIS defaults.
+
         foreach ($patches as $patch) {
+            //TODO: check time used vs. max execution - break if need be
             if (!$this->load_sql_file($patch, $this->getTablePrefix()))
                 return false;
 
@@ -214,14 +240,24 @@ class Upgrader extends SetupWizard {
             $ost->logDebug('Upgrader - Patch applied', $logMsg);
             
             //Check if the said patch has scripted tasks
-            if(!($tasks=$this->getTasksForPatch($phash)))
+            if(!($tasks=$this->getTasksForPatch($phash))) {
+                //Break IF elapsed time is greater than 80% max time allowed.
+                if(($elapsedtime=(Misc::micro_time()-$start_time)) && $max_time && $elapsedtime>($max_time*0.80))
+                    break;
+
                 continue;
 
+            }
+
             //We have work to do... set the tasks and break.
             $shash = substr($phash, 9, 8);
             $_SESSION['ost_upgrader'][$shash]['tasks'] = $tasks;
             $_SESSION['ost_upgrader'][$shash]['state'] = 'upgrade';
+            
+            $ost->logDebug('Upgrader', sprintf('Found %d tasks to be executed for %s',
+                            count($tasks), $shash));
             break;
+
         }
 
         return true;
@@ -232,25 +268,39 @@ class Upgrader extends SetupWizard {
 
         $tasks=array();
         switch($phash) { //Add  patch specific scripted tasks.
-            case 'd4fe13b1-7be60a84': //V1.6 ST- 1.7 *
+            case 'c00511c7-7be60a84': //V1.6 ST- 1.7 * {{MD5('1.6 ST') -> c00511c7c1db65c0cfad04b4842afc57}}
                 $tasks[] = array('func' => 'migrateAttachments2DB',
                                  'desc' => 'Migrating attachments to database, it might take a while depending on the number of files.');
+                $tasks[] = array('func' => 'migrateSessionFile2DB',
+                                 'desc' => 'Transitioning to db-backed sessions');
+                break;
+            case '98ae1ed2-e342f869': //v1.6 RC1-4 -> v1.6 RC5
+                $tasks[] = array('func' => 'migrateAPIKeys',
+                                 'desc' => 'Migrating API keys to a new table');
+                break;
+            case '435c62c3-2e7531a2':
+                $tasks[] = array('func' => 'migrateGroupDeptAccess',
+                                 'desc' => 'Migrating group\'s department access to a new table');
                 break;
         }
 
-        //Check if cleanup p 
+        //Check IF SQL cleanup exists. 
         $file=$this->getSQLDir().$phash.'.cleanup.sql';
         if(file_exists($file)) 
-            $tasks[] = array('func' => 'cleanup', 'desc' => 'Post-upgrade cleanup!');
-
+            $tasks[] = array('func' => 'cleanup',
+                             'desc' => 'Post-upgrade cleanup!',
+                             'phash' => $phash);
 
         return $tasks;
     }
 
     /************* TASKS **********************/
-    function cleanup($tId=0) {
+    function cleanup($taskId) {
+        global $ost;
+
+        $phash = $this->tasks[$taskId]['phash'];
+        $file=$this->getSQLDir().$phash.'.cleanup.sql';
 
-        $file=$this->getSQLDir().$this->getShash().'-cleanup.sql';
         if(!file_exists($file)) //No cleanup script.
             return 0;
 
@@ -258,18 +308,68 @@ class Upgrader extends SetupWizard {
         if($this->load_sql_file($file, $this->getTablePrefix(), false, true))
             return 0;
 
-        //XXX: ???
-        return false;
+        $ost->logDebug('Upgrader', sprintf("%s: Unable to process cleanup file",
+                        $phash));
+        return 0;
     }
-    
 
-    function migrateAttachments2DB($tId=0) {
-        echo "Process attachments here - $tId";
+    function migrateAttachments2DB($taskId) {
+        global $ost;
+        
+        if(!($max_time = ini_get('max_execution_time')))
+            $max_time = 30; //Default to 30 sec batches.
+
         $att_migrater = new AttachmentMigrater();
-        $att_migrater->start_migration();
-        # XXX: Loop here (with help of task manager)
-        $att_migrater->do_batch();
+        if($att_migrater->do_batch(($max_time*0.9), 100)===0)
+            return 0;
+
+        return $att_migrater->getQueueLength();
+    }
+
+    function migrateSessionFile2DB($taskId) {
+        # How about 'dis for a hack?
+        osTicketSession::write(session_id(), session_encode()); 
         return 0;
     }
+
+    function migrateAPIKeys($taskId) {
+
+        $res = db_query('SELECT api_whitelist, api_key FROM '.CONFIG_TABLE.' WHERE id=1');
+        if(!$res || !db_num_rows($res))
+            return 0;  //Reporting success.
+
+        list($whitelist, $key) = db_fetch_row($res);
+
+        $ips=array_filter(array_map('trim', explode(',', $whitelist)));
+        foreach($ips as $ip) {
+            $sql='INSERT INTO '.API_KEY_TABLE.' SET created=NOW(), updated=NOW(), isactive=1 '
+                .',ipaddr='.db_input($ip)
+                .',apikey='.db_input(strtoupper(md5($ip.md5($key))));
+            db_query($sql);
+        }
+
+        return 0;
+    }
+
+    function migrateGroupDeptAccess($taskId) {
+
+        $res = db_query('SELECT group_id, dept_access FROM '.GROUP_TABLE);
+        if(!$res || !db_num_rows($res))
+            return 0;  //No groups??
+
+        while(list($groupId, $access) = db_fetch_row($res)) {
+            $depts=array_filter(array_map('trim', explode(',', $access)));
+            foreach($depts as $deptId) {
+                $sql='INSERT INTO '.GROUP_DEPT_TABLE
+                    .' SET dept_id='.db_input($deptId).', group_id='.db_input($groupId);
+                db_query($sql);
+            }
+        }
+
+        return 0;
+
+
+
+    }
 }
 ?>
diff --git a/include/class.validator.php b/include/class.validator.php
index d41bf027fe826c855893146dfee680c578598feb..addbfac4df3be2333c986ea26e76cac5b43e5dce 100644
--- a/include/class.validator.php
+++ b/include/class.validator.php
@@ -109,8 +109,8 @@ class Validator {
                     $this->errors[$k]=$field['error'].' (5 chars min)';
                 break;
             case 'username':
-                if(strlen($this->input[$k])<3)
-                    $this->errors[$k]=$field['error'].' (3 chars min)';
+                if(strlen($this->input[$k])<2)
+                    $this->errors[$k]=$field['error'].' (2 chars min)';
                 break;
             case 'zipcode':
                 if(!is_numeric($this->input[$k]) || (strlen($this->input[$k])!=5))
@@ -172,10 +172,15 @@ class Validator {
             return false;
       
         $ip=trim($ip);
-        if(preg_match("/^[0-9]{1,3}(.[0-9]{1,3}){3}$/",$ip)) {
-            foreach(explode(".", $ip) as $block)
-                if($block<0 || $block>255 )
-                    return false;
+        # Thanks to http://stackoverflow.com/a/1934546
+        if (function_exists('inet_pton')) { # PHP 5.1.0
+            # Let the built-in library parse the IP address
+            return @inet_pton($ip) !== false;
+        } else if (preg_match(
+            '/^(?>(?>([a-f0-9]{1,4})(?>:(?1)){7}|(?!(?:.*[a-f0-9](?>:|$)){7,})'
+            .'((?1)(?>:(?1)){0,5})?::(?2)?)|(?>(?>(?1)(?>:(?1)){5}:|(?!(?:.*[a-f0-9]:){5,})'
+            .'(?3)?::(?>((?1)(?>:(?1)){0,3}):)?)?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])'
+            .'(?>\.(?4)){3}))$/iD', $ip)) {
             return true;
         }
         return false;
diff --git a/include/client/header.inc.php b/include/client/header.inc.php
index 969e9e66b8d977256e8087fc8cba2dadebb8fc62..da763a7bbf7b1e5b9481b8d26a0dfca2c79a9997 100644
--- a/include/client/header.inc.php
+++ b/include/client/header.inc.php
@@ -12,8 +12,9 @@ header("Content-Type: text/html; charset=UTF-8\r\n");
     <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
     <link rel="stylesheet" href="<?php echo ASSETS_PATH; ?>css/theme.css" media="screen">
     <link rel="stylesheet" href="<?php echo ASSETS_PATH; ?>css/print.css" media="print">
-    <script src="./js/jquery-1.7.2.min.js"></script>
-    <script src="./js/osticket.js"></script>
+    <script src="<?php echo ROOT_PATH; ?>js/jquery-1.7.2.min.js"></script>
+    <script src="<?php echo ROOT_PATH; ?>js/jquery.multifile.js"></script>
+    <script src="<?php echo ROOT_PATH; ?>js/osticket.js"></script>
 </head>
 <body>
     <div id="container">
diff --git a/include/client/login.inc.php b/include/client/login.inc.php
index 0ff10e3f41ea37e5f956b1b7add8877548e3f6b5..e1e52e9d454e7a1a4f62fdfec39c5625e496c5d2 100644
--- a/include/client/login.inc.php
+++ b/include/client/login.inc.php
@@ -7,6 +7,7 @@ $ticketid=Format::input($_POST['lticket']?$_POST['lticket']:$_GET['t']);
 <h1>Check Ticket Status</h1>
 <p>To view the status of a ticket, provide us with the login details below.</p>
 <form action="login.php" method="post" id="clientLogin">
+    <?php csrf_token(); ?>
     <strong>Authentication Required</strong>
     <div>
         <label for="email">E-Mail Address:</label>
diff --git a/include/client/open.inc.php b/include/client/open.inc.php
index 9c2a82b4706e1fc83253471eea8224e47cd7b382..2fd076100388888765970d1a561dc3c5235a8b90 100644
--- a/include/client/open.inc.php
+++ b/include/client/open.inc.php
@@ -13,120 +13,136 @@ $info=($_POST && $errors)?Format::htmlchars($_POST):$info;
 <h1>Open a New Ticket</h1>
 <p>Please fill in the form below to open a new ticket.</p>
 <form id="ticketForm" method="post" action="open.php" enctype="multipart/form-data">
-    <input type="hidden" name="a" value="open">
-    <div>
-        <label for="name" class="required">Full Name:</label>
-        <?php
-        if($thisclient && $thisclient->isValid()) {
-            echo $thisclient->getName();
-        } else { ?>
-        <input id="name" type="text" name="name" size="30" value="<?php echo $info['name']; ?>">
-        <font class="error">*&nbsp;<?php echo $errors['name']; ?></font>
-        <?php
-        } ?>
-    </div>
-    <div>
-        <label for="email" class="required">Email Address:</label>
-        <?php
-        if($thisclient && $thisclient->isValid()) { 
-            echo $thisclient->getEmail();
-        } else { ?>
-        <input id="email" type="text" name="email" size="30" value="<?php echo $info['email']; ?>">
-        <font class="error">*&nbsp;<?php echo $errors['email']; ?></font>
-        <?php
-        } ?>
-    </div>
-    <div>
-        <label for="phone">Telephone:</label>
-        <input id="phone" type="text" name="phone" size="17" value="<?php echo $info['phone']; ?>">
-        <label for="ext" class="inline">Ext.:</label>
-        <input id="ext" type="text" name="phone_ext" size="3" value="<?php echo $info['phone_ext']; ?>">
-        <font class="error">&nbsp;<?php echo $errors['phone']; ?>&nbsp;&nbsp;<?php echo $errors['phone_ext']; ?></font>
-    </div>
-    <br>
-    <div>
-        <label for="topicId" class="required">Help Topic:</label>
-        <select id="topicId" name="topicId">
-            <option value="" selected="selected">&mdash; Select a Help Topics &mdash;</option>
+  <?php csrf_token(); ?>
+  <input type="hidden" name="a" value="open">
+  <table width="800" cellpadding="1" cellspacing="0" border="0">
+    <tr>
+        <th class="required" width="160">Full Name:</th>
+        <td>
             <?php
-            if($topics=Topic::getPublicHelpTopics()) {
-                foreach($topics as $id =>$name) {
-                    echo sprintf('<option value="%d" %s>%s</option>',
-                            $id, ($info['topicId']==$id)?'selected="selected"':'', $name);
-                }
+            if($thisclient && $thisclient->isValid()) {
+                echo $thisclient->getName();
             } else { ?>
-                <option value="0" >General Inquiry</option>
-            <?php } ?>
-        </select>
-        <font class="error">*&nbsp;<?php echo $errors['topicId']; ?></font>
-    </div>
-    <div>
-        <label for="subject" class="required">Subject:</label>
-        <input id="subject" type="text" name="subject" size="40" value="<?php echo $info['subject']; ?>">
-        <font class="error">*&nbsp;<?php echo $errors['subject']; ?></font>
-    </div>
-    <div>
-        <label for="msg" class="required">Message:</label>
-        <span id="msg">
-        <em>Please provide as much details as possible so we can best assist you.</em> <font class="error">*&nbsp;<?php echo $errors['message']; ?></font></span>
-    </div>
-    <div>
-        <label for="message" class="required">&nbsp;</label>
-        <textarea id="message" cols="60" rows="8" name="message"><?php echo $info['message']; ?></textarea>
-    </div>
+                <input id="name" type="text" name="name" size="30" value="<?php echo $info['name']; ?>">
+                <font class="error">*&nbsp;<?php echo $errors['name']; ?></font>
+            <?php
+            } ?>
+        </td>
+    </tr>
+    <tr>
+        <th class="required" width="160">Email Address:</th>
+        <td>
+            <?php
+            if($thisclient && $thisclient->isValid()) { 
+                echo $thisclient->getEmail();
+            } else { ?>
+                <input id="email" type="text" name="email" size="30" value="<?php echo $info['email']; ?>">
+                <font class="error">*&nbsp;<?php echo $errors['email']; ?></font>
+            <?php
+            } ?>
+        </td>
+    </tr>
+    <tr>
+        <th>Telephone:</th>
+        <td>
+
+            <input id="phone" type="text" name="phone" size="17" value="<?php echo $info['phone']; ?>">
+            <label for="ext" class="inline">Ext.:</label>
+            <input id="ext" type="text" name="phone_ext" size="3" value="<?php echo $info['phone_ext']; ?>">
+            <font class="error">&nbsp;<?php echo $errors['phone']; ?>&nbsp;&nbsp;<?php echo $errors['phone_ext']; ?></font>
+        </td>   
+    </tr>
+    <tr><td colspan=2>&nbsp;</td></tr>
+    <tr>
+        <td class="required">Help Topic:</td>
+        <td>
+            <select id="topicId" name="topicId">
+                <option value="" selected="selected">&mdash; Select a Help Topics &mdash;</option>
+                <?php
+                if($topics=Topic::getPublicHelpTopics()) {
+                    foreach($topics as $id =>$name) {
+                        echo sprintf('<option value="%d" %s>%s</option>',
+                                $id, ($info['topicId']==$id)?'selected="selected"':'', $name);
+                    }
+                } else { ?>
+                    <option value="0" >General Inquiry</option>
+                <?php
+                } ?>
+            </select>
+            <font class="error">*&nbsp;<?php echo $errors['topicId']; ?></font>
+        </td>
+    </tr>
+    <tr>
+        <td class="required">Subject:</td>
+        <td>
+            <input id="subject" type="text" name="subject" size="40" value="<?php echo $info['subject']; ?>">
+            <font class="error">*&nbsp;<?php echo $errors['subject']; ?></font>
+        </td>
+    </tr>
+    <tr>
+        <td class="required">Message:</td>
+        <td>
+            <div><em>Please provide as much details as possible so we can best assist you.</em> <font class="error">*&nbsp;<?php echo $errors['message']; ?></font></div>
+            <textarea id="message" cols="60" rows="8" name="message"><?php echo $info['message']; ?></textarea>
+        </td>
+    </tr>
+
     <?php if(($cfg->allowOnlineAttachments() && !$cfg->allowAttachmentsOnlogin())
             || ($cfg->allowAttachmentsOnlogin() && ($thisclient && $thisclient->isValid()))) { ?>
-     <div>
-        <label for="attachments">Attachments:</label>
-        <span id="uploads"></span>
-        <input type="file" class="multifile" name="attachments[]" id="attachments" size="30" value="" />
-        <font class="error">&nbsp;<?php echo $errors['attachments']; ?></font>
-    </div>                                                                
+    <tr>
+        <td>Attachments:</td>
+        <td>
+            <div class="uploads"></div><br>
+            <input type="file" class="multifile" name="attachments[]" id="attachments" size="30" value="" />
+            <font class="error">&nbsp;<?php echo $errors['attachments']; ?></font>
+        </td>
+    </tr>
+    <tr><td colspan=2>&nbsp;</td></tr>
     <?php } ?>
     <?php
     if($cfg->allowPriorityChange() && ($priorities=Priority::getPriorities())) { ?>
-    <div>
-        <label for="priority">Ticket Priority:</label>
-        <select id="priority" name="priorityId">
-            <?php
-                if(!$info['priorityId'])
-                    $info['priorityId'] = $cfg->getDefaultPriorityId(); //System default.
-                foreach($priorities as $id =>$name) {
-                    echo sprintf('<option value="%d" %s>%s</option>',
-                                    $id, ($info['priorityId']==$id)?'selected="selected"':'', $name);
+    <tr>
+        <td>Ticket Priority:</td>
+        <td>
+            <select id="priority" name="priorityId">
+                <?php
+                    if(!$info['priorityId'])
+                        $info['priorityId'] = $cfg->getDefaultPriorityId(); //System default.
+                    foreach($priorities as $id =>$name) {
+                        echo sprintf('<option value="%d" %s>%s</option>',
+                                        $id, ($info['priorityId']==$id)?'selected="selected"':'', $name);
                         
-                }
-            ?>
-
-                
-                
-        </select>
-        
-        <font class="error">&nbsp;<?php echo $errors['priorityId']; ?></font>
-        
-    </div>
+                    }
+                ?>
+            </select>
+            <font class="error">&nbsp;<?php echo $errors['priorityId']; ?></font>
+        </td>
+    </tr>
     <?php
     }
     ?>
     <?php
-    if($cfg && $cfg->enableCaptcha() && (!$thisclient || !$thisclient->isValid())) {
+    if($cfg && $cfg->isCaptchaEnabled() && (!$thisclient || !$thisclient->isValid())) {
         if($_POST && $errors && !$errors['captcha'])
             $errors['captcha']='Please re-enter the text again';
         ?>
-    <br>
-    <div class="captchaRow">
-        <label for="captcha" class="required">CAPTCHA Text:</label>
-        <span class="captcha"><img src="captcha.php" border="0" align="left"></span>
-        <input id="captcha" type="text" name="captcha" size="6">
-        <em>Enter the text shown on the image.</em>
-        <font class="error">*&nbsp;<?php echo $errors['captcha']; ?></font>
-    </div>
+    <tr class="captchaRow">
+        <td class="required">CAPTCHA Text:</td>
+        <td>
+            <span class="captcha"><img src="captcha.php" border="0" align="left"></span>
+            &nbsp;&nbsp;
+            <input id="captcha" type="text" name="captcha" size="6">
+            <em>Enter the text shown on the image.</em>
+            <font class="error">*&nbsp;<?php echo $errors['captcha']; ?></font>
+        </td>
+    </tr>
     <?php
     } ?>
-    <br>
-    <p style="padding-left:150px;">
+    <tr><td colspan=2>&nbsp;</td></tr>
+  </table>
+  <p style="padding-left:150px;">
         <input type="submit" value="Create Ticket">
         <input type="reset" value="Reset">
         <input type="button" value="Cancel" onClick='window.location.href="index.php"'>
-    </p>
+  </p>
 </form>
diff --git a/include/client/view.inc.php b/include/client/view.inc.php
index debddc4ed4713aeb3dec50b48e1fcb5bfe2f9ccc..ccea4c927cfdf31793ae325f79572a743fa35f26 100644
--- a/include/client/view.inc.php
+++ b/include/client/view.inc.php
@@ -91,6 +91,7 @@ if($ticket->getThreadCount() && ($thread=$ticket->getClientThread())) {
     <div id="msg_warning"><?php echo $warn; ?></div>
 <?php } ?>
 <form id="reply" action="tickets.php?id=<?php echo $ticket->getExtId(); ?>#reply" name="reply" method="post" enctype="multipart/form-data">
+    <?php csrf_token(); ?>
     <h2>Post a Reply</h2>
     <input type="hidden" name="id" value="<?php echo $ticket->getExtId(); ?>">
     <input type="hidden" name="a" value="reply">
@@ -121,7 +122,7 @@ if($ticket->getThreadCount() && ($thread=$ticket->getClientThread())) {
                 <div class="uploads">
                 </div>
                 <div class="file_input">
-                    <input type="file" name="attachments[]" size="30" value="" />
+                    <input class="multifile" type="file" name="attachments[]" size="30" value="" />
                 </div>
             </td>
         </tr>
diff --git a/include/mysql.php b/include/mysql.php
index 71ea2f073cbcd054853fb6a8f26eacd8d78bd3ea..65adb6298a632ebe0d8c0a127d2c0af8982bf546 100644
--- a/include/mysql.php
+++ b/include/mysql.php
@@ -38,12 +38,12 @@
         return $dblink;	
     }
 
-    function db_close(){
+    function db_close() {
         global $dblink;
         return @mysql_close($dblink);
     }
 
-    function db_version(){
+    function db_version() {
 
         $version=0;
         if(preg_match('/(\d{1,2}\.\d{1,2}\.\d{1,2})/', 
@@ -59,7 +59,7 @@
     }
 
     function db_get_variable($variable, $type='session') {
-        $sql =sprintf('SELECT @@%s.%s',$type,$variable);
+        $sql =sprintf('SELECT @@%s.%s', $type, $variable);
         return db_result(db_query($sql));
     }
 
@@ -74,112 +74,105 @@
     }
 
     function db_create_database($database, $charset='utf8', $collate='utf8_unicode_ci') {
-        return @mysql_query(sprintf('CREATE DATABASE %s DEFAULT CHARACTER SET %s COLLATE %s',$database,$charset,$collate));
+        return @mysql_query(sprintf('CREATE DATABASE %s DEFAULT CHARACTER SET %s COLLATE %s', $database, $charset, $collate));
     }
    
 	// execute sql query
-	function db_query($query, $database="", $conn=""){
+	function db_query($query, $database="", $conn="") {
         global $ost;
        
 		if($conn) { /* connection is provided*/
-            $result = ($database)?mysql_db_query($database, $query, $conn):mysql_query($query, $conn);
+            $res = ($database)?mysql_db_query($database, $query, $conn):mysql_query($query, $conn);
    	    } else {
-            $result = ($database)?mysql_db_query($database, $query):mysql_query($query);
+            $res = ($database)?mysql_db_query($database, $query):mysql_query($query);
    	    }
                 
-        if(!$result && $ost) { //error reporting
-            $alert='['.$query.']'."\n\n".db_error();
-            $ost->logError('DB Error #'.db_errno(), $alert, ($ost->alertONSQLError()));
-            //echo $alert; #uncomment during debuging or dev.
+        if(!$res && $ost) { //error reporting
+            $msg='['.$query.']'."\n\n".db_error();
+            $ost->logDBError('DB Error #'.db_errno(), $msg);
+            //echo $msg; #uncomment during debuging or dev.
         }
 
-        return $result;
+        return $res;
 	}
 
-	function db_squery($query){ //smart db query...utilizing args and sprintf
+	function db_squery($query) { //smart db query...utilizing args and sprintf
 	
 		$args  = func_get_args();
   		$query = array_shift($args);
   		$query = str_replace("?", "%s", $query);
   		$args  = array_map('db_real_escape', $args);
-  		array_unshift($args,$query);
-  		$query = call_user_func_array('sprintf',$args);
+  		array_unshift($args, $query);
+  		$query = call_user_func_array('sprintf', $args);
 		return db_query($query);
 	}
 
-	function db_count($query){		
+	function db_count($query) {		
         return db_result(db_query($query));
 	}
 
-    function db_result($result,$row=0) {
-        return ($result)?mysql_result($result,$row):NULL;
+    function db_result($res, $row=0) {
+        return ($res)?mysql_result($res, $row):NULL;
     }
 
-	function db_fetch_array($result,$mode=false) {
-   	    return ($result)?db_output(mysql_fetch_array($result,($mode)?$mode:MYSQL_ASSOC)):NULL;
+	function db_fetch_array($res, $mode=false) {
+   	    return ($res)?db_output(mysql_fetch_array($res, ($mode)?$mode:MYSQL_ASSOC)):NULL;
   	}
 
-    function db_fetch_row($result) {
-        return ($result)?db_output(mysql_fetch_row($result)):NULL;
+    function db_fetch_row($res) {
+        return ($res)?db_output(mysql_fetch_row($res)):NULL;
     }
 
-    function db_fetch_field($result) {
-        return ($result)?mysql_fetch_field($result):NULL;
+    function db_fetch_field($res) {
+        return ($res)?mysql_fetch_field($res):NULL;
     }   
 
-    function db_assoc_array($result,$mode=false) {
-	    if($result && db_num_rows($result)) {
-      	    while ($row=db_fetch_array($result,$mode))
-         	    $results[]=$row;
+    function db_assoc_array($res, $mode=false) {
+	    if($res && db_num_rows($res)) {
+      	    while ($row=db_fetch_array($res, $mode))
+         	    $result[]=$row;
         }
-        return $results;
+        return $result;
     }
 
-    function db_num_rows($result) {
-   	    return ($result)?mysql_num_rows($result):0;
+    function db_num_rows($res) {
+   	    return ($res)?mysql_num_rows($res):0;
     }
 
 	function db_affected_rows() {
       return mysql_affected_rows();
     }
 
-  	function db_data_seek($result, $row_number) {
-   	    return mysql_data_seek($result, $row_number);
+  	function db_data_seek($res, $row_number) {
+   	    return mysql_data_seek($res, $row_number);
   	}
 
-  	function db_data_reset($result) {
-   	    return mysql_data_seek($result,0);
+  	function db_data_reset($res) {
+   	    return mysql_data_seek($res,0);
   	}
 
   	function db_insert_id() {
    	    return mysql_insert_id();
   	}
 
-	function db_free_result($result) {
-   	    return mysql_free_result($result);
+	function db_free_result($res) {
+   	    return mysql_free_result($res);
   	}
   
-	function db_output($param) {
+	function db_output($var) {
 
         if(!function_exists('get_magic_quotes_runtime') || !get_magic_quotes_runtime()) //Sucker is NOT on - thanks.
-            return $param;
+            return $var;
 
-        if (is_array($param)) {
-      	    reset($param);
-      	    while(list($key, $value) = each($param))
-        	    $param[$key] = db_output($value);
+        if (is_array($var)) 
+            return array_map('db_output', $var);
 
-      	    return $param;
+        return (!is_numeric($var))?stripslashes($var):$var;
 
-    	}elseif(!is_numeric($param)) {
-            $param=trim(stripslashes($param));
-        }
-
-        return $param;
-  	}
+    }
 
     //Do not call this function directly...use db_input
-    function db_real_escape($val,$quote=false){
+    function db_real_escape($val, $quote=false) {
 
         //Magic quotes crap is taken care of in main.inc.php
         $val=mysql_real_escape_string($val);
@@ -187,29 +180,21 @@
         return ($quote)?"'$val'":$val;
     }
 
-    function db_input($param,$quote=true) {
-
-        //is_numeric doesn't work all the time...9e8 is considered numeric..which is correct...but not expected.
-        if($param && preg_match("/^\d+(\.\d+)?$/",$param))
-            return $param;
+    function db_input($var, $quote=true) {
 
-        if($param && is_array($param)) {
-            reset($param);
-            while (list($key, $value) = each($param)) {
-                $param[$key] = db_input($value,$quote);
-            }
-
-            return $param;
-        }
+        if(is_array($var))
+            return array_map('db_input', $var, array_fill(0, count($var), $quote));
+        elseif($var && preg_match("/^\d+(\.\d+)?$/", $var))
+            return $var;
 
-        return db_real_escape($param,$quote);
+        return db_real_escape($var, $quote);
     }
 
-	function db_error(){
+	function db_error() {
    	    return mysql_error();   
 	}
    
-    function db_errno(){
+    function db_errno() {
         return mysql_errno();
     }
 ?>
diff --git a/include/staff/apikey.inc.php b/include/staff/apikey.inc.php
index 7bcac1cb03e257feb855fbf0436769b8b3a3650e..ff5592b46fd57b374bb0a2d0825f99d3156bceef 100644
--- a/include/staff/apikey.inc.php
+++ b/include/staff/apikey.inc.php
@@ -20,6 +20,7 @@ if($api && $_REQUEST['a']!='add'){
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
 <form action="apikeys.php?<?php echo $qstr; ?>" method="post" id="save">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
  <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
diff --git a/include/staff/apikeys.inc.php b/include/staff/apikeys.inc.php
index 3deccb941222f8d771eb120ea90ab7e27557203c..fc0d418e76606ee7dc64f78fde73db932133ac79 100644
--- a/include/staff/apikeys.inc.php
+++ b/include/staff/apikeys.inc.php
@@ -46,6 +46,7 @@ else
  <b><a href="apikeys.php?a=add" class="Icon newapi">Add New API Key</a></b></div>
 <div class="clear"></div>
 <form action="apikeys.php" method="POST" name="keys" onSubmit="return checkbox_checker(this,1,0);">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="mass_process" >
  <table class="list" border="0" cellspacing="1" cellpadding="0" width="940">
     <caption><?php echo $showing; ?></caption>
diff --git a/include/staff/banlist.inc.php b/include/staff/banlist.inc.php
index 430b51f4835bbf7038941109621774b409485b2e..0b61d1e8b779edaf48c448c82eb38c3d1ce3deed 100644
--- a/include/staff/banlist.inc.php
+++ b/include/staff/banlist.inc.php
@@ -72,6 +72,7 @@ if($search)
     
 ?>
 <form action="banlist.php" method="POST" name="banlist" onSubmit="return checkbox_checker(this,1,0);">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="mass_process" >
  <table class="list" border="0" cellspacing="1" cellpadding="0" width="940">
     <caption><?php echo $showing; ?></caption>
diff --git a/include/staff/banrule.inc.php b/include/staff/banrule.inc.php
index 0560b4a4d6268961220dad69de5d7b73617afec2..1f1314736f6943a6563f6ac1b9761fa2fbd98fea 100644
--- a/include/staff/banrule.inc.php
+++ b/include/staff/banrule.inc.php
@@ -20,6 +20,7 @@ if($rule && $_REQUEST['a']!='add'){
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
 <form action="banlist.php?<?php echo $qstr; ?>" method="post" id="save">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
  <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
diff --git a/include/staff/cannedreplies.inc.php b/include/staff/cannedreplies.inc.php
index 39aaaae815a8479233e3959c26b4dc28764b1ef0..2f19cbd194a1ee7570fcda67eca30f295bc1d2fa 100644
--- a/include/staff/cannedreplies.inc.php
+++ b/include/staff/cannedreplies.inc.php
@@ -53,6 +53,7 @@ else
     <b><a href="canned.php?a=add" class="Icon newReply">Add New Reply</a></b></div>
 <div class="clear"></div>
 <form action="canned.php" method="POST" name="canned" onSubmit="return checkbox_checker(this,1,0);">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="mass_process" >
  <table class="list" border="0" cellspacing="1" cellpadding="0" width="940">
     <caption><?php echo $showing; ?></caption>
@@ -83,7 +84,8 @@ else
                 <td width=7px>
                   <input type="checkbox" name="ids[]" value="<?php echo $row['canned_id']; ?>"
                             <?php echo $sel?'checked="checked"':''; ?>  <?php echo $default?'disabled="disabled"':''; ?>
-                                onClick="highLight(this.value,this.checked);"> </td>
+                                onClick="highLight(this.value,this.checked);"/>
+                </td>
                 <td>
                     <a href="canned.php?id=<?php echo $row['canned_id']; ?>"><?php echo Format::truncate($row['title'],200); echo "&nbsp;$files"; ?></a>&nbsp;
                 </td>
diff --git a/include/staff/cannedreply.inc.php b/include/staff/cannedreply.inc.php
index 55e29db7d686880c5b3267f9803acfb94f83574b..f18b114a2225fde48d9bddbc73ff3ec93e5a3fd4 100644
--- a/include/staff/cannedreply.inc.php
+++ b/include/staff/cannedreply.inc.php
@@ -20,6 +20,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 
 ?>
 <form action="canned.php?<?php echo $qstr; ?>" method="post" id="save" enctype="multipart/form-data">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
  <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
@@ -107,6 +108,11 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
         </tr>
     </tbody>
 </table>
+ <?php if ($canned && $canned->getFilters()) { ?>
+    <br/>
+    <div id="msg_warning">Canned reply is in use by email filter(s): <?php
+    echo implode(', ', $canned->getFilters()); ?></div>
+ <?php } ?>
 <p style="padding-left:225px;">
     <input type="submit" name="submit" value="<?php echo $submit_text; ?>">
     <input type="reset"  name="reset"  value="Reset">
diff --git a/include/staff/categories.inc.php b/include/staff/categories.inc.php
index 9e90869c0d24acd79eabced4a1eed76c133681cc..df750fe795f680963663edd7282d0bfa66e316ef 100644
--- a/include/staff/categories.inc.php
+++ b/include/staff/categories.inc.php
@@ -47,6 +47,7 @@ else
     <b><a href="categories.php?a=add" class="Icon newCategory">Add New Category</a></b></div>
 <div class="clear"></div>
 <form action="categories.php" method="POST" name="cat" onSubmit="return checkbox_checker(this,1,0);">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="mass_process" >
  <table class="list" border="0" cellspacing="1" cellpadding="0" width="940">
     <caption><?php echo $showing; ?></caption>
diff --git a/include/staff/category.inc.php b/include/staff/category.inc.php
index 8272d7da13e24f1531b577fd051dccbfc487b108..c682219b0331e089a22a6b38054dd83997a38962 100644
--- a/include/staff/category.inc.php
+++ b/include/staff/category.inc.php
@@ -19,6 +19,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 
 ?>
 <form action="categories.php?<?php echo $qstr; ?>" method="post" id="save">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
  <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
diff --git a/include/staff/department.inc.php b/include/staff/department.inc.php
index 521cee9bf9e9eb7446420c26c4e0ab03a1c3ad69..b900087331721347ee1b1c57dd37f43e274ed2d2 100644
--- a/include/staff/department.inc.php
+++ b/include/staff/department.inc.php
@@ -2,15 +2,17 @@
 if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
 $info=array();
 $qstr='';
-if($dept && $_REQUEST['a']!='add'){
+if($dept && $_REQUEST['a']!='add') {
     //Editing Department.
     $title='Update Department';
     $action='update';
     $submit_text='Save Changes';
     $info=$dept->getInfo();
     $info['id']=$dept->getId();
+    $info['groups'] = $dept->getAllowedGroups();
+
     $qstr.='&id='.$dept->getId();
-}else {
+} else {
     $title='Add New Department';
     $action='create';
     $submit_text='Create Dept';
@@ -22,6 +24,7 @@ if($dept && $_REQUEST['a']!='add'){
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
 <form action="departments.php?<?php echo $qstr; ?>" method="post" id="save">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
  <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
@@ -128,8 +131,9 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                     <option value="0">&mdash; None &mdash;</option>
                     <option value="0" disabled="disabled">Select Department Manager (Optional)</option>
                     <?php
-                    $sql='SELECT staff_id,CONCAT_WS(" ",firstname,lastname) as name FROM '.STAFF_TABLE.' staff '.
-                         'WHERE dept_id='.db_input($dept->getId()).' ORDER by name';
+                    $sql='SELECT staff_id,CONCAT_WS(", ",lastname, firstname) as name '
+                        .' FROM '.STAFF_TABLE.' staff '
+                        .' ORDER by name';
                     if(($res=db_query($sql)) && db_num_rows($res)){
                         while(list($id,$name)=db_fetch_row($res)){
                             $selected=($info['manager_id'] && $id==$info['manager_id'])?'selected="selected"':'';
@@ -141,7 +145,18 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                 &nbsp;<span class="error">&nbsp;<?php echo $errors['manager_id']; ?></span>
             </td>
         </tr>
-        <?php } ?>
+        <?php 
+        } ?>
+
+        <tr>
+            <td width="180">
+                Group Membership:
+            </td>
+            <td>
+                <input type="checkbox" name="group_membership" value="0" <?php echo $info['group_membership']?'checked="checked"':''; ?> >
+                Extend membership to groups with access. <i>(Alerts and  notices will include groups)</i>
+            </td>
+        </tr>
         <tr>
             <th colspan="2">
                 <em><strong>Auto Response Settings</strong>: Overwrite global auto-response settings for tickets routed to the Dept.</em>
@@ -189,6 +204,29 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                 &nbsp;<span class="error">&nbsp;<?php echo $errors['autoresp_email_id']; ?></span>
             </td>
         </tr>
+        <tr>
+            <th colspan="2">
+                <em><strong>Department Access</strong>: Check all groups allowed to access this department.</em>
+            </th>
+        </tr>
+        <tr><td colspan=2><em>Department manager and primary members will always have access independent of group selection or assignment.</em></td></tr>
+        <?php
+         $sql='SELECT group_id, group_name, count(staff.staff_id) as members '
+             .' FROM '.GROUP_TABLE.' grp '
+             .' LEFT JOIN '.STAFF_TABLE. ' staff USING(group_id) '
+             .' GROUP by grp.group_id '
+             .' ORDER BY group_name';
+         if(($res=db_query($sql)) && db_num_rows($res)){
+            while(list($id, $name, $members) = db_fetch_row($res)) {
+                if($members>0) 
+                    $members=sprintf('<a href="staff.php?a=filter&gid=%d">%d</a>', $id, $members);
+
+                $ck=($info['groups'] && in_array($id,$info['groups']))?'checked="checked"':'';
+                echo sprintf('<tr><td colspan=2>&nbsp;&nbsp;<label><input type="checkbox" name="groups[]" value="%d" %s>&nbsp;%s</label> (%s)</td></tr>',
+                        $id, $ck, $name, $members);
+            }
+         }
+        ?>
         <tr>
             <th colspan="2">
                 <em><strong>Department Signature</strong>: Optional signature used on outgoing emails. &nbsp;<span class="error">&nbsp;<?php echo $errors['signature']; ?></span></em>
@@ -197,7 +235,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
         <tr>
             <td colspan=2>
                 <textarea name="signature" cols="21" rows="5" style="width: 60%;"><?php echo $info['signature']; ?></textarea>
-                <br><em>Signature is made available as a choice, on ticket reply, for public departments.</em>
+                <br><em>Signature is made available as a choice, for public departments, on ticket reply.</em>
             </td>
         </tr>
     </tbody>
diff --git a/include/staff/departments.inc.php b/include/staff/departments.inc.php
index 71b702a0676cff5f6824c933fc458882fff9e991..a46115f422b87abc4446cd4f301e171aa92e539d 100644
--- a/include/staff/departments.inc.php
+++ b/include/staff/departments.inc.php
@@ -47,6 +47,7 @@ else
     <b><a href="departments.php?a=add" class="Icon newDepartment">Add New Department</a></b></div>
 <div class="clear"></div>
 <form action="departments.php" method="POST" name="depts" onSubmit="return checkbox_checker(this,1,0);">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="mass_process" >
  <table class="list" border="0" cellspacing="1" cellpadding="0" width="940">
     <caption><?php echo $showing; ?></caption>
diff --git a/include/staff/email.inc.php b/include/staff/email.inc.php
index 2fd2b8857494c64c061524a5bd294e4433299ee4..5e2935e06a02157c4cc7f62e45a38eb4af87326d 100644
--- a/include/staff/email.inc.php
+++ b/include/staff/email.inc.php
@@ -31,6 +31,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
 <h2>Email Address</h2>
 <form action="emails.php?<?php echo $qstr; ?>" method="post" id="save">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
  <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
@@ -76,7 +77,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                 Login Password
             </td>
             <td>
-                <input type="text" size="35" name="passwd" value="<?php echo $info['passwd']; ?>">
+                <input type="password" size="35" name="passwd" value="<?php echo $info['passwd']; ?>">
                 &nbsp;<span class="error">&nbsp;<?php echo $errors['passwd']; ?>&nbsp;</span>
                 <br><em><?php echo $passwdtxt; ?></em>
             </td>
@@ -117,10 +118,10 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 
         <tr><td>Encryption</td>
             <td>
-                 <label><input type="radio" name="mail_encryption"  value="NONE"
-                    <?php echo ($info['mail_encryption']!='SSL')?'checked="checked"':''; ?> />None</label>
-                 <label><input type="radio" name="mail_encryption"  value="SSL"
-                    <?php echo ($info['mail_encryption']=='SSL')?'checked="checked"':''; ?> />SSL</label>
+                <select name="mail_encryption">
+                    <option value='NONE'>None</option>
+                    <option value='SSL' <?php echo ($info['mail_encryption']=='SSL')?'selected="selected"':''; ?> >SSL</option>
+                </select>
                 <font class="error">&nbsp;<?php echo $errors['mail_encryption']; ?></font>
             </td>
         </tr>
diff --git a/include/staff/emails.inc.php b/include/staff/emails.inc.php
index 8d5f221177051e484fcaff4457c5f9f60bffbc99..4ab93d22105e3d42ba11efe6321a13d912548ee2 100644
--- a/include/staff/emails.inc.php
+++ b/include/staff/emails.inc.php
@@ -49,6 +49,7 @@ else
     <b><a href="emails.php?a=add" class="Icon newEmail">Add New Email</a></b></div>
 <div class="clear"></div>
 <form action="emails.php" method="POST" name="emails" onSubmit="return checkbox_checker(this,1,0);">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="mass_process" >
  <table class="list" border="0" cellspacing="1" cellpadding="0" width="940">
     <caption><?php echo $showing; ?></caption>
diff --git a/include/staff/faq-view.inc.php b/include/staff/faq-view.inc.php
index cdbb266d106940fa267dd03743428832ed6656f6..ee7d743e4044d93ea18971e055b842985f6f656b 100644
--- a/include/staff/faq-view.inc.php
+++ b/include/staff/faq-view.inc.php
@@ -40,6 +40,7 @@ if($thisstaff->canManageFAQ()) {
     ?>
    <div>
     <form action="faq.php?id=<?php echo  $faq->getId(); ?>" method="post">
+	 <?php csrf_token(); ?>
         <input type="hidden" name="id" value="<?php echo  $faq->getId(); ?>">
         <input type="hidden" name="do" value="manage-faq">
         <div>
diff --git a/include/staff/faq.inc.php b/include/staff/faq.inc.php
index 8882da2fa817cf1e5000d4700fab0cc2b9bb0a19..fb87156b97d5f33254efcce57b24b7cfef638c7d 100644
--- a/include/staff/faq.inc.php
+++ b/include/staff/faq.inc.php
@@ -23,6 +23,7 @@ if($faq){
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
 <form action="faq.php?<?php echo $qstr; ?>" method="post" id="save" enctype="multipart/form-data">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
  <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
@@ -90,7 +91,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                 <div><b>Attachments</b> (optional) <font class="error">&nbsp;<?php echo $errors['files']; ?></font></div>
                 <?php
                 if($faq && ($files=$faq->getAttachments())) {
-                    echo '<div id="faq_attachments"><span class="faded">Uncheck to delete the attachment on submit</span><br>';
+                    echo '<div class="faq_attachments"><span class="faded">Uncheck to delete the attachment on submit</span><br>';
                     foreach($files as $file) {
                         $hash=$file['hash'].md5($file['id'].session_id().$file['hash']);
                         echo sprintf('<label><input type="checkbox" name="files[]" id="f%d" value="%d" checked="checked">
@@ -99,14 +100,12 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                     }
                     echo '</div><br>';
                 }
-                //TODO: add a setting on admin panel
-                if(count($files)<5) {
                 ?>
-                <div>
-                    <input type="file" name="attachments[]" value=""/>
+                <div class="faded">Select files to upload.</div>
+                <div class="uploads"></div>
+                <div class="file_input">
+                    <input type="file" class="multifile" name="attachments[]" size="30" value="" />
                 </div>
-                <?}?>
-                <div class="faded">You can upload up to 5 attachments.</div>
             </td>
         </tr>
         <?php
diff --git a/include/staff/filter.inc.php b/include/staff/filter.inc.php
index 6f8cce2c41a1e6acd8f4810b3cdc7e643a9a4471..c2aad0bcf4456d5bade4fa323a4ba3c991c39929 100644
--- a/include/staff/filter.inc.php
+++ b/include/staff/filter.inc.php
@@ -1,9 +1,8 @@
 <?php
 if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
 
-$matches=array('name'=>"Sender's Name",'email'=>"Sender's Email",'subject'=>'Email Subject','body'=>'Email Body/Text','header'=>'Email Header');
-$match_types=array('equal'=>'Equal','not_equal'=>'Not Equal','contains'=>'Contains','dn_contain'=>'Does Not Contain');
-
+$matches=Filter::getSupportedMatches();
+$match_types=Filter::getSupportedMatchTypes();
 
 $info=array();
 $qstr='';
@@ -24,6 +23,7 @@ if($filter && $_REQUEST['a']!='add'){
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
 <form action="filters.php?<?php echo $qstr; ?>" method="post" id="save">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
  <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
@@ -181,6 +181,30 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                     <strong>Disable</strong> auto-response. <em>(Overwrites Dept. settings)</em>
             </td>
         </tr>
+        <tr>
+            <td width="180">
+                Canned Response:
+            </td>
+                <td>
+                <select name="canned_response_id">
+                    <option value="">&mdash; None &mdash;</option>
+                    <?php
+                    $sql='SELECT canned_id,title FROM '.CANNED_TABLE
+                        .' WHERE isenabled ORDER by title';
+                    if ($res=db_query($sql)) {
+                        while (list($id,$title)=db_fetch_row($res)) {
+                            $selected=($info['canned_response_id'] &&
+                                    $id==$info['canned_response_id'])
+                                ? 'selected="selected"' : '';
+                            echo sprintf('<option value="%d" %s>%s</option>',
+                                $id, $selected, $title);
+                        }
+                    }
+                    ?>
+                </select>
+                <em>(Automatically respond with this canned response)</em>
+            </td>
+        </tr>
         <tr>
             <td width="180">
                 Department:
diff --git a/include/staff/filters.inc.php b/include/staff/filters.inc.php
index b5534bdde77a12ffe88a8f2362046c5d2e64fce2..7f3aab393f56cb3b1eb3f8dc3da0113204d35e41 100644
--- a/include/staff/filters.inc.php
+++ b/include/staff/filters.inc.php
@@ -50,6 +50,7 @@ else
  <b><a href="filters.php?a=add" class="Icon newEmailFilter">Add New Filter</a></b></div>
 <div class="clear"></div>
 <form action="filters.php" method="POST" name="filters" onSubmit="return checkbox_checker(this,1,0);">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="mass_process" >
  <table class="list" border="0" cellspacing="1" cellpadding="0" width="940">
     <caption><?php echo $showing; ?></caption>
diff --git a/include/staff/footer.inc.php b/include/staff/footer.inc.php
index 2591a55af87caf67b56208c27e7c9ceab678b6cc..d789c14474ef63caf5c06f61d60cdfb6df881bcc 100644
--- a/include/staff/footer.inc.php
+++ b/include/staff/footer.inc.php
@@ -12,5 +12,6 @@ if(is_object($thisstaff) && $thisstaff->isStaff()) { ?>
 <?php
 } ?>
 </div>
+<div id="overlay"></div>
 </body>
 </html>
diff --git a/include/staff/group.inc.php b/include/staff/group.inc.php
index afb574f5f3cea7ff161dc34e90c05fa77f955b51..a442c3ce02e91c249636d4c762cd9a9ed54b6c89 100644
--- a/include/staff/group.inc.php
+++ b/include/staff/group.inc.php
@@ -8,7 +8,7 @@ if($group && $_REQUEST['a']!='add'){
     $submit_text='Save Changes';
     $info=$group->getInfo();
     $info['id']=$group->getId();
-    $info['depts']=$info['dept_access']?explode(',',$info['dept_access']):array();
+    $info['depts']=$group->getDepartments();
     $qstr.='&id='.$group->getId();
 }else {
     $title='Add New Group';
@@ -21,6 +21,7 @@ if($group && $_REQUEST['a']!='add'){
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
 <form action="groups.php?<?php echo $qstr; ?>" method="post" id="save" name="group">
+ <?php csrf_token(); ?>
  <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']; ?>">
diff --git a/include/staff/groups.inc.php b/include/staff/groups.inc.php
index ed5e3638a8d0528908584ddfad5320d885a38e4d..ccb16257bf74660ae43d4a6abad2013984323221 100644
--- a/include/staff/groups.inc.php
+++ b/include/staff/groups.inc.php
@@ -3,10 +3,13 @@ if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access
 
 $qstr='';
 
-$sql='SELECT grp.*,count(staff.staff_id) as users '
-     .' FROM '.GROUP_TABLE.' grp LEFT JOIN '.STAFF_TABLE.' staff USING(group_id) ';
-$sql.=' WHERE 1';
-$sortOptions=array('name'=>'grp.group_name','status'=>'grp.group_enabled','users'=>'users','created'=>'grp.created','updated'=>'grp.updated');
+$sql='SELECT grp.*,count(staff.staff_id) as users, count(dept.dept_id) as depts '
+     .' FROM '.GROUP_TABLE.' grp '
+     .' LEFT JOIN '.STAFF_TABLE.' staff ON(staff.group_id=grp.group_id) '
+     .' LEFT JOIN '.GROUP_DEPT_TABLE.' dept ON(dept.group_id=grp.group_id) '
+     .' WHERE 1';
+$sortOptions=array('name'=>'grp.group_name','status'=>'grp.group_enabled', 
+                   'users'=>'users', 'depts'=>'depts', 'created'=>'grp.created','updated'=>'grp.updated');
 $orderWays=array('DESC'=>'DESC','ASC'=>'ASC');
 $sort=($_REQUEST['sort'] && $sortOptions[strtolower($_REQUEST['sort'])])?strtolower($_REQUEST['sort']):'name';
 //Sorting options...
@@ -43,15 +46,17 @@ else
     <b><a href="groups.php?a=add" class="Icon newgroup">Add New Group</a></b></div>
 <div class="clear"></div>
 <form action="groups.php" method="POST" name="groups" onSubmit="return checkbox_checker(this,1,0);">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="mass_process" >
  <table class="list" border="0" cellspacing="1" cellpadding="0" width="940">
     <caption><?php echo $showing; ?></caption>
     <thead>
         <tr>
             <th width="7px">&nbsp;</th>        
-            <th width="250"><a <?php echo $name_sort; ?> href="groups.php?<?php echo $qstr; ?>&sort=name">Group Name</a></th>
-            <th width="80"><a  <?php echo $status_sort; ?> href="groups.php?<?php echo $qstr; ?>&sort=status">Group Status</a></th>
+            <th width="200"><a <?php echo $name_sort; ?> href="groups.php?<?php echo $qstr; ?>&sort=name">Group Name</a></th>
+            <th width="80"><a  <?php echo $status_sort; ?> href="groups.php?<?php echo $qstr; ?>&sort=status">Status</a></th>
             <th width="80" style="text-align:center;"><a  <?php echo $users_sort; ?>href="groups.php?<?php echo $qstr; ?>&sort=users">Members</a></th>
+            <th width="80" style="text-align:center;"><a  <?php echo $depts_sort; ?>href="groups.php?<?php echo $qstr; ?>&sort=depts">Departments</a></th>
             <th width="100"><a  <?php echo $created_sort; ?> href="groups.php?<?php echo $qstr; ?>&sort=created">Created On</a></th>
             <th width="120"><a  <?php echo $updated_sort; ?> href="groups.php?<?php echo $qstr; ?>&sort=updated">Last Updated</a></th>
         </tr>
@@ -81,6 +86,9 @@ else
                     <?php } ?>
                     &nbsp;
                 </td>
+                <td style="text-align:right;padding-right:30px">&nbsp;&nbsp;
+                    <?php echo $row['depts']; ?>
+                </td>
                 <td><?php echo Format::db_date($row['created']); ?>&nbsp;</td>
                 <td><?php echo Format::db_datetime($row['updated']); ?>&nbsp;</td>
             </tr>
diff --git a/include/staff/header.inc.php b/include/staff/header.inc.php
index c48ee8b360070be6f82cf74e073f8122aa0ff897..1f4a3da546c99b645d81c73597cc1c47cc7927c6 100644
--- a/include/staff/header.inc.php
+++ b/include/staff/header.inc.php
@@ -2,6 +2,8 @@
 <html>
 <head>
     <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+    <meta http-equiv="cache-control" content="no-cache" />
+    <meta http-equiv="pragma" content="no-cache" />
     <title>osTicket Staff Control Panel</title>
     <!--[if IE]>
     <style type="text/css">
@@ -10,6 +12,7 @@
     <![endif]-->
     <script type="text/javascript" src="../js/jquery-1.7.2.min.js"></script>
     <script type="text/javascript" src="../js/jquery-ui-1.8.18.custom.min.js"></script>
+    <script type="text/javascript" src="../js/jquery.multifile.js"></script>
     <script type="text/javascript" src="./js/tips.js"></script>
     <script type="text/javascript" src="./js/nicEdit.js"></script>
     <script type="text/javascript" src="./js/bootstrap-typeahead.js"></script>
@@ -23,7 +26,7 @@
     }
     ?>
 </head>
-<body>
+<body onunload="">
 <div id="container">
     <div id="header">
         <a href="index.php" id="logo">osTicket - Customer Support System</a>
@@ -34,7 +37,8 @@
             <?php }else{ ?>
             | <a href="index.php">Staff Panel</a>
             <?php } ?>
-            | <a href="profile.php">My Preferences</a> | <a href="logout.php">Log Out</a>
+            | <a href="profile.php">My Preferences</a> 
+            | <a href="logout.php?auth=<?php echo md5($ost->getCSRFToken().SECRET_SALT.session_id()); ?>">Log Out</a>
         </p>
     </div>
     <ul id="nav">
diff --git a/include/staff/helptopic.inc.php b/include/staff/helptopic.inc.php
index c0fdcd34010266a802bbffdd3f31c741c36f0b9a..6c7c94211ec855b5b7c4111c7382b15f93883239 100644
--- a/include/staff/helptopic.inc.php
+++ b/include/staff/helptopic.inc.php
@@ -20,6 +20,7 @@ if($topic && $_REQUEST['a']!='add'){
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
 <form action="helptopics.php?<?php echo $qstr; ?>" method="post" id="save">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
  <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
diff --git a/include/staff/helptopics.inc.php b/include/staff/helptopics.inc.php
index b3d58c777517753e02b41d1aaa703ed6e5500c01..9e5482ff9b1197a14aa732ee161f3ff5e392724c 100644
--- a/include/staff/helptopics.inc.php
+++ b/include/staff/helptopics.inc.php
@@ -50,6 +50,7 @@ else
     <b><a href="helptopics.php?a=add" class="Icon newHelpTopic">Add New Help Topic</a></b></div>
 <div class="clear"></div>
 <form action="helptopics.php" method="POST" name="topics" onSubmit="return checkbox_checker(this,1,0);">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="mass_process" >
  <table class="list" border="0" cellspacing="1" cellpadding="0" width="940">
     <caption><?php echo $showing; ?></caption>
diff --git a/include/staff/login.tpl.php b/include/staff/login.tpl.php
index 4f2364e1ae9fa21a0e79135ae5580fcaffdbcb63..2d8a41f650601c2ec8396ecb89a8ea5ac90a4790 100644
--- a/include/staff/login.tpl.php
+++ b/include/staff/login.tpl.php
@@ -15,6 +15,7 @@
     <h1 id="logo"><a href="index.php">osTicket Staff Control Panel</a></h1>
     <h3><?php echo Format::htmlchars($msg); ?></h3>
     <form action="login.php" method="post">
+        <?php csrf_token(); ?>
         <input type="hidden" name="d"o value="scplogin">
         <fieldset>
             <input type="text" name="username" id="name" value="" placeholder="username" autocorrect="off" autocapitalize="off">
diff --git a/include/staff/preference.inc.php b/include/staff/preference.inc.php
deleted file mode 100644
index 6eb27354b0d4cd019964b460b58a3c4b0db1110e..0000000000000000000000000000000000000000
--- a/include/staff/preference.inc.php
+++ /dev/null
@@ -1,498 +0,0 @@
-<?php
-if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied');
-
-//Get the config info.
-$config=($errors && $_POST)?Format::input($_POST):Format::htmlchars($cfg->getConfigInfo());
-//Basic checks for warnings...
-$warn=array();
-if($config['allow_attachments'] && !$config['upload_dir']) {
-    $errors['allow_attachments']='You need to setup upload dir.';    
-}else{
-    if(!$config['allow_attachments'] && $config['allow_email_attachments'])
-        $warn['allow_email_attachments']='*Attachments Disabled.';
-    if(!$config['allow_attachments'] && ($config['allow_online_attachments'] or $config['allow_online_attachments_onlogin']))
-        $warn['allow_online_attachments']='<br>*Attachments Disabled.';
-}
-
-if(!$errors['enable_captcha'] && $config['enable_captcha'] && !extension_loaded('gd'))
-    $errors['enable_captcha']='GD required for captcha to work';
-    
-
-//Not showing err on post to avoid alarming the user...after an update.
-if(!$errors['err'] &&!$msg && $warn )
-    $errors['err']='Possible errors detected, please check the warnings below';
-    
-$gmtime=Misc::gmtime();
-$depts= db_query('SELECT dept_id,dept_name FROM '.DEPT_TABLE.' WHERE ispublic=1');
-$templates=db_query('SELECT tpl_id,name FROM '.EMAIL_TEMPLATE_TABLE.' WHERE cfg_id='.db_input($cfg->getId()));
-?>
-<div class="msg">System Preferences and Settings&nbsp;&nbsp;(v<?php echo $config['ostversion']; ?>)</div>
-<table width="100%" border="0" cellspacing=0 cellpadding=0>
- <form action="admin.php?t=pref" method="post">
- <input type="hidden" name="t" value="pref">
- <tr><td>
-    <table width="100%" border="0" cellspacing=0 cellpadding=2 class="tform">
-        <tr class="header" ><td colspan=2>General Settings</td></tr>
-        <tr class="subheader">
-            <td colspan=2">Offline mode will disable client interface and <b>only</b> allow <b>super admins</b> to login to Staff Control Panel</td>
-        </tr>
-        <tr><th><b>Helpdesk Status</b></th>
-            <td>
-                <input type="radio" name="isonline"  value="1"   <?php echo $config['isonline']?'checked':''; ?> /><b>Online</b> (Active)
-                <input type="radio" name="isonline"  value="0"   <?php echo !$config['isonline']?'checked':''; ?> /><b>Offline</b> (Disabled)
-                &nbsp;<font class="warn">&nbsp;<?php echo $config['isoffline']?'osTicket offline':''; ?></font>
-            </td>
-        </tr>
-        <tr><th>Helpdesk URL:</th>
-            <td>
-                <input type="text" size="40" name="helpdesk_url" value="<?php echo $config['helpdesk_url']; ?>"> 
-                &nbsp;<font class="error">*&nbsp;<?php echo $errors['helpdesk_url']; ?></font></td>
-        </tr>
-        <tr><th>Helpdesk Name/Title:</th>
-            <td><input type="text" size="40" name="helpdesk_title" value="<?php echo $config['helpdesk_title']; ?>"> </td>
-        </tr>
-        <tr><th>Default Email Templates:</th>
-            <td>
-                <select name="default_template_id">
-                    <option value=0>Select Default Template</option>
-                    <?php
-                    while (list($id,$name) = db_fetch_row($templates)){
-                        $selected = ($config['default_template_id']==$id)?'SELECTED':''; ?>
-                        <option value="<?php echo $id; ?>"<?php echo $selected; ?>><?php echo $name; ?></option>
-                    <?php
-                    } ?>
-                </select>&nbsp;<font class="error">*&nbsp;<?php echo $errors['default_template_id']; ?></font>
-            </td>
-        </tr>
-        <tr><th>Default Department:</th>
-            <td>
-                <select name="default_dept_id">
-                    <option value=0>Select Default Dept</option>
-                    <?php
-                    while (list($id,$name) = db_fetch_row($depts)){
-                    $selected = ($config['default_dept_id']==$id)?'SELECTED':''; ?>
-                    <option value="<?php echo $id; ?>"<?php echo $selected; ?>><?php echo $name; ?> Dept</option>
-                    <?php
-                    } ?>
-                </select>&nbsp;<font class="error">*&nbsp;<?php echo $errors['default_dept_id']; ?></font>
-            </td>
-        </tr>
-        <tr><th>Default Page Size:</th>
-            <td>
-                <select name="max_page_size">
-                    <?php
-                     $pagelimit=$config['max_page_size'];
-                    for ($i = 5; $i <= 50; $i += 5) {
-                        ?>
-                        <option <?php echo $config['max_page_size'] == $i ? 'SELECTED':''; ?> value="<?php echo $i; ?>"><?php echo $i; ?></option>
-                        <?php
-                    } ?>
-                </select>
-            </td>
-        </tr>
-        <tr><th>System Log Level:</th>
-            <td>
-                <select name="log_level">
-                    <option value=0 <?php echo $config['log_level'] == 0 ? 'selected="selected"':''; ?>>None (Disable Logger)</option>
-                    <option value=3 <?php echo $config['log_level'] == 3 ? 'selected="selected"':''; ?>> DEBUG</option>
-                    <option value=2 <?php echo $config['log_level'] == 2 ? 'selected="selected"':''; ?>> WARN</option>
-                    <option value=1 <?php echo $config['log_level'] == 1 ? 'selected="selected"':''; ?>> ERROR</option>
-                </select>
-                &nbsp;Purge logs after
-                <select name="log_graceperiod">
-                    <option value=0 selected> None (Disable)</option>
-                    <?php
-                    for ($i = 1; $i <=12; $i++) {
-                        ?>
-                        <option <?php echo $config['log_graceperiod'] == $i ? 'SELECTED':''; ?> value="<?php echo $i; ?>"><?php echo $i; ?>&nbsp;<?php echo ($i>1)?'Months':'Month'; ?></option>
-                        <?php
-                    } ?>
-                </select>
-            </td>
-        </tr>
-        <tr><th>Staff Excessive Logins:</th>
-            <td>
-                <select name="staff_max_logins">
-                  <?php
-                    for ($i = 1; $i <= 10; $i++) {
-                        echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['staff_max_logins']==$i)?'selected="selected"':''),$i);
-                    }
-                    ?>
-                </select> attempt(s) allowed
-                &nbsp;before a
-                <select name="staff_login_timeout">
-                  <?php
-                    for ($i = 1; $i <= 10; $i++) {
-                        echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['staff_login_timeout']==$i)?'selected="selected"':''),$i);
-                    }
-                    ?>
-                </select> min. timeout (penalty in minutes)
-            </td>
-        </tr>
-        <tr><th>Staff Session Timeout:</th>
-            <td>
-              <input type="text" name="staff_session_timeout" size=6 value="<?php echo $config['staff_session_timeout']; ?>">
-                (<i>Staff's max Idle time in minutes. Enter 0 to disable timeout</i>)
-            </td>
-        </tr>
-       <tr><th>Bind Staff Session to IP:</th>
-            <td>
-              <input type="checkbox" name="staff_ip_binding" <?php echo $config['staff_ip_binding']?'checked':''; ?>>
-               Bind staff's session to login IP.
-            </td>
-        </tr>
-
-        <tr><th>Client Excessive Logins:</th>
-            <td>
-                <select name="client_max_logins">
-                  <?php
-                    for ($i = 1; $i <= 10; $i++) {
-                        echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['client_max_logins']==$i)?'selected="selected"':''),$i);
-                    }
-
-                    ?>
-                </select> attempt(s) allowed
-                &nbsp;before a
-                <select name="client_login_timeout">
-                  <?php
-                    for ($i = 1; $i <= 10; $i++) {
-                        echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['client_login_timeout']==$i)?'selected="selected"':''),$i);
-                    }
-                    ?>
-                </select> min. timeout (penalty in minutes)
-            </td>
-        </tr>
-
-        <tr><th>Client Session Timeout:</th>
-            <td>
-              <input type="text" name="client_session_timeout" size=6 value="<?php echo $config['client_session_timeout']; ?>">
-                (<i>Client's max Idle time in minutes. Enter 0 to disable timeout</i>)
-            </td>
-        </tr>
-        <tr><th>Clickable URLs:</th>
-            <td>
-              <input type="checkbox" name="clickable_urls" <?php echo $config['clickable_urls']?'checked':''; ?>>
-                Make URLs clickable
-            </td>
-        </tr>
-        <tr><th>Enable Auto Cron:</th>
-            <td>
-              <input type="checkbox" name="enable_auto_cron" <?php echo $config['enable_auto_cron']?'checked':''; ?>>
-                Enable cron call on staff's activity
-            </td>
-        </tr>
-    </table>
-    
-    <table width="100%" border="0" cellspacing=0 cellpadding=2 class="tform">
-        <tr class="header"><td colspan=2>Date &amp; Time</td></tr>
-        <tr class="subheader">
-            <td colspan=2>Please refer to <a href="http://php.net/date" target="_blank">PHP Manual</a> for supported parameters.</td>
-        </tr>
-        <tr><th>Time Format:</th>
-            <td>
-                <input type="text" name="time_format" value="<?php echo $config['time_format']; ?>">
-                    &nbsp;<font class="error">*&nbsp;<?php echo $errors['time_format']; ?></font>
-                    <i><?php echo Format::date($config['time_format'],$gmtime,$config['timezone_offset'],$config['enable_daylight_saving']); ?></i></td>
-        </tr>
-        <tr><th>Date Format:</th>
-            <td><input type="text" name="date_format" value="<?php echo $config['date_format']; ?>">
-                        &nbsp;<font class="error">*&nbsp;<?php echo $errors['date_format']; ?></font>
-                        <i><?php echo Format::date($config['date_format'],$gmtime,$config['timezone_offset'],$config['enable_daylight_saving']); ?></i>
-            </td>
-        </tr>
-        <tr><th>Date &amp; Time Format:</th>
-            <td><input type="text" name="datetime_format" value="<?php echo $config['datetime_format']; ?>">
-                        &nbsp;<font class="error">*&nbsp;<?php echo $errors['datetime_format']; ?></font>
-                        <i><?php echo Format::date($config['datetime_format'],$gmtime,$config['timezone_offset'],$config['enable_daylight_saving']); ?></i>
-            </td>
-        </tr>
-        <tr><th>Day, Date &amp; Time Format:</th>
-            <td><input type="text" name="daydatetime_format" value="<?php echo $config['daydatetime_format']; ?>">
-                        &nbsp;<font class="error">*&nbsp;<?php echo $errors['daydatetime_format']; ?></font>
-                        <i><?php echo Format::date($config['daydatetime_format'],$gmtime,$config['timezone_offset'],$config['enable_daylight_saving']); ?></i>
-            </td>
-        </tr>
-        <tr><th>Default Timezone:</th>
-            <td>
-                <select name="timezone_offset">
-                    <?php
-                    $gmoffset = date("Z") / 3600; //Server's offset.
-                    echo"<option value=\"$gmoffset\">Server Time (GMT $gmoffset:00)</option>"; //Default if all fails.
-                    $timezones= db_query('SELECT offset,timezone FROM '.TIMEZONE_TABLE);
-                    while (list($offset,$tz) = db_fetch_row($timezones)){
-                        $selected = ($config['timezone_offset'] ==$offset) ?'SELECTED':'';
-                        $tag=($offset)?"GMT $offset ($tz)":" GMT ($tz)";
-                        ?>
-                        <option value="<?php echo $offset; ?>"<?php echo $selected; ?>><?php echo $tag; ?></option>
-                        <?php
-                    } ?>
-                </select>
-            </td>
-        </tr>
-        <tr>
-            <th>Daylight Saving:</th>
-            <td>
-                <input type="checkbox" name="enable_daylight_saving" <?php echo $config['enable_daylight_saving'] ? 'checked': ''; ?>>Observe daylight savings
-            </td>
-        </tr>
-    </table>
-   
-    <table width="100%" border="0" cellspacing=0 cellpadding=2 class="tform">
-        <tr class="header"><td colspan=2>Ticket Options &amp; Settings</td></tr>
-        <tr class="subheader"><td colspan=2>If enabled ticket lock get auto-renewed on form activity.</td></tr>
-        <tr><th valign="top">Ticket IDs:</th>
-            <td>
-                <input type="radio" name="random_ticket_ids"  value="0"   <?php echo !$config['random_ticket_ids']?'checked':''; ?> /> Sequential
-                <input type="radio" name="random_ticket_ids"  value="1"   <?php echo $config['random_ticket_ids']?'checked':''; ?> />Random  (recommended)
-            </td>
-        </tr>
-        <tr><th valign="top">Ticket Priority:</th>
-            <td>
-                <select name="default_priority_id">
-                    <?php
-                    $priorities= db_query('SELECT priority_id,priority_desc FROM '.TICKET_PRIORITY_TABLE);
-                    while (list($id,$tag) = db_fetch_row($priorities)){ ?>
-                        <option value="<?php echo $id; ?>"<?php echo ($config['default_priority_id']==$id)?'selected':''; ?>><?php echo $tag; ?></option>
-                    <?php
-                    } ?>
-                </select> &nbsp;Default priority<br/>
-                <input type="checkbox" name="allow_priority_change" <?php echo $config['allow_priority_change'] ?'checked':''; ?>>
-                    Allow user to overwrite/set priority (new web tickets)<br/>
-                <input type="checkbox" name="use_email_priority" <?php echo $config['use_email_priority'] ?'checked':''; ?> >
-                    Use email priority when available (new emailed tickets)
-
-            </td>
-        </tr>
-        <tr><th>Maximum <b>Open</b> Tickets:</th>
-            <td>
-              <input type="text" name="max_open_tickets" size=4 value="<?php echo $config['max_open_tickets']; ?>"> 
-                per email. (<i>Helps with spam and flood control. Enter 0 for unlimited</i>)
-            </td>
-        </tr>
-        <tr><th>Auto-Lock Time:</td>
-            <td>
-              <input type="text" name="autolock_minutes" size=4 value="<?php echo $config['autolock_minutes']; ?>">
-                 <font class="error"><?php echo $errors['autolock_minutes']; ?></font>
-                (<i>Minutes to lock a ticket on activity. Enter 0 to disable locking</i>)
-            </td>
-        </tr>
-        <tr><th>Ticket Grace Period:</th>
-            <td>
-              <input type="text" name="overdue_grace_period" size=4 value="<?php echo $config['overdue_grace_period']; ?>">
-                (<i>Hours before ticket is marked overdue. Enter 0 to disable aging.</i>)
-            </td>
-        </tr>
-        <tr><th>Reopened Tickets:</th>
-            <td>
-              <input type="checkbox" name="auto_assign_reopened_tickets" <?php echo $config['auto_assign_reopened_tickets'] ? 'checked': ''; ?>> 
-                Auto-assign reopened tickets to last respondent 'available'. (<i> 3 months limit</i>)
-            </td>
-        </tr>
-        <tr><th>Assigned Tickets:</th>
-            <td>
-              <input type="checkbox" name="show_assigned_tickets" <?php echo $config['show_assigned_tickets']?'checked':''; ?>>
-                Show assigned tickets on open queue.
-            </td>
-        </tr>
-        <tr><th>Answered Tickets:</th>
-            <td>
-              <input type="checkbox" name="show_answered_tickets" <?php echo $config['show_answered_tickets']?'checked':''; ?>>
-                Show answered tickets on open queue.
-            </td>
-        </tr>
-        <tr><th>Ticket Activity Log:</th>
-            <td>
-              <input type="checkbox" name="log_ticket_activity" <?php echo $config['log_ticket_activity']?'checked':''; ?>>
-                Log ticket's activity as internal notes.
-            </td>
-        </tr>
-        <tr><th>Staff Identity:</th>
-            <td>
-              <input type="checkbox" name="hide_staff_name" <?php echo $config['hide_staff_name']?'checked':''; ?>>
-                Hide staff's name on responses.
-            </td>
-        </tr>
-        <tr><th>Human Verification:</th>
-            <td>
-                <?php
-                   if($config['enable_captcha'] && !$errors['enable_captcha']) { ?>
-                        <img src="../captcha.php" border="0" align="left">&nbsp;
-                <?php } ?>
-              <input type="checkbox" name="enable_captcha" <?php echo $config['enable_captcha']?'checked':''; ?>>
-                Enable captcha on new web tickets.&nbsp;<font class="error">&nbsp;<?php echo $errors['enable_captcha']; ?></font><br/>
-            </td>
-        </tr>
-
-    </table>
-    <table width="100%" border="0" cellspacing=0 cellpadding=2 class="tform">
-        <tr class="header"><td colspan=2 >Email Settings</td></tr>
-        <tr class="subheader"><td colspan=2>Note that global settings can be disabled at dept/email level.</td></tr>
-        <tr><th valign="top"><br><b>Incoming Emails</b>:</th>
-            <td><i>For mail fetcher (POP/IMAP) to work you must set a cron job or simply enable auto-cron</i><br/>
-                <input type="checkbox" name="enable_mail_fetch" value=1 <?php echo $config['enable_mail_fetch']? 'checked': ''; ?>  > Enable POP/IMAP email fetch
-                    &nbsp;&nbsp;(<i>Global setting which can be disabled at email level</i>) <br/>
-                <input type="checkbox" name="enable_email_piping" value=1 <?php echo $config['enable_email_piping']? 'checked': ''; ?>  > Enable email piping
-                   &nbsp;(<i>You pipe we accept policy</i>)<br/>
-                <input type="checkbox" name="strip_quoted_reply" <?php echo $config['strip_quoted_reply'] ? 'checked':''; ?>>
-                    Strip quoted reply (<i>depends on the tag below</i>)<br/>
-                <input type="text" name="reply_separator" value="<?php echo $config['reply_separator']; ?>"> Reply Separator Tag
-                &nbsp;<font class="error">&nbsp;<?php echo $errors['reply_separator']; ?></font>
-            </td>
-        </tr>
-        <tr><th valign="top"><br><b>Outgoing Emails</b>:</th>
-            <td>
-                <i><b>Default Email:</b> Only applies to outgoing emails with no SMTP settings.</i><br/>
-                <select name="default_smtp_id"
-                    onChange="document.getElementById('overwrite').style.display=(this.options[this.selectedIndex].value>0)?'block':'none';">
-                    <option value=0>Select One</option>
-                    <option value=0 selected="selected">None: Use PHP mail function</option>
-                    <?php
-                    $emails=db_query('SELECT email_id,email,name,smtp_host FROM '.EMAIL_TABLE.' WHERE smtp_active=1');
-                    if($emails && db_num_rows($emails)) {
-                        while (list($id,$email,$name,$host) = db_fetch_row($emails)){
-                            $email=$name?"$name &lt;$email&gt;":$email;
-                            $email=sprintf('%s (%s)',$email,$host);
-                            ?>
-                            <option value="<?php echo $id; ?>"<?php echo ($config['default_smtp_id']==$id)?'selected="selected"':''; ?>><?php echo $email; ?></option>
-                        <?php
-                        }
-                    } ?>
-                 </select>&nbsp;&nbsp;<font class="error">&nbsp;<?php echo $errors['default_smtp_id']; ?></font><br/>
-                 <span id="overwrite" style="display:<?php echo ($config['default_smtp_id']?'display':'none'); ?>">
-                    <input type="checkbox" name="spoof_default_smtp" <?php echo $config['spoof_default_smtp'] ? 'checked':''; ?>>
-                        Allow spoofing (No Overwrite).&nbsp;<font class="error">&nbsp;<?php echo $errors['spoof_default_smtp']; ?></font><br/>
-                        </span>
-             </td>
-        </tr>
-        <tr><th>Default System Email:</th>
-            <td>
-                <select name="default_email_id">
-                    <option value=0 disabled>Select One</option>
-                    <?php
-                    $emails=db_query('SELECT email_id,email,name FROM '.EMAIL_TABLE);
-                    while (list($id,$email,$name) = db_fetch_row($emails)){ 
-                        $email=$name?"$name &lt;$email&gt;":$email;
-                        ?>
-                     <option value="<?php echo $id; ?>"<?php echo ($config['default_email_id']==$id)?'selected':''; ?>><?php echo $email; ?></option>
-                    <?php
-                    } ?>
-                 </select>
-                 &nbsp;<font class="error">*&nbsp;<?php echo $errors['default_email_id']; ?></font></td>
-        </tr>
-        <tr><th valign="top">Default Alert Email:</th>
-            <td>
-                <select name="alert_email_id">
-                    <option value=0 disabled>Select One</option>
-                    <option value=0 selected="selected">Use Default System Email (above)</option>
-                    <?php
-                    $emails=db_query('SELECT email_id,email,name FROM '.EMAIL_TABLE.' WHERE email_id != '.db_input($config['default_email_id']));
-                    while (list($id,$email,$name) = db_fetch_row($emails)){
-                        $email=$name?"$name &lt;$email&gt;":$email;
-                        ?>
-                     <option value="<?php echo $id; ?>"<?php echo ($config['alert_email_id']==$id)?'selected':''; ?>><?php echo $email; ?></option>
-                    <?php
-                    } ?>
-                 </select>
-                 &nbsp;<font class="error">*&nbsp;<?php echo $errors['alert_email_id']; ?></font>
-                <br/><i>Used to send out alerts and notices to staff.</i>
-            </td>
-        </tr>
-        <tr><th>System Admin Email Address:</th>
-            <td>
-                <input type="text" size=25 name="admin_email" value="<?php echo $config['admin_email']; ?>">
-                    &nbsp;<font class="error">*&nbsp;<?php echo $errors['admin_email']; ?></font></td>
-        </tr>
-    </table>
-
-    <table width="100%" border="0" cellspacing=0 cellpadding=2 class="tform">
-        <tr class="header"><td colspan=2>Autoresponders &nbsp;(Global Setting)</td></tr>
-        <tr class="subheader"><td colspan=2">This is global setting which can be disabled at department level.</td></tr>
-        <tr><th valign="top">New Ticket:</th>
-            <td><i>Autoresponse includes the ticket ID required to check status of the ticket</i><br>
-                <input type="radio" name="ticket_autoresponder"  value="1"   <?php echo $config['ticket_autoresponder']?'checked':''; ?> />Enable
-                <input type="radio" name="ticket_autoresponder"  value="0"   <?php echo !$config['ticket_autoresponder']?'checked':''; ?> />Disable
-            </td>
-        </tr>
-        <tr><th valign="top">New Ticket by Staff:</th>
-            <td><i>Notice sent when staff creates a ticket on behalf of the user (Staff can disable)</i><br>
-                <input type="radio" name="ticket_notice_active"  value="1"   <?php echo $config['ticket_notice_active']?'checked':''; ?> />Enable
-                <input type="radio" name="ticket_notice_active"  value="0"   <?php echo !$config['ticket_notice_active']?'checked':''; ?> />Disable
-            </td>
-        </tr>
-        <tr><th valign="top">New Message:</th>
-            <td><i>Message appended to an existing ticket confirmation</i><br>
-                <input type="radio" name="message_autoresponder"  value="1"   <?php echo $config['message_autoresponder']?'checked':''; ?> />Enable
-                <input type="radio" name="message_autoresponder"  value="0"   <?php echo !$config['message_autoresponder']?'checked':''; ?> />Disable
-            </td>
-        </tr>
-        <tr><th valign="top">Overlimit notice:</th>
-            <td><i>Ticket denied notice sent <b>only once</b> on limit violation to the user.</i><br/>               
-                <input type="radio" name="overlimit_notice_active"  value="1"   <?php echo $config['overlimit_notice_active']?'checked':''; ?> />Enable
-                <input type="radio" name="overlimit_notice_active"  value="0"   <?php echo !$config['overlimit_notice_active']?'checked':''; ?> />Disable
-                <br><i><b>Note:</b> Admin gets alerts on ALL denials by default.</i><br>
-            </td>
-        </tr>
-    </table>
-    <table width="100%" border="0" cellspacing=0 cellpadding=2 class="tform">
-        <tr class="header"><td colspan=2>&nbsp;Alerts &amp; Notices</td></tr>
-        <tr class="subheader"><td colspan=2>
-            Notices sent to user use 'No Reply Email' whereas alerts to staff use 'Alert Email' set above as FROM address respectively.</td>
-        </tr>
-        <tr><th valign="top">New Ticket Alert:</th>
-            <td>
-                <input type="radio" name="ticket_alert_active"  value="1"   <?php echo $config['ticket_alert_active']?'checked':''; ?> />Enable
-                <input type="radio" name="ticket_alert_active"  value="0"   <?php echo !$config['ticket_alert_active']?'checked':''; ?> />Disable
-                <br><i>Select recipients</i>&nbsp;<font class="error">&nbsp;<?php echo $errors['ticket_alert_active']; ?></font><br>
-                <input type="checkbox" name="ticket_alert_admin" <?php echo $config['ticket_alert_admin']?'checked':''; ?>> Admin Email
-                <input type="checkbox" name="ticket_alert_dept_manager" <?php echo $config['ticket_alert_dept_manager']?'checked':''; ?>> Department Manager
-                <input type="checkbox" name="ticket_alert_dept_members" <?php echo $config['ticket_alert_dept_members']?'checked':''; ?>> Department Members (spammy)
-            </td>
-        </tr>
-        <tr><th valign="top">New Message Alert:</th>
-            <td>
-              <input type="radio" name="message_alert_active"  value="1"   <?php echo $config['message_alert_active']?'checked':''; ?> />Enable
-              <input type="radio" name="message_alert_active"  value="0"   <?php echo !$config['message_alert_active']?'checked':''; ?> />Disable
-              <br><i>Select recipients</i>&nbsp;<font class="error">&nbsp;<?php echo $errors['message_alert_active']; ?></font><br>
-              <input type="checkbox" name="message_alert_laststaff" <?php echo $config['message_alert_laststaff']?'checked':''; ?>> Last Respondent
-              <input type="checkbox" name="message_alert_assigned" <?php echo $config['message_alert_assigned']?'checked':''; ?>> Assigned Staff
-              <input type="checkbox" name="message_alert_dept_manager" <?php echo $config['message_alert_dept_manager']?'checked':''; ?>> Department Manager (spammy)
-            </td>
-        </tr>
-        <tr><th valign="top">New Internal Note Alert:</th>
-            <td>
-              <input type="radio" name="note_alert_active"  value="1"   <?php echo $config['note_alert_active']?'checked':''; ?> />Enable
-              <input type="radio" name="note_alert_active"  value="0"   <?php echo !$config['note_alert_active']?'checked':''; ?> />Disable
-              <br><i>Select recipients</i>&nbsp;<font class="error">&nbsp;<?php echo $errors['note_alert_active']; ?></font><br>
-              <input type="checkbox" name="note_alert_laststaff" <?php echo $config['note_alert_laststaff']?'checked':''; ?>> Last Respondent
-              <input type="checkbox" name="note_alert_assigned" <?php echo $config['note_alert_assigned']?'checked':''; ?>> Assigned Staff
-              <input type="checkbox" name="note_alert_dept_manager" <?php echo $config['note_alert_dept_manager']?'checked':''; ?>> Department Manager (spammy)
-            </td>
-        </tr>
-        <tr><th valign="top">Overdue Ticket Alert:</th>
-            <td>
-              <input type="radio" name="overdue_alert_active"  value="1"   <?php echo $config['overdue_alert_active']?'checked':''; ?> />Enable
-              <input type="radio" name="overdue_alert_active"  value="0"   <?php echo !$config['overdue_alert_active']?'checked':''; ?> />Disable
-              <br><i>Admin Email gets an alert by default. Select additional recipients below</i>&nbsp;<font class="error">&nbsp;<?php echo $errors['overdue_alert_active']; ?></font><br>
-              <input type="checkbox" name="overdue_alert_assigned" <?php echo $config['overdue_alert_assigned']?'checked':''; ?>> Assigned Staff
-              <input type="checkbox" name="overdue_alert_dept_manager" <?php echo $config['overdue_alert_dept_manager']?'checked':''; ?>> Department Manager
-              <input type="checkbox" name="overdue_alert_dept_members" <?php echo $config['overdue_alert_dept_members']?'checked':''; ?>> Department Members (spammy)
-            </td>
-        </tr>
-        <tr><th valign="top">System Errors:</th>
-            <td><i>Enabled errors are sent to admin email set above</i><br>
-              <input type="checkbox" name="send_sys_errors" <?php echo $config['send_sys_errors']?'checked':'checked'; ?> disabled>System Errors
-              <input type="checkbox" name="send_sql_errors" <?php echo $config['send_sql_errors']?'checked':''; ?>>SQL errors
-              <input type="checkbox" name="send_login_errors" <?php echo $config['send_login_errors']?'checked':''; ?>>Excessive Login attempts
-            </td>
-        </tr> 
-        
-    </table>
- </td></tr>
- <tr>
-    <td style="padding:10px 0 10px 240px;">
-        <input class="button" type="submit" name="submit" value="Save Changes">
-        <input class="button" type="reset" name="reset" value="Reset Changes">
-    </td>
- </tr>
- </form>
-</table>
diff --git a/include/staff/profile.inc.php b/include/staff/profile.inc.php
index 39eaf80a54e0aa53611239b0fdccacfbfb38ceeb..073a7c8a44229e1b18bf7b7b4cc738d8689d8396 100644
--- a/include/staff/profile.inc.php
+++ b/include/staff/profile.inc.php
@@ -6,6 +6,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 $info['id']=$staff->getId();
 ?>
 <form action="profile.php" method="post" id="save" autocomplete="off">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="update">
  <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
  <h2>My Account Profile</h2>
diff --git a/include/staff/settings-alerts.inc.php b/include/staff/settings-alerts.inc.php
index a71b9e8a88d8da1ff155de7f73bff66ef6089aa8..5bb5d393246ede7266440c30a7e9f5e41df8cc8e 100644
--- a/include/staff/settings-alerts.inc.php
+++ b/include/staff/settings-alerts.inc.php
@@ -1,4 +1,5 @@
 <form action="settings.php?t=alerts" method="post" id="save">
+<?php csrf_token(); ?>
 <input type="hidden" name="t" value="alerts" >
 <table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2">
     <thead>
diff --git a/include/staff/settings-attachments.inc.php b/include/staff/settings-attachments.inc.php
index 572c5da5a52db9fcfda21a49069efb21d7c5deb0..b381fa40d334f9f2c9077f91698c6ec90aa31491 100644
--- a/include/staff/settings-attachments.inc.php
+++ b/include/staff/settings-attachments.inc.php
@@ -4,6 +4,7 @@ if(!($maxfileuploads=ini_get('max_file_uploads')))
 
 ?>
 <form action="settings.php?t=attachments" method="post" id="save">
+<?php csrf_token(); ?>
 <input type="hidden" name="t" value="attachments" >
 <table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2">
     <thead>
diff --git a/include/staff/settings-autoresponders.inc.php b/include/staff/settings-autoresponders.inc.php
index 70bddc826e47c4000b8afca8c35998d36384486d..106e7f3f4d7063a6bcb4835cdbd07006b6f16b5c 100644
--- a/include/staff/settings-autoresponders.inc.php
+++ b/include/staff/settings-autoresponders.inc.php
@@ -1,4 +1,5 @@
 <form action="settings.php?t=autoresponders" method="post" id="save">
+<?php csrf_token(); ?>
 <input type="hidden" name="t" value="autoresponders" >
 <table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2">
     <thead>
diff --git a/include/staff/settings-dates.inc.php b/include/staff/settings-dates.inc.php
index 0434e94c73313ee76c790ddb90315d16636b0afb..f8085cfc3193342bf1bd6c66df87b48d9dcf5edd 100644
--- a/include/staff/settings-dates.inc.php
+++ b/include/staff/settings-dates.inc.php
@@ -2,6 +2,7 @@
 $gmtime=Misc::gmtime();
 ?>
 <form action="settings.php?t=dates" method="post" id="save">
+<?php csrf_token(); ?>
 <input type="hidden" name="t" value="dates" >
 <table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2">
     <thead>
diff --git a/include/staff/settings-emails.inc.php b/include/staff/settings-emails.inc.php
index 017eb29ec14b00dbc2575d812d5f3a2aa5727f3e..e4ccaf3a4e69329c15d474bfd3f136f9a8fe17f9 100644
--- a/include/staff/settings-emails.inc.php
+++ b/include/staff/settings-emails.inc.php
@@ -1,4 +1,5 @@
 <form action="settings.php?t=emails" method="post" id="save">
+<?php csrf_token(); ?>
 <input type="hidden" name="t" value="emails" >
 <table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2">
     <thead>
diff --git a/include/staff/settings-general.inc.php b/include/staff/settings-general.inc.php
index 2e1e347bef5c45eab3826c2b263a59149cb32fc4..20bbd94866960d2e06ae4d3451825d5752c853ac 100644
--- a/include/staff/settings-general.inc.php
+++ b/include/staff/settings-general.inc.php
@@ -1,4 +1,5 @@
 <form action="settings.php?t=general" method="post" id="save">
+<?php csrf_token(); ?>
 <input type="hidden" name="t" value="general" >
 <table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2">
     <thead>
diff --git a/include/staff/settings-kb.inc.php b/include/staff/settings-kb.inc.php
index 2d368b3bac7702f9a8ff9e76f1c1edd645a1799e..6fe8433f5ee580c5a201a42518652106af63d313 100644
--- a/include/staff/settings-kb.inc.php
+++ b/include/staff/settings-kb.inc.php
@@ -1,6 +1,5 @@
-<?php
-?>
 <form action="settings.php?t=kb" method="post" id="save">
+<?php csrf_token(); ?>
 <input type="hidden" name="t" value="kb" >
 <table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2">
     <thead>
diff --git a/include/staff/settings-tickets.inc.php b/include/staff/settings-tickets.inc.php
index 5ada80f48bca4edfb7221e6916aa5e46efb85d94..280abca08ea44d698e0a41b56b1d8d0a62cd1693 100644
--- a/include/staff/settings-tickets.inc.php
+++ b/include/staff/settings-tickets.inc.php
@@ -1,4 +1,5 @@
 <form action="settings.php?t=tickets" method="post" id="save">
+<?php csrf_token(); ?>
 <input type="hidden" name="t" value="tickets" >
 <table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2">
     <thead>
diff --git a/include/staff/settings.php b/include/staff/settings.php
deleted file mode 100644
index 1dac69a5c1e8ce899e2c6b79ce5d85cb90c79d84..0000000000000000000000000000000000000000
--- a/include/staff/settings.php
+++ /dev/null
@@ -1,721 +0,0 @@
-<?php include "./include/header.php" ?>
-<h2>System Preferences and Settings  (v1.6 ST)</h2>
-
-<form action="settings.php" method="post">
-<br>
-<a href="#" class="expand_all">Expand All</a> |
-<a href="#" class="collapse_all">Collapse All</a>
-<table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2">
-    <thead>
-        <tr>
-            <th colspan="2">
-                <h4><a href="#"><span>&ndash;</span>&nbsp;General Settings</a></h4>
-                <em>Offline mode will disable client interface and only allow super admins to login to Staff Control Panel</em>
-            </th>
-        </tr>
-    </thead>
-    <tbody>
-        <tr>
-            <td width="220" class="required">
-                Helpdesk Status:
-            </td>
-            <td>
-                <input type="radio" name="isonline" value="1" checked="checked"><strong>Online</strong> (Active)
-                <input type="radio" name="isonline" value="0"><strong>Offline</strong> (Disabled)
-                &nbsp;<span class="warn">&nbsp;</span>
-            </td>
-        </tr>
-        <tr>
-            <td width="220" class="required">
-                Helpdesk URL:
-            </td>
-            <td>
-                <input type="text" size="40" name="helpdesk_url" value="http://helpdesk.enhancesoft.com/">
-                &nbsp;<span class="error">&nbsp;</span>
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Helpdesk Name/Title:
-            </td>
-            <td>
-                <input type="text" size="40" name="helpdesk_title" value="Enhancesoft :: Support Ticket System">
-            </td>
-        </tr>
-        <tr>
-            <td width="220" class="required">
-                Default E-Mail Templates:
-            </td>
-            <td>
-                <select name="default_template_id">
-                    <option value="0">Select Default Template</option>
-                    <option value="1">osTicket Default Template</option>
-                    <option value="3" selected="selected">No Links</option>
-                </select>
-                &nbsp;<span class="error">&nbsp;</span>
-            </td>
-        </tr>
-        <tr>
-            <td width="220" class="required">
-                Default Department:
-            </td>
-            <td>
-                <select name="default_dept_id">
-                    <option value="0">Select Default Dept</option>
-                    <option value="1" selected="selected">Support Dept</option>
-                    <option value="2">Billing Dept</option>
-                    <option value="4">Test Dept</option>
-                </select>
-                &nbsp;<span class="error">&nbsp;</span>
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Default Page Size:
-            </td>
-            <td>
-                <select name="max_page_size">
-                    <option value="5">5</option>
-                    <option value="10">10</option>
-                    <option value="15">15</option>
-                    <option value="20">20</option>
-                    <option value="25" selected="selected">25</option>
-                    <option value="30">30</option>
-                    <option value="35">35</option>
-                    <option value="40">40</option>
-                    <option value="45">45</option>
-                    <option value="50">50</option>
-                </select>
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Default Log Level:
-            </td>
-            <td>
-                <select name="log_level">
-                    <option value="0">None (Disable Logger)</option>
-                    <option value="3">DEBUG</option>
-                    <option value="2" selected="selected">WARN</option>
-                    <option value="1">ERROR</option>
-                </select>
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Purge Logs:
-            </td>
-            <td>
-                <select name="log_graceperiod">
-                    <option value="0" selected>Never Purge Logs</option>
-                    <option value="1">After 1 Month</option>
-                    <option value="2">After 2 Months</option>
-                    <option value="3">After 3 Months</option>
-                    <option value="4">After 4 Months</option>
-                    <option value="5">After 5 Months</option>
-                    <option value="6">After 6 Months</option>
-                    <option value="7">After 7 Months</option>
-                    <option value="8">After 8 Months</option>
-                    <option value="9">After 9 Months</option>
-                    <option value="10">After 10 Months</option>
-                    <option value="11">After 11 Months</option>
-                    <option value="12">After 12 Months</option>
-                </select>
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Excessive Staff Logins:
-            </td>
-            <td>
-                <select name="staff_max_logins">
-                    <option value="1">1</option>
-                    <option value="2">2</option>
-                    <option value="3">3</option>
-                    <option value="4" selected="selected">4</option>
-                    <option value="5">5</option>
-                    <option value="6">6</option>
-                    <option value="7">7</option>
-                    <option value="8">8</option>
-                    <option value="9">9</option>
-                    <option value="10">10</option>
-                </select> failed login attempt(s) allowed before a
-                <select name="staff_login_timeout">
-                    <option value="1">1</option>
-                    <option value="2" selected="selected">2</option>
-                    <option value="3">3</option>
-                    <option value="4">4</option>
-                    <option value="5">5</option>
-                    <option value="6">6</option>
-                    <option value="7">7</option>
-                    <option value="8">8</option>
-                    <option value="9">9</option>
-                    <option value="10">10</option>
-                </select> minute lock-out is enforced.
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Staff Session Timeout:
-            </td>
-            <td>
-                <input type="text" name="staff_session_timeout" size="4" value="0">
-                &nbsp;Maximum idle time in minutes before a staff member must log in again (enter 0 to disable).
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Staff Session IP Binding:
-            </td>
-            <td>
-                <input type="checkbox" name="staff_ip_binding" checked="checked" value="1">
-                <em>(binds staff session to originating IP address upon login)</em>
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Excessive Client Logins:
-            </td>
-            <td>
-                <select name="client_max_logins">
-                    <option value="1">1</option>
-                    <option value="2">2</option>
-                    <option value="3">3</option>
-                    <option value="4" selected="selected">4</option>
-                    <option value="5">5</option>
-                    <option value="6">6</option>
-                    <option value="7">7</option>
-                    <option value="8">8</option>
-                    <option value="9">9</option>
-                    <option value="10">10</option>
-                </select> failed login attempt(s) allowed before a
-                <select name="client_login_timeout">
-                    <option value="1">1</option>
-                    <option value="2" selected="selected">2</option>
-                    <option value="3">3</option>
-                    <option value="4">4</option>
-                    <option value="5">5</option>
-                    <option value="6">6</option>
-                    <option value="7">7</option>
-                    <option value="8">8</option>
-                    <option value="9">9</option>
-                    <option value="10">10</option>
-                </select> minute lock-out is enforced.
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Client Session Timeout:
-            </td>
-            <td>
-                <input type="text" name="client_session_timeout" size="4" value="0">
-                &nbsp;Maximum idle time in minutes before a client must log in again (enter 0 to disable).
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Clickable URLs:
-            </td>
-            <td>
-                <input type="checkbox" name="clickable_urls" checked="checked" value="1">
-                <em>(converts URLs in messages to clickable links)</em>
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Enable Auto-cron:
-            </td>
-            <td>
-                <input type="checkbox" name="enable_auto_cron" value="1">
-                <em>(executes cron jobs based on staff activity - not recommended)</em>
-            </td>
-        </tr>
-    </tbody>
-</table>
-
-<table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2">
-    <thead>
-        <tr>
-            <th colspan="2">
-                <h4><a href="#"><span>&ndash;</span>&nbsp;Date and Time Settings</a></h4>
-                <em>Please refer to <a href="http://php.net/date" target="_blank">PHP Manual</a> for supported parameters.</em>
-            </th>
-        </tr>
-    </thead>
-    <tbody>
-        <tr>
-            <td width="220" class="required">
-                Time Format:
-            </td>
-            <td>
-                <input type="text" name="time_format" value="h:i A">
-                &nbsp;<span class="error">&nbsp;</span>
-                <em> 09:24 AM</em>
-            </td>
-        </tr>
-        <tr>
-            <td width="220" class="required">
-                Date Format:
-            </td>
-            <td>
-                <input type="text" name="date_format" value="m/d/Y">
-                &nbsp;<span class="error">&nbsp;</span>
-                <em>05/06/2011</em>
-            </td>
-        </tr>
-        <tr>
-            <td width="220" class="required">
-                Date &amp; Time Format:
-            </td>
-            <td>
-                <input type="text" name="datetime_format" value="m/d/Y g:i a">
-                &nbsp;<span class="error">&nbsp;</span>
-                <em>05/06/2011 9:24 am</em>
-            </td>
-        </tr>
-        <tr>
-            <td width="220" class="required">
-                Day, Date &amp; Time Format:
-            </td>
-            <td>
-                <input type="text" name="daydatetime_format" value="D, M j Y g:ia">
-                &nbsp;<span class="error">*&nbsp;</span>
-                <em>Fri, May 6 2011 9:24am</em>
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Default Timezone:
-            </td>
-            <td>
-                <select name="timezone_offset">
-                    <option value="0">Server Time (GMT 0:00)</option>                        <option value="-12.0">GMT -12.0 (Eniwetok, Kwajalein)</option>
-                    <option value="-11.0">GMT -11.0 (Midway Island, Samoa)</option>
-                    <option value="-10.0">GMT -10.0 (Hawaii)</option>
-                    <option value="-9.0">GMT -9.0 (Alaska)</option>
-                    <option value="-8.0">GMT -8.0 (Pacific Time (US & Canada))</option>
-                    <option value="-7.0">GMT -7.0 (Mountain Time (US & Canada))</option>
-                    <option value="-6.0">GMT -6.0 (Central Time (US & Canada), Mexico City)</option>
-                    <option value="-5.0" selected="selected">GMT -5.0 (Eastern Time (US & Canada), Bogota, Lima)</option>
-                    <option value="-4.0">GMT -4.0 (Atlantic Time (Canada), Caracas, La Paz)</option>
-                    <option value="-3.5">GMT -3.5 (Newfoundland)</option>
-                    <option value="-3.0">GMT -3.0 (Brazil, Buenos Aires, Georgetown)</option>
-                    <option value="-2.0">GMT -2.0 (Mid-Atlantic)</option>
-                    <option value="-1.0">GMT -1.0 (Azores, Cape Verde Islands)</option>
-                    <option value="0.0">GMT 0.0 (Western Europe Time, London, Lisbon, Casablanca)</option>
-                    <option value="1.0">GMT 1.0 (Brussels, Copenhagen, Madrid, Paris)</option>
-                    <option value="2.0">GMT 2.0 (Kaliningrad, South Africa)</option>
-                    <option value="3.0">GMT 3.0 (Baghdad, Riyadh, Moscow, St. Petersburg)</option>
-                    <option value="3.5">GMT 3.5 (Tehran)</option>
-                    <option value="4.0">GMT 4.0 (Abu Dhabi, Muscat, Baku, Tbilisi)</option>
-                    <option value="4.5">GMT 4.5 (Kabul)</option>
-                    <option value="5.0">GMT 5.0 (Ekaterinburg, Islamabad, Karachi, Tashkent)</option>
-                    <option value="5.5">GMT 5.5 (Bombay, Calcutta, Madras, New Delhi)</option>
-                    <option value="6.0">GMT 6.0 (Almaty, Dhaka, Colombo)</option>
-                    <option value="7.0">GMT 7.0 (Bangkok, Hanoi, Jakarta)</option>
-                    <option value="8.0">GMT 8.0 (Beijing, Perth, Singapore, Hong Kong)</option>
-                    <option value="9.0">GMT 9.0 (Tokyo, Seoul, Osaka, Sapporo, Yakutsk)</option>
-                    <option value="9.5">GMT 9.5 (Adelaide, Darwin)</option>
-                    <option value="10.0">GMT 10.0 (Eastern Australia, Guam, Vladivostok)</option>
-                    <option value="11.0">GMT 11.0 (Magadan, Solomon Islands, New Caledonia)</option>
-                    <option value="12.0">GMT 12.0 (Auckland, Wellington, Fiji, Kamchatka)</option>
-                </select>
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Daylight Savings
-            </td>
-            <td>
-                <input type="checkbox" name="daylight_savings" value="1">
-                <em>observe daylight savings time</em>
-            </td>
-        </tr>
-    </tbody>
-</table>
-<table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2">
-    <thead>
-        <tr>
-            <th colspan="2">
-                <h4><a href="#"><span>&ndash;</span>&nbsp;Ticket Options and Settings</a></h4>
-                <em>If enabled ticket lock get auto-renewed on form activity.</em>
-            </th>
-        </tr>
-    </thead>
-    <tbody>
-        <tr>
-            <td width="220">
-                Ticket IDs:
-            </td>
-            <td>
-                <input type="radio" name="random_ticket_ids" value="0"> Sequential
-                <input type="radio" name="random_ticket_ids" value="1" checked="checked">Random  (recommended)
-            </td>
-        </tr>
-        <tr>
-            <td width="220" class="multi-line">
-                Ticket Priority:
-            </td>
-            <td>
-                <select name="default_priority_id">
-                    <option value="1">Low</option>
-                    <option value="2" selected="selected">Normal</option>
-                    <option value="3">High</option>
-                    <option value="4">Emergency</option>
-                </select> &nbsp;Default Priority<br>
-                <input type="checkbox" name="allow_priority_change" >
-                Allow user to overwrite/set priority (new web tickets)<br>
-
-                <input type="checkbox" name="use_email_priority"  >
-                Use email priority when available (new emailed tickets)
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Maximum <strong>Open</strong> Tickets:
-            </td>
-            <td>
-                <input type="text" name="max_open_tickets" size="4" value="0">
-                per email <em>(helps with spam and flood control - enter 0 for unlimited)</em>
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Ticket Auto-lock Time:
-            </td>
-            <td>
-                <input type="text" name="autolock_minutes" size="4" value="3">
-                <em>(minutes to lock a ticket on activity - enter 0 to disable locking)</em>
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Ticket Grace Period:
-            </td>
-            <td>
-                <input type="text" name="overdue_grace_period" size=4 value="0">
-                <em>(hours before ticket is marked overdue - enter 0 to disable aging)</em>
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Reopened Tickets:
-            </td>
-            <td>
-                <input type="checkbox" name="auto_assign_reopened_tickets" checked="checked">
-                Auto-assign reopened tickets to last available respondent. <em>(3 months limit)</em>
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Assigned Tickets:
-            </td>
-            <td>
-                <input type="checkbox" name="show_assigned_tickets">
-                Show assigned tickets on open queue.
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Answered Tickets:
-            </td>
-            <td>
-                <input type="checkbox" name="show_nswered_tickets">
-                Show answered tickets on open queue.
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Ticket Activity Log:
-            </td>
-            <td>
-                <input type="checkbox" name="log_ticket_activity">
-                Log ticket activity as an internal note.
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Staff Identity Masking:
-            </td>
-            <td>
-                <input type="checkbox" name="hide_staff_name">
-                Hide staff's name on responses.
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                Human Verification:
-            </td>
-            <td>
-                <input type="checkbox" name="enable_captcha">
-                Enable CAPTCHA on new web tickets.
-                <em>(requires GDLib)</em>
-            </td>
-        </tr>
-    </tbody>
-</table>
-<table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2">
-    <thead>
-        <tr>
-            <th colspan="2">
-                <h4><a href="#"><span>&ndash;</span>&nbsp;E-mail Settings</a></h4>
-                <em>Note that global settings can be disabled at dept/e-mail level.</em>
-            </th>
-        </tr>
-    </thead>
-    <tbody>
-        <tr>
-            <td width="220" class="required multi-line">
-                Incoming Email:
-                <br><em>For mail fetcher (POP/IMAP) to work you must set a cron job or enable auto-cron</em>
-            </td>
-            <td>
-                <input type="checkbox" name="enable_mail_fetch" value="1" checked="checked"> Enable POP/IMAP email fetch
-                &nbsp;<em>(Global setting which can be disabled at email level)</em><br>
-
-                <input type="checkbox" name="enable_email_piping" value="1" checked="checked"> Enable email piping
-                &nbsp;<em>(You pipe we accept policy)</em><br>
-
-                <input type="checkbox" name="strip_quoted_reply" checked="checked">
-                Strip quoted reply <em>(depends on the tag below)</em><br><br>
-
-                Reply Separator Tag:
-                <input type="text" name="reply_separator" value="-- do not edit --">
-                &nbsp;<span class="error">&nbsp;</span>
-            </td>
-        </tr>
-        <tr>
-            <td width="220" class="required multi-line">
-                Outgoing Email:
-                <br><em><strong>Default Email:</strong> Only applies to outgoing emails with no SMTP settings.</em><br/>
-
-            </td>
-            <td>
-                <select name="default_smtp_id" onChange="document.getElementById('overwrite').style.display=(this.options[this.selectedIndex].value>0)?'block':'none';">
-                    <option value="0">Select One</option>
-                    <option value="0">None: Use PHP mail function</option>
-                    <option value="1" selected="selected">osTicket Support &lt;support@osticket.com&gt; (smtp.gmail.com)</option>
-                </select>
-
-                <span id="overwrite" style="display:display">
-                <br><input type="checkbox" name="spoof_default_smtp" >
-                    Allow spoofing (No Overwrite).
-                </span>
-            </td>
-        </tr>
-        <tr>
-            <td width="220" class="required">
-                Default System E-Mail:
-            </td>
-            <td>
-                <select name="default_email_id">
-                    <option value="0">Select One</option>
-                    <option value="1" selected="selected">osTicket Support &lt;support@osticket.com&gt;</option>
-                    <option value="2">osTicket Alerts &lt;alerts@osticket.com&gt;</option>
-                    <option value="3">noreply@osticket.com</option>
-                    <option value="5">lvcta.com (Test) &lt;support@lvcta.com&gt;</option>
-                </select>
-            </td>
-        </tr>
-        <tr>
-            <td width="220" class="required">
-                Default Alert E-Mail:
-            </td>
-            <td>
-                <select name="alert_email_id">
-                    <option value="0">Select One</option>
-                    <option value="1">osTicket Support &lt;support@osticket.com&gt;</option>
-                    <option value="2" selected="selected">osTicket Alerts &lt;alerts@osticket.com&gt;</option>
-                    <option value="3">noreply@osticket.com</option>
-                    <option value="5">lvcta.com (Test) &lt;support@lvcta.com&gt;</option>
-                </select>
-            </td>
-        </tr>
-        <tr>
-            <td width="220" class="required">
-                System Admin E-mail Address:
-            </td>
-            <td>
-                <input type="text" size="25" name="admin_email" value="peter@osticket.com">
-                &nbsp;<span class="error">&nbsp;</span>
-            </td>
-        </tr>
-    </tbody>
-</table>
-<table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2">
-    <thead>
-        <tr>
-            <th colspan="2">
-                <h4><a href="#"><span>&ndash;</span>&nbsp;Autoresponders (Global Setting)</a></h4>
-                <em>This is global setting which can be disabled at department level.</em>
-            </th>
-        </tr>
-    </thead>
-    <tbody>
-        <tr>
-            <td width="220" class="multi-line">
-                New Ticket:
-            </td>
-            <td>
-                <em>Autoresponse includes the ticket ID required to check status of the ticket</em><br>
-                <input type="radio" name="ticket_autoresponder"  value="1">Enable
-                <input type="radio" name="ticket_autoresponder"  value="0" checked="checked">Disable
-                <br><br>
-            </td>
-        </tr>
-        <tr>
-            <td width="220" class="multi-line">
-                New Ticket by Staff:
-            </td>
-            <td>
-                <em>Notice sent when staff creates a ticket on behalf of the user (Staff can disable)</em><br>
-                <input type="radio" name="ticket_notice_active" value="1" checked="checked">Enable
-                <input type="radio" name="ticket_notice_active" value="0">Disable
-                <br><br>
-            </td>
-        </tr>
-        <tr>
-            <td width="220" class="multi-line">
-                New Message:
-            </td>
-            <td>
-                <em>Message appended to an existing ticket confirmation</em><br>
-                <input type="radio" name="message_autoresponder" value="1">Enable
-                <input type="radio" name="message_autoresponder" value="0" checked="checked">Disable
-                <br><br>
-            </td>
-        </tr>
-        <tr>
-            <td width="220" class="multi-line">
-                Ticket Denied:
-            </td>
-            <td>
-                <em>Ticket denied notice sent <strong>only once</strong> on limit violation to the user.</em><br>
-                <input type="radio" name="overlimit_notice_active"  value="1">Enable
-                <input type="radio" name="overlimit_notice_active"  value="0" checked="checked">Disable
-                <em><strong>Note:</strong> Admin gets alerts on ALL denials by default.</em>
-                <br><br>
-            </td>
-        </tr>
-    </tbody>
-</table>
-<table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2">
-    <thead>
-        <tr>
-            <th colspan="2">
-                <h4><a href="#"><span>&ndash;</span>&nbsp;Alerts and Notices</a></h4>
-                <em>Notices sent to user use 'No Reply Email' whereas alerts to staff use 'Alert Email' set above as FROM address respectively.</em>
-            </th>
-        </tr>
-    </thead>
-    <tbody>
-        <tr>
-            <td width="220" class="multi-line">
-                New Ticket Alert:
-            </td>
-            <td>
-                <input type="radio" name="ticket_alert_active" value="1" checked="checked">Enable
-                <input type="radio" name="ticket_alert_active" value="0">Disable
-                <br>
-                <strong>Select recipients:</strong>&nbsp;
-                <input type="checkbox" name="ticket_alert_admin" checked="checked"> Admin Email
-                <input type="checkbox" name="ticket_alert_dept_manager"> Department Manager
-                <input type="checkbox" name="ticket_alert_dept_members"> Department Members (spammy)
-            </td>
-        </tr>
-        <tr>
-            <td width="220" class="multi-line">
-                New Message Alert:
-            </td>
-            <td>
-                <input type="radio" name="message_alert_active" value="1" checked="checked">Enable
-                <input type="radio" name="message_alert_active" value="0">Disable
-                <br>
-                <strong>Select recipients:</strong>&nbsp;
-                <input type="checkbox" name="message_alert_laststaff" checked="checked"> Last Respondent
-                <input type="checkbox" name="message_alert_assigned" checked="checked"> Assigned Staff
-                <input type="checkbox" name="message_alert_dept_manager"> Department Manager (spammy)
-            </td>
-        </tr>
-        <tr>
-            <td width="220">
-                New Internal Note Alert:
-            </td>
-            <td>
-                <input type="radio" name="note_alert_active" value="1" checked="checked">Enable
-                <input type="radio" name="note_alert_active" value="0">Disable
-                <br>
-                <strong>Select recipients:</strong>&nbsp;
-                <input type="checkbox" name="note_alert_laststaff" checked="checked"> Last Respondent
-                <input type="checkbox" name="note_alert_assigned" checked="checked"> Assigned Staff
-                <input type="checkbox" name="note_alert_dept_manager"> Department Manager (spammy)
-            </td>
-        </tr>
-        <tr>
-            <td width="220" class="multi-line">
-                Overdue Ticket Alert:
-            </td>
-            <td>
-                <input type="radio" name="overdue_alert_active" value="1" checked="checked">Enable
-                <input type="radio" name="overdue_alert_active"  value="0">Disable
-                <br>
-                <strong>Select recipients:</strong>
-                <input type="checkbox" name="overdue_alert_assigned" checked="checked"> Assigned Staff
-                <input type="checkbox" name="overdue_alert_dept_manager" checked="checked"> Department Manager
-                <input type="checkbox" name="overdue_alert_dept_members"> Department Members (spammy)
-                <br><em><strong>Note:</strong> Admin gets all overdue alerts by default.</em>
-            </td>
-        </tr>
-        <tr>
-            <td width="220" class="multi-line">
-                System Errors:
-            </td>
-            <td>
-                <input type="checkbox" name="send_sys_errors" checked="checked" disabled="disabled">System Errors
-                <input type="checkbox" name="send_sql_errors" checked="checked">SQL errors
-                <input type="checkbox" name="send_login_errors" checked="checked">Excessive Login attempts
-                <br><em>Enabled errors are sent to admin email set above</em>
-            </td>
-        </tr>
-    </tbody>
-</table>
-<p class="centered">
-    <input class="btn_sm" type="submit" name="submit" value="Save Changes">
-    <input class="btn_sm" type="reset" name="reset" value="Reset Changes">
-</p>
-</form>
-
-<script type="text/javascript">
-    jQuery(function($) {
-        $('.expand_all').click(function(e) {
-            e.preventDefault();
-            $('.settings_table tbody').each(function() {
-                $(this).slideDown();
-            })
-            $('.settings_table h4 span').each(function() {
-                $(this).html('&ndash;');
-            })
-        })
-        $('.collapse_all').click(function(e) {
-            e.preventDefault();
-            $('.settings_table tbody').each(function() {
-                $(this).slideUp();
-            })
-            $('.settings_table h4 span').each(function() {
-                $(this).text('+');
-            })
-        })
-        $('.settings_table h4 a').click(function(e) {
-            e.preventDefault();
-            var parent_elem = $(this).parent().parent().parent().parent().parent();
-            $('tbody', parent_elem).slideToggle();
-            if($('th span', parent_elem).text() == '+') {
-                $('th span', parent_elem).html('&ndash;')
-            } else {
-                $('th span', parent_elem).text('+')
-            }
-        })
-    });
-</script>
-
-<?php include "./include/footer.php" ?>
diff --git a/include/staff/slaplan.inc.php b/include/staff/slaplan.inc.php
index 70db620e84d83dc66a53cf6c08e1d97ea2b31f24..d9c1574feaa1a2bb80e6dc5145f1461dd0fcd0a0 100644
--- a/include/staff/slaplan.inc.php
+++ b/include/staff/slaplan.inc.php
@@ -21,6 +21,7 @@ if($sla && $_REQUEST['a']!='add'){
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
 <form action="slas.php?<?php echo $qstr; ?>" method="post" id="save">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
  <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
diff --git a/include/staff/slaplans.inc.php b/include/staff/slaplans.inc.php
index b8997b6a34be75b697624384e0e39006c5c16feb..c30d4459a24e824aa3724e844bdf0deaca14d532 100644
--- a/include/staff/slaplans.inc.php
+++ b/include/staff/slaplans.inc.php
@@ -46,6 +46,7 @@ else
  <b><a href="slas.php?a=add" class="Icon newsla">Add New SLA Plan</a></b></div>
 <div class="clear"></div>
 <form action="slas.php" method="POST" name="slas" onSubmit="return checkbox_checker(this,1,0);">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="mass_process" >
  <table class="list" border="0" cellspacing="1" cellpadding="0" width="940">
     <caption><?php echo $showing; ?></caption>
diff --git a/include/staff/staff.inc.php b/include/staff/staff.inc.php
index 39651227105158adcadf5283517589ff8dc52ce8..ab10d7d1955c090adeef4887c319045e7190265a 100644
--- a/include/staff/staff.inc.php
+++ b/include/staff/staff.inc.php
@@ -27,6 +27,7 @@ if($staff && $_REQUEST['a']!='add'){
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
 <form action="staff.php?<?php echo $qstr; ?>" method="post" id="save" autocomplete="off">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
  <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
diff --git a/include/staff/staffmembers.inc.php b/include/staff/staffmembers.inc.php
index b01e3387ff28da3e2f8e419b4e728293fe851254..d923815a0c876b8e5a4ff76d9b4ed96a12e90286 100644
--- a/include/staff/staffmembers.inc.php
+++ b/include/staff/staffmembers.inc.php
@@ -116,6 +116,7 @@ else
     $showing='No staff found!';
 ?>
 <form action="staff.php" method="POST" name="staff" onSubmit="return checkbox_checker(this,1,0);">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="mass_process" >
  <table class="list" border="0" cellspacing="1" cellpadding="0" width="940">
     <caption><?php echo $showing; ?></caption>
diff --git a/include/staff/syslogs.inc.php b/include/staff/syslogs.inc.php
index e0f5d2098717dfd360b16fce6959b4a222fd241b..ead5cf544932569261cecf166bfa0f152d309a76 100644
--- a/include/staff/syslogs.inc.php
+++ b/include/staff/syslogs.inc.php
@@ -73,7 +73,7 @@ $total=db_count("SELECT count(*) $qfrom $qwhere");
 $page = ($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
 //pagenate
 $pageNav=new Pagenate($total, $page, PAGE_LIMIT);
-$pageNav->setURL('syslogs.php',$qstr);
+$pageNav->setURL('logs.php',$qstr);
 $qstr.='&order='.($order=='DESC'?'ASC':'DESC');
 $query="$qselect $qfrom $qwhere ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
 $res=db_query($query);
@@ -85,7 +85,7 @@ else
 
 <h2>System Logs</h2>
 <div id='filter' >
- <form action="syslogs.php" method="get">
+ <form action="logs.php" method="get">
     <div style="padding-left:2px;">
         <b>Date Span</b>:
         &nbsp;From&nbsp;<input class="dp" id="sd" size=15 name="startDate" value="<?php echo Format::htmlchars($_REQUEST['startDate']); ?>" autocomplete=OFF>
@@ -104,17 +104,18 @@ else
     </div>
  </form>
 </div>
-<form action="syslogs.php" method="POST" name="logs" onSubmit="return checkbox_checker(this,1,0);">
+<form action="logs.php" method="POST" name="logs" onSubmit="return checkbox_checker(this,1,0);">
+<?php csrf_token(); ?>
  <input type="hidden" name="do" value="mass_process" >
  <table class="list" border="0" cellspacing="1" cellpadding="0" width="940">
     <caption><?php echo $showing; ?></caption>
     <thead>
         <tr>
             <th width="7">&nbsp;</th>        
-            <th width="320"><a <?php echo $title_sort; ?> href="syslogs.php?<?php echo $qstr; ?>&sort=title">Log Title</a></th>
-            <th width="100"><a  <?php echo $type_sort; ?> href="syslogs.php?<?php echo $qstr; ?>&sort=type">Log Type</a></th>
-            <th width="200" nowrap><a  <?php echo $date_sort; ?>href="syslogs.php?<?php echo $qstr; ?>&sort=date">Log Date</a></th>
-            <th width="120"><a  <?php echo $ip_sort; ?> href="syslogs.php?<?php echo $qstr; ?>&sort=ip">IP Address</a></th>
+            <th width="320"><a <?php echo $title_sort; ?> href="logs.php?<?php echo $qstr; ?>&sort=title">Log Title</a></th>
+            <th width="100"><a  <?php echo $type_sort; ?> href="logs.php?<?php echo $qstr; ?>&sort=type">Log Type</a></th>
+            <th width="200" nowrap><a  <?php echo $date_sort; ?>href="logs.php?<?php echo $qstr; ?>&sort=date">Log Date</a></th>
+            <th width="120"><a  <?php echo $ip_sort; ?> href="logs.php?<?php echo $qstr; ?>&sort=ip">IP Address</a></th>
         </tr>
     </thead>
     <tbody>
diff --git a/include/staff/team.inc.php b/include/staff/team.inc.php
index 51b06ce2d1fa51344dbef35258a72cc68ddbf60b..f533bf12b85c7fa29b7435e0c037081a6a626378 100644
--- a/include/staff/team.inc.php
+++ b/include/staff/team.inc.php
@@ -21,6 +21,7 @@ if($team && $_REQUEST['a']!='add'){
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
 <form action="teams.php?<?php echo $qstr; ?>" method="post" id="save">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
  <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
diff --git a/include/staff/teams.inc.php b/include/staff/teams.inc.php
index ab3a2f58d4a88e94ea4d08653b853352d37be680..d9dcee5bbc0031e2707394932294f9e5b88e612b 100644
--- a/include/staff/teams.inc.php
+++ b/include/staff/teams.inc.php
@@ -45,6 +45,7 @@ else
     <b><a href="teams.php?a=add" class="Icon newteam">Add New Team</a></b></div>
 <div class="clear"></div>
 <form action="teams.php" method="POST" name="teams" onSubmit="return checkbox_checker(this,1,0);">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="mass_process" >
  <table class="list" border="0" cellspacing="1" cellpadding="0" width="940">
     <caption><?php echo $showing; ?></caption>
diff --git a/include/staff/template.inc.php b/include/staff/template.inc.php
index ac5c09a744879021e7286f116dc91e18a26df95f..aff5f8e3b780e46bd54bc23e0ded14694fe63e71 100644
--- a/include/staff/template.inc.php
+++ b/include/staff/template.inc.php
@@ -20,6 +20,7 @@ if($template && $_REQUEST['a']!='add'){
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
 <form action="templates.php?<?php echo $qstr; ?>" method="post" id="save">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
  <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
diff --git a/include/staff/templates.inc.php b/include/staff/templates.inc.php
index f60e3b010ec7efe053fd1a73df1cefe9366b9daa..dfdfb91c858d820b965867874282d76eeddab30c 100644
--- a/include/staff/templates.inc.php
+++ b/include/staff/templates.inc.php
@@ -49,6 +49,7 @@ else
  <b><a href="templates.php?a=add" class="Icon newEmailTemplate">Add New Template</a></b></div>
 <div class="clear"></div>
 <form action="templates.php" method="POST" name="tpls" onSubmit="return checkbox_checker(this,1,0);">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="mass_process" >
  <table class="list" border="0" cellspacing="1" cellpadding="0" width="940">
     <caption><?php echo $showing; ?></caption>
diff --git a/include/staff/ticket-edit.inc.php b/include/staff/ticket-edit.inc.php
index 7bbf0921e5ed97a076e0dc5df4aa61dde44e27fb..a0138118886857922da11f3a10bcb5d7bb1d1938 100644
--- a/include/staff/ticket-edit.inc.php
+++ b/include/staff/ticket-edit.inc.php
@@ -4,6 +4,7 @@ if(!defined('OSTSCPINC') || !$thisstaff || !$thisstaff->canEditTickets() || !$ti
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$ticket->getUpdateInfo());
 ?>
 <form action="tickets.php?id=<?php echo $ticket->getId(); ?>&a=edit" method="post" id="save"  enctype="multipart/form-data">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="update">
  <input type="hidden" name="a" value="edit">
  <input type="hidden" name="id" value="<?php echo $ticket->getId(); ?>">
diff --git a/include/staff/ticket-open.inc.php b/include/staff/ticket-open.inc.php
index 680fbad151ba038104410a3a778f3371841d4ed1..db3aca84018b1d0744a46363243a6f111f3bfdba 100644
--- a/include/staff/ticket-open.inc.php
+++ b/include/staff/ticket-open.inc.php
@@ -4,6 +4,7 @@ $info=array();
 $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 ?>
 <form action="tickets.php?a=open" method="post" id="save"  enctype="multipart/form-data">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="create">
  <input type="hidden" name="a" value="open">
  <h2>Open New Ticket</h2>
@@ -161,7 +162,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
             <?php
             if($cfg->allowAttachments()) { ?>
                 <br><em><b>Attachments:</b> Response required when files are attached.</em>
-                <div id="canned_attachments">
+                <div class="canned_attachments">
                     <?php
                     if($info['cannedattachments']) {
                         foreach($info['cannedattachments'] as $k=>$id) {
@@ -174,7 +175,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                     }
                     ?>
                 </div>
-                <div id="uploads"></div>
+                <div class="uploads"></div>
                 <div class="file_input">
                     <input type="file" class="multifile" name="attachments[]" size="30" value="" />
                 </div>
diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php
index b8a2e8097c5e3ff81c0bdbd800114d2be3510a43..a58206963acf4deb36fd48bf17d80c2ea63020aa 100644
--- a/include/staff/ticket-view.inc.php
+++ b/include/staff/ticket-view.inc.php
@@ -20,7 +20,10 @@ $lock  = $ticket->getLock();  //Ticket lock obj
 $id    = $ticket->getId();    //Ticket ID.
 
 //Useful warnings and errors the user might want to know!
-if($ticket->isAssigned() && $staff->getId()!=$thisstaff->getId())
+if($ticket->isAssigned() && (
+            ($staff && $staff->getId()!=$thisstaff->getId())
+         || ($team && !$team->hasMember($thisstaff))
+        ))
     $warn.='&nbsp;&nbsp;<span class="Icon assignedTicket">Ticket is assigned to '.implode('/', $ticket->getAssignees()).'</span>';
 if(!$errors['err'] && ($lock && $lock->getStaffId()!=$thisstaff->getId()))
     $errors['err']='This ticket is currently locked by '.$lock->getStaffName();
@@ -40,8 +43,12 @@ if($ticket->isOverdue())
                 <a href="tickets.php?id=<?php echo $ticket->getId(); ?>" title="Reload" class="reload">Reload</a></h2>
         </td>
         <td width="50%" class="right_align">
-            <a href="tickets.php?id=<?php echo $ticket->getId(); ?>&a=print" title="Print Ticket" class="print">Print Ticket</a>
-            <a href="tickets.php?id=<?php echo $ticket->getId(); ?>&a=edit" title="Edit Ticket" class="edit">Edit Ticket</a>
+            <a href="tickets.php?id=<?php echo $ticket->getId(); ?>&a=print" title="Print Ticket" class="print" id="ticket-print">Print Ticket</a>
+            <?php
+            if($thisstaff->canEditTickets()) { ?>
+             <a href="tickets.php?id=<?php echo $ticket->getId(); ?>&a=edit" title="Edit Ticket" class="edit">Edit Ticket</a>
+            <?php
+            } ?>
         </td>
     </tr>
 </table>
@@ -236,12 +243,13 @@ if(!$cfg->showNotesInline()) { ?>
             <tr>
                 <th width="200"><?php echo Format::db_datetime($entry['created']);?></th>
                 <th width="440"><span><?php echo Format::htmlchars($entry['title']); ?></span></th>
-                <th width="300" class="tmeta"><?php echo Format::htmlchars($entry['poster']); ?></th></tr>
-            <tr><td colspan=2><?php echo Format::display($entry['body']); ?></td></tr>
+                <th width="300" class="tmeta"><?php echo Format::htmlchars($entry['poster']); ?></th>
+            </tr>
+            <tr><td colspan=3><?php echo Format::display($entry['body']); ?></td></tr>
             <?php
             if($entry['attachments'] && ($links=$ticket->getAttachmentsLinks($entry['id'], $entry['thread_type']))) {?>
             <tr>
-                <td class="info" colspan=2><?php echo $links; ?></td>
+                <td class="info" colspan=3><?php echo $links; ?></td>
             </tr>
             <?php
             }?>
@@ -280,6 +288,7 @@ if(!$cfg->showNotesInline()) { ?>
     </ul>
 
     <form id="reply" action="tickets.php?id=<?php echo $ticket->getId(); ?>#reply" name="reply" method="post" enctype="multipart/form-data">
+        <?php csrf_token(); ?>
         <input type="hidden" name="id" value="<?php echo $ticket->getId(); ?>">
         <input type="hidden" name="msgId" value="<?php echo $msgId; ?>">
         <input type="hidden" name="a" value="reply">
@@ -325,9 +334,9 @@ if(!$cfg->showNotesInline()) { ?>
                     <label for="attachment">Attachments:</label>
                 </td>
                 <td width="765" id="reply_form_attachments" class="attachments">
-                    <div id="canned_attachments">
+                    <div class="canned_attachments">
                     </div>
-                    <div id="uploads">
+                    <div class="uploads">
                     </div>
                     <div class="file_input">
                         <input type="file" class="multifile" name="attachments[]" size="30" value="" />
@@ -390,6 +399,7 @@ if(!$cfg->showNotesInline()) { ?>
         </p>
     </form>
     <form id="note" action="tickets.php?id=<?php echo $ticket->getId(); ?>#note" name="note" method="post" enctype="multipart/form-data">
+        <?php csrf_token(); ?>
         <input type="hidden" name="id" value="<?php echo $ticket->getId(); ?>">
         <input type="hidden" name="a" value="postnote">
         <table border="0" cellspacing="0" cellpadding="3">
@@ -478,6 +488,7 @@ if(!$cfg->showNotesInline()) { ?>
     <?php
     if($thisstaff->canTransferTickets()) { ?>
     <form id="transfer" action="tickets.php?id=<?php echo $ticket->getId(); ?>#transfer" name="transfer" method="post" enctype="multipart/form-data">
+        <?php csrf_token(); ?>
         <input type="hidden" name="ticket_id" value="<?php echo $ticket->getId(); ?>">
         <input type="hidden" name="a" value="transfer">
         <table border="0" cellspacing="0" cellpadding="3">
@@ -526,6 +537,7 @@ if(!$cfg->showNotesInline()) { ?>
     <?php
     if($thisstaff->canAssignTickets()) { ?>
     <form id="assign" action="tickets.php?id=<?php echo $ticket->getId(); ?>#assign" name="assign" method="post" enctype="multipart/form-data">
+        <?php csrf_token(); ?>
         <input type="hidden" name="id" value="<?php echo $ticket->getId(); ?>">
         <input type="hidden" name="a" value="assign">
         <table border="0" cellspacing="0" cellpadding="3">
@@ -597,4 +609,42 @@ if(!$cfg->showNotesInline()) { ?>
     <?php
     } ?>
 </div>
+<div style="display:none;" id="print-options">
+    <h3>Ticket Print Options</h3>
+    <a class="close" href="">&times;</a>
+    <hr/>
+    <form action="tickets.php?id=<?php echo $ticket->getId(); ?>" method="post" id="print-form" name="print-form">
+        <?php csrf_token(); ?>
+        <input type="hidden" name="a" value="print">
+        <input type="hidden" name="id" value="<?php echo $ticket->getId(); ?>">
+        <fieldset class="notes">
+            <label for="notes">Print Notes:</label>
+            <input type="checkbox" id="notes" name="notes" value="1"> Print <b>Internal</b> Notes/Comments
+        </fieldset>
+        <fieldset>
+            <label for="psize">Paper Size:</label>
+            <select id="psize" name="psize">
+                <option value="">&mdash; Select Print Paper Size &mdash;</option>
+                <?php
+                  $options=array('Letter', 'Legal', 'A4', 'A3');
+                  $psize =$_SESSION['PAPER_SIZE']?$_SESSION['PAPER_SIZE']:$thisstaff->getDefaultPaperSize();
+                  foreach($options as $v) {
+                      echo sprintf('<option value="%s" %s>%s</option>',
+                                $v,($psize==$v)?'selected="selected"':'', $v);
+                  }
+                ?>
+            </select>
+        </fieldset>
+        <hr style="margin-top:3em"/>
+        <p class="full-width">
+            <span class="buttons" style="float:left">
+                <input type="reset" value="Reset">
+                <input type="button" value="Cancel" class="close">
+            </span>
+            <span class="buttons" style="float:right">
+                <input type="submit" value="Print">
+            </span>
+         </p>
+    </form>
+</div>
 <script type="text/javascript" src="js/ticket.js"></script>
diff --git a/include/staff/tickets.inc.php b/include/staff/tickets.inc.php
index 2c01180495fb73096c9d09555e848177697768c6..cbe8a6a982c22ee6c5c2ecfc2427164f9254e65d 100644
--- a/include/staff/tickets.inc.php
+++ b/include/staff/tickets.inc.php
@@ -63,6 +63,7 @@ $qwhere ='';
 $depts=$thisstaff->getDepts();    
 $qwhere =' WHERE ( '
         .'  ticket.staff_id='.db_input($thisstaff->getId());
+
 if(!$thisstaff->showAssignedOnly())
     $qwhere.=' OR ticket.dept_id IN ('.($depts?implode(',',$depts):0).')';
 
@@ -269,6 +270,7 @@ $negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting..
 <!-- SEARCH FORM START -->
 <div id='basic_search'>
     <form action="tickets.php" method="get">
+    <?php csrf_token(); ?>
     <input type="hidden" name="a" value="search">
     <table>
         <tr>
@@ -284,6 +286,7 @@ $negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting..
 <div class="clear"></div>
 <div style="margin-bottom:20px">
 <form action="tickets.php" method="POST" name='tickets' onSubmit="return checkbox_checker(this,1,0);">
+<?php csrf_token(); ?>
  <a class="refresh" href="<?php echo $_SERVER['REQUEST_URI']; ?>">Refresh</a>
  <input type="hidden" name="a" value="mass_process" >
  <input type="hidden" name="status" value="<?php echo $status; ?>" >
@@ -467,7 +470,7 @@ $negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting..
     } ?>
     </form>
 </div>
-<div id="overlay"></div>
+<div id="search_overlay"></div>
 <div style="display:none;" id="advanced-search">
     <h3>Advanced Ticket Search</h3>
     <a class="close" href="">&times;</a>
diff --git a/include/staff/topic.inc.php b/include/staff/topic.inc.php
deleted file mode 100644
index f0f895409d99ebd2c39c4013572b1ee455887090..0000000000000000000000000000000000000000
--- a/include/staff/topic.inc.php
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied');
-
-$info=($_POST && $errors)?Format::input($_POST):array(); //Re-use the post info on error...savekeyboards.org
-if($topic && $_REQUEST['a']!='new'){
-    $title='Edit Topic';
-    $action='update';
-    $info=$info?$info:$topic->getInfo();
-}else {
-   $title='New Help Topic';
-   $action='create';
-   $info['isactive']=isset($info['isactive'])?$info['isactive']:1;
-}
-//get the goodies.
-$depts= db_query('SELECT dept_id,dept_name FROM '.DEPT_TABLE);
-$priorities= db_query('SELECT priority_id,priority_desc FROM '.TICKET_PRIORITY_TABLE);
-?>
-<form action="admin.php?t=topics" method="post">
- <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='t' value='topics'>
- <input type="hidden" name="topic_id" value="<?php echo $info['topic_id']; ?>">
-<table width="100%" border="0" cellspacing=0 cellpadding=2 class="tform">
-    <tr class="header"><td colspan=2><?php echo $title; ?></td></tr>
-    <tr class="subheader">
-        <td colspan=2 >Disabling auto response will overwrite dept settings.</td>
-    </tr>
-    <tr>
-        <th width="20%">Help Topic:</th>
-        <td><input type="text" name="topic" size="55" value="<?php echo $info['topic']; ?>">
-            &nbsp;<font class="error">*&nbsp;<?php echo $errors['topic']; ?></font></td>
-    </tr>
-    <tr><th>Topic Status</th>
-        <td>
-            <input type="radio" name="isactive"  value="1"   <?php echo $info['isactive']?'checked':''; ?> />Active
-            <input type="radio" name="isactive"  value="0"   <?php echo !$info['isactive']?'checked':''; ?> />Disabled
-        </td>
-    </tr>
-    <tr>
-        <th nowrap>Auto Response:</th>
-        <td>
-            <input type="checkbox" name="noautoresp" value=1 <?php echo $info['noautoresp']? 'checked': ''; ?> >
-                <b>Disable</b> autoresponse for this topic.   (<i>Overwrite Dept setting</i>)
-        </td>
-    </tr>
-    <tr>
-        <th>New Ticket Priority:</th>
-        <td>
-            <select name="priority_id">
-                <option value=0>Select Priority</option>
-                <?php
-                while (list($id,$name) = db_fetch_row($priorities)){
-                    $selected = ($info['priority_id']==$id)?'selected':''; ?>
-                    <option value="<?php echo $id; ?>"<?php echo $selected; ?>><?php echo $name; ?></option>
-                <?php
-                } ?>
-            </select>&nbsp;<font class="error">*&nbsp;<?php echo $errors['priority_id']; ?></font>
-        </td>
-    </tr>
-    <tr>
-        <th nowrap>New Ticket Department:</th>
-        <td>
-            <select name="dept_id">
-                <option value=0>Select Department</option>
-                <?php
-                while (list($id,$name) = db_fetch_row($depts)){
-                    $selected = ($info['dept_id']==$id)?'selected':''; ?>
-                    <option value="<?php echo $id; ?>"<?php echo $selected; ?>><?php echo $name; ?> Dept</option>
-                <?php
-                } ?>
-            </select>&nbsp;<font class="error">*&nbsp;<?php echo $errors['dept_id']; ?></font>
-        </td>
-    </tr>
-</table>
-<div style="padding-left:220px;">
-    <input class="button" type="submit" name="submit" value="Submit">
-    <input class="button" type="reset" name="reset" value="Reset">
-    <input class="button" type="button" name="cancel" value="Cancel" onClick='window.location.href="admin.php?t=topics"'>
-</div>
-</form>
diff --git a/include/staff/tpl.inc.php b/include/staff/tpl.inc.php
index 43412bcad7b0ac01aeb3ff80edc6f857232f6313..c973ab9ff9c1d083e6a6a13643e8d49ea14ff16b 100644
--- a/include/staff/tpl.inc.php
+++ b/include/staff/tpl.inc.php
@@ -26,6 +26,7 @@ $info=array_merge($template->getMsgTemplate($info['tpl']),$info);
     </form>
 </div>
 <form action="templates.php?id=<?php echo $template->getId(); ?>" method="post" id="save">
+<?php csrf_token(); ?>
 <input type="hidden" name="id" value="<?php echo $template->getId(); ?>">
 <input type="hidden" name="tpl" value="<?php echo $info['tpl']; ?>">
 <input type="hidden" name="a" value="manage">
diff --git a/setup/inc/upgrade-aborted.inc.php b/include/upgrader/aborted.inc.php
similarity index 66%
rename from setup/inc/upgrade-aborted.inc.php
rename to include/upgrader/aborted.inc.php
index 8624590d35710a42906952afab82b2688f028315..44e065b14f87ede8644f284ff1a923e08963f4e1 100644
--- a/setup/inc/upgrade-aborted.inc.php
+++ b/include/upgrader/aborted.inc.php
@@ -1,10 +1,12 @@
 <?php
-if(!defined('SETUPINC')) die('Kwaheri!');
+if(!defined('OSTSCPINC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
 ?>    
-<div id="main">
+<div id="upgrader">
+   <div id="main">
     <h1 style="color:#FF7700;">Upgrade Aborted!</h1>
     <div id="intro">
-        <p>Upgrade aborted due to errors. Any errors at this stage are fatal. Please note the error(s), if any, when contacting us.<p>
+        <p><strong>Upgrade aborted due to errors. Any errors at this stage are fatal.</strong></p>
+        <p>Please note the error(s), if any, when <a target="_blank" href="http://osticket.com/support/">seeking help</a>.<p>
         <?php
         if($upgrader && ($errors=$upgrader->getErrors())) {
             if($errors['err'])
@@ -18,11 +20,15 @@ if(!defined('SETUPINC')) die('Kwaheri!');
             echo '<b><font color="red">Internal error occurred - get technical help.</font></b>';
         }
         ?>
+        <p><b>For detailed - please view <a href="logs.php">system logs</a> or check your email.</b></p>
+        <br>
         <p>Please, refer to the <a target="_blank" href="http://osticket.com/wiki/Upgrade_and_Migration">Upgrade Guide</a> on the wiki for more information.</p>
     </div>
-    <p><strong>Need Help?</strong> We provide <a target="_blank" href="http://osticket.com/support/professional_services.php"><u>professional upgrade services</u></a> and commercial support. <a target="_blank" href="http://osticket.com/support/">Contact us</a> today for expedited help.</p>
-</div>    
-<div id="sidebar">
+    <p><strong>Need Help?</strong> We provide <a target="_blank" href="http://osticket.com/support/professional_services.php"><u>professional upgrade services</u></a> and commercial support. <a target="_blank" href="http://osticket.com/support/">Contact us</a> today for <u>expedited</u> help.</p>
+  </div>    
+  <div id="sidebar">
     <h3>What to do?</h3>
-    <p>Restore your previous version from backup and try again or <a target="_blank" href="http://osticket.com/support/">seek help</a>.</p>    
+    <p>Restore your previous version from backup and try again or <a target="_blank" href="http://osticket.com/support/">seek help</a>.</p>
+  </div>
+  <div class="clear"></div>
 </div>
diff --git a/include/upgrader/done.inc.php b/include/upgrader/done.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..f4a55538991d4b8fd6f6814bcb7f08c31e390b7f
--- /dev/null
+++ b/include/upgrader/done.inc.php
@@ -0,0 +1,29 @@
+<?php
+if(!defined('OSTSCPINC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
+//Destroy the upgrader - we're done! 
+$_SESSION['ost_upgrader']=null;
+?> 
+<div id="upgrader">
+    <div id="main">
+        <h1 style="color:green;">Upgrade Completed!</h1>
+        <div id="intro">
+        <p>Congratulations osTicket upgrade has been completed successfully.</p>
+        <p>Please refer to <a href="http://osticket.com/wiki/Release_Notes" target="_blank">Release Notes</a> for more information about changes and/or new features.</p>
+        </div>
+        <p>Once again, thank you for choosing osTicket.</p>
+        <p>Please feel free to <a target="_blank" href="http://osticket.com/support/">let us know</a> of any other improvements and features you would like to see in osTicket, so that we may add them in the future as we continue to develop better and better versions of osTicket.</p>
+        <p>We take user feedback seriously and we're dedicated to making changes based on your input.</p>
+        <p>Good luck.<p>
+        <p>osTicket Team.</p>
+        <br>
+        <p><b>PS</b>: Don't just make customers happy, make happy customers!</p>
+    </div>
+    <div id="sidebar">
+            <h3>What's Next?</h3>
+            <p><b>Post-upgrade</b>: You can now go to <a href="scp/settings.php" target="_blank">Admin Panel</a> to enable the system and explore the new features. For complete and upto date release notes see <a href="http://osticket.com/wiki/Release_Notes" target="_blank">osTicket wiki</a></p>
+            <p><b>Stay up to date</b>: It's important to keep your osTicket installation up to date. Get announcements, security updates and alerts delivered directly to you! 
+            <a target="_blank" href="http://osticket.com/support/subscribe.php">Get in the loop</a> today and stay informed!</p>
+            <p><b>Commercial support available</b>: Get guidance and hands-on expertise to address unique challenges and make sure your osTicket runs smoothly, efficiently, and securely. <a target="_blank" href="http://osticket.com/support/commercial_support.php.php">Learn More!</a></p>
+   </div>
+   <div class="clear"></div>
+</div>
diff --git a/setup/inc/upgrade-prereq.inc.php b/include/upgrader/prereq.inc.php
similarity index 77%
rename from setup/inc/upgrade-prereq.inc.php
rename to include/upgrader/prereq.inc.php
index 5f60cece25500679de83b01981ea05ac634949e9..d32fc328fbe3dd51759ddbaee6f58ac25d862aa2 100644
--- a/setup/inc/upgrade-prereq.inc.php
+++ b/include/upgrader/prereq.inc.php
@@ -1,10 +1,10 @@
 <?php
-if(!defined('SETUPINC')) die('Kwaheri!');
-
+if(!defined('OSTSCPINC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
 ?>
+<h2>osTicket Upgrader</h2>
+<div id="upgrader">
+    
     <div id="main">
-            <h1>osTicket Upgrade!</h1>
-            <font color="red"><b><?php echo $errors['err']; ?></b></font>
             <div id="intro">
              <p>Thank you for being a loyal osTicket user!</p>
              <p>The upgrade wizard will guide you every step of the way in the upgrade process. While we try to ensure that the upgrade process is straightforward and painless, we can't guarantee it will be the case for every user.</p>
@@ -12,7 +12,7 @@ if(!defined('SETUPINC')) die('Kwaheri!');
             <h2>Getting ready!</h2>
             <p>Before we begin, we'll check your server configuration to make sure you meet the minimum requirements to run the latest version of osTicket.</p>
             <h3>Prerequisites: <font color="red"><?php echo $errors['prereq']; ?></font></h3>
-            These items are necessary in order to use osTicket the latest version of osTicket.
+            These items are necessary in order to run the latest version of osTicket.
             <ul class="progress">
                 <li class="<? echo $upgrader->check_php()?'yes':'no'; ?>">
                 PHP v4.3 or greater - (<small><b><?php echo PHP_VERSION; ?></b></small>)</li>
@@ -22,12 +22,12 @@ if(!defined('SETUPINC')) die('Kwaheri!');
             <h3>Higly Recommended:</h3>
             We hightly recommend that you follow the steps below.
             <ul>
-                <li>Take osTicket offline momentarily during upgrade.</li>
                 <li>Backup the current database, if you haven't done so already.</li>
                 <li>Be patient the upgrade process will take a couple of seconds.</li>
             </ul>
             <div id="bar">
                 <form method="post" action="upgrade.php" id="prereq">
+                    <?php csrf_token(); ?>
                     <input type="hidden" name="s" value="prereq">
                     <input class="btn"  type="submit" name="submit" value="Start Upgrade Now &raquo;">
                 </form>
@@ -36,15 +36,17 @@ if(!defined('SETUPINC')) die('Kwaheri!');
     <div id="sidebar">
             <h3>Upgrade Tips</h3>
             <p>1. Remember to backup your osTicket database</p>
-            <p>2. Take osTicket offline momentarily</p>
+            <p>2. Refer to <a href="http://osticket.com/wiki/Upgrade_and_Migration" target="_blank">Upgrade Guide</a> for the latest tips</a>
             <p>3. If you experience any problems, you can always restore your files/dabase backup.</p>
             <p>4. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p>
 
     </div>
-
-    <div id="overlay"></div>
-    <div id="loading">
-        <h4>Doing stuff!</h4>
-        Please wait... while we upgrade your osTicket installation!
-        <div id="udb"></div>
-    </div>
+    <div class="clear"></div>
+</div>
+    
+<div id="overlay"></div>
+<div id="loading">
+    <h4>Doing stuff!</h4>
+    Please wait... while we upgrade your osTicket installation!
+    <div id="msg"></div>
+</div>
diff --git a/include/upgrader/rename.inc.php b/include/upgrader/rename.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..0b649bfa0a3dc1902e0aad168573719eab905bde
--- /dev/null
+++ b/include/upgrader/rename.inc.php
@@ -0,0 +1,34 @@
+<?php
+if(!defined('OSTSCPINC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
+?>
+<div id="upgrader">
+    <br>
+    <h2 style="color:#FF7700;">Configuration file rename required!</h2>
+    <div id="main">
+            <div id="intro">
+             <p>To avoid possible conflicts, please take a minute to rename configuration file as shown below.</p>
+            </div>
+            <h3>Solution:</h3>
+            Rename file <b>include/settings.php</b> to <b>include/ost-config.php</b> and click continue below.
+            <ul>
+                <li><b>CLI:</b><br><i>mv include/settings.php include/ost-config.php</i></li>
+                <li><b>FTP:</b><br> </li>
+                <li><b>Cpanel:</b><br> </li>
+            </ul>
+            <p>Please refer to the <a target="_blank" href="http://osticket.com/wiki/Upgrade_and_Migration">Upgrade Guide</a> for more information.</p>
+            <div id="bar">
+                <form method="post" action="upgrade.php">
+                    <?php csrf_token(); ?>
+                    <input type="hidden" name="s" value="prereq">
+                    <input class="btn" type="submit" name="submit" value="Continue &raquo;">
+                </form>
+            </div>
+    </div>
+    <div id="sidebar">
+            <h3>Need Help?</h3>
+            <p>
+            If you are looking for a greater level of support, we provide <u>professional upgrade</u> 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. <a target="_blank" href="http://osticket.com/support/professional_services.php">Learn More!</a>
+            </p>
+    </div>
+    <div class="clear"></div>
+</div>
diff --git a/setup/inc/sql/02decaa2-60fcbee1.patch.sql b/include/upgrader/sql/02decaa2-60fcbee1.patch.sql
similarity index 100%
rename from setup/inc/sql/02decaa2-60fcbee1.patch.sql
rename to include/upgrader/sql/02decaa2-60fcbee1.patch.sql
diff --git a/include/upgrader/sql/15af7cd3-98ae1ed2.patch.sql b/include/upgrader/sql/15af7cd3-98ae1ed2.patch.sql
new file mode 100644
index 0000000000000000000000000000000000000000..775509266684bec3f34284603fbd69da87f407c2
--- /dev/null
+++ b/include/upgrader/sql/15af7cd3-98ae1ed2.patch.sql
@@ -0,0 +1,8 @@
+/*
+ * @version=1.6RC1-4
+ * 
+ * Stage RC2 for 1.6RC5 upgrade
+ */
+
+UPDATE `%TABLE_PREFIX%config`
+    SET `ostversion`='1.6 RC1-4';
diff --git a/include/upgrader/sql/2e20a0eb-98ae1ed2.patch.sql b/include/upgrader/sql/2e20a0eb-98ae1ed2.patch.sql
new file mode 100644
index 0000000000000000000000000000000000000000..49d1e93623337eebc83463dbfe2c4686d518825e
--- /dev/null
+++ b/include/upgrader/sql/2e20a0eb-98ae1ed2.patch.sql
@@ -0,0 +1,8 @@
+/*
+ * @version=1.6RC1-4
+ * 
+ * Stage RC4 for 1.6RC5 upgrade
+ */
+
+UPDATE `%TABLE_PREFIX%config`
+    SET `ostversion`='1.6 RC1-4';
diff --git a/include/upgrader/sql/435c62c3-2e7531a2.cleanup.sql b/include/upgrader/sql/435c62c3-2e7531a2.cleanup.sql
new file mode 100644
index 0000000000000000000000000000000000000000..75192e141510d052fda52b338170ea7b8bc52e4c
--- /dev/null
+++ b/include/upgrader/sql/435c62c3-2e7531a2.cleanup.sql
@@ -0,0 +1 @@
+ALTER TABLE `%TABLE_PREFIX%groups` DROP `dept_access`;
diff --git a/include/upgrader/sql/435c62c3-2e7531a2.patch.sql b/include/upgrader/sql/435c62c3-2e7531a2.patch.sql
new file mode 100644
index 0000000000000000000000000000000000000000..9537d1acba838be54ec1ece8c7ab4a80545f1bc0
--- /dev/null
+++ b/include/upgrader/sql/435c62c3-2e7531a2.patch.sql
@@ -0,0 +1,31 @@
+/**
+ *  Move dept_access from group table to group_dept_access table.
+ *
+ * @version 1.7-rc1 Dept_Access
+ */
+
+-- Group department access table
+CREATE TABLE `%TABLE_PREFIX%group_dept_access` (
+  `group_id` int(10) unsigned NOT NULL default '0',
+  `dept_id` int(10) unsigned NOT NULL default '0',
+  UNIQUE KEY `group_dept`  (`group_id`,`dept_id`),
+  KEY `dept_id` (`dept_id`)
+) ENGINE=MyISAM;
+
+-- Extend membership to groups
+ALTER TABLE `%TABLE_PREFIX%department`
+    ADD `group_membership` tinyint( 1 ) unsigned NOT NULL DEFAULT '0' AFTER `ispublic`;
+
+-- Fix teams dates...
+UPDATE `%TABLE_PREFIX%team` 
+    SET `created`=IF(TO_DAYS(`created`), `created`, IF(TO_DAYS(`updated`), `updated`, NOW())),
+        `updated`=IF(TO_DAYS(`updated`), `updated`, NOW());
+
+-- Fix groups dates... 
+UPDATE `%TABLE_PREFIX%groups` 
+    SET `created`=IF(TO_DAYS(`created`), `created`, IF(TO_DAYS(`updated`), `updated`, NOW())),
+        `updated`=IF(TO_DAYS(`updated`), `updated`, NOW());
+
+-- Finished with patch
+UPDATE `%TABLE_PREFIX%config`
+    SET `schema_signature`='2e7531a201b5b8650dcd43681a832ebd';
diff --git a/setup/inc/sql/49478749-c2d2fabf.patch.sql b/include/upgrader/sql/49478749-c2d2fabf.patch.sql
similarity index 100%
rename from setup/inc/sql/49478749-c2d2fabf.patch.sql
rename to include/upgrader/sql/49478749-c2d2fabf.patch.sql
diff --git a/setup/inc/sql/522e5b78-02decaa2.patch.sql b/include/upgrader/sql/522e5b78-02decaa2.patch.sql
similarity index 100%
rename from setup/inc/sql/522e5b78-02decaa2.patch.sql
rename to include/upgrader/sql/522e5b78-02decaa2.patch.sql
diff --git a/include/upgrader/sql/60fcbee1-f8856d56.patch.sql b/include/upgrader/sql/60fcbee1-f8856d56.patch.sql
new file mode 100644
index 0000000000000000000000000000000000000000..624e88968ef3f673bea2f1a96d4b1733fbff9c8a
--- /dev/null
+++ b/include/upgrader/sql/60fcbee1-f8856d56.patch.sql
@@ -0,0 +1,61 @@
+DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_event`;
+CREATE TABLE `%TABLE_PREFIX%ticket_event` (
+  `ticket_id` int(11) unsigned NOT NULL default '0',
+  `staff_id` int(11) unsigned NOT NULL,
+  `team_id` int(11) unsigned NOT NULL,
+  `dept_id` int(11) unsigned NOT NULL,
+  `topic_id` int(11) unsigned NOT NULL,
+  `state` enum('created','closed','reopened','assigned','transferred','overdue') NOT NULL,
+  `staff` varchar(255) NOT NULL default 'SYSTEM',
+  `timestamp` datetime NOT NULL,
+  KEY `ticket_state` (`ticket_id`, `state`, `timestamp`),
+  KEY `ticket_stats` (`timestamp`, `state`)
+) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
+
+DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_history`;
+DROP TABLE IF EXISTS `%TABLE_PREFIX%history`;
+
+-- Transfer ticket statistics from the %ticket table (inaccurate)
+-- REOPENED
+INSERT INTO `%TABLE_PREFIX%ticket_event`
+    (`ticket_id`, `staff_id`, `team_id`, `dept_id`, `topic_id`,
+        `state`, `staff`, `timestamp`)
+    SELECT `ticket_id`, T1.`staff_id`, `team_id`, T1.`dept_id`, `topic_id`,
+        'reopened', T2.`username`, `reopened`
+    FROM `%TABLE_PREFIX%ticket` T1
+        INNER JOIN `%TABLE_PREFIX%staff` T2
+        ON (T1.`staff_id` = T2.`staff_id`)
+    WHERE `status` = 'open' and `reopened` is not null;
+
+-- CLOSED
+INSERT INTO `%TABLE_PREFIX%ticket_event`
+    (`ticket_id`, `staff_id`, `team_id`, `dept_id`, `topic_id`,
+        `state`, `staff`, `timestamp`)
+    SELECT `ticket_id`, T1.`staff_id`, `team_id`, T1.`dept_id`, `topic_id`,
+        'closed', COALESCE(T2.`username`,'unknown'), `closed`
+    FROM `%TABLE_PREFIX%ticket` T1
+        LEFT JOIN `%TABLE_PREFIX%staff` T2
+        ON (T1.`staff_id` = T2.`staff_id`)
+    WHERE `status` = 'closed' and `closed` is not null;
+
+-- OVERDUE
+INSERT INTO `%TABLE_PREFIX%ticket_event`
+    (`ticket_id`, `staff_id`, `team_id`, `dept_id`, `topic_id`,
+        `state`, `staff`, `timestamp`)
+    SELECT `ticket_id`, T1.`staff_id`, `team_id`, T1.`dept_id`, `topic_id`,
+        'overdue', 'SYSTEM', `duedate`
+    FROM `%TABLE_PREFIX%ticket` T1
+        INNER JOIN `%TABLE_PREFIX%staff` T2
+        ON (T1.`staff_id` = T2.`staff_id`)
+    WHERE `status` = 'open' and `isoverdue`;
+
+-- OPENED
+INSERT INTO `%TABLE_PREFIX%ticket_event`
+    (`ticket_id`, `staff_id`, `team_id`, `dept_id`, `topic_id`,
+        `state`, `staff`, `timestamp`)
+    SELECT `ticket_id`, 0, 0, 0, `topic_id`,
+        'created', 'SYSTEM', T1.`created`
+    FROM `%TABLE_PREFIX%ticket` T1;
+
+UPDATE `%TABLE_PREFIX%config`
+    SET `schema_signature`='f8856d56e51c5cc3416389de78b54515';
diff --git a/include/upgrader/sql/7be60a84-522e5b78.patch.sql b/include/upgrader/sql/7be60a84-522e5b78.patch.sql
new file mode 100644
index 0000000000000000000000000000000000000000..a31af302d3b10908fdded3c2359b61b426c5a87d
--- /dev/null
+++ b/include/upgrader/sql/7be60a84-522e5b78.patch.sql
@@ -0,0 +1,9 @@
+/**
+ * No longer necessary -- don't clobber email templates for previous
+ * osTicket administrators
+ *
+ * @version v1.7-DPR1 (P1)
+ */
+
+UPDATE `%TABLE_PREFIX%config`
+    SET `schema_signature`='522e5b783c2824c67222260ee22baa93';
diff --git a/include/upgrader/sql/98ae1ed2-e342f869.cleanup.sql b/include/upgrader/sql/98ae1ed2-e342f869.cleanup.sql
new file mode 100644
index 0000000000000000000000000000000000000000..90cf207f5354b3f40aec3cfab8e3c385e7bbc410
--- /dev/null
+++ b/include/upgrader/sql/98ae1ed2-e342f869.cleanup.sql
@@ -0,0 +1,10 @@
+ALTER TABLE `%TABLE_PREFIX%department` DROP `noreply_autoresp`;
+
+ALTER TABLE `%TABLE_PREFIX%config`
+    DROP `noreply_email`,
+    DROP `alert_email`,
+    DROP `api_whitelist`;
+
+-- %email_pop3 migrated to %email table
+TRUNCATE TABLE `%TABLE_PREFIX%email_pop3`;
+DROP TABLE `%TABLE_PREFIX%email_pop3`;
diff --git a/include/upgrader/sql/98ae1ed2-e342f869.patch.sql b/include/upgrader/sql/98ae1ed2-e342f869.patch.sql
new file mode 100644
index 0000000000000000000000000000000000000000..4fc011ce8a01ec56e8dfafa0d4da9a5300335b4c
--- /dev/null
+++ b/include/upgrader/sql/98ae1ed2-e342f869.patch.sql
@@ -0,0 +1,163 @@
+/**
+ * @version v1.6 RC5
+ * @signature e342f869c7a537ab3ee937fb6e21cdd4
+ *
+ *  Upgrade from 1.6 RC1-4 to 1.6 RC5
+ *  
+ */
+
+ALTER TABLE `%TABLE_PREFIX%config`
+    CHANGE `default_priority` `default_priority_id` TINYINT( 2 ) UNSIGNED NOT NULL DEFAULT '2',
+    CHANGE `default_template` `default_template_id` TINYINT( 4 ) UNSIGNED NOT NULL DEFAULT '1',
+    CHANGE `default_email` `default_email_id` TINYINT( 4 ) UNSIGNED NOT NULL DEFAULT '0',
+    CHANGE `default_dept` `default_dept_id` TINYINT( 3 ) UNSIGNED NOT NULL DEFAULT '0',
+    CHANGE `enable_pop3_fetch` `enable_mail_fetch` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0',
+    CHANGE `api_key` `api_passphrase` VARCHAR( 125 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL;
+
+ALTER TABLE `%TABLE_PREFIX%config`
+    ADD `note_alert_active` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `message_alert_dept_manager`,
+    ADD `note_alert_laststaff` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '1' AFTER `note_alert_active`,
+    ADD `note_alert_assigned` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '1' AFTER `note_alert_laststaff`,
+    ADD `note_alert_dept_manager` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `note_alert_assigned`,
+    ADD `alert_email_id` TINYINT( 4 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `overdue_grace_period`,
+    ADD `default_smtp_id` TINYINT( 4 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `default_template_id`,
+    ADD `spoof_default_smtp` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `default_smtp_id`,
+    ADD `log_level` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '2' AFTER `random_ticket_ids`,
+    ADD `staff_max_logins` TINYINT UNSIGNED NOT NULL DEFAULT '4' AFTER `enable_daylight_saving`,
+    ADD `staff_login_timeout` INT UNSIGNED NOT NULL DEFAULT '2' AFTER `staff_max_logins`,
+    ADD `client_max_logins` TINYINT UNSIGNED NOT NULL DEFAULT '4' AFTER `staff_session_timeout`,
+    ADD `client_login_timeout` INT UNSIGNED NOT NULL DEFAULT '2' AFTER `client_max_logins`,
+    ADD `show_answered_tickets` TINYINT( 1 ) NOT NULL DEFAULT '0' AFTER `show_assigned_tickets`,
+    ADD `hide_staff_name` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `show_answered_tickets`,
+    ADD `log_graceperiod` INT UNSIGNED NOT NULL DEFAULT '12' AFTER `log_level`;
+
+ALTER TABLE `%TABLE_PREFIX%email` 
+    ADD `userid` VARCHAR( 125 ) NOT NULL AFTER `name` ,
+    ADD `userpass` VARCHAR( 125 ) NOT NULL AFTER `userid`,
+    ADD `mail_active` TINYINT( 1 ) NOT NULL DEFAULT '0' AFTER `userpass` ,
+    ADD `mail_host` VARCHAR( 125 ) NOT NULL AFTER `mail_active` ,
+    ADD `mail_protocol` ENUM( 'POP', 'IMAP' ) NOT NULL AFTER `mail_host` ,
+    ADD `mail_encryption` ENUM( 'NONE', 'SSL' ) NOT NULL AFTER `mail_protocol` ,
+    ADD `mail_port` INT( 6 ) NULL AFTER `mail_encryption` ,
+    ADD `mail_fetchfreq` TINYINT( 3 ) NOT NULL DEFAULT '5' AFTER `mail_port` ,
+    ADD `mail_fetchmax` TINYINT( 4 ) NOT NULL DEFAULT '30' AFTER `mail_fetchfreq` ,
+    ADD `mail_delete` TINYINT( 1 ) NOT NULL DEFAULT '0' AFTER `mail_fetchmax` ,
+    ADD `mail_errors` TINYINT( 3 ) NOT NULL DEFAULT '0' AFTER `mail_delete` ,
+    ADD `mail_lasterror` DATETIME NULL AFTER `mail_errors` ,
+    ADD `mail_lastfetch` DATETIME NULL AFTER `mail_lasterror` ,
+    ADD `smtp_active` TINYINT( 1 ) NOT NULL AFTER `mail_lastfetch` ,
+    ADD `smtp_host` VARCHAR( 125 ) NOT NULL AFTER `smtp_active` ,
+    ADD `smtp_port` INT( 6 ) NULL AFTER `smtp_host` ,
+    ADD `smtp_auth` TINYINT( 1 ) NOT NULL DEFAULT '1' AFTER `smtp_port` ;
+
+-- Transfer old POP3 settings to "new" email table
+UPDATE `%TABLE_PREFIX%email` as T1 JOIN `%TABLE_PREFIX%email_pop3` as T2 ON(T1.email_id = T2.`email_id`)
+    SET 
+     `updated`=NOW(),
+     `mail_protocol`='POP',
+     `mail_encryption`='NONE',
+     `mail_port`=110,
+     `mail_active`=0,
+     `mail_delete`=T2.`delete_msgs`,
+     `mail_host`=T2.`pophost`,
+     `mail_fetchfreq`=T2.`fetchfreq`,
+     `userid`=T2.`popuser`,
+     `userpass`=T2.`poppasswd`;
+
+-- Transfer alert email configuration
+INSERT INTO `%TABLE_PREFIX%email` (`created`, `updated`, `priority_id`,
+    `dept_id`, `name`, `email`)
+    SELECT NOW(), NOW(), 2, COALESCE(`default_dept_id`, 1), 'osTicket Alerts',
+        `alert_email`
+    FROM `%TABLE_PREFIX%config` WHERE `id`=1;
+
+UPDATE `%TABLE_PREFIX%config` SET `alert_email_id` = last_insert_id()
+    WHERE id=1;
+
+ALTER TABLE `%TABLE_PREFIX%department`
+    ADD `autoresp_email_id` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `email_id`,
+    ADD `tpl_id` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `dept_id`,
+    ADD INDEX ( `tpl_id` ),
+    ADD INDEX ( `autoresp_email_id` ) ;
+
+-- Transfer no-reply email configuration
+INSERT INTO `%TABLE_PREFIX%email` (`created`, `updated`, `priority_id`,
+    `dept_id`, `name`, `email`)
+    SELECT NOW(), NOW(), 2, COALESCE(`default_dept_id`, 1), 'No Reply',
+        `noreply_email`
+    FROM `%TABLE_PREFIX%config` WHERE `id`=1;
+
+UPDATE `%TABLE_PREFIX%department` SET `autoresp_email_id` = last_insert_id()
+    WHERE noreply_autoresp=1;
+
+ALTER TABLE `%TABLE_PREFIX%groups` ADD `can_edit_tickets` TINYINT UNSIGNED NOT NULL DEFAULT '0' AFTER `dept_access` ;
+
+UPDATE `%TABLE_PREFIX%groups`  SET `can_edit_tickets`=1 WHERE `can_delete_tickets`=1;
+
+ALTER TABLE `%TABLE_PREFIX%ticket`
+    ADD `phone_ext` VARCHAR( 8 ) NULL DEFAULT NULL AFTER `phone`,
+    ADD `topic`  VARCHAR(64) NULL DEFAULT NULL AFTER `subject`,
+    ADD `duedate` DATETIME NULL AFTER `isoverdue`,
+    ADD `isanswered` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `isoverdue`,
+    ADD `lastmessage` DATETIME NULL AFTER `closed`,
+    ADD `lastresponse` DATETIME NULL AFTER `lastmessage`,
+    ADD INDEX ( `duedate` ) ;
+
+ALTER TABLE `%TABLE_PREFIX%ticket` 
+    CHANGE `source` `source` ENUM( 'Web', 'Email', 'Phone', 'Other' ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT 'Other' ;
+ 
+ALTER TABLE `%TABLE_PREFIX%email_template` 
+    ADD `note_alert_subj` VARCHAR( 255 ) NOT NULL AFTER `message_alert_body` ,
+    ADD `note_alert_body` TEXT NOT NULL AFTER `note_alert_subj`,
+    ADD `notes` TEXT NULL AFTER `name`;
+
+UPDATE `%TABLE_PREFIX%email_template`  SET  `note_alert_subj` = 'New Internal Note Alert',
+       `note_alert_body` = '%staff,\r\n\r\nInternal note appended to ticket #%ticket\r\n\r\n----------------------\r\nName: %name\r\n\r\n%note\r\n-------------------\r\n\r\nTo view/respond to the ticket, please login to the support ticket system.\r\n\r\nYour friendly,\r\n\r\nCustomer Support System - powered by osTicket.';
+
+-- Update path and variables on email templates
+UPDATE `%TABLE_PREFIX%email_template`
+    SET `ticket_autoresp_body` = REPLACE(`ticket_autoresp_body`, 'view.php', 'ticket.php'),
+        `message_autoresp_body` = REPLACE(`message_autoresp_body`, 'view.php', 'ticket.php'),
+        `ticket_overlimit_body` = REPLACE(`ticket_overlimit_body`, 'view.php', 'ticket.php'),
+        `ticket_reply_body` = REPLACE(
+                REPLACE(`ticket_reply_body`, 'view.php', 'ticket.php'),
+            '%message', '%response');
+
+ALTER TABLE `%TABLE_PREFIX%ticket_message` 
+    ADD `messageId` VARCHAR( 255 ) NULL AFTER `ticket_id`,
+    ADD INDEX ( `messageId` ) ;
+
+ALTER TABLE `%TABLE_PREFIX%ticket_message` ADD FULLTEXT (`message`);
+
+ALTER TABLE `%TABLE_PREFIX%ticket_response` ADD FULLTEXT (`response`);
+
+ALTER TABLE `%TABLE_PREFIX%ticket_note` ADD FULLTEXT (`note`);
+  
+DROP TABLE IF EXISTS `%TABLE_PREFIX%api_key`;
+CREATE TABLE `%TABLE_PREFIX%api_key` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `isactive` tinyint(1) NOT NULL default '1',
+  `ipaddr` varchar(16) NOT NULL,
+  `apikey` varchar(255) NOT NULL,
+  `updated` datetime NOT NULL default '0000-00-00 00:00:00',
+  `created` datetime NOT NULL default '0000-00-00 00:00:00',
+  PRIMARY KEY  (`id`),
+  UNIQUE KEY `ipaddr` (`ipaddr`)
+) ENGINE=MyISAM;
+
+DROP TABLE IF EXISTS `%TABLE_PREFIX%syslog`;
+CREATE TABLE `%TABLE_PREFIX%syslog` (
+  `log_id` int(11) unsigned NOT NULL auto_increment,
+  `log_type` enum('Debug','Warning','Error') NOT NULL,
+  `title` varchar(255) NOT NULL,
+  `log` text NOT NULL,
+  `logger` varchar(64) NOT NULL,
+  `ip_address` varchar(16) NOT NULL,
+  `created` datetime NOT NULL default '0000-00-00 00:00:00',
+  `updated` datetime NOT NULL default '0000-00-00 00:00:00',
+  PRIMARY KEY  (`log_id`),
+  KEY `log_type` (`log_type`)
+) ENGINE=MyISAM;
+
+UPDATE `%TABLE_PREFIX%config`
+    SET `ostversion`='1.6 RC5';
diff --git a/include/upgrader/sql/a67ba35e-98ae1ed2.patch.sql b/include/upgrader/sql/a67ba35e-98ae1ed2.patch.sql
new file mode 100644
index 0000000000000000000000000000000000000000..750eb1e293b7144565016e1ed5e754e0c9ec36b6
--- /dev/null
+++ b/include/upgrader/sql/a67ba35e-98ae1ed2.patch.sql
@@ -0,0 +1,8 @@
+/*
+ * @version=1.6RC1-4
+ * 
+ * Stage RC3 for 1.6RC5 upgrade
+ */
+
+UPDATE `%TABLE_PREFIX%config`
+    SET `ostversion`='1.6 RC1-4';
diff --git a/include/upgrader/sql/aa4664af-b19dc97d.patch.sql b/include/upgrader/sql/aa4664af-b19dc97d.patch.sql
new file mode 100644
index 0000000000000000000000000000000000000000..8b5ce9eb37fd24d4257f7e14ed1f7f4f962e1597
--- /dev/null
+++ b/include/upgrader/sql/aa4664af-b19dc97d.patch.sql
@@ -0,0 +1,23 @@
+/**
+ * Change IP address columns to have sufficient room to store IPv6 address
+ *
+ * @version 1.7-rc1 ipv6-addresses
+ */
+
+ALTER TABLE `%TABLE_PREFIX%api_key`
+    CHANGE `ipaddr` `ipaddr` varchar(64) NOT NULL;
+
+ALTER TABLE `%TABLE_PREFIX%session`
+    CHANGE `user_id` `user_id` int(10) unsigned NOT NULL default '0'
+        COMMENT 'osTicket staff ID',
+    CHANGE `user_ip` `user_ip` varchar(64) NOT NULL;
+
+ALTER TABLE `%TABLE_PREFIX%syslog`
+    CHANGE `ip_address` `ip_address` varchar(64) NOT NULL;
+
+ALTER TABLE `%TABLE_PREFIX%ticket`
+    CHANGE `ip_address` `ip_address` varchar(64) NOT NULL default '';
+
+-- Finished with patch
+UPDATE `%TABLE_PREFIX%config`
+    SET `schema_signature`='b19dc97d19f7a30f59663c812d1f3ddc';
diff --git a/setup/inc/sql/abe9c0cb-bbb021fb.patch.sql b/include/upgrader/sql/abe9c0cb-bbb021fb.patch.sql
similarity index 100%
rename from setup/inc/sql/abe9c0cb-bbb021fb.patch.sql
rename to include/upgrader/sql/abe9c0cb-bbb021fb.patch.sql
diff --git a/include/upgrader/sql/aee589ab-98ae1ed2.patch.sql b/include/upgrader/sql/aee589ab-98ae1ed2.patch.sql
new file mode 100644
index 0000000000000000000000000000000000000000..f786bbb22b34bb33c53c76321be16d558caa3044
--- /dev/null
+++ b/include/upgrader/sql/aee589ab-98ae1ed2.patch.sql
@@ -0,0 +1,8 @@
+/*
+ * @version=1.6RC1-4
+ * 
+ * Stage RC1 for 1.6RC5 upgrade
+ */
+
+UPDATE `%TABLE_PREFIX%config`
+    SET `ostversion`='1.6 RC1-4';
diff --git a/include/upgrader/sql/b19dc97d-435c62c3.patch.sql b/include/upgrader/sql/b19dc97d-435c62c3.patch.sql
new file mode 100644
index 0000000000000000000000000000000000000000..b908348a728445778725b9215eebe432e270e9dc
--- /dev/null
+++ b/include/upgrader/sql/b19dc97d-435c62c3.patch.sql
@@ -0,0 +1,16 @@
+/**
+ * Support canned response definition for email filters
+ *
+ * @version 1.7-rc1 canned-response-in-filter
+ */
+
+ALTER TABLE `%TABLE_PREFIX%email_filter`
+    ADD `canned_response_id` int(11) unsigned NOT NULL default '0'
+        AFTER `disable_autoresponder`;
+
+-- Add index for linking responses to messages quickly
+ALTER TABLE `%TABLE_PREFIX%ticket_thread` ADD KEY `pid` (`pid`);
+
+-- Finished with patch
+UPDATE `%TABLE_PREFIX%config`
+    SET `schema_signature`='435c62c3b23795529bcfae7e7371d82e';
diff --git a/setup/inc/sql/bbb021fb-49478749.patch.sql b/include/upgrader/sql/bbb021fb-49478749.patch.sql
similarity index 100%
rename from setup/inc/sql/bbb021fb-49478749.patch.sql
rename to include/upgrader/sql/bbb021fb-49478749.patch.sql
diff --git a/setup/inc/sql/v1.7-cleanup-mysql.sql b/include/upgrader/sql/c00511c7-7be60a84.cleanup.sql
similarity index 75%
rename from setup/inc/sql/v1.7-cleanup-mysql.sql
rename to include/upgrader/sql/c00511c7-7be60a84.cleanup.sql
index 6464a100101f330cc8b3425adbd27104721ac632..01d69e2d72b732b2d7c3f618fd6e595ccb7c67f7 100644
--- a/setup/inc/sql/v1.7-cleanup-mysql.sql
+++ b/include/upgrader/sql/c00511c7-7be60a84.cleanup.sql
@@ -1,3 +1,9 @@
+-- Drop columns we nolonger need - (must be at the very bottom or after session table is created)
+ALTER TABLE `%TABLE_PREFIX%config`
+    DROP COLUMN `ostversion`,
+    DROP COLUMN `timezone_offset`,
+    DROP COLUMN `api_passphrase`;
+
 -- Drop fields we no longer need in the reference table.
 ALTER TABLE `%TABLE_PREFIX%ticket_attachment`
     DROP `file_size`,
@@ -6,10 +12,6 @@ ALTER TABLE `%TABLE_PREFIX%ticket_attachment`
     DROP `updated`,
     DROP `isdeleted`;
 
--- Drop fields we no longer need in config table.
-ALTER TABLE `%TABLE_PREFIX%config`
-    DROP `api_passphrase`;
-
 -- Drop fields we no longer need in staff table.
 ALTER TABLE `%TABLE_PREFIX%staff`
     DROP `append_signature`,
diff --git a/setup/inc/sql/v1.6st-1.7-upgrade-mysql.sql b/include/upgrader/sql/c00511c7-7be60a84.patch.sql
similarity index 92%
rename from setup/inc/sql/v1.6st-1.7-upgrade-mysql.sql
rename to include/upgrader/sql/c00511c7-7be60a84.patch.sql
index 3a2acf2295170c9b6263b33f05d649c378ed5dbb..638248b976019a670c773578b564d99a3daacc6a 100644
--- a/setup/inc/sql/v1.6st-1.7-upgrade-mysql.sql
+++ b/include/upgrader/sql/c00511c7-7be60a84.patch.sql
@@ -1,3 +1,9 @@
+/**
+ * @version v1.7
+ *
+ * @schema c00511c7c1db65c0cfad04b4842afc57
+ */
+
 -- Add a table to contain the attachment file contents
 DROP TABLE IF EXISTS `%TABLE_PREFIX%file`;
 CREATE TABLE `%TABLE_PREFIX%file` (
@@ -65,8 +71,8 @@ ALTER TABLE `%TABLE_PREFIX%config`
 ALTER TABLE `%TABLE_PREFIX%staff` 
     ADD `passwdreset` DATETIME NULL DEFAULT NULL AFTER `lastlogin`;
 
-DROP TABLE IF EXISTS `%TICKET_PREFIX%sla`;
-CREATE TABLE IF NOT EXISTS `%TICKET_PREFIX%sla` (
+DROP TABLE IF EXISTS `%TABLE_PREFIX%sla`;
+CREATE TABLE IF NOT EXISTS `%TABLE_PREFIX%sla` (
     `id` int(11) unsigned NOT NULL auto_increment,
     `isactive` tinyint(1) unsigned NOT NULL default '1',
     `enable_priority_escalation` tinyint(1) unsigned NOT NULL default '1',
@@ -102,8 +108,16 @@ CREATE TABLE IF NOT EXISTS `%TABLE_PREFIX%team` (
 ) ENGINE=MyISAM;
 
 -- Create a default TEAM
-INSERT INTO `%TABLE_PREFIX%team` (`lead_id`, `isenabled`, `noalerts`, `name`, `notes`)
-    VALUES (0, 1, 0, 'Level I Support', '');
+INSERT INTO `%TABLE_PREFIX%team` (`lead_id`, `isenabled`, `noalerts`, `name`, `notes`, `created`, `updated`)
+    VALUES (0, 1, 0, 'Level I Support', '', NOW(), NOW());
+
+DROP TABLE IF EXISTS `%TABLE_PREFIX%team_member`;
+CREATE TABLE IF NOT EXISTS `%TABLE_PREFIX%team_member` (
+  `team_id` int(10) unsigned NOT NULL default '0',
+  `staff_id` int(10) unsigned NOT NULL,
+  `updated` datetime NOT NULL,
+  PRIMARY KEY  (`team_id`,`staff_id`)
+) ENGINE=MyISAM;
 
 ALTER TABLE `%TABLE_PREFIX%department`
     ADD sla_id INT UNSIGNED NOT NULL DEFAULT '0' AFTER tpl_id;
@@ -120,10 +134,10 @@ UPDATE `%TABLE_PREFIX%staff` SET timezone_id =
     (SELECT id FROM `%TABLE_PREFIX%timezone` WHERE offset = `%TABLE_PREFIX%staff`.timezone_offset);
 
 ALTER TABLE `%TABLE_PREFIX%groups`
-    ADD notes TEXT NULL AFTER can_manage_kb,
     CHANGE `can_manage_kb` `can_manage_premade` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
     ADD `can_manage_faq` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0' AFTER `can_manage_premade`,
-    ADD `can_assign_tickets` TINYINT( 1 ) UNSIGNED NOT NULL default '1' AFTER `can_close_tickets`;
+    ADD `can_assign_tickets` TINYINT( 1 ) UNSIGNED NOT NULL default '1' AFTER `can_close_tickets`,
+    ADD notes TEXT NULL AFTER can_manage_faq;
 
 -- Add new columns to the templates table
 ALTER TABLE `%TABLE_PREFIX%email_template`
@@ -195,7 +209,7 @@ CREATE TABLE `%TABLE_PREFIX%email_filter_rule` (
   `what` enum('name','email','subject','body','header') NOT NULL,
   `how` enum('equal','not_equal','contains','dn_contain') NOT NULL,
   `val` varchar(255) NOT NULL,
-  `isactive` tinytext( 1 ) UNSIGNED NOT NULL DEFAULT '1',
+  `isactive` tinyint( 1 ) UNSIGNED NOT NULL DEFAULT '1',
   `notes` tinytext NOT NULL,
   `created` datetime NOT NULL,
   `updated` datetime NOT NULL,
@@ -205,8 +219,8 @@ CREATE TABLE `%TABLE_PREFIX%email_filter_rule` (
 ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
 
 -- SYSTEM BAN LIST was the first filter created, with ID of '1'
-INSERT INTO `%TABLE_PREFIX%email_filter_rule` (`filter_id`, `what`, `how`, `val`) VALUES
-SELECT 1, 'email', 'equals', email FROM `%TABLE_PREFIX%email_banlist`;
+INSERT INTO `%TABLE_PREFIX%email_filter_rule` (`filter_id`, `what`, `how`, `val`) 
+    SELECT 1, 'email', 'equals', email FROM `%TABLE_PREFIX%email_banlist`;
 
 -- Create table session
 DROP TABLE IF EXISTS `%TABLE_PREFIX%session`;
@@ -259,12 +273,12 @@ CREATE TABLE IF NOT EXISTS `%TABLE_PREFIX%canned_attachment` (
 
 -- Rename kb_premade to canned_response
 ALTER TABLE `%TABLE_PREFIX%kb_premade`
-  ADD `notes` TEXT NOT NULL AFTER `answer`,
   CHANGE `premade_id` `canned_id` int(10) unsigned NOT NULL auto_increment,
   CHANGE `title` `title` VARCHAR( 255 ) NOT NULL DEFAULT '',
-  CHANGE `answer` `response` TEXT NOT NULL.
-  DROP INDEX `title` ,
-  ADD FULLTEXT `resp` (`title` ,`answer`);
+  CHANGE `answer` `response` TEXT NOT NULL,
+  ADD `notes` TEXT NOT NULL AFTER `response`,
+  DROP INDEX `title`,
+  ADD FULLTEXT `resp` (`title` ,`response`);
   
 ALTER TABLE `%TABLE_PREFIX%kb_premade` RENAME TO `%TABLE_PREFIX%canned_response`;
 
@@ -287,3 +301,7 @@ CREATE TABLE IF NOT EXISTS `%TABLE_PREFIX%faq_topic` (
   `topic_id` int(10) unsigned NOT NULL,
   PRIMARY KEY  (`faq_id`,`topic_id`)
 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+
+UPDATE `%TABLE_PREFIX%config`
+    SET `schema_signature`='7be60a8432e44989e782d5914ef784d2'; 
diff --git a/setup/inc/sql/c2d2fabf-aa4664af.patch.sql b/include/upgrader/sql/c2d2fabf-aa4664af.patch.sql
similarity index 100%
rename from setup/inc/sql/c2d2fabf-aa4664af.patch.sql
rename to include/upgrader/sql/c2d2fabf-aa4664af.patch.sql
diff --git a/include/upgrader/sql/e342f869-c00511c7.patch.sql b/include/upgrader/sql/e342f869-c00511c7.patch.sql
new file mode 100644
index 0000000000000000000000000000000000000000..8f393a295b9a055e63c014b4e9b6f31d6d56975d
--- /dev/null
+++ b/include/upgrader/sql/e342f869-c00511c7.patch.sql
@@ -0,0 +1,47 @@
+/**
+ * @version v1.6 ST
+ * @signature c00511c7c1db65c0cfad04b4842afc57
+ *
+ *  Upgrade from 1.6 RC5 to 1.6 ST
+ *  
+ */
+
+ALTER TABLE `%TABLE_PREFIX%ticket` 
+    CHANGE `topic` `helptopic` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
+    ADD `topic_id` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `priority_id`,
+    ADD INDEX ( `topic_id` );
+
+ALTER TABLE `%TABLE_PREFIX%groups` 
+    ADD `can_create_tickets` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '1' AFTER `dept_access`;
+
+ALTER TABLE `%TABLE_PREFIX%staff` 
+    ADD `auto_refresh_rate` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `max_page_size`,
+    CHANGE `signature` `signature` TINYTEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
+
+ALTER TABLE `%TABLE_PREFIX%department`
+    CHANGE `dept_signature` `dept_signature` TINYTEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
+
+ALTER TABLE `%TABLE_PREFIX%config`
+    ADD `ticket_notice_active` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `message_autoresponder`,
+    ADD `enable_captcha` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `use_email_priority`,
+    ADD `log_ticket_activity` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '1' AFTER `strip_quoted_reply`,
+    ADD `staff_ip_binding` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '1' AFTER `enable_daylight_saving`;
+
+
+ALTER TABLE `%TABLE_PREFIX%email_template`
+    ADD `ticket_notice_subj` VARCHAR( 255 ) NOT NULL AFTER `ticket_autoresp_body` ,
+    ADD `ticket_notice_body` TEXT NOT NULL AFTER `ticket_notice_subj`;
+
+UPDATE `%TABLE_PREFIX%email_template` SET updated=NOW(),
+    `ticket_notice_subj` = '[#%ticket] %subject',
+    `ticket_notice_body` = '%name,\r\n\r\nOur customer care team personnel has created a ticket #%ticket on your behalf, with the following message:\r\n\r\n%message\r\n\r\nIf you wish to provide additional comments or information regarding this issue, please don''t open a new ticket. You can update or view this ticket''s progress online here: %url/view.php?e=%email&t=%ticket.\r\n\r\n%signature';
+
+UPDATE `%TABLE_PREFIX%email_template`
+    SET `ticket_overlimit_subj` = REPLACE(`ticket_overlimit_subj`, '%id', '%ticket'),
+        `ticket_overlimit_body` = REPLACE(`ticket_overlimit_body`, '%id', '%ticket');
+
+INSERT INTO `%TABLE_PREFIX%kb_premade` (`premade_id`, `dept_id`, `isenabled`, `title`, `answer`, `created`, `updated`) 
+    VALUES ('', 0, 1, 'Sample (with variables)', '\r\n%name,\r\n\r\nYour ticket #%ticket created on %createdate is in %dept department.\r\n\r\n', NOW(), NOW());
+
+UPDATE `%TABLE_PREFIX%config`
+    SET `ostversion`='1.6 ST';
diff --git a/setup/inc/sql/f8856d56-abe9c0cb.patch.sql b/include/upgrader/sql/f8856d56-abe9c0cb.patch.sql
similarity index 85%
rename from setup/inc/sql/f8856d56-abe9c0cb.patch.sql
rename to include/upgrader/sql/f8856d56-abe9c0cb.patch.sql
index a5f54aa8516aaaaf268e363b8ae58674725b61af..c0e5dd298482de89fda33bb04edf011d478f0b4d 100644
--- a/setup/inc/sql/f8856d56-abe9c0cb.patch.sql
+++ b/include/upgrader/sql/f8856d56-abe9c0cb.patch.sql
@@ -23,12 +23,13 @@ CREATE TABLE `%TABLE_PREFIX%ticket_thread` (
   `ip_address` varchar(64) NOT NULL default '',
   `created` datetime NOT NULL,
   `updated` datetime NOT NULL,
-  -- Temporary columns for conversion
   `old_pk` int(11) unsigned NOT NULL,
   `old_pid` int(11) unsigned,
   PRIMARY KEY  (`id`),
   KEY `ticket_id` (`ticket_id`),
   KEY `staff_id` (`staff_id`),
+  KEY `old_pk` (`old_pk`),
+  KEY `created` (`created`),
   FULLTEXT KEY `body` (`body`)
 ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
 
@@ -58,7 +59,12 @@ INSERT INTO `%TABLE_PREFIX%ticket_thread`
 
 -- Connect responses to (new) messages
 CREATE TABLE `%TABLE_PREFIX%T_resp_links`
-    SELECT `id`, `old_pk`, `old_pid` FROM `%TABLE_PREFIX%ticket_thread`;
+    SELECT `id`, `old_pk`
+      FROM `%TABLE_PREFIX%ticket_thread`
+     WHERE `thread_type` = 'M';
+
+-- Add an index to speed up the linking process
+ALTER TABLE `%TABLE_PREFIX%T_resp_links` ADD KEY `old_pk` (`old_pk`, `id`);
 
 UPDATE `%TABLE_PREFIX%ticket_thread`
     SET `pid` = ( SELECT T2.`id` FROM `%TABLE_PREFIX%T_resp_links` T2
@@ -70,14 +76,13 @@ DROP TABLE `%TABLE_PREFIX%T_resp_links`;
 
 -- Transfer notes
 INSERT INTO `%TABLE_PREFIX%ticket_thread`
-  (`ticket_id`, `staff_id`, `thread_type`, `body`, `title`,
-    `source`, `poster`, `created`, `updated`, `old_pk`)
-  SELECT `ticket_id`, `staff_id`, 'N', `note`, `title`,
-    `source`, ( SELECT CONCAT_WS(' ', T2.`firstname`, T2.`lastname`)
-                FROM `%TABLE_PREFIX%staff` T2
-                WHERE T2.`staff_id` = `staff_id` ),
-    `created`, NOW(), `note_id`
-    FROM `%TABLE_PREFIX%ticket_note`;
+ (`ticket_id`, `staff_id`, `thread_type`, `body`, `title`,
+   `source`, `poster`, `created`, `updated`, `old_pk`)
+ SELECT `ticket_id`, N.staff_id, 'N', `note`, `title`,
+   `source`, CONCAT_WS(' ', S.`firstname`, S.`lastname`),
+   N.created, NOW(), `note_id`
+   FROM `%TABLE_PREFIX%ticket_note` N
+   LEFT JOIN `%TABLE_PREFIX%staff` S ON(S.staff_id=N.staff_id);
 
 -- Transfer email information from messages
 INSERT INTO `%TABLE_PREFIX%ticket_email_info`
diff --git a/setup/inc/upgrade.inc.php b/include/upgrader/upgrade.inc.php
similarity index 79%
rename from setup/inc/upgrade.inc.php
rename to include/upgrader/upgrade.inc.php
index 6f05cd169c66d49163908d8a6c6bef9d5b9a1a18..7c8a8aae47e692d9337a51c46a46f2114c4a2848 100644
--- a/setup/inc/upgrade.inc.php
+++ b/include/upgrader/upgrade.inc.php
@@ -1,14 +1,13 @@
 <?php
-if(!defined('SETUPINC') || !$upgrader)  die('Kwaheri!');
+if(!defined('OSTSCPINC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
 $action=$upgrader->getNextAction();
-
 ?>
+<h2>osTicket Upgrade</h2>
+<div id="upgrader">
     <div id="main">
-            <h1>osTicket Upgrade</h1>
             <div id="intro">
              <p>Thank you for taking the time to upgrade your osTicket intallation!</p>
-             <p>Please don't cancel or close the browser, any errors at this
-              stage will be fatal.</p>
+             <p>Please don't cancel or close the browser, any errors at this stage will be fatal.</p>
             </div>
             <h2><?php echo $action ?></h2>
             <p>The upgrade wizard will now attempt to upgrade your database and core settings!</p>
@@ -19,6 +18,7 @@ $action=$upgrader->getNextAction();
             </ul>
             <div id="bar">
                 <form method="post" action="upgrade.php" id="upgrade">
+                    <?php csrf_token(); ?>
                     <input type="hidden" name="s" value="upgrade">
                     <input type="hidden" name="sh" value="<?php echo $upgrader->getSchemaSignature(); ?>">
                     <input class="btn"  type="submit" name="submit" value="Do It Now!">
@@ -27,14 +27,15 @@ $action=$upgrader->getNextAction();
     </div>
     <div id="sidebar">
             <h3>Upgrade Tips</h3>
-            <p>1. Be patient the process will take a couple of seconds.</p>
-            <p>2. If you experience any problems, you can always restore your files/dabase backup.</p>
+            <p>1. Be patient the process will take a couple of minutes.</p>
+            <p>2. If you experience any problems, you can always restore your files/database backup.</p>
             <p>3. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p>
     </div>
-
-    <div id="overlay"></div>
+    <div class="clear"></div>
     <div id="loading">
         <h4><?php echo $action; ?></h4>
         Please wait... while we upgrade your osTicket installation!
         <div id="msg" style="font-weight: bold;padding-top:10px;">Smile!</div>
     </div>
+</div>
+<div class="clear"></div>`
diff --git a/js/jquery.multifile.js b/js/jquery.multifile.js
new file mode 100644
index 0000000000000000000000000000000000000000..3ae6835d2f233f71073709e25560163d7550f733
--- /dev/null
+++ b/js/jquery.multifile.js
@@ -0,0 +1,178 @@
+/*********************************************************************
+    jquery.multifile.js
+
+    Multifile plugin that allows users to upload multiple files at once in unobstructive manner - cleaner interface.
+
+    Allows limiting number of files and file type(s) using file extension.
+
+    NOTE:
+    * Files are not uploaded until the form is submitted
+    * Server side file type validation is a MUST
+    * Plugin doesn't take into account PHP related limitations e.g max uploads + max size.
+
+    Peter Rotich <peter@osticket.com>
+    Copyright (c) 2006-2012 osTicket
+    http://www.osticket.com
+
+    Credits:
+    The plugin borrows heavily from a plugin by Rocky Meza @ fusionbox
+    https://github.com/fusionbox/jquery-multifile
+
+    vim: expandtab sw=4 ts=4 sts=4:
+**********************************************************************/
+
+;(function($, global, undefined) {
+        
+    $.fn.multifile = function(options) {
+        var container = null;
+        var options = $.extend({}, $.fn.multifile.defaults, options);
+
+        options.allowedFileTypes = $.map(options.file_types.toLowerCase().split(','), $.trim);
+        options.inputTemplate = options.inputTemplate || $.fn.multifile.inputTemplate;
+
+        container = options.container || null;
+
+
+        return this.each(function() {
+
+            var settings = options;
+            var $container
+                
+            , addInput = function(event) {
+            
+                var $this = $(this)
+                , fObj = $(this).closest('form')
+                , new_input = $.fn.multifile.cloneInput($this)
+                , file = $.fn.multifile.getFileObject(this);
+
+                if(fObj.data('files') == undefined)
+                    fObj.data('files', 0);
+
+                if(fObj.data('files')>=settings.max_uploads || (fObj.data('files')+file.count)>settings.max_uploads) {
+                    alert('You have reached the maximum number of files ('+ settings.max_uploads+') allowed per upload');
+                } else if($.fn.multifile.checkFileTypes(file, settings.allowedFileTypes)) {
+                    $this.hide();
+                    
+                    settings
+                    .inputTemplate(file)
+                    .appendTo($container)
+                    .on('click', 'input',  bindRemoveInput($this, file));
+
+                    fObj.data('files', fObj.data('files')+file.count);
+                    if(fObj.data('files')<settings.max_uploads)
+                        $this.after(new_input);
+
+                } else {
+                    var msg = 'Selected file type is NOT allowed';
+                    if(file.count>1)
+                        msg = 'File type of one or more of the selected files is NOT allowed';
+
+                    alert('Error: '+msg);
+                    
+                    $this.replaceWith(new_input);
+                }
+        
+            }
+      
+            , bindRemoveInput = function($input, file) {
+
+                return function(event) {
+
+                    event.preventDefault();
+           
+                    if(confirm('Are you sure you want to remove '+file.name+'?')) {
+                        var fObj = $(this).closest('form');
+
+                        fObj.data('files', fObj.data('files')-file.count);
+                        if(fObj.data('files')<settings.max_uploads && (fObj.data('files')+file.count)>=settings.max_uploads)
+                            $input.after($.fn.multifile.cloneInput($input).show());
+                        
+                        $input.remove();
+                        $(this).parent().remove();
+                    }
+
+                    return false;
+                };
+        
+            };
+    
+            if ( container ) {
+                if ( typeof container == 'string' ) 
+                    $container = $(container, $(this).closest('form'));
+                else
+                    $container = container;
+            } else {
+                $container = $('<div class="uploads" />');
+                $(this).after($container);
+            }
+
+            $(this).bind('change.multifile', addInput);
+  
+        });
+  };
+
+  $.fn.multifile.inputTemplate = function(file) {
+    return $('<label style="padding-right:5px;"><input type="checkbox" name="uploads[]" value="' + file.name + '" checked="checked"> ' + file.name + '</label>');
+  };
+
+  $.fn.multifile.checkFileTypes = function(file, allowedFileTypes) {
+     
+      //Wildcard.
+      if(allowedFileTypes[0]=='.*')
+          return true;
+
+      var filenames = $.map(file.name.toLowerCase().split(','), $.trim);
+      for (var i = 0, _len = filenames.length; i < _len; i++)
+          if(filenames[i] && $.inArray('.'+filenames[i].split('.').pop(), allowedFileTypes) == -1)
+              return false;
+
+      return true;
+  };
+
+  //Clone file input and clear the value without triggering a warning!
+  $.fn.multifile.cloneInput = function(input) {
+
+      var $clone = input.clone(true);
+                      
+      if ($.browser.msie) {
+          $clone.replaceWith(function () { return $(this).clone(true); });
+      } else {
+          $clone.val('');
+      }
+
+      return $clone;
+  }
+
+  //Get file object 
+  $.fn.multifile.getFileObject = function(input) {
+    var file = {};
+
+    file.count = 1; 
+    // check for HTML5 FileList support
+    if ( !!global.FileList ) {
+      if ( input.files.length == 1 )
+        file.name = input.files[0].name;
+      else { //Multi-select
+        // We do this in order to support `multiple` files.
+        // You can't display them separately because they 
+        // belong to only one file input.  It is impossible
+        // to remove just one of the files.
+        file.name = input.files[0].name;
+        for (var i = 1, _len = input.files.length; i < _len; i++)
+          file.name += ', ' + input.files[i].name;
+
+        file.count = i;
+      }
+    } else {
+      file.name = input.value;
+    }
+
+    return file;
+  };
+
+  //Default options 
+  $.fn.multifile.defaults = { 
+                              max_uploads: 1,
+                              file_types: '.*'
+                            };
+})(jQuery, this);
diff --git a/js/osticket.js b/js/osticket.js
index a809e6f2f794a0534096c69b2a210428424d703d..4057b04b84a25e0cc7d2e249e17cac5efaa5c9e5 100644
--- a/js/osticket.js
+++ b/js/osticket.js
@@ -1 +1,55 @@
-//Nothing for now...
+/* 
+   osticket.js
+   Copyright (c) osTicket.com
+ */
+
+$(document).ready(function(){
+
+    $("input:not(.dp):visible:enabled:first").focus();
+    $('table.list tbody tr:odd').addClass('odd');
+
+    $("form#save :input").change(function() {
+        var fObj = $(this).closest('form');
+        if(!fObj.data('changed')){
+            fObj.data('changed', true);
+            $('input[type=submit]', fObj).css('color', 'red');
+            $(window).bind('beforeunload', function(e) {
+                return 'Are you sure you want to leave? Any changes or info you\'ve entered will be discarded!';
+             });
+        }
+       });
+
+    $("form#save :input[type=reset]").click(function() {
+        var fObj = $(this).closest('form');
+        if(fObj.data('changed')){
+            $('input[type=submit]', fObj).removeAttr('style');
+            $('label', fObj).removeAttr('style');
+            $('label', fObj).removeClass('strike');
+            fObj.data('changed', false);
+            $(window).unbind('beforeunload');
+        }
+       });
+
+    $('form#save').submit(function() {
+        $(window).unbind('beforeunload');
+        return true;
+       });
+
+    /* Get config settings from the backend */
+    var $config = null;
+    $.ajax({
+        url: "ajax.php/config/client",
+        dataType: 'json',
+        async: false,
+        success: function (config) {
+            $config = config;
+            }
+        });
+     
+    /* Multifile uploads */
+     $('.multifile').multifile({
+        container:   '.uploads',
+        max_uploads: ($config && $config.max_file_uploads)?$config.max_file_uploads:1,
+        file_types:  ($config && $config.file_types)?$config.file_types:".*"
+       });
+});
diff --git a/main.inc.php b/main.inc.php
index 3660625d6b1280b9e7b2ab7b836cbf8ce5f23399..6fd31bbbd8f7a72cf4fd6997d6172bd2ab20fbc6 100644
--- a/main.inc.php
+++ b/main.inc.php
@@ -33,7 +33,7 @@
     #Disable session ids on url.
     ini_set('session.use_trans_sid', 0);
     #No cache
-    ini_set('session.cache_limiter', 'nocache');
+    session_cache_limiter('nocache');
     #Cookies
     //ini_set('session.cookie_path','/osticket/');
 
@@ -55,20 +55,26 @@
     define('INCLUDE_DIR',ROOT_DIR.'include/'); //Change this if include is moved outside the web path.
     define('PEAR_DIR',INCLUDE_DIR.'pear/');
     define('SETUP_DIR',INCLUDE_DIR.'setup/');
-  
+
+    define('UPGRADE_DIR', INCLUDE_DIR.'upgrader/');
+    define('SQL_DIR', UPGRADE_DIR.'sql/');
+
     /*############## Do NOT monkey with anything else beyond this point UNLESS you really know what you are doing ##############*/
 
     #Current version && schema signature (Changes from version to version)
-    define('THIS_VERSION','1.7-DPR4'); //Shown on admin panel
-    define('SCHEMA_SIGNATURE','aa4664afc3b43d4068eb2e82684fc28e'); //MD5 signature of the db schema. (used to trigger upgrades)
+    define('THIS_VERSION','1.7-RC1'); //Shown on admin panel
+    define('SCHEMA_SIGNATURE','2e7531a201b5b8650dcd43681a832ebd'); //MD5 signature of the db schema. (used to trigger upgrades)
 
     #load config info
     $configfile='';
     if(file_exists(ROOT_DIR.'ostconfig.php')) //Old installs prior to v 1.6 RC5
         $configfile=ROOT_DIR.'ostconfig.php';
-    elseif(file_exists(INCLUDE_DIR.'settings.php')) //OLD config file.. v 1.6 RC5
+    elseif(file_exists(INCLUDE_DIR.'settings.php')) { //OLD config file.. v 1.6 RC5
         $configfile=INCLUDE_DIR.'settings.php';
-    elseif(file_exists(INCLUDE_DIR.'ost-config.php')) //NEW config file v 1.6 stable ++
+        //Die gracefully on upgraded v1.6 RC5 installation - otherwise script dies with confusing message. 
+        if(!strcasecmp(basename($_SERVER['SCRIPT_NAME']), 'settings.php'))
+            die('Please rename config file include/settings.php to include/ost-config.php to continue!');
+    } elseif(file_exists(INCLUDE_DIR.'ost-config.php')) //NEW config file v 1.6 stable ++
         $configfile=INCLUDE_DIR.'ost-config.php';
     elseif(file_exists(ROOT_DIR.'setup/'))
         header('Location: '.ROOT_PATH.'setup/');
@@ -98,10 +104,12 @@
     require(INCLUDE_DIR.'class.log.php');
     require(INCLUDE_DIR.'class.mcrypt.php');
     require(INCLUDE_DIR.'class.misc.php');
+    require(INCLUDE_DIR.'class.timezone.php');
     require(INCLUDE_DIR.'class.http.php');
     require(INCLUDE_DIR.'class.nav.php');
     require(INCLUDE_DIR.'class.format.php'); //format helpers
     require(INCLUDE_DIR.'class.validator.php'); //Class to help with basic form input validation...please help improve it.
+    require(INCLUDE_DIR.'class.mailer.php');
     require(INCLUDE_DIR.'mysql.php');
 
     #CURRENT EXECUTING SCRIPT.
@@ -129,6 +137,7 @@
     define('DEPT_TABLE',TABLE_PREFIX.'department');
     define('TOPIC_TABLE',TABLE_PREFIX.'help_topic');
     define('GROUP_TABLE',TABLE_PREFIX.'groups');
+    define('GROUP_DEPT_TABLE', TABLE_PREFIX.'group_dept_access');
     define('TEAM_TABLE',TABLE_PREFIX.'team');
     define('TEAM_MEMBER_TABLE',TABLE_PREFIX.'team_member');
 
@@ -170,7 +179,7 @@
     if($ferror) { //Fatal error
         //try alerting admin using email in config file
         $msg=$ferror."\n\n".THISPAGE;
-        Email::sendmail(ADMIN_EMAIL, 'osTicket Fatal Error', $msg, sprintf('"osTicket Alerts"<%s>', ADMIN_EMAIL));
+        Mailer::sendmail(ADMIN_EMAIL, 'osTicket Fatal Error', $msg, sprintf('"osTicket Alerts"<%s>', ADMIN_EMAIL));
         //Display generic error to the user
         die("<b>Fatal Error:</b> Contact system administrator.");
         exit;
diff --git a/offline.php b/offline.php
index 24f8401a14c9710de2f9bf7af3a13985a47a099d..8c09a20010c4e6348e625ff7688ecab912bb0824 100644
--- a/offline.php
+++ b/offline.php
@@ -14,7 +14,7 @@
     vim: expandtab sw=4 ts=4 sts=4:
 **********************************************************************/
 require_once('client.inc.php');
-if($cfg && !$cfg->isHelpDeskOffline()) { 
+if(is_object($ost) && $ost->isSystemOnline()) {
     @header('Location: index.php'); //Redirect if the system is online.
     include('index.php');
     exit;
diff --git a/open.php b/open.php
index 11d3a0a9d3397d64941886169a5fa2892ea663a1..a7f064fb9ca58d26f4827b0abb8537df8ef4c3b2 100644
--- a/open.php
+++ b/open.php
@@ -22,7 +22,7 @@ if($_POST):
     if($thisclient) {
         $_POST['name']=$thisclient->getName();
         $_POST['email']=$thisclient->getEmail();
-    } elseif($cfg->enableCaptcha()) {
+    } elseif($cfg->isCaptchaEnabled()) {
         if(!$_POST['captcha'])
             $errors['captcha']='Enter text shown on the image';
         elseif(strcmp($_SESSION['captcha'],md5($_POST['captcha'])))
@@ -32,6 +32,14 @@ if($_POST):
     //Ticket::create...checks for errors..
     if(($ticket=Ticket::create($_POST,$errors,SOURCE))){
         $msg='Support ticket request created';
+        //Upload attachments...         
+        if($cfg->allowOnlineAttachments()
+                && $_FILES['attachments']
+                && ($files=Format::files($_FILES['attachments']))) {
+            $ost->validateFileUploads($files); //Validator sets errors - if any.
+            $ticket->uploadAttachments($files, $ticket->getLastMsgId(), 'M');
+        }
+
         //Logged in...simply view the newly created ticket.
         if($thisclient && $thisclient->isValid()) {
             if(!$cfg->showRelatedTickets())
diff --git a/scp/admin.inc.php b/scp/admin.inc.php
index 89e234e2f13e14204701348fa2222ae195930ea2..28db6fab7ba04c5100a26e6dadc615deb121b7be 100644
--- a/scp/admin.inc.php
+++ b/scp/admin.inc.php
@@ -20,19 +20,34 @@ if(!$ost or !$thisstaff or !$thisstaff->isAdmin()){
     require('index.php'); // just in case!
     exit;
 }
+//Define some constants.
+define('OSTADMININC',TRUE); //checked by admin include files
+define('ADMINPAGE',TRUE);   //Used by the header to swap menus.
 
 //Some security related warnings - bitch until fixed!!! :)
 if($ost->isUpgradePending()) {
-    $errors['err']=$sysnotice='System upgrade is pending <a href="../setup/upgrade.php">Upgrade Now</a>';
+    $errors['err']=$sysnotice='System upgrade is pending <a href="upgrade.php">Upgrade Now</a>';
+    if(!in_array(basename($_SERVER['SCRIPT_NAME']), array('upgrade.php', 'logs.php'))) {
+        header('Location: upgrade.php');
+        require('upgrade.php');
+        exit;
+    }
 } else {
     
-    if(file_exists('../setup/')) {
+    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. 
+        if(!strcasecmp(basename($_SERVER['SCRIPT_NAME']), 'settings.php'))
+            die($sysnotice);
+
+    } elseif(file_exists('../setup/')) {
         $sysnotice='Please take a minute to delete <strong>setup/install</strong> directory (../setup/) for security reasons.';
     } elseif(CONFIG_FILE && file_exists(CONFIG_FILE) && is_writable(CONFIG_FILE)) {
             //Confirm for real that the file is writable by group or world.
             clearstatcache(); //clear the cache!
             $perms = @fileperms(CONFIG_FILE);
-            if(($perms & 0x0002) || ($perms & 0x0010)) { 
+            if(($perms & 0x0002) || ($perms & 0x0010)) {
                 $sysnotice=sprintf('Please change permission of config file (%s) to remove write access. e.g <i>chmod 644 %s</i>',
                                 basename(CONFIG_FILE), basename(CONFIG_FILE));
             }
@@ -42,9 +57,6 @@ if($ost->isUpgradePending()) {
         $sysnotice='Please consider turning off register globals if possible';
 }
 
-//Define some constants.
-define('OSTADMININC',TRUE); //checked by admin include files
-define('ADMINPAGE',TRUE);   //Used by the header to swap menus.
 //Admin navigation - overwrites what was set in staff.inc.php
 $nav = new AdminNav($thisstaff);
 ?>
diff --git a/scp/admin.php b/scp/admin.php
index d84edfed805878660e72fa9712270168bc6a6107..ffe48ee59a99816ec27ceba32e8956cc375bd456 100644
--- a/scp/admin.php
+++ b/scp/admin.php
@@ -1,4 +1,4 @@
 <?php
-header('Location: syslogs.php');
-require('syslogs.php');
+header('Location: settings.php');
+require('./settings.php');
 ?>
diff --git a/scp/ajax.php b/scp/ajax.php
index 2310fc67ae9102ab1df3865b45c816ae26595cb0..259413dab83034c23c52ca5e6017bf9b5d9b9719 100644
--- a/scp/ajax.php
+++ b/scp/ajax.php
@@ -28,7 +28,7 @@ ini_set('display_errors','0'); //Disable error display
 ini_set('display_startup_errors','0');
 
 //TODO: disable direct access via the browser? i,e All request must have REFER? 
-if(!defined('INCLUDE_DIR'))	Http::response(500,'config error');
+if(!defined('INCLUDE_DIR'))	Http::response(500, 'Server configuration error');
 
 require_once INCLUDE_DIR.'/class.dispatcher.php';
 require_once INCLUDE_DIR.'/class.ajax.php';
@@ -43,7 +43,7 @@ $dispatcher = patterns('',
         url_get('^ticket_variables', 'ticket_variables')
     )),
     url('^/config/', patterns('ajax.config.php:ConfigAjaxAPI',
-        url_get('^ui', 'scp_ui')
+        url_get('^scp', 'scp')
     )),
     url('^/report/overview/', patterns('ajax.reports.php:OverviewReportAjaxAPI',
         # Send
@@ -52,21 +52,16 @@ $dispatcher = patterns('',
         url_get('^table/export$', 'downloadTabularData'),
         url_get('^table$', 'getTabularData')
     )),
-    url('^/report/overview/', patterns('ajax.reports.php:OverviewReportAjaxAPI',
-        # Send
-        url_get('^graph$', 'getPlotData'),
-        url_get('^table/groups$', 'enumTabularGroups'),
-        url_get('^table$', 'getTabularData')
-    )),
     url_get('^/users$', array('ajax.users.php:UsersAjaxAPI', 'search')),
     url('^/tickets/', patterns('ajax.tickets.php:TicketsAjaxAPI',
         url_get('^(?P<tid>\d+)/preview', 'previewTicket'),
-        url_get('^(?P<tid>\d+)/lock', 'acquireLock'),
+        url_post('^(?P<tid>\d+)/lock', 'acquireLock'),
         url_post('^(?P<tid>\d+)/lock/(?P<id>\d+)/renew', 'renewLock'),
         url_post('^(?P<tid>\d+)/lock/(?P<id>\d+)/release', 'releaseLock'),
         url_get('^lookup', 'lookup'),
         url_get('^search', 'search')
-    ))
+    )),
+    url_post('^/upgrader', array('ajax.upgrader.php:UpgraderAjaxAPI', 'upgrade'))
 );
 
 # Call the respective function
diff --git a/scp/apikeys.php b/scp/apikeys.php
index ece24444537c8243a91779e59704314a672efe65..e393a31c5f2bea0647a238240ba5e9021ad3c9ab 100644
--- a/scp/apikeys.php
+++ b/scp/apikeys.php
@@ -45,7 +45,8 @@ if($_POST){
             }else{
                 $count=count($_POST['ids']);
                 if($_POST['enable']){
-                    $sql='UPDATE '.API_KEY_TABLE.' SET isactive=1 WHERE id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.API_KEY_TABLE.' SET isactive=1 WHERE id IN ('.
+                        implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())){
                         if($num==$count)
                             $msg='Selected API keys enabled';
@@ -55,7 +56,8 @@ if($_POST){
                         $errors['err']='Unable to enable selected API keys.';
                     }
                 }elseif($_POST['disable']){
-                    $sql='UPDATE '.API_KEY_TABLE.' SET isactive=0  WHERE id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.API_KEY_TABLE.' SET isactive=0  WHERE id IN ('.
+                        implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())) {
                         if($num==$count)
                             $msg='Selected API keys disabled';
diff --git a/scp/autocron.php b/scp/autocron.php
index 366351c9defedffd2bccd478b1d3c8bd2e349ba4..08b65ba3481e65f99e6bb06567c3be46efb60631 100644
--- a/scp/autocron.php
+++ b/scp/autocron.php
@@ -19,10 +19,10 @@ ignore_user_abort(1);//Leave me a lone bro!
 @set_time_limit(0); //useless when safe_mode is on
 $data=sprintf ("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%",
         71,73,70,56,57,97,1,0,1,0,128,255,0,192,192,192,0,0,0,33,249,4,1,0,0,0,0,44,0,0,0,0,1,0,1,0,0,2,2,68,1,0,59);
-$datasize=strlen($data);
+
 header('Content-type:  image/gif');
 header('Cache-Control: no-cache, must-revalidate');
-header("Content-Length: $datasize");
+header('Content-Length: '.strlen($data));
 header('Connection: Close');
 print $data;
 
@@ -32,10 +32,10 @@ ob_start(); //Keep the image output clean. Hide our dirt.
 $sec=time()-$_SESSION['lastcroncall'];
 if($sec>180): //user can call cron once every 3 minutes.
 require_once(INCLUDE_DIR.'class.cron.php');    
-Cron::TicketMonitor(); //Age tickets: We're going to age tickets ever regardless of cron settings. 
-if($cfg && $cfg->enableAutoCron()){ //ONLY fetch tickets if autocron is enabled!
+Cron::TicketMonitor(); //Age tickets: We're going to age tickets regardless of cron settings. 
+if($cfg && $cfg->isAutoCronEnabled()) { //ONLY fetch tickets if autocron is enabled!
     Cron::MailFetcher();  //Fetch mail.
-    $ost->logDebug('Autocron', 'Cron job executed ['.$thisstaff->getUserName().']');
+    $ost->logDebug('Auto Cron', 'Mail fetcher cron call ['.$thisstaff->getUserName().']');
 } 
 
 $_SESSION['lastcroncall']=time();
diff --git a/scp/banlist.php b/scp/banlist.php
index b56d05c6d07b28b2536127abe9a5b3be6330cb69..081fde9b4ed0cd18713cab78e795c2e0eaf1df1b 100644
--- a/scp/banlist.php
+++ b/scp/banlist.php
@@ -68,8 +68,10 @@ if($_POST && !$errors && $filter){
             }else{
                 $count=count($_POST['ids']);
                 if($_POST['enable']){
-                    $sql='UPDATE '.EMAIL_FILTER_RULE_TABLE.' SET isactive=1 WHERE filter_id='.db_input($filter->getId()).
-                         ' AND id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.EMAIL_FILTER_RULE_TABLE.' SET isactive=1 WHERE filter_id='.
+                            db_input($filter->getId()).
+                         ' AND id IN ('.
+                            implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())){
                         if($num==$count)
                             $msg='Selected emails ban status set to enabled';
@@ -79,8 +81,10 @@ if($_POST && !$errors && $filter){
                         $errors['err']='Unable to enable selected emails';
                     }
                 }elseif($_POST['disable']){
-                    $sql='UPDATE '.EMAIL_FILTER_RULE_TABLE.' SET isactive=0  WHERE filter_id='.db_input($filter->getId()).
-                         ' AND id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.EMAIL_FILTER_RULE_TABLE.' SET isactive=0 WHERE filter_id='.
+                            db_input($filter->getId()).
+                         ' AND id IN ('.
+                            implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())) {
                         if($num==$count)
                             $msg='Selected emails ban status set to disabled';
diff --git a/scp/canned.php b/scp/canned.php
index cb6da802e404396d561ba306eb4972da3ec2249a..2a2252233627510e35f0f12da6f9c916751c8143 100644
--- a/scp/canned.php
+++ b/scp/canned.php
@@ -71,7 +71,8 @@ if($_POST && $thisstaff->canManageCannedResponses()) {
             } else {
                 $count=count($_POST['ids']);
                 if($_POST['enable']) {
-                    $sql='UPDATE '.CANNED_TABLE.' SET isenabled=1 WHERE canned_id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.CANNED_TABLE.' SET isenabled=1 WHERE canned_id IN ('.
+                        implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())) {
                         if($num==$count)
                             $msg='Selected canned replies enabled';
@@ -81,7 +82,8 @@ if($_POST && $thisstaff->canManageCannedResponses()) {
                         $errors['err']='Unable to enable selected canned replies.';
                     }
                 } elseif($_POST['disable']) {
-                    $sql='UPDATE '.CANNED_TABLE.' SET isenabled=0  WHERE canned_id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.CANNED_TABLE.' SET isenabled=0 WHERE canned_id IN ('.
+                        implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())) {
                         if($num==$count)
                             $msg='Selected canned replies disabled';
diff --git a/scp/categories.php b/scp/categories.php
index 787b81b5f2bb50d4aa63cdb7a15b8f3adf52af27..6b645fc847737e335feb0c474d868b819f8c7c2d 100644
--- a/scp/categories.php
+++ b/scp/categories.php
@@ -52,7 +52,8 @@ if($_POST){
             } else {
                 $count=count($_POST['ids']);
                 if($_POST['public']) {
-                    $sql='UPDATE '.FAQ_CATEGORY_TABLE.' SET ispublic=1 WHERE category_id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.FAQ_CATEGORY_TABLE.' SET ispublic=1 WHERE category_id IN ('.
+                        implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())) {
                         if($num==$count)
                             $msg='Selected categories made PUBLIC';
@@ -62,7 +63,8 @@ if($_POST){
                         $errors['err']='Unable to enable selected categories public.';
                     }
                 } elseif($_POST['private']) {
-                    $sql='UPDATE '.FAQ_CATEGORY_TABLE.' SET ispublic=0  WHERE category_id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.FAQ_CATEGORY_TABLE.' SET ispublic=0 WHERE category_id IN ('.
+                        implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())) {
                         if($num==$count)
                             $msg='Selected categories made PRIVATE';
diff --git a/scp/css/bootstrap.css b/scp/css/bootstrap.css
index 27de4b50704514f22930e034d004b27a707c35ea..596bdd56453bc4187ae7e1368c80d7f9918fb652 100644
--- a/scp/css/bootstrap.css
+++ b/scp/css/bootstrap.css
@@ -7,136 +7,17 @@
  *
  * Designed and built with all the love in the world @twitter by @mdo and @fat.
  */
-
-article,
-aside,
-details,
-figcaption,
-figure,
-footer,
-header,
-hgroup,
-nav,
-section {
-  display: block;
-}
-
-audio,
-canvas,
-video {
-  display: inline-block;
-  *display: inline;
-  *zoom: 1;
-}
-
-audio:not([controls]) {
-  display: none;
-}
-
-html {
-  font-size: 100%;
-  -webkit-text-size-adjust: 100%;
-      -ms-text-size-adjust: 100%;
-}
-
-a:focus {
-  outline: thin dotted #333;
-  outline: 5px auto -webkit-focus-ring-color;
-  outline-offset: -2px;
-}
-
-a:hover,
-a:active {
-  outline: 0;
-}
-
-sub,
-sup {
-  position: relative;
-  font-size: 75%;
-  line-height: 0;
-  vertical-align: baseline;
-}
-
-sup {
-  top: -0.5em;
-}
-
-sub {
-  bottom: -0.25em;
-}
-
-img {
-  max-width: 100%;
-  vertical-align: middle;
-  border: 0;
-  -ms-interpolation-mode: bicubic;
-}
-
-#map_canvas img {
-  max-width: none;
-}
-
-button,
-input,
-select,
-textarea {
-  margin: 0;
-  font-size: 100%;
-  vertical-align: middle;
-}
-
-button,
-input {
-  *overflow: visible;
-  line-height: normal;
-}
-
-button::-moz-focus-inner,
-input::-moz-focus-inner {
-  padding: 0;
-  border: 0;
-}
-
-button,
-input[type="button"],
-input[type="reset"],
-input[type="submit"] {
-  cursor: pointer;
-  -webkit-appearance: button;
-}
-
-input[type="search"] {
-  -webkit-box-sizing: content-box;
-     -moz-box-sizing: content-box;
-          box-sizing: content-box;
-  -webkit-appearance: textfield;
-}
-
-input[type="search"]::-webkit-search-decoration,
-input[type="search"]::-webkit-search-cancel-button {
-  -webkit-appearance: none;
-}
-
-textarea {
-  overflow: auto;
-  vertical-align: top;
-}
-
 .clearfix {
   *zoom: 1;
 }
-
 .clearfix:before,
 .clearfix:after {
   display: table;
   content: "";
 }
-
 .clearfix:after {
   clear: both;
 }
-
 .hide-text {
   font: 0/0 a;
   color: transparent;
@@ -144,298 +25,28 @@ textarea {
   background-color: transparent;
   border: 0;
 }
-
 .input-block-level {
   display: block;
   width: 100%;
   min-height: 28px;
   -webkit-box-sizing: border-box;
-     -moz-box-sizing: border-box;
-      -ms-box-sizing: border-box;
-          box-sizing: border-box;
-}
-
-body {
-  margin: 0;
-  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
-  font-size: 13px;
-  line-height: 18px;
-  color: #333333;
-  background-color: #ffffff;
-}
-
-a {
-  color: #0088cc;
-  text-decoration: none;
-}
-
-a:hover {
-  color: #005580;
-  text-decoration: underline;
-}
-
-.row {
-  margin-left: -20px;
-  *zoom: 1;
-}
-
-.row:before,
-.row:after {
-  display: table;
-  content: "";
-}
-
-.row:after {
-  clear: both;
-}
-
-[class*="span"] {
-  float: left;
-  margin-left: 20px;
-}
-
-.container,
-.navbar-fixed-top .container,
-.navbar-fixed-bottom .container {
-  width: 940px;
-}
-
-.span12 {
-  width: 940px;
-}
-
-.span11 {
-  width: 860px;
-}
-
-.span10 {
-  width: 780px;
-}
-
-.span9 {
-  width: 700px;
-}
-
-.span8 {
-  width: 620px;
-}
-
-.span7 {
-  width: 540px;
-}
-
-.span6 {
-  width: 460px;
-}
-
-.span5 {
-  width: 380px;
-}
-
-.span4 {
-  width: 300px;
-}
-
-.span3 {
-  width: 220px;
-}
-
-.span2 {
-  width: 140px;
-}
-
-.span1 {
-  width: 60px;
-}
-
-.offset12 {
-  margin-left: 980px;
-}
-
-.offset11 {
-  margin-left: 900px;
-}
-
-.offset10 {
-  margin-left: 820px;
-}
-
-.offset9 {
-  margin-left: 740px;
-}
-
-.offset8 {
-  margin-left: 660px;
-}
-
-.offset7 {
-  margin-left: 580px;
-}
-
-.offset6 {
-  margin-left: 500px;
-}
-
-.offset5 {
-  margin-left: 420px;
-}
-
-.offset4 {
-  margin-left: 340px;
-}
-
-.offset3 {
-  margin-left: 260px;
-}
-
-.offset2 {
-  margin-left: 180px;
-}
-
-.offset1 {
-  margin-left: 100px;
-}
-
-.row-fluid {
-  width: 100%;
-  *zoom: 1;
-}
-
-.row-fluid:before,
-.row-fluid:after {
-  display: table;
-  content: "";
-}
-
-.row-fluid:after {
-  clear: both;
-}
-
-.row-fluid [class*="span"] {
-  display: block;
-  float: left;
-  width: 100%;
-  min-height: 28px;
-  margin-left: 2.127659574%;
-  *margin-left: 2.0744680846382977%;
-  -webkit-box-sizing: border-box;
-     -moz-box-sizing: border-box;
-      -ms-box-sizing: border-box;
-          box-sizing: border-box;
-}
-
-.row-fluid [class*="span"]:first-child {
-  margin-left: 0;
-}
-
-.row-fluid .span12 {
-  width: 99.99999998999999%;
-  *width: 99.94680850063828%;
-}
-
-.row-fluid .span11 {
-  width: 91.489361693%;
-  *width: 91.4361702036383%;
-}
-
-.row-fluid .span10 {
-  width: 82.97872339599999%;
-  *width: 82.92553190663828%;
-}
-
-.row-fluid .span9 {
-  width: 74.468085099%;
-  *width: 74.4148936096383%;
-}
-
-.row-fluid .span8 {
-  width: 65.95744680199999%;
-  *width: 65.90425531263828%;
-}
-
-.row-fluid .span7 {
-  width: 57.446808505%;
-  *width: 57.3936170156383%;
-}
-
-.row-fluid .span6 {
-  width: 48.93617020799999%;
-  *width: 48.88297871863829%;
-}
-
-.row-fluid .span5 {
-  width: 40.425531911%;
-  *width: 40.3723404216383%;
-}
-
-.row-fluid .span4 {
-  width: 31.914893614%;
-  *width: 31.8617021246383%;
+  -moz-box-sizing: border-box;
+  -ms-box-sizing: border-box;
+  box-sizing: border-box;
 }
-
-.row-fluid .span3 {
-  width: 23.404255317%;
-  *width: 23.3510638276383%;
-}
-
-.row-fluid .span2 {
-  width: 14.89361702%;
-  *width: 14.8404255306383%;
-}
-
-.row-fluid .span1 {
-  width: 6.382978723%;
-  *width: 6.329787233638298%;
-}
-
-.container {
-  margin-right: auto;
-  margin-left: auto;
-  *zoom: 1;
-}
-
-.container:before,
-.container:after {
-  display: table;
-  content: "";
-}
-
-.container:after {
-  clear: both;
-}
-
-.container-fluid {
-  padding-right: 20px;
-  padding-left: 20px;
-  *zoom: 1;
-}
-
-.container-fluid:before,
-.container-fluid:after {
-  display: table;
-  content: "";
-}
-
-.container-fluid:after {
-  clear: both;
-}
-
 p {
   margin: 0 0 9px;
 }
-
 p small {
   font-size: 11px;
   color: #999999;
 }
-
 .lead {
   margin-bottom: 18px;
   font-size: 20px;
   font-weight: 200;
   line-height: 27px;
 }
-
 h1,
 h2,
 h3,
@@ -448,7 +59,6 @@ h6 {
   color: inherit;
   text-rendering: optimizelegibility;
 }
-
 h1 small,
 h2 small,
 h3 small,
@@ -458,183 +68,147 @@ h6 small {
   font-weight: normal;
   color: #999999;
 }
-
 h1 {
   font-size: 30px;
   line-height: 36px;
 }
-
 h1 small {
   font-size: 18px;
 }
-
 h2 {
   font-size: 24px;
   line-height: 36px;
 }
-
 h2 small {
   font-size: 18px;
 }
-
 h3 {
   font-size: 18px;
   line-height: 27px;
 }
-
 h3 small {
   font-size: 14px;
 }
-
 h4,
 h5,
 h6 {
   line-height: 18px;
 }
-
 h4 {
   font-size: 14px;
 }
-
 h4 small {
   font-size: 12px;
 }
-
 h5 {
   font-size: 12px;
 }
-
 h6 {
   font-size: 11px;
   color: #999999;
   text-transform: uppercase;
 }
-
 .page-header {
   padding-bottom: 17px;
   margin: 18px 0;
   border-bottom: 1px solid #eeeeee;
 }
-
 .page-header h1 {
   line-height: 1;
 }
-
 ul,
 ol {
   padding: 0;
   margin: 0 0 9px 25px;
 }
-
 ul ul,
 ul ol,
 ol ol,
 ol ul {
   margin-bottom: 0;
 }
-
 ul {
   list-style: disc;
 }
-
 ol {
   list-style: decimal;
 }
-
-li {
-  /* line-height: 18px; */
-}
-
+/*li {
+  line-height: 18px;
+}*/
 ul.unstyled,
 ol.unstyled {
   margin-left: 0;
   list-style: none;
 }
-
 dl {
   margin-bottom: 18px;
 }
-
 dt,
 dd {
   line-height: 18px;
 }
-
 dt {
   font-weight: bold;
   line-height: 17px;
 }
-
 dd {
   margin-left: 9px;
 }
-
 .dl-horizontal dt {
   float: left;
   width: 120px;
-  overflow: hidden;
   clear: left;
   text-align: right;
+  overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
 }
-
 .dl-horizontal dd {
   margin-left: 130px;
 }
-
 hr {
   margin: 18px 0;
   border: 0;
   border-top: 1px solid #eeeeee;
   border-bottom: 1px solid #ffffff;
 }
-
 strong {
   font-weight: bold;
 }
-
 em {
   font-style: italic;
 }
-
 .muted {
   color: #999999;
 }
-
 abbr[title] {
   cursor: help;
   border-bottom: 1px dotted #999999;
 }
-
 abbr.initialism {
   font-size: 90%;
   text-transform: uppercase;
 }
-
 blockquote {
   padding: 0 0 0 15px;
   margin: 0 0 18px;
   border-left: 5px solid #eeeeee;
 }
-
 blockquote p {
   margin-bottom: 0;
   font-size: 16px;
   font-weight: 300;
   line-height: 22.5px;
 }
-
 blockquote small {
   display: block;
   line-height: 18px;
   color: #999999;
 }
-
 blockquote small:before {
   content: '\2014 \00A0';
 }
-
 blockquote.pull-right {
   float: right;
   padding-right: 15px;
@@ -642,4342 +216,1374 @@ blockquote.pull-right {
   border-right: 5px solid #eeeeee;
   border-left: 0;
 }
-
 blockquote.pull-right p,
 blockquote.pull-right small {
   text-align: right;
 }
-
 q:before,
 q:after,
 blockquote:before,
 blockquote:after {
   content: "";
 }
-
 address {
   display: block;
   margin-bottom: 18px;
   font-style: normal;
   line-height: 18px;
 }
-
 small {
   font-size: 100%;
 }
-
 cite {
   font-style: normal;
 }
-
-code,
-pre {
-  padding: 0 3px 2px;
-  font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
-  font-size: 12px;
-  color: #333333;
+.label,
+.badge {
+  font-size: 10.998px;
+  font-weight: bold;
+  line-height: 14px;
+  color: #ffffff;
+  vertical-align: baseline;
+  white-space: nowrap;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+  background-color: #999999;
+}
+.label {
+  padding: 1px 4px 2px;
   -webkit-border-radius: 3px;
-     -moz-border-radius: 3px;
-          border-radius: 3px;
+  -moz-border-radius: 3px;
+  border-radius: 3px;
 }
-
-code {
-  padding: 2px 4px;
-  color: #d14;
-  background-color: #f7f7f9;
-  border: 1px solid #e1e1e8;
+.badge {
+  padding: 1px 9px 2px;
+  -webkit-border-radius: 9px;
+  -moz-border-radius: 9px;
+  border-radius: 9px;
 }
-
-pre {
-  display: block;
-  padding: 8.5px;
-  margin: 0 0 9px;
-  font-size: 12.025px;
-  line-height: 18px;
-  word-break: break-all;
-  word-wrap: break-word;
-  white-space: pre;
-  white-space: pre-wrap;
-  background-color: #f5f5f5;
-  border: 1px solid #ccc;
-  border: 1px solid rgba(0, 0, 0, 0.15);
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
+a.label:hover,
+a.badge:hover {
+  color: #ffffff;
+  text-decoration: none;
+  cursor: pointer;
 }
-
-pre.prettyprint {
-  margin-bottom: 18px;
+.label-important,
+.badge-important {
+  background-color: #b94a48;
 }
-
-pre code {
-  padding: 0;
-  color: inherit;
-  background-color: transparent;
-  border: 0;
+.label-important[href],
+.badge-important[href] {
+  background-color: #953b39;
 }
-
-.pre-scrollable {
-  max-height: 340px;
-  overflow-y: scroll;
+.label-warning,
+.badge-warning {
+  background-color: #f89406;
 }
-
-form {
-  margin: 0 0 18px;
+.label-warning[href],
+.badge-warning[href] {
+  background-color: #c67605;
 }
-
-fieldset {
-  padding: 0;
-  margin: 0;
-  border: 0;
+.label-success,
+.badge-success {
+  background-color: #468847;
 }
-
-legend {
-  display: block;
-  width: 100%;
-  padding: 0;
-  margin-bottom: 27px;
-  font-size: 19.5px;
-  line-height: 36px;
-  color: #333333;
-  border: 0;
-  border-bottom: 1px solid #e5e5e5;
+.label-success[href],
+.badge-success[href] {
+  background-color: #356635;
 }
-
-legend small {
-  font-size: 13.5px;
-  color: #999999;
+.label-info,
+.badge-info {
+  background-color: #3a87ad;
 }
-
-label,
-input,
-button,
-select,
-textarea {
-  font-size: 13px;
-  font-weight: normal;
-  line-height: 18px;
+.label-info[href],
+.badge-info[href] {
+  background-color: #2d6987;
 }
-
-input,
-button,
-select,
-textarea {
-  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+.label-inverse,
+.badge-inverse {
+  background-color: #333333;
 }
-
-label {
-  display: block;
-  margin-bottom: 5px;
+.label-inverse[href],
+.badge-inverse[href] {
+  background-color: #1a1a1a;
 }
-
-select,
-textarea,
-input[type="text"],
-input[type="password"],
-input[type="datetime"],
-input[type="datetime-local"],
-input[type="date"],
-input[type="month"],
-input[type="time"],
-input[type="week"],
-input[type="number"],
-input[type="email"],
-input[type="url"],
-input[type="search"],
-input[type="tel"],
-input[type="color"],
-.uneditable-input {
-  display: inline-block;
-  height: 18px;
-  padding: 4px;
-  margin-bottom: 9px;
-  font-size: 13px;
-  line-height: 18px;
-  color: #555555;
+table {
+  max-width: 100%;
+  background-color: transparent;
+  border-collapse: collapse;
+  border-spacing: 0;
 }
-
-input,
-textarea {
-  width: 210px;
+.table {
+  width: 100%;
+  margin-bottom: 18px;
 }
-
-textarea {
-  height: auto;
+.table th,
+.table td {
+  padding: 8px;
+  line-height: 18px;
+  text-align: left;
+  vertical-align: top;
+  border-top: 1px solid #dddddd;
 }
-
-textarea,
-input[type="text"],
-input[type="password"],
-input[type="datetime"],
-input[type="datetime-local"],
-input[type="date"],
-input[type="month"],
-input[type="time"],
-input[type="week"],
-input[type="number"],
-input[type="email"],
-input[type="url"],
-input[type="search"],
-input[type="tel"],
-input[type="color"],
-.uneditable-input {
-  background-color: #ffffff;
-  border: 1px solid #cccccc;
-  -webkit-border-radius: 3px;
-     -moz-border-radius: 3px;
-          border-radius: 3px;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-  -webkit-transition: border linear 0.2s, box-shadow linear 0.2s;
-     -moz-transition: border linear 0.2s, box-shadow linear 0.2s;
-      -ms-transition: border linear 0.2s, box-shadow linear 0.2s;
-       -o-transition: border linear 0.2s, box-shadow linear 0.2s;
-          transition: border linear 0.2s, box-shadow linear 0.2s;
+.table th {
+  font-weight: bold;
 }
-
-textarea:focus,
-input[type="text"]:focus,
-input[type="password"]:focus,
-input[type="datetime"]:focus,
-input[type="datetime-local"]:focus,
-input[type="date"]:focus,
-input[type="month"]:focus,
-input[type="time"]:focus,
-input[type="week"]:focus,
-input[type="number"]:focus,
-input[type="email"]:focus,
-input[type="url"]:focus,
-input[type="search"]:focus,
-input[type="tel"]:focus,
-input[type="color"]:focus,
-.uneditable-input:focus {
-  border-color: rgba(82, 168, 236, 0.8);
-  outline: 0;
-  outline: thin dotted \9;
-  /* IE6-9 */
-
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
-     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+.table thead th {
+  vertical-align: bottom;
 }
-
-input[type="radio"],
-input[type="checkbox"] {
-  margin: 3px 0;
-  *margin-top: 0;
-  /* IE7 */
-
-  line-height: normal;
-  cursor: pointer;
+.table caption + thead tr:first-child th,
+.table caption + thead tr:first-child td,
+.table colgroup + thead tr:first-child th,
+.table colgroup + thead tr:first-child td,
+.table thead:first-child tr:first-child th,
+.table thead:first-child tr:first-child td {
+  border-top: 0;
 }
-
-input[type="submit"],
-input[type="reset"],
-input[type="button"],
-input[type="radio"],
-input[type="checkbox"] {
-  width: auto;
+.table tbody + tbody {
+  border-top: 2px solid #dddddd;
 }
-
-.uneditable-textarea {
-  width: auto;
-  height: auto;
+.table-condensed th,
+.table-condensed td {
+  padding: 4px 5px;
 }
-
-select,
-input[type="file"] {
-  height: 28px;
-  /* In IE7, the height of the select element cannot be changed by height, only font-size */
-
-  *margin-top: 4px;
-  /* For IE7, add top margin to align select with labels */
-
-  line-height: 28px;
-}
-
-select {
-  width: 220px;
-  border: 1px solid #bbb;
-}
-
-select[multiple],
-select[size] {
-  height: auto;
-}
-
-select:focus,
-input[type="file"]:focus,
-input[type="radio"]:focus,
-input[type="checkbox"]:focus {
-  outline: thin dotted #333;
-  outline: 5px auto -webkit-focus-ring-color;
-  outline-offset: -2px;
-}
-
-.radio,
-.checkbox {
-  min-height: 18px;
-  padding-left: 18px;
-}
-
-.radio input[type="radio"],
-.checkbox input[type="checkbox"] {
-  float: left;
-  margin-left: -18px;
-}
-
-.controls > .radio:first-child,
-.controls > .checkbox:first-child {
-  padding-top: 5px;
+.table-bordered {
+  border: 1px solid #dddddd;
+  border-collapse: separate;
+  *border-collapse: collapsed;
+  border-left: 0;
+  -webkit-border-radius: 4px;
+  -moz-border-radius: 4px;
+  border-radius: 4px;
 }
-
-.radio.inline,
-.checkbox.inline {
-  display: inline-block;
-  padding-top: 5px;
-  margin-bottom: 0;
-  vertical-align: middle;
+.table-bordered th,
+.table-bordered td {
+  border-left: 1px solid #dddddd;
 }
-
-.radio.inline + .radio.inline,
-.checkbox.inline + .checkbox.inline {
-  margin-left: 10px;
+.table-bordered caption + thead tr:first-child th,
+.table-bordered caption + tbody tr:first-child th,
+.table-bordered caption + tbody tr:first-child td,
+.table-bordered colgroup + thead tr:first-child th,
+.table-bordered colgroup + tbody tr:first-child th,
+.table-bordered colgroup + tbody tr:first-child td,
+.table-bordered thead:first-child tr:first-child th,
+.table-bordered tbody:first-child tr:first-child th,
+.table-bordered tbody:first-child tr:first-child td {
+  border-top: 0;
 }
-
-.input-mini {
-  width: 60px;
+.table-bordered thead:first-child tr:first-child th:first-child,
+.table-bordered tbody:first-child tr:first-child td:first-child {
+  -webkit-border-top-left-radius: 4px;
+  border-top-left-radius: 4px;
+  -moz-border-radius-topleft: 4px;
 }
-
-.input-small {
-  width: 90px;
+.table-bordered thead:first-child tr:first-child th:last-child,
+.table-bordered tbody:first-child tr:first-child td:last-child {
+  -webkit-border-top-right-radius: 4px;
+  border-top-right-radius: 4px;
+  -moz-border-radius-topright: 4px;
 }
-
-.input-medium {
-  width: 150px;
+.table-bordered thead:last-child tr:last-child th:first-child,
+.table-bordered tbody:last-child tr:last-child td:first-child {
+  -webkit-border-radius: 0 0 0 4px;
+  -moz-border-radius: 0 0 0 4px;
+  border-radius: 0 0 0 4px;
+  -webkit-border-bottom-left-radius: 4px;
+  border-bottom-left-radius: 4px;
+  -moz-border-radius-bottomleft: 4px;
 }
-
-.input-large {
-  width: 210px;
+.table-bordered thead:last-child tr:last-child th:last-child,
+.table-bordered tbody:last-child tr:last-child td:last-child {
+  -webkit-border-bottom-right-radius: 4px;
+  border-bottom-right-radius: 4px;
+  -moz-border-radius-bottomright: 4px;
 }
-
-.input-xlarge {
-  width: 270px;
+.table-striped tbody tr:nth-child(odd) td,
+.table-striped tbody tr:nth-child(odd) th {
+  background-color: #f9f9f9;
 }
-
-.input-xxlarge {
-  width: 530px;
+.table tbody tr:hover td,
+.table tbody tr:hover th {
+  background-color: #f5f5f5;
 }
-
-input[class*="span"],
-select[class*="span"],
-textarea[class*="span"],
-.uneditable-input[class*="span"],
-.row-fluid input[class*="span"],
-.row-fluid select[class*="span"],
-.row-fluid textarea[class*="span"],
-.row-fluid .uneditable-input[class*="span"] {
+table .span1 {
   float: none;
+  width: 44px;
   margin-left: 0;
 }
-
-.input-append input[class*="span"],
-.input-append .uneditable-input[class*="span"],
-.input-prepend input[class*="span"],
-.input-prepend .uneditable-input[class*="span"],
-.row-fluid .input-prepend [class*="span"],
-.row-fluid .input-append [class*="span"] {
-  display: inline-block;
-}
-
-input,
-textarea,
-.uneditable-input {
+table .span2 {
+  float: none;
+  width: 124px;
   margin-left: 0;
 }
-
-input.span12,
-textarea.span12,
-.uneditable-input.span12 {
-  width: 930px;
-}
-
-input.span11,
-textarea.span11,
-.uneditable-input.span11 {
-  width: 850px;
-}
-
-input.span10,
-textarea.span10,
-.uneditable-input.span10 {
-  width: 770px;
+table .span3 {
+  float: none;
+  width: 204px;
+  margin-left: 0;
 }
-
-input.span9,
-textarea.span9,
-.uneditable-input.span9 {
-  width: 690px;
+table .span4 {
+  float: none;
+  width: 284px;
+  margin-left: 0;
 }
-
-input.span8,
-textarea.span8,
-.uneditable-input.span8 {
-  width: 610px;
+table .span5 {
+  float: none;
+  width: 364px;
+  margin-left: 0;
 }
-
-input.span7,
-textarea.span7,
-.uneditable-input.span7 {
-  width: 530px;
+table .span6 {
+  float: none;
+  width: 444px;
+  margin-left: 0;
 }
-
-input.span6,
-textarea.span6,
-.uneditable-input.span6 {
-  width: 450px;
+table .span7 {
+  float: none;
+  width: 524px;
+  margin-left: 0;
 }
-
-input.span5,
-textarea.span5,
-.uneditable-input.span5 {
-  width: 370px;
+table .span8 {
+  float: none;
+  width: 604px;
+  margin-left: 0;
 }
-
-input.span4,
-textarea.span4,
-.uneditable-input.span4 {
-  width: 290px;
+table .span9 {
+  float: none;
+  width: 684px;
+  margin-left: 0;
 }
-
-input.span3,
-textarea.span3,
-.uneditable-input.span3 {
-  width: 210px;
+table .span10 {
+  float: none;
+  width: 764px;
+  margin-left: 0;
 }
-
-input.span2,
-textarea.span2,
-.uneditable-input.span2 {
-  width: 130px;
+table .span11 {
+  float: none;
+  width: 844px;
+  margin-left: 0;
 }
-
-input.span1,
-textarea.span1,
-.uneditable-input.span1 {
-  width: 50px;
+table .span12 {
+  float: none;
+  width: 924px;
+  margin-left: 0;
 }
-
-input[disabled],
-select[disabled],
-textarea[disabled],
-input[readonly],
-select[readonly],
-textarea[readonly] {
-  cursor: not-allowed;
-  background-color: #eeeeee;
-  border-color: #ddd;
+table .span13 {
+  float: none;
+  width: 1004px;
+  margin-left: 0;
 }
-
-input[type="radio"][disabled],
-input[type="checkbox"][disabled],
-input[type="radio"][readonly],
-input[type="checkbox"][readonly] {
-  background-color: transparent;
+table .span14 {
+  float: none;
+  width: 1084px;
+  margin-left: 0;
 }
-
-.control-group.warning > label,
-.control-group.warning .help-block,
-.control-group.warning .help-inline {
-  color: #c09853;
+table .span15 {
+  float: none;
+  width: 1164px;
+  margin-left: 0;
 }
-
-.control-group.warning .checkbox,
-.control-group.warning .radio,
-.control-group.warning input,
-.control-group.warning select,
-.control-group.warning textarea {
-  color: #c09853;
-  border-color: #c09853;
+table .span16 {
+  float: none;
+  width: 1244px;
+  margin-left: 0;
 }
-
-.control-group.warning .checkbox:focus,
-.control-group.warning .radio:focus,
-.control-group.warning input:focus,
-.control-group.warning select:focus,
-.control-group.warning textarea:focus {
-  border-color: #a47e3c;
-  -webkit-box-shadow: 0 0 6px #dbc59e;
-     -moz-box-shadow: 0 0 6px #dbc59e;
-          box-shadow: 0 0 6px #dbc59e;
-}
-
-.control-group.warning .input-prepend .add-on,
-.control-group.warning .input-append .add-on {
-  color: #c09853;
-  background-color: #fcf8e3;
-  border-color: #c09853;
-}
-
-.control-group.error > label,
-.control-group.error .help-block,
-.control-group.error .help-inline {
-  color: #b94a48;
-}
-
-.control-group.error .checkbox,
-.control-group.error .radio,
-.control-group.error input,
-.control-group.error select,
-.control-group.error textarea {
-  color: #b94a48;
-  border-color: #b94a48;
-}
-
-.control-group.error .checkbox:focus,
-.control-group.error .radio:focus,
-.control-group.error input:focus,
-.control-group.error select:focus,
-.control-group.error textarea:focus {
-  border-color: #953b39;
-  -webkit-box-shadow: 0 0 6px #d59392;
-     -moz-box-shadow: 0 0 6px #d59392;
-          box-shadow: 0 0 6px #d59392;
-}
-
-.control-group.error .input-prepend .add-on,
-.control-group.error .input-append .add-on {
-  color: #b94a48;
-  background-color: #f2dede;
-  border-color: #b94a48;
-}
-
-.control-group.success > label,
-.control-group.success .help-block,
-.control-group.success .help-inline {
-  color: #468847;
-}
-
-.control-group.success .checkbox,
-.control-group.success .radio,
-.control-group.success input,
-.control-group.success select,
-.control-group.success textarea {
-  color: #468847;
-  border-color: #468847;
-}
-
-.control-group.success .checkbox:focus,
-.control-group.success .radio:focus,
-.control-group.success input:focus,
-.control-group.success select:focus,
-.control-group.success textarea:focus {
-  border-color: #356635;
-  -webkit-box-shadow: 0 0 6px #7aba7b;
-     -moz-box-shadow: 0 0 6px #7aba7b;
-          box-shadow: 0 0 6px #7aba7b;
-}
-
-.control-group.success .input-prepend .add-on,
-.control-group.success .input-append .add-on {
-  color: #468847;
-  background-color: #dff0d8;
-  border-color: #468847;
-}
-
-input:focus:required:invalid,
-textarea:focus:required:invalid,
-select:focus:required:invalid {
-  color: #b94a48;
-  border-color: #ee5f5b;
-}
-
-input:focus:required:invalid:focus,
-textarea:focus:required:invalid:focus,
-select:focus:required:invalid:focus {
-  border-color: #e9322d;
-  -webkit-box-shadow: 0 0 6px #f8b9b7;
-     -moz-box-shadow: 0 0 6px #f8b9b7;
-          box-shadow: 0 0 6px #f8b9b7;
-}
-
-.form-actions {
-  padding: 17px 20px 18px;
-  margin-top: 18px;
-  margin-bottom: 18px;
-  background-color: #f5f5f5;
-  border-top: 1px solid #e5e5e5;
-  *zoom: 1;
-}
-
-.form-actions:before,
-.form-actions:after {
-  display: table;
-  content: "";
-}
-
-.form-actions:after {
-  clear: both;
-}
-
-.uneditable-input {
-  overflow: hidden;
-  white-space: nowrap;
-  cursor: not-allowed;
-  background-color: #ffffff;
-  border-color: #eee;
-  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
-     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
-          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
-}
-
-:-moz-placeholder {
-  color: #999999;
-}
-
-:-ms-input-placeholder {
-  color: #999999;
-}
-
-::-webkit-input-placeholder {
-  color: #999999;
-}
-
-.help-block,
-.help-inline {
-  color: #555555;
-}
-
-.help-block {
-  display: block;
-  margin-bottom: 9px;
-}
-
-.help-inline {
-  display: inline-block;
-  *display: inline;
-  padding-left: 5px;
-  vertical-align: middle;
-  *zoom: 1;
-}
-
-.input-prepend,
-.input-append {
-  margin-bottom: 5px;
-}
-
-.input-prepend input,
-.input-append input,
-.input-prepend select,
-.input-append select,
-.input-prepend .uneditable-input,
-.input-append .uneditable-input {
-  position: relative;
-  margin-bottom: 0;
-  *margin-left: 0;
-  vertical-align: middle;
-  -webkit-border-radius: 0 3px 3px 0;
-     -moz-border-radius: 0 3px 3px 0;
-          border-radius: 0 3px 3px 0;
-}
-
-.input-prepend input:focus,
-.input-append input:focus,
-.input-prepend select:focus,
-.input-append select:focus,
-.input-prepend .uneditable-input:focus,
-.input-append .uneditable-input:focus {
-  z-index: 2;
-}
-
-.input-prepend .uneditable-input,
-.input-append .uneditable-input {
-  border-left-color: #ccc;
-}
-
-.input-prepend .add-on,
-.input-append .add-on {
-  display: inline-block;
-  width: auto;
-  height: 18px;
-  min-width: 16px;
-  padding: 4px 5px;
-  font-weight: normal;
-  line-height: 18px;
-  text-align: center;
-  text-shadow: 0 1px 0 #ffffff;
-  vertical-align: middle;
-  background-color: #eeeeee;
-  border: 1px solid #ccc;
-}
-
-.input-prepend .add-on,
-.input-append .add-on,
-.input-prepend .btn,
-.input-append .btn {
-  margin-left: -1px;
-  -webkit-border-radius: 0;
-     -moz-border-radius: 0;
-          border-radius: 0;
-}
-
-.input-prepend .active,
-.input-append .active {
-  background-color: #a9dba9;
-  border-color: #46a546;
-}
-
-.input-prepend .add-on,
-.input-prepend .btn {
-  margin-right: -1px;
-}
-
-.input-prepend .add-on:first-child,
-.input-prepend .btn:first-child {
-  -webkit-border-radius: 3px 0 0 3px;
-     -moz-border-radius: 3px 0 0 3px;
-          border-radius: 3px 0 0 3px;
-}
-
-.input-append input,
-.input-append select,
-.input-append .uneditable-input {
-  -webkit-border-radius: 3px 0 0 3px;
-     -moz-border-radius: 3px 0 0 3px;
-          border-radius: 3px 0 0 3px;
-}
-
-.input-append .uneditable-input {
-  border-right-color: #ccc;
-  border-left-color: #eee;
-}
-
-.input-append .add-on:last-child,
-.input-append .btn:last-child {
-  -webkit-border-radius: 0 3px 3px 0;
-     -moz-border-radius: 0 3px 3px 0;
-          border-radius: 0 3px 3px 0;
-}
-
-.input-prepend.input-append input,
-.input-prepend.input-append select,
-.input-prepend.input-append .uneditable-input {
-  -webkit-border-radius: 0;
-     -moz-border-radius: 0;
-          border-radius: 0;
-}
-
-.input-prepend.input-append .add-on:first-child,
-.input-prepend.input-append .btn:first-child {
-  margin-right: -1px;
-  -webkit-border-radius: 3px 0 0 3px;
-     -moz-border-radius: 3px 0 0 3px;
-          border-radius: 3px 0 0 3px;
-}
-
-.input-prepend.input-append .add-on:last-child,
-.input-prepend.input-append .btn:last-child {
-  margin-left: -1px;
-  -webkit-border-radius: 0 3px 3px 0;
-     -moz-border-radius: 0 3px 3px 0;
-          border-radius: 0 3px 3px 0;
-}
-
-.search-query {
-  padding-right: 14px;
-  padding-right: 4px \9;
-  padding-left: 14px;
-  padding-left: 4px \9;
-  /* IE7-8 doesn't have border-radius, so don't indent the padding */
-
-  margin-bottom: 0;
-  -webkit-border-radius: 14px;
-     -moz-border-radius: 14px;
-          border-radius: 14px;
-}
-
-.form-search input,
-.form-inline input,
-.form-horizontal input,
-.form-search textarea,
-.form-inline textarea,
-.form-horizontal textarea,
-.form-search select,
-.form-inline select,
-.form-horizontal select,
-.form-search .help-inline,
-.form-inline .help-inline,
-.form-horizontal .help-inline,
-.form-search .uneditable-input,
-.form-inline .uneditable-input,
-.form-horizontal .uneditable-input,
-.form-search .input-prepend,
-.form-inline .input-prepend,
-.form-horizontal .input-prepend,
-.form-search .input-append,
-.form-inline .input-append,
-.form-horizontal .input-append {
-  display: inline-block;
-  *display: inline;
-  margin-bottom: 0;
-  *zoom: 1;
-}
-
-.form-search .hide,
-.form-inline .hide,
-.form-horizontal .hide {
-  display: none;
-}
-
-.form-search label,
-.form-inline label {
-  display: inline-block;
-}
-
-.form-search .input-append,
-.form-inline .input-append,
-.form-search .input-prepend,
-.form-inline .input-prepend {
-  margin-bottom: 0;
-}
-
-.form-search .radio,
-.form-search .checkbox,
-.form-inline .radio,
-.form-inline .checkbox {
-  padding-left: 0;
-  margin-bottom: 0;
-  vertical-align: middle;
-}
-
-.form-search .radio input[type="radio"],
-.form-search .checkbox input[type="checkbox"],
-.form-inline .radio input[type="radio"],
-.form-inline .checkbox input[type="checkbox"] {
-  float: left;
-  margin-right: 3px;
-  margin-left: 0;
-}
-
-.control-group {
-  margin-bottom: 9px;
-}
-
-legend + .control-group {
-  margin-top: 18px;
-  -webkit-margin-top-collapse: separate;
-}
-
-.form-horizontal .control-group {
-  margin-bottom: 18px;
-  *zoom: 1;
-}
-
-.form-horizontal .control-group:before,
-.form-horizontal .control-group:after {
-  display: table;
-  content: "";
-}
-
-.form-horizontal .control-group:after {
-  clear: both;
-}
-
-.form-horizontal .control-label {
-  float: left;
-  width: 140px;
-  padding-top: 5px;
-  text-align: right;
-}
-
-.form-horizontal .controls {
-  *display: inline-block;
-  *padding-left: 20px;
-  margin-left: 160px;
-  *margin-left: 0;
-}
-
-.form-horizontal .controls:first-child {
-  *padding-left: 160px;
-}
-
-.form-horizontal .help-block {
-  margin-top: 9px;
-  margin-bottom: 0;
-}
-
-.form-horizontal .form-actions {
-  padding-left: 160px;
-}
-
-table {
-  max-width: 100%;
-  background-color: transparent;
-  border-collapse: collapse;
-  border-spacing: 0;
-}
-
-.table {
-  width: 100%;
-  margin-bottom: 18px;
-}
-
-.table th,
-.table td {
-  padding: 8px;
-  line-height: 18px;
-  text-align: left;
-  vertical-align: top;
-  border-top: 1px solid #dddddd;
-}
-
-.table th {
-  font-weight: bold;
-}
-
-.table thead th {
-  vertical-align: bottom;
-}
-
-.table caption + thead tr:first-child th,
-.table caption + thead tr:first-child td,
-.table colgroup + thead tr:first-child th,
-.table colgroup + thead tr:first-child td,
-.table thead:first-child tr:first-child th,
-.table thead:first-child tr:first-child td {
-  border-top: 0;
-}
-
-.table tbody + tbody {
-  border-top: 2px solid #dddddd;
-}
-
-.table-condensed th,
-.table-condensed td {
-  padding: 4px 5px;
-}
-
-.table-bordered {
-  border: 1px solid #dddddd;
-  border-collapse: separate;
-  *border-collapse: collapsed;
-  border-left: 0;
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-}
-
-.table-bordered th,
-.table-bordered td {
-  border-left: 1px solid #dddddd;
-}
-
-.table-bordered caption + thead tr:first-child th,
-.table-bordered caption + tbody tr:first-child th,
-.table-bordered caption + tbody tr:first-child td,
-.table-bordered colgroup + thead tr:first-child th,
-.table-bordered colgroup + tbody tr:first-child th,
-.table-bordered colgroup + tbody tr:first-child td,
-.table-bordered thead:first-child tr:first-child th,
-.table-bordered tbody:first-child tr:first-child th,
-.table-bordered tbody:first-child tr:first-child td {
-  border-top: 0;
-}
-
-.table-bordered thead:first-child tr:first-child th:first-child,
-.table-bordered tbody:first-child tr:first-child td:first-child {
-  -webkit-border-top-left-radius: 4px;
-          border-top-left-radius: 4px;
-  -moz-border-radius-topleft: 4px;
-}
-
-.table-bordered thead:first-child tr:first-child th:last-child,
-.table-bordered tbody:first-child tr:first-child td:last-child {
-  -webkit-border-top-right-radius: 4px;
-          border-top-right-radius: 4px;
-  -moz-border-radius-topright: 4px;
-}
-
-.table-bordered thead:last-child tr:last-child th:first-child,
-.table-bordered tbody:last-child tr:last-child td:first-child {
-  -webkit-border-radius: 0 0 0 4px;
-     -moz-border-radius: 0 0 0 4px;
-          border-radius: 0 0 0 4px;
-  -webkit-border-bottom-left-radius: 4px;
-          border-bottom-left-radius: 4px;
-  -moz-border-radius-bottomleft: 4px;
-}
-
-.table-bordered thead:last-child tr:last-child th:last-child,
-.table-bordered tbody:last-child tr:last-child td:last-child {
-  -webkit-border-bottom-right-radius: 4px;
-          border-bottom-right-radius: 4px;
-  -moz-border-radius-bottomright: 4px;
-}
-
-.table-striped tbody tr:nth-child(odd) td,
-.table-striped tbody tr:nth-child(odd) th {
-  background-color: #f9f9f9;
-}
-
-.table tbody tr:hover td,
-.table tbody tr:hover th {
-  background-color: #f5f5f5;
-}
-
-table .span1 {
-  float: none;
-  width: 44px;
-  margin-left: 0;
-}
-
-table .span2 {
-  float: none;
-  width: 124px;
-  margin-left: 0;
-}
-
-table .span3 {
-  float: none;
-  width: 204px;
-  margin-left: 0;
-}
-
-table .span4 {
-  float: none;
-  width: 284px;
-  margin-left: 0;
-}
-
-table .span5 {
-  float: none;
-  width: 364px;
-  margin-left: 0;
-}
-
-table .span6 {
-  float: none;
-  width: 444px;
-  margin-left: 0;
-}
-
-table .span7 {
-  float: none;
-  width: 524px;
-  margin-left: 0;
-}
-
-table .span8 {
-  float: none;
-  width: 604px;
-  margin-left: 0;
-}
-
-table .span9 {
-  float: none;
-  width: 684px;
-  margin-left: 0;
-}
-
-table .span10 {
-  float: none;
-  width: 764px;
-  margin-left: 0;
-}
-
-table .span11 {
-  float: none;
-  width: 844px;
-  margin-left: 0;
-}
-
-table .span12 {
-  float: none;
-  width: 924px;
-  margin-left: 0;
-}
-
-table .span13 {
-  float: none;
-  width: 1004px;
-  margin-left: 0;
-}
-
-table .span14 {
-  float: none;
-  width: 1084px;
-  margin-left: 0;
-}
-
-table .span15 {
-  float: none;
-  width: 1164px;
-  margin-left: 0;
-}
-
-table .span16 {
-  float: none;
-  width: 1244px;
-  margin-left: 0;
-}
-
-table .span17 {
-  float: none;
-  width: 1324px;
-  margin-left: 0;
-}
-
-table .span18 {
-  float: none;
-  width: 1404px;
-  margin-left: 0;
-}
-
-table .span19 {
-  float: none;
-  width: 1484px;
-  margin-left: 0;
-}
-
-table .span20 {
-  float: none;
-  width: 1564px;
-  margin-left: 0;
-}
-
-table .span21 {
-  float: none;
-  width: 1644px;
-  margin-left: 0;
-}
-
-table .span22 {
-  float: none;
-  width: 1724px;
-  margin-left: 0;
-}
-
-table .span23 {
-  float: none;
-  width: 1804px;
-  margin-left: 0;
-}
-
-table .span24 {
-  float: none;
-  width: 1884px;
-  margin-left: 0;
-}
-
-[class^="icon-"],
-[class*=" icon-"] {
-  display: inline-block;
-  width: 14px;
-  height: 14px;
-  *margin-right: .3em;
-  line-height: 14px;
-  vertical-align: text-top;
-  background-image: url("../img/glyphicons-halflings.png");
-  background-position: 14px 14px;
-  background-repeat: no-repeat;
-}
-
-[class^="icon-"]:last-child,
-[class*=" icon-"]:last-child {
-  *margin-left: 0;
-}
-
-.icon-white {
-  background-image: url("../img/glyphicons-halflings-white.png");
-}
-
-.icon-glass {
-  background-position: 0      0;
-}
-
-.icon-music {
-  background-position: -24px 0;
-}
-
-.icon-search {
-  background-position: -48px 0;
-}
-
-.icon-envelope {
-  background-position: -72px 0;
-}
-
-.icon-heart {
-  background-position: -96px 0;
-}
-
-.icon-star {
-  background-position: -120px 0;
-}
-
-.icon-star-empty {
-  background-position: -144px 0;
-}
-
-.icon-user {
-  background-position: -168px 0;
-}
-
-.icon-film {
-  background-position: -192px 0;
-}
-
-.icon-th-large {
-  background-position: -216px 0;
-}
-
-.icon-th {
-  background-position: -240px 0;
-}
-
-.icon-th-list {
-  background-position: -264px 0;
-}
-
-.icon-ok {
-  background-position: -288px 0;
-}
-
-.icon-remove {
-  background-position: -312px 0;
-}
-
-.icon-zoom-in {
-  background-position: -336px 0;
-}
-
-.icon-zoom-out {
-  background-position: -360px 0;
-}
-
-.icon-off {
-  background-position: -384px 0;
-}
-
-.icon-signal {
-  background-position: -408px 0;
-}
-
-.icon-cog {
-  background-position: -432px 0;
-}
-
-.icon-trash {
-  background-position: -456px 0;
-}
-
-.icon-home {
-  background-position: 0 -24px;
-}
-
-.icon-file {
-  background-position: -24px -24px;
-}
-
-.icon-time {
-  background-position: -48px -24px;
-}
-
-.icon-road {
-  background-position: -72px -24px;
-}
-
-.icon-download-alt {
-  background-position: -96px -24px;
-}
-
-.icon-download {
-  background-position: -120px -24px;
-}
-
-.icon-upload {
-  background-position: -144px -24px;
-}
-
-.icon-inbox {
-  background-position: -168px -24px;
-}
-
-.icon-play-circle {
-  background-position: -192px -24px;
-}
-
-.icon-repeat {
-  background-position: -216px -24px;
-}
-
-.icon-refresh {
-  background-position: -240px -24px;
-}
-
-.icon-list-alt {
-  background-position: -264px -24px;
-}
-
-.icon-lock {
-  background-position: -287px -24px;
-}
-
-.icon-flag {
-  background-position: -312px -24px;
-}
-
-.icon-headphones {
-  background-position: -336px -24px;
-}
-
-.icon-volume-off {
-  background-position: -360px -24px;
-}
-
-.icon-volume-down {
-  background-position: -384px -24px;
-}
-
-.icon-volume-up {
-  background-position: -408px -24px;
-}
-
-.icon-qrcode {
-  background-position: -432px -24px;
-}
-
-.icon-barcode {
-  background-position: -456px -24px;
-}
-
-.icon-tag {
-  background-position: 0 -48px;
-}
-
-.icon-tags {
-  background-position: -25px -48px;
-}
-
-.icon-book {
-  background-position: -48px -48px;
-}
-
-.icon-bookmark {
-  background-position: -72px -48px;
-}
-
-.icon-print {
-  background-position: -96px -48px;
-}
-
-.icon-camera {
-  background-position: -120px -48px;
-}
-
-.icon-font {
-  background-position: -144px -48px;
-}
-
-.icon-bold {
-  background-position: -167px -48px;
-}
-
-.icon-italic {
-  background-position: -192px -48px;
-}
-
-.icon-text-height {
-  background-position: -216px -48px;
-}
-
-.icon-text-width {
-  background-position: -240px -48px;
-}
-
-.icon-align-left {
-  background-position: -264px -48px;
-}
-
-.icon-align-center {
-  background-position: -288px -48px;
-}
-
-.icon-align-right {
-  background-position: -312px -48px;
-}
-
-.icon-align-justify {
-  background-position: -336px -48px;
-}
-
-.icon-list {
-  background-position: -360px -48px;
-}
-
-.icon-indent-left {
-  background-position: -384px -48px;
-}
-
-.icon-indent-right {
-  background-position: -408px -48px;
-}
-
-.icon-facetime-video {
-  background-position: -432px -48px;
-}
-
-.icon-picture {
-  background-position: -456px -48px;
-}
-
-.icon-pencil {
-  background-position: 0 -72px;
-}
-
-.icon-map-marker {
-  background-position: -24px -72px;
-}
-
-.icon-adjust {
-  background-position: -48px -72px;
-}
-
-.icon-tint {
-  background-position: -72px -72px;
-}
-
-.icon-edit {
-  background-position: -96px -72px;
-}
-
-.icon-share {
-  background-position: -120px -72px;
-}
-
-.icon-check {
-  background-position: -144px -72px;
-}
-
-.icon-move {
-  background-position: -168px -72px;
-}
-
-.icon-step-backward {
-  background-position: -192px -72px;
-}
-
-.icon-fast-backward {
-  background-position: -216px -72px;
-}
-
-.icon-backward {
-  background-position: -240px -72px;
-}
-
-.icon-play {
-  background-position: -264px -72px;
-}
-
-.icon-pause {
-  background-position: -288px -72px;
-}
-
-.icon-stop {
-  background-position: -312px -72px;
-}
-
-.icon-forward {
-  background-position: -336px -72px;
-}
-
-.icon-fast-forward {
-  background-position: -360px -72px;
-}
-
-.icon-step-forward {
-  background-position: -384px -72px;
-}
-
-.icon-eject {
-  background-position: -408px -72px;
-}
-
-.icon-chevron-left {
-  background-position: -432px -72px;
-}
-
-.icon-chevron-right {
-  background-position: -456px -72px;
-}
-
-.icon-plus-sign {
-  background-position: 0 -96px;
-}
-
-.icon-minus-sign {
-  background-position: -24px -96px;
-}
-
-.icon-remove-sign {
-  background-position: -48px -96px;
-}
-
-.icon-ok-sign {
-  background-position: -72px -96px;
-}
-
-.icon-question-sign {
-  background-position: -96px -96px;
-}
-
-.icon-info-sign {
-  background-position: -120px -96px;
-}
-
-.icon-screenshot {
-  background-position: -144px -96px;
-}
-
-.icon-remove-circle {
-  background-position: -168px -96px;
-}
-
-.icon-ok-circle {
-  background-position: -192px -96px;
-}
-
-.icon-ban-circle {
-  background-position: -216px -96px;
-}
-
-.icon-arrow-left {
-  background-position: -240px -96px;
-}
-
-.icon-arrow-right {
-  background-position: -264px -96px;
-}
-
-.icon-arrow-up {
-  background-position: -289px -96px;
-}
-
-.icon-arrow-down {
-  background-position: -312px -96px;
-}
-
-.icon-share-alt {
-  background-position: -336px -96px;
-}
-
-.icon-resize-full {
-  background-position: -360px -96px;
-}
-
-.icon-resize-small {
-  background-position: -384px -96px;
-}
-
-.icon-plus {
-  background-position: -408px -96px;
-}
-
-.icon-minus {
-  background-position: -433px -96px;
-}
-
-.icon-asterisk {
-  background-position: -456px -96px;
-}
-
-.icon-exclamation-sign {
-  background-position: 0 -120px;
-}
-
-.icon-gift {
-  background-position: -24px -120px;
-}
-
-.icon-leaf {
-  background-position: -48px -120px;
-}
-
-.icon-fire {
-  background-position: -72px -120px;
-}
-
-.icon-eye-open {
-  background-position: -96px -120px;
-}
-
-.icon-eye-close {
-  background-position: -120px -120px;
-}
-
-.icon-warning-sign {
-  background-position: -144px -120px;
-}
-
-.icon-plane {
-  background-position: -168px -120px;
-}
-
-.icon-calendar {
-  background-position: -192px -120px;
-}
-
-.icon-random {
-  background-position: -216px -120px;
-}
-
-.icon-comment {
-  background-position: -240px -120px;
-}
-
-.icon-magnet {
-  background-position: -264px -120px;
-}
-
-.icon-chevron-up {
-  background-position: -288px -120px;
-}
-
-.icon-chevron-down {
-  background-position: -313px -119px;
-}
-
-.icon-retweet {
-  background-position: -336px -120px;
-}
-
-.icon-shopping-cart {
-  background-position: -360px -120px;
-}
-
-.icon-folder-close {
-  background-position: -384px -120px;
-}
-
-.icon-folder-open {
-  background-position: -408px -120px;
-}
-
-.icon-resize-vertical {
-  background-position: -432px -119px;
-}
-
-.icon-resize-horizontal {
-  background-position: -456px -118px;
-}
-
-.icon-hdd {
-  background-position: 0 -144px;
-}
-
-.icon-bullhorn {
-  background-position: -24px -144px;
-}
-
-.icon-bell {
-  background-position: -48px -144px;
-}
-
-.icon-certificate {
-  background-position: -72px -144px;
-}
-
-.icon-thumbs-up {
-  background-position: -96px -144px;
-}
-
-.icon-thumbs-down {
-  background-position: -120px -144px;
-}
-
-.icon-hand-right {
-  background-position: -144px -144px;
-}
-
-.icon-hand-left {
-  background-position: -168px -144px;
-}
-
-.icon-hand-up {
-  background-position: -192px -144px;
-}
-
-.icon-hand-down {
-  background-position: -216px -144px;
-}
-
-.icon-circle-arrow-right {
-  background-position: -240px -144px;
-}
-
-.icon-circle-arrow-left {
-  background-position: -264px -144px;
-}
-
-.icon-circle-arrow-up {
-  background-position: -288px -144px;
-}
-
-.icon-circle-arrow-down {
-  background-position: -312px -144px;
-}
-
-.icon-globe {
-  background-position: -336px -144px;
-}
-
-.icon-wrench {
-  background-position: -360px -144px;
-}
-
-.icon-tasks {
-  background-position: -384px -144px;
-}
-
-.icon-filter {
-  background-position: -408px -144px;
-}
-
-.icon-briefcase {
-  background-position: -432px -144px;
-}
-
-.icon-fullscreen {
-  background-position: -456px -144px;
-}
-
-.dropup,
-.dropdown {
-  position: relative;
-}
-
-.dropdown-toggle {
-  *margin-bottom: -3px;
-}
-
-.dropdown-toggle:active,
-.open .dropdown-toggle {
-  outline: 0;
-}
-
-.caret {
-  display: inline-block;
-  width: 0;
-  height: 0;
-  vertical-align: top;
-  border-top: 4px solid #000000;
-  border-right: 4px solid transparent;
-  border-left: 4px solid transparent;
-  content: "";
-  opacity: 0.3;
-  filter: alpha(opacity=30);
-}
-
-.dropdown .caret {
-  margin-top: 8px;
-  margin-left: 2px;
-}
-
-.dropdown:hover .caret,
-.open .caret {
-  opacity: 1;
-  filter: alpha(opacity=100);
-}
-
-.dropdown-menu {
-  position: absolute;
-  top: 100%;
-  left: 0;
-  z-index: 1000;
-  display: none;
-  float: left;
-  min-width: 160px;
-  padding: 4px 0;
-  margin: 1px 0 0;
-  list-style: none;
-  background-color: #ffffff;
-  border: 1px solid #ccc;
-  border: 1px solid rgba(0, 0, 0, 0.2);
-  *border-right-width: 2px;
-  *border-bottom-width: 2px;
-  -webkit-border-radius: 5px;
-     -moz-border-radius: 5px;
-          border-radius: 5px;
-  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-     -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-          box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-  -webkit-background-clip: padding-box;
-     -moz-background-clip: padding;
-          background-clip: padding-box;
-}
-
-.dropdown-menu.pull-right {
-  right: 0;
-  left: auto;
-}
-
-.dropdown-menu .divider {
-  *width: 100%;
-  height: 1px;
-  margin: 8px 1px;
-  *margin: -5px 0 5px;
-  overflow: hidden;
-  background-color: #e5e5e5;
-  border-bottom: 1px solid #ffffff;
-}
-
-.dropdown-menu a {
-  display: block;
-  padding: 3px 15px;
-  clear: both;
-  font-weight: normal;
-  line-height: 18px;
-  color: #333333;
-  white-space: nowrap;
-}
-
-.dropdown-menu li > a:hover,
-.dropdown-menu .active > a,
-.dropdown-menu .active > a:hover {
-  color: #ffffff;
-  text-decoration: none;
-  background-color: #0088cc;
-}
-
-.open {
-  *z-index: 1000;
-}
-
-.open > .dropdown-menu {
-  display: block;
-}
-
-.pull-right > .dropdown-menu {
-  right: 0;
-  left: auto;
-}
-
-.dropup .caret,
-.navbar-fixed-bottom .dropdown .caret {
-  border-top: 0;
-  border-bottom: 4px solid #000000;
-  content: "\2191";
-}
-
-.dropup .dropdown-menu,
-.navbar-fixed-bottom .dropdown .dropdown-menu {
-  top: auto;
-  bottom: 100%;
-  margin-bottom: 1px;
-}
-
-.typeahead {
-  margin-top: 2px;
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-}
-
-.well {
-  min-height: 20px;
-  padding: 19px;
-  margin-bottom: 20px;
-  background-color: #f5f5f5;
-  border: 1px solid #eee;
-  border: 1px solid rgba(0, 0, 0, 0.05);
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
-     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
-          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
-}
-
-.well blockquote {
-  border-color: #ddd;
-  border-color: rgba(0, 0, 0, 0.15);
-}
-
-.well-large {
-  padding: 24px;
-  -webkit-border-radius: 6px;
-     -moz-border-radius: 6px;
-          border-radius: 6px;
-}
-
-.well-small {
-  padding: 9px;
-  -webkit-border-radius: 3px;
-     -moz-border-radius: 3px;
-          border-radius: 3px;
-}
-
-.fade {
-  opacity: 0;
-  -webkit-transition: opacity 0.15s linear;
-     -moz-transition: opacity 0.15s linear;
-      -ms-transition: opacity 0.15s linear;
-       -o-transition: opacity 0.15s linear;
-          transition: opacity 0.15s linear;
-}
-
-.fade.in {
-  opacity: 1;
-}
-
-.collapse {
-  position: relative;
-  height: 0;
-  overflow: hidden;
-  -webkit-transition: height 0.35s ease;
-     -moz-transition: height 0.35s ease;
-      -ms-transition: height 0.35s ease;
-       -o-transition: height 0.35s ease;
-          transition: height 0.35s ease;
-}
-
-.collapse.in {
-  height: auto;
-}
-
-.close {
-  float: right;
-  font-size: 20px;
-  font-weight: bold;
-  line-height: 18px;
-  color: #000000;
-  text-shadow: 0 1px 0 #ffffff;
-  opacity: 0.2;
-  filter: alpha(opacity=20);
-}
-
-.close:hover {
-  color: #000000;
-  text-decoration: none;
-  cursor: pointer;
-  opacity: 0.4;
-  filter: alpha(opacity=40);
-}
-
-button.close {
-  padding: 0;
-  cursor: pointer;
-  background: transparent;
-  border: 0;
-  -webkit-appearance: none;
-}
-
-.btn {
-  display: inline-block;
-  *display: inline;
-  padding: 4px 10px 4px;
-  margin-bottom: 0;
-  *margin-left: .3em;
-  font-size: 13px;
-  line-height: 18px;
-  *line-height: 20px;
-  color: #333333;
-  text-align: center;
-  text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
-  vertical-align: middle;
-  cursor: pointer;
-  background-color: #f5f5f5;
-  *background-color: #e6e6e6;
-  background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
-  background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
-  background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
-  background-image: linear-gradient(top, #ffffff, #e6e6e6);
-  background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
-  background-repeat: repeat-x;
-  border: 1px solid #cccccc;
-  *border: 0;
-  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
-  border-color: #e6e6e6 #e6e6e6 #bfbfbf;
-  border-bottom-color: #b3b3b3;
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);
-  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
-  *zoom: 1;
-  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
-     -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
-          box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
-}
-
-.btn:hover,
-.btn:active,
-.btn.active,
-.btn.disabled,
-.btn[disabled] {
-  background-color: #e6e6e6;
-  *background-color: #d9d9d9;
-}
-
-.btn:active,
-.btn.active {
-  background-color: #cccccc \9;
-}
-
-.btn:first-child {
-  *margin-left: 0;
-}
-
-.btn:hover {
-  color: #333333;
-  text-decoration: none;
-  background-color: #e6e6e6;
-  *background-color: #d9d9d9;
-  /* Buttons in IE7 don't get borders, so darken on hover */
-
-  background-position: 0 -15px;
-  -webkit-transition: background-position 0.1s linear;
-     -moz-transition: background-position 0.1s linear;
-      -ms-transition: background-position 0.1s linear;
-       -o-transition: background-position 0.1s linear;
-          transition: background-position 0.1s linear;
-}
-
-.btn:focus {
-  outline: thin dotted #333;
-  outline: 5px auto -webkit-focus-ring-color;
-  outline-offset: -2px;
-}
-
-.btn.active,
-.btn:active {
-  background-color: #e6e6e6;
-  background-color: #d9d9d9 \9;
-  background-image: none;
-  outline: 0;
-  -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
-     -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
-          box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
-}
-
-.btn.disabled,
-.btn[disabled] {
-  cursor: default;
-  background-color: #e6e6e6;
-  background-image: none;
-  opacity: 0.65;
-  filter: alpha(opacity=65);
-  -webkit-box-shadow: none;
-     -moz-box-shadow: none;
-          box-shadow: none;
-}
-
-.btn-large {
-  padding: 9px 14px;
-  font-size: 15px;
-  line-height: normal;
-  -webkit-border-radius: 5px;
-     -moz-border-radius: 5px;
-          border-radius: 5px;
-}
-
-.btn-large [class^="icon-"] {
-  margin-top: 1px;
-}
-
-.btn-small {
-  padding: 5px 9px;
-  font-size: 11px;
-  line-height: 16px;
-}
-
-.btn-small [class^="icon-"] {
-  margin-top: -1px;
-}
-
-.btn-mini {
-  padding: 2px 6px;
-  font-size: 11px;
-  line-height: 14px;
-}
-
-.btn-primary,
-.btn-primary:hover,
-.btn-warning,
-.btn-warning:hover,
-.btn-danger,
-.btn-danger:hover,
-.btn-success,
-.btn-success:hover,
-.btn-info,
-.btn-info:hover,
-.btn-inverse,
-.btn-inverse:hover {
-  color: #ffffff;
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
-}
-
-.btn-primary.active,
-.btn-warning.active,
-.btn-danger.active,
-.btn-success.active,
-.btn-info.active,
-.btn-inverse.active {
-  color: rgba(255, 255, 255, 0.75);
-}
-
-.btn {
-  border-color: #ccc;
-  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
-}
-
-.btn-primary {
-  background-color: #0074cc;
-  *background-color: #0055cc;
-  background-image: -ms-linear-gradient(top, #0088cc, #0055cc);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc));
-  background-image: -webkit-linear-gradient(top, #0088cc, #0055cc);
-  background-image: -o-linear-gradient(top, #0088cc, #0055cc);
-  background-image: -moz-linear-gradient(top, #0088cc, #0055cc);
-  background-image: linear-gradient(top, #0088cc, #0055cc);
-  background-repeat: repeat-x;
-  border-color: #0055cc #0055cc #003580;
-  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
-  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0);
-  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
-}
-
-.btn-primary:hover,
-.btn-primary:active,
-.btn-primary.active,
-.btn-primary.disabled,
-.btn-primary[disabled] {
-  background-color: #0055cc;
-  *background-color: #004ab3;
-}
-
-.btn-primary:active,
-.btn-primary.active {
-  background-color: #004099 \9;
-}
-
-.btn-warning {
-  background-color: #faa732;
-  *background-color: #f89406;
-  background-image: -ms-linear-gradient(top, #fbb450, #f89406);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));
-  background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
-  background-image: -o-linear-gradient(top, #fbb450, #f89406);
-  background-image: -moz-linear-gradient(top, #fbb450, #f89406);
-  background-image: linear-gradient(top, #fbb450, #f89406);
-  background-repeat: repeat-x;
-  border-color: #f89406 #f89406 #ad6704;
-  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
-  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);
-  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
-}
-
-.btn-warning:hover,
-.btn-warning:active,
-.btn-warning.active,
-.btn-warning.disabled,
-.btn-warning[disabled] {
-  background-color: #f89406;
-  *background-color: #df8505;
-}
-
-.btn-warning:active,
-.btn-warning.active {
-  background-color: #c67605 \9;
-}
-
-.btn-danger {
-  background-color: #da4f49;
-  *background-color: #bd362f;
-  background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));
-  background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f);
-  background-image: -o-linear-gradient(top, #ee5f5b, #bd362f);
-  background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f);
-  background-image: linear-gradient(top, #ee5f5b, #bd362f);
-  background-repeat: repeat-x;
-  border-color: #bd362f #bd362f #802420;
-  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
-  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);
-  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
-}
-
-.btn-danger:hover,
-.btn-danger:active,
-.btn-danger.active,
-.btn-danger.disabled,
-.btn-danger[disabled] {
-  background-color: #bd362f;
-  *background-color: #a9302a;
-}
-
-.btn-danger:active,
-.btn-danger.active {
-  background-color: #942a25 \9;
-}
-
-.btn-success {
-  background-color: #5bb75b;
-  *background-color: #51a351;
-  background-image: -ms-linear-gradient(top, #62c462, #51a351);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));
-  background-image: -webkit-linear-gradient(top, #62c462, #51a351);
-  background-image: -o-linear-gradient(top, #62c462, #51a351);
-  background-image: -moz-linear-gradient(top, #62c462, #51a351);
-  background-image: linear-gradient(top, #62c462, #51a351);
-  background-repeat: repeat-x;
-  border-color: #51a351 #51a351 #387038;
-  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
-  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);
-  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
-}
-
-.btn-success:hover,
-.btn-success:active,
-.btn-success.active,
-.btn-success.disabled,
-.btn-success[disabled] {
-  background-color: #51a351;
-  *background-color: #499249;
-}
-
-.btn-success:active,
-.btn-success.active {
-  background-color: #408140 \9;
-}
-
-.btn-info {
-  background-color: #49afcd;
-  *background-color: #2f96b4;
-  background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));
-  background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4);
-  background-image: -o-linear-gradient(top, #5bc0de, #2f96b4);
-  background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4);
-  background-image: linear-gradient(top, #5bc0de, #2f96b4);
-  background-repeat: repeat-x;
-  border-color: #2f96b4 #2f96b4 #1f6377;
-  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
-  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);
-  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
-}
-
-.btn-info:hover,
-.btn-info:active,
-.btn-info.active,
-.btn-info.disabled,
-.btn-info[disabled] {
-  background-color: #2f96b4;
-  *background-color: #2a85a0;
-}
-
-.btn-info:active,
-.btn-info.active {
-  background-color: #24748c \9;
-}
-
-.btn-inverse {
-  background-color: #414141;
-  *background-color: #222222;
-  background-image: -ms-linear-gradient(top, #555555, #222222);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222));
-  background-image: -webkit-linear-gradient(top, #555555, #222222);
-  background-image: -o-linear-gradient(top, #555555, #222222);
-  background-image: -moz-linear-gradient(top, #555555, #222222);
-  background-image: linear-gradient(top, #555555, #222222);
-  background-repeat: repeat-x;
-  border-color: #222222 #222222 #000000;
-  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
-  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0);
-  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
-}
-
-.btn-inverse:hover,
-.btn-inverse:active,
-.btn-inverse.active,
-.btn-inverse.disabled,
-.btn-inverse[disabled] {
-  background-color: #222222;
-  *background-color: #151515;
-}
-
-.btn-inverse:active,
-.btn-inverse.active {
-  background-color: #080808 \9;
-}
-
-button.btn,
-input[type="submit"].btn {
-  *padding-top: 2px;
-  *padding-bottom: 2px;
-}
-
-button.btn::-moz-focus-inner,
-input[type="submit"].btn::-moz-focus-inner {
-  padding: 0;
-  border: 0;
-}
-
-button.btn.btn-large,
-input[type="submit"].btn.btn-large {
-  *padding-top: 7px;
-  *padding-bottom: 7px;
-}
-
-button.btn.btn-small,
-input[type="submit"].btn.btn-small {
-  *padding-top: 3px;
-  *padding-bottom: 3px;
-}
-
-button.btn.btn-mini,
-input[type="submit"].btn.btn-mini {
-  *padding-top: 1px;
-  *padding-bottom: 1px;
-}
-
-.btn-group {
-  position: relative;
-  *margin-left: .3em;
-  *zoom: 1;
-}
-
-.btn-group:before,
-.btn-group:after {
-  display: table;
-  content: "";
-}
-
-.btn-group:after {
-  clear: both;
-}
-
-.btn-group:first-child {
-  *margin-left: 0;
-}
-
-.btn-group + .btn-group {
-  margin-left: 5px;
-}
-
-.btn-toolbar {
-  margin-top: 9px;
-  margin-bottom: 9px;
-}
-
-.btn-toolbar .btn-group {
-  display: inline-block;
-  *display: inline;
-  /* IE7 inline-block hack */
-
-  *zoom: 1;
-}
-
-.btn-group > .btn {
-  position: relative;
-  float: left;
-  margin-left: -1px;
-  -webkit-border-radius: 0;
-     -moz-border-radius: 0;
-          border-radius: 0;
-}
-
-.btn-group > .btn:first-child {
-  margin-left: 0;
-  -webkit-border-bottom-left-radius: 4px;
-          border-bottom-left-radius: 4px;
-  -webkit-border-top-left-radius: 4px;
-          border-top-left-radius: 4px;
-  -moz-border-radius-bottomleft: 4px;
-  -moz-border-radius-topleft: 4px;
-}
-
-.btn-group > .btn:last-child,
-.btn-group > .dropdown-toggle {
-  -webkit-border-top-right-radius: 4px;
-          border-top-right-radius: 4px;
-  -webkit-border-bottom-right-radius: 4px;
-          border-bottom-right-radius: 4px;
-  -moz-border-radius-topright: 4px;
-  -moz-border-radius-bottomright: 4px;
-}
-
-.btn-group > .btn.large:first-child {
-  margin-left: 0;
-  -webkit-border-bottom-left-radius: 6px;
-          border-bottom-left-radius: 6px;
-  -webkit-border-top-left-radius: 6px;
-          border-top-left-radius: 6px;
-  -moz-border-radius-bottomleft: 6px;
-  -moz-border-radius-topleft: 6px;
-}
-
-.btn-group > .btn.large:last-child,
-.btn-group > .large.dropdown-toggle {
-  -webkit-border-top-right-radius: 6px;
-          border-top-right-radius: 6px;
-  -webkit-border-bottom-right-radius: 6px;
-          border-bottom-right-radius: 6px;
-  -moz-border-radius-topright: 6px;
-  -moz-border-radius-bottomright: 6px;
-}
-
-.btn-group > .btn:hover,
-.btn-group > .btn:focus,
-.btn-group > .btn:active,
-.btn-group > .btn.active {
-  z-index: 2;
-}
-
-.btn-group .dropdown-toggle:active,
-.btn-group.open .dropdown-toggle {
-  outline: 0;
-}
-
-.btn-group > .dropdown-toggle {
-  *padding-top: 4px;
-  padding-right: 8px;
-  *padding-bottom: 4px;
-  padding-left: 8px;
-  -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
-     -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
-          box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
-}
-
-.btn-group > .btn-mini.dropdown-toggle {
-  padding-right: 5px;
-  padding-left: 5px;
-}
-
-.btn-group > .btn-small.dropdown-toggle {
-  *padding-top: 4px;
-  *padding-bottom: 4px;
-}
-
-.btn-group > .btn-large.dropdown-toggle {
-  padding-right: 12px;
-  padding-left: 12px;
-}
-
-.btn-group.open .dropdown-toggle {
-  background-image: none;
-  -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
-     -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
-          box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
-}
-
-.btn-group.open .btn.dropdown-toggle {
-  background-color: #e6e6e6;
-}
-
-.btn-group.open .btn-primary.dropdown-toggle {
-  background-color: #0055cc;
-}
-
-.btn-group.open .btn-warning.dropdown-toggle {
-  background-color: #f89406;
-}
-
-.btn-group.open .btn-danger.dropdown-toggle {
-  background-color: #bd362f;
-}
-
-.btn-group.open .btn-success.dropdown-toggle {
-  background-color: #51a351;
-}
-
-.btn-group.open .btn-info.dropdown-toggle {
-  background-color: #2f96b4;
-}
-
-.btn-group.open .btn-inverse.dropdown-toggle {
-  background-color: #222222;
-}
-
-.btn .caret {
-  margin-top: 7px;
-  margin-left: 0;
-}
-
-.btn:hover .caret,
-.open.btn-group .caret {
-  opacity: 1;
-  filter: alpha(opacity=100);
-}
-
-.btn-mini .caret {
-  margin-top: 5px;
-}
-
-.btn-small .caret {
-  margin-top: 6px;
-}
-
-.btn-large .caret {
-  margin-top: 6px;
-  border-top-width: 5px;
-  border-right-width: 5px;
-  border-left-width: 5px;
-}
-
-.dropup .btn-large .caret {
-  border-top: 0;
-  border-bottom: 5px solid #000000;
-}
-
-.btn-primary .caret,
-.btn-warning .caret,
-.btn-danger .caret,
-.btn-info .caret,
-.btn-success .caret,
-.btn-inverse .caret {
-  border-top-color: #ffffff;
-  border-bottom-color: #ffffff;
-  opacity: 0.75;
-  filter: alpha(opacity=75);
-}
-
-.alert {
-  padding: 8px 35px 8px 14px;
-  margin-bottom: 18px;
-  color: #c09853;
-  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
-  background-color: #fcf8e3;
-  border: 1px solid #fbeed5;
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-}
-
-.alert-heading {
-  color: inherit;
-}
-
-.alert .close {
-  position: relative;
-  top: -2px;
-  right: -21px;
-  line-height: 18px;
-}
-
-.alert-success {
-  color: #468847;
-  background-color: #dff0d8;
-  border-color: #d6e9c6;
-}
-
-.alert-danger,
-.alert-error {
-  color: #b94a48;
-  background-color: #f2dede;
-  border-color: #eed3d7;
-}
-
-.alert-info {
-  color: #3a87ad;
-  background-color: #d9edf7;
-  border-color: #bce8f1;
-}
-
-.alert-block {
-  padding-top: 14px;
-  padding-bottom: 14px;
-}
-
-.alert-block > p,
-.alert-block > ul {
-  margin-bottom: 0;
-}
-
-.alert-block p + p {
-  margin-top: 5px;
-}
-
-.nav {
-  margin-bottom: 18px;
-  margin-left: 0;
-  list-style: none;
-}
-
-.nav > li > a {
-  display: block;
-}
-
-.nav > li > a:hover {
-  text-decoration: none;
-  background-color: #eeeeee;
-}
-
-.nav > .pull-right {
-  float: right;
-}
-
-.nav .nav-header {
-  display: block;
-  padding: 3px 15px;
-  font-size: 11px;
-  font-weight: bold;
-  line-height: 18px;
-  color: #999999;
-  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
-  text-transform: uppercase;
-}
-
-.nav li + .nav-header {
-  margin-top: 9px;
-}
-
-.nav-list {
-  padding-right: 15px;
-  padding-left: 15px;
-  margin-bottom: 0;
-}
-
-.nav-list > li > a,
-.nav-list .nav-header {
-  margin-right: -15px;
-  margin-left: -15px;
-  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
-}
-
-.nav-list > li > a {
-  padding: 3px 15px;
-}
-
-.nav-list > .active > a,
-.nav-list > .active > a:hover {
-  color: #ffffff;
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
-  background-color: #0088cc;
-}
-
-.nav-list [class^="icon-"] {
-  margin-right: 2px;
-}
-
-.nav-list .divider {
-  *width: 100%;
-  height: 1px;
-  margin: 8px 1px;
-  *margin: -5px 0 5px;
-  overflow: hidden;
-  background-color: #e5e5e5;
-  border-bottom: 1px solid #ffffff;
-}
-
-.nav-tabs,
-.nav-pills {
-  *zoom: 1;
-}
-
-.nav-tabs:before,
-.nav-pills:before,
-.nav-tabs:after,
-.nav-pills:after {
-  display: table;
-  content: "";
-}
-
-.nav-tabs:after,
-.nav-pills:after {
-  clear: both;
-}
-
-.nav-tabs > li,
-.nav-pills > li {
-  float: left;
-}
-
-.nav-tabs > li > a,
-.nav-pills > li > a {
-  padding-right: 12px;
-  padding-left: 12px;
-  margin-right: 2px;
-  line-height: 14px;
-}
-
-.nav-tabs {
-  border-bottom: 1px solid #ddd;
-}
-
-.nav-tabs > li {
-  margin-bottom: -1px;
-}
-
-.nav-tabs > li > a {
-  padding-top: 8px;
-  padding-bottom: 8px;
-  line-height: 18px;
-  border: 1px solid transparent;
-  -webkit-border-radius: 4px 4px 0 0;
-     -moz-border-radius: 4px 4px 0 0;
-          border-radius: 4px 4px 0 0;
-}
-
-.nav-tabs > li > a:hover {
-  border-color: #eeeeee #eeeeee #dddddd;
-}
-
-.nav-tabs > .active > a,
-.nav-tabs > .active > a:hover {
-  color: #555555;
-  cursor: default;
-  background-color: #ffffff;
-  border: 1px solid #ddd;
-  border-bottom-color: transparent;
-}
-
-.nav-pills > li > a {
-  padding-top: 8px;
-  padding-bottom: 8px;
-  margin-top: 2px;
-  margin-bottom: 2px;
-  -webkit-border-radius: 5px;
-     -moz-border-radius: 5px;
-          border-radius: 5px;
-}
-
-.nav-pills > .active > a,
-.nav-pills > .active > a:hover {
-  color: #ffffff;
-  background-color: #0088cc;
-}
-
-.nav-stacked > li {
-  float: none;
-}
-
-.nav-stacked > li > a {
-  margin-right: 0;
-}
-
-.nav-tabs.nav-stacked {
-  border-bottom: 0;
-}
-
-.nav-tabs.nav-stacked > li > a {
-  border: 1px solid #ddd;
-  -webkit-border-radius: 0;
-     -moz-border-radius: 0;
-          border-radius: 0;
-}
-
-.nav-tabs.nav-stacked > li:first-child > a {
-  -webkit-border-radius: 4px 4px 0 0;
-     -moz-border-radius: 4px 4px 0 0;
-          border-radius: 4px 4px 0 0;
-}
-
-.nav-tabs.nav-stacked > li:last-child > a {
-  -webkit-border-radius: 0 0 4px 4px;
-     -moz-border-radius: 0 0 4px 4px;
-          border-radius: 0 0 4px 4px;
-}
-
-.nav-tabs.nav-stacked > li > a:hover {
-  z-index: 2;
-  border-color: #ddd;
-}
-
-.nav-pills.nav-stacked > li > a {
-  margin-bottom: 3px;
-}
-
-.nav-pills.nav-stacked > li:last-child > a {
-  margin-bottom: 1px;
-}
-
-.nav-tabs .dropdown-menu {
-  -webkit-border-radius: 0 0 5px 5px;
-     -moz-border-radius: 0 0 5px 5px;
-          border-radius: 0 0 5px 5px;
-}
-
-.nav-pills .dropdown-menu {
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-}
-
-.nav-tabs .dropdown-toggle .caret,
-.nav-pills .dropdown-toggle .caret {
-  margin-top: 6px;
-  border-top-color: #0088cc;
-  border-bottom-color: #0088cc;
-}
-
-.nav-tabs .dropdown-toggle:hover .caret,
-.nav-pills .dropdown-toggle:hover .caret {
-  border-top-color: #005580;
-  border-bottom-color: #005580;
-}
-
-.nav-tabs .active .dropdown-toggle .caret,
-.nav-pills .active .dropdown-toggle .caret {
-  border-top-color: #333333;
-  border-bottom-color: #333333;
-}
-
-.nav > .dropdown.active > a:hover {
-  color: #000000;
-  cursor: pointer;
-}
-
-.nav-tabs .open .dropdown-toggle,
-.nav-pills .open .dropdown-toggle,
-.nav > li.dropdown.open.active > a:hover {
-  color: #ffffff;
-  background-color: #999999;
-  border-color: #999999;
-}
-
-.nav li.dropdown.open .caret,
-.nav li.dropdown.open.active .caret,
-.nav li.dropdown.open a:hover .caret {
-  border-top-color: #ffffff;
-  border-bottom-color: #ffffff;
-  opacity: 1;
-  filter: alpha(opacity=100);
-}
-
-.tabs-stacked .open > a:hover {
-  border-color: #999999;
-}
-
-.tabbable {
-  *zoom: 1;
-}
-
-.tabbable:before,
-.tabbable:after {
-  display: table;
-  content: "";
-}
-
-.tabbable:after {
-  clear: both;
-}
-
-.tab-content {
-  overflow: auto;
-}
-
-.tabs-below > .nav-tabs,
-.tabs-right > .nav-tabs,
-.tabs-left > .nav-tabs {
-  border-bottom: 0;
-}
-
-.tab-content > .tab-pane,
-.pill-content > .pill-pane {
-  display: none;
-}
-
-.tab-content > .active,
-.pill-content > .active {
-  display: block;
-}
-
-.tabs-below > .nav-tabs {
-  border-top: 1px solid #ddd;
-}
-
-.tabs-below > .nav-tabs > li {
-  margin-top: -1px;
-  margin-bottom: 0;
-}
-
-.tabs-below > .nav-tabs > li > a {
-  -webkit-border-radius: 0 0 4px 4px;
-     -moz-border-radius: 0 0 4px 4px;
-          border-radius: 0 0 4px 4px;
-}
-
-.tabs-below > .nav-tabs > li > a:hover {
-  border-top-color: #ddd;
-  border-bottom-color: transparent;
-}
-
-.tabs-below > .nav-tabs > .active > a,
-.tabs-below > .nav-tabs > .active > a:hover {
-  border-color: transparent #ddd #ddd #ddd;
-}
-
-.tabs-left > .nav-tabs > li,
-.tabs-right > .nav-tabs > li {
+table .span17 {
   float: none;
+  width: 1324px;
+  margin-left: 0;
 }
-
-.tabs-left > .nav-tabs > li > a,
-.tabs-right > .nav-tabs > li > a {
-  min-width: 74px;
-  margin-right: 0;
-  margin-bottom: 3px;
-}
-
-.tabs-left > .nav-tabs {
-  float: left;
-  margin-right: 19px;
-  border-right: 1px solid #ddd;
-}
-
-.tabs-left > .nav-tabs > li > a {
-  margin-right: -1px;
-  -webkit-border-radius: 4px 0 0 4px;
-     -moz-border-radius: 4px 0 0 4px;
-          border-radius: 4px 0 0 4px;
-}
-
-.tabs-left > .nav-tabs > li > a:hover {
-  border-color: #eeeeee #dddddd #eeeeee #eeeeee;
-}
-
-.tabs-left > .nav-tabs .active > a,
-.tabs-left > .nav-tabs .active > a:hover {
-  border-color: #ddd transparent #ddd #ddd;
-  *border-right-color: #ffffff;
-}
-
-.tabs-right > .nav-tabs {
-  float: right;
-  margin-left: 19px;
-  border-left: 1px solid #ddd;
-}
-
-.tabs-right > .nav-tabs > li > a {
-  margin-left: -1px;
-  -webkit-border-radius: 0 4px 4px 0;
-     -moz-border-radius: 0 4px 4px 0;
-          border-radius: 0 4px 4px 0;
+table .span18 {
+  float: none;
+  width: 1404px;
+  margin-left: 0;
 }
-
-.tabs-right > .nav-tabs > li > a:hover {
-  border-color: #eeeeee #eeeeee #eeeeee #dddddd;
+table .span19 {
+  float: none;
+  width: 1484px;
+  margin-left: 0;
 }
-
-.tabs-right > .nav-tabs .active > a,
-.tabs-right > .nav-tabs .active > a:hover {
-  border-color: #ddd #ddd #ddd transparent;
-  *border-left-color: #ffffff;
+table .span20 {
+  float: none;
+  width: 1564px;
+  margin-left: 0;
 }
-
-.navbar {
-  *position: relative;
-  *z-index: 2;
-  margin-bottom: 18px;
-  overflow: visible;
+table .span21 {
+  float: none;
+  width: 1644px;
+  margin-left: 0;
 }
-
-.navbar-inner {
-  min-height: 40px;
-  padding-right: 20px;
-  padding-left: 20px;
-  background-color: #2c2c2c;
-  background-image: -moz-linear-gradient(top, #333333, #222222);
-  background-image: -ms-linear-gradient(top, #333333, #222222);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));
-  background-image: -webkit-linear-gradient(top, #333333, #222222);
-  background-image: -o-linear-gradient(top, #333333, #222222);
-  background-image: linear-gradient(top, #333333, #222222);
-  background-repeat: repeat-x;
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);
-  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
-     -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
-          box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
+table .span22 {
+  float: none;
+  width: 1724px;
+  margin-left: 0;
 }
-
-.navbar .container {
-  width: auto;
+table .span23 {
+  float: none;
+  width: 1804px;
+  margin-left: 0;
 }
-
-.nav-collapse.collapse {
-  height: auto;
+table .span24 {
+  float: none;
+  width: 1884px;
+  margin-left: 0;
 }
-
-.navbar {
-  color: #999999;
+form {
+  margin: 0 0 18px;
 }
-
-.navbar .brand:hover {
-  text-decoration: none;
+fieldset {
+  padding: 0;
+  margin: 0;
+  border: 0;
 }
-
-.navbar .brand {
+legend {
   display: block;
-  float: left;
-  padding: 8px 20px 12px;
-  margin-left: -20px;
-  font-size: 20px;
-  font-weight: 200;
-  line-height: 1;
+  width: 100%;
+  padding: 0;
+  margin-bottom: 27px;
+  font-size: 19.5px;
+  line-height: 36px;
+  color: #333333;
+  border: 0;
+  border-bottom: 1px solid #e5e5e5;
+}
+legend small {
+  font-size: 13.5px;
   color: #999999;
 }
-
-.navbar .navbar-text {
-  margin-bottom: 0;
-  line-height: 40px;
+label,
+input,
+button,
+select,
+textarea {
+  font-size: 13px;
+  font-weight: normal;
+  line-height: 18px;
 }
-
-.navbar .navbar-link {
-  color: #999999;
+input,
+button,
+select,
+textarea {
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
 }
-
-.navbar .navbar-link:hover {
-  color: #ffffff;
+label {
+  display: block;
+  margin-bottom: 5px;
 }
-
-.navbar .btn,
-.navbar .btn-group {
-  margin-top: 5px;
+select,
+textarea,
+input[type="text"],
+input[type="password"],
+input[type="datetime"],
+input[type="datetime-local"],
+input[type="date"],
+input[type="month"],
+input[type="time"],
+input[type="week"],
+input[type="number"],
+input[type="email"],
+input[type="url"],
+input[type="search"],
+input[type="tel"],
+input[type="color"],
+.uneditable-input {
+  display: inline-block;
+  height: 18px;
+  padding: 4px;
+  margin-bottom: 9px;
+  font-size: 13px;
+  line-height: 18px;
+  color: #555555;
 }
-
-.navbar .btn-group .btn {
-  margin: 0;
+input,
+textarea {
+  width: 210px;
 }
-
-.navbar-form {
-  margin-bottom: 0;
-  *zoom: 1;
+textarea {
+  height: auto;
 }
-
-.navbar-form:before,
-.navbar-form:after {
-  display: table;
-  content: "";
+textarea,
+input[type="text"],
+input[type="password"],
+input[type="datetime"],
+input[type="datetime-local"],
+input[type="date"],
+input[type="month"],
+input[type="time"],
+input[type="week"],
+input[type="number"],
+input[type="email"],
+input[type="url"],
+input[type="search"],
+input[type="tel"],
+input[type="color"],
+.uneditable-input {
+  background-color: #ffffff;
+  border: 1px solid #cccccc;
+  -webkit-border-radius: 3px;
+  -moz-border-radius: 3px;
+  border-radius: 3px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  -webkit-transition: border linear 0.2s, box-shadow linear 0.2s;
+  -moz-transition: border linear 0.2s, box-shadow linear 0.2s;
+  -ms-transition: border linear 0.2s, box-shadow linear 0.2s;
+  -o-transition: border linear 0.2s, box-shadow linear 0.2s;
+  transition: border linear 0.2s, box-shadow linear 0.2s;
 }
+textarea:focus,
+input[type="text"]:focus,
+input[type="password"]:focus,
+input[type="datetime"]:focus,
+input[type="datetime-local"]:focus,
+input[type="date"]:focus,
+input[type="month"]:focus,
+input[type="time"]:focus,
+input[type="week"]:focus,
+input[type="number"]:focus,
+input[type="email"]:focus,
+input[type="url"]:focus,
+input[type="search"]:focus,
+input[type="tel"]:focus,
+input[type="color"]:focus,
+.uneditable-input:focus {
+  border-color: rgba(82, 168, 236, 0.8);
+  outline: 0;
+  outline: thin dotted \9;
+  /* IE6-9 */
 
-.navbar-form:after {
-  clear: both;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);
+  -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);
+  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);
 }
+input[type="radio"],
+input[type="checkbox"] {
+  margin: 3px 0;
+  *margin-top: 0;
+  /* IE7 */
 
-.navbar-form input,
-.navbar-form select,
-.navbar-form .radio,
-.navbar-form .checkbox {
-  margin-top: 5px;
+  line-height: normal;
+  cursor: pointer;
 }
-
-.navbar-form input,
-.navbar-form select {
-  display: inline-block;
-  margin-bottom: 0;
+input[type="submit"],
+input[type="reset"],
+input[type="button"],
+input[type="radio"],
+input[type="checkbox"] {
+  width: auto;
 }
-
-.navbar-form input[type="image"],
-.navbar-form input[type="checkbox"],
-.navbar-form input[type="radio"] {
-  margin-top: 3px;
+.uneditable-textarea {
+  width: auto;
+  height: auto;
 }
+select,
+input[type="file"] {
+  height: 28px;
+  /* In IE7, the height of the select element cannot be changed by height, only font-size */
 
-.navbar-form .input-append,
-.navbar-form .input-prepend {
-  margin-top: 6px;
-  white-space: nowrap;
-}
+  *margin-top: 4px;
+  /* For IE7, add top margin to align select with labels */
 
-.navbar-form .input-append input,
-.navbar-form .input-prepend input {
-  margin-top: 0;
+  line-height: 28px;
 }
-
-.navbar-search {
-  position: relative;
-  float: left;
-  margin-top: 6px;
-  margin-bottom: 0;
+select {
+  width: 220px;
+  border: 1px solid #bbb;
 }
-
-.navbar-search .search-query {
-  padding: 4px 9px;
-  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
-  font-size: 13px;
-  font-weight: normal;
-  line-height: 1;
-  color: #ffffff;
-  background-color: #626262;
-  border: 1px solid #151515;
-  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);
-     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);
-          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);
-  -webkit-transition: none;
-     -moz-transition: none;
-      -ms-transition: none;
-       -o-transition: none;
-          transition: none;
+select[multiple],
+select[size] {
+  height: auto;
 }
-
-.navbar-search .search-query:-moz-placeholder {
-  color: #cccccc;
+select:focus,
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+  outline: thin dotted #333;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
 }
-
-.navbar-search .search-query:-ms-input-placeholder {
-  color: #cccccc;
+.radio,
+.checkbox {
+  min-height: 18px;
+  padding-left: 18px;
 }
-
-.navbar-search .search-query::-webkit-input-placeholder {
-  color: #cccccc;
+.radio input[type="radio"],
+.checkbox input[type="checkbox"] {
+  float: left;
+  margin-left: -18px;
 }
-
-.navbar-search .search-query:focus,
-.navbar-search .search-query.focused {
-  padding: 5px 10px;
-  color: #333333;
-  text-shadow: 0 1px 0 #ffffff;
-  background-color: #ffffff;
-  border: 0;
-  outline: 0;
-  -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
-     -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
-          box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
+.controls > .radio:first-child,
+.controls > .checkbox:first-child {
+  padding-top: 5px;
 }
-
-.navbar-fixed-top,
-.navbar-fixed-bottom {
-  position: fixed;
-  right: 0;
-  left: 0;
-  z-index: 1030;
+.radio.inline,
+.checkbox.inline {
+  display: inline-block;
+  padding-top: 5px;
   margin-bottom: 0;
+  vertical-align: middle;
 }
-
-.navbar-fixed-top .navbar-inner,
-.navbar-fixed-bottom .navbar-inner {
-  padding-right: 0;
-  padding-left: 0;
-  -webkit-border-radius: 0;
-     -moz-border-radius: 0;
-          border-radius: 0;
+.radio.inline + .radio.inline,
+.checkbox.inline + .checkbox.inline {
+  margin-left: 10px;
 }
-
-.navbar-fixed-top .container,
-.navbar-fixed-bottom .container {
-  width: 940px;
+.input-mini {
+  width: 60px;
 }
-
-.navbar-fixed-top {
-  top: 0;
+.input-small {
+  width: 90px;
 }
-
-.navbar-fixed-bottom {
-  bottom: 0;
+.input-medium {
+  width: 150px;
 }
-
-.navbar .nav {
-  position: relative;
-  left: 0;
-  display: block;
-  float: left;
-  margin: 0 10px 0 0;
+.input-large {
+  width: 210px;
 }
-
-.navbar .nav.pull-right {
-  float: right;
+.input-xlarge {
+  width: 270px;
 }
-
-.navbar .nav > li {
-  display: block;
-  float: left;
+.input-xxlarge {
+  width: 530px;
 }
-
-.navbar .nav > li > a {
+input[class*="span"],
+select[class*="span"],
+textarea[class*="span"],
+.uneditable-input[class*="span"],
+.row-fluid input[class*="span"],
+.row-fluid select[class*="span"],
+.row-fluid textarea[class*="span"],
+.row-fluid .uneditable-input[class*="span"] {
   float: none;
-  padding: 9px 10px 11px;
-  line-height: 19px;
-  color: #999999;
-  text-decoration: none;
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+  margin-left: 0;
 }
-
-.navbar .btn {
+.input-append input[class*="span"],
+.input-append .uneditable-input[class*="span"],
+.input-prepend input[class*="span"],
+.input-prepend .uneditable-input[class*="span"],
+.row-fluid .input-prepend [class*="span"],
+.row-fluid .input-append [class*="span"] {
   display: inline-block;
-  padding: 4px 10px 4px;
-  margin: 5px 5px 6px;
-  line-height: 18px;
-}
-
-.navbar .btn-group {
-  padding: 5px 5px 6px;
-  margin: 0;
 }
-
-.navbar .nav > li > a:hover {
-  color: #ffffff;
-  text-decoration: none;
-  background-color: transparent;
-}
-
-.navbar .nav .active > a,
-.navbar .nav .active > a:hover {
-  color: #ffffff;
-  text-decoration: none;
-  background-color: #222222;
+input,
+textarea,
+.uneditable-input {
+  margin-left: 0;
 }
-
-.navbar .divider-vertical {
-  width: 1px;
-  height: 40px;
-  margin: 0 9px;
-  overflow: hidden;
-  background-color: #222222;
-  border-right: 1px solid #333333;
+input.span12, textarea.span12, .uneditable-input.span12 {
+  width: 930px;
 }
-
-.navbar .nav.pull-right {
-  margin-right: 0;
-  margin-left: 10px;
+input.span11, textarea.span11, .uneditable-input.span11 {
+  width: 850px;
 }
-
-.navbar .btn-navbar {
-  display: none;
-  float: right;
-  padding: 7px 10px;
-  margin-right: 5px;
-  margin-left: 5px;
-  background-color: #2c2c2c;
-  *background-color: #222222;
-  background-image: -ms-linear-gradient(top, #333333, #222222);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));
-  background-image: -webkit-linear-gradient(top, #333333, #222222);
-  background-image: -o-linear-gradient(top, #333333, #222222);
-  background-image: linear-gradient(top, #333333, #222222);
-  background-image: -moz-linear-gradient(top, #333333, #222222);
-  background-repeat: repeat-x;
-  border-color: #222222 #222222 #000000;
-  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
-  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);
-  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
-  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
-     -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
-          box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
+input.span10, textarea.span10, .uneditable-input.span10 {
+  width: 770px;
 }
-
-.navbar .btn-navbar:hover,
-.navbar .btn-navbar:active,
-.navbar .btn-navbar.active,
-.navbar .btn-navbar.disabled,
-.navbar .btn-navbar[disabled] {
-  background-color: #222222;
-  *background-color: #151515;
+input.span9, textarea.span9, .uneditable-input.span9 {
+  width: 690px;
 }
-
-.navbar .btn-navbar:active,
-.navbar .btn-navbar.active {
-  background-color: #080808 \9;
+input.span8, textarea.span8, .uneditable-input.span8 {
+  width: 610px;
 }
-
-.navbar .btn-navbar .icon-bar {
-  display: block;
-  width: 18px;
-  height: 2px;
-  background-color: #f5f5f5;
-  -webkit-border-radius: 1px;
-     -moz-border-radius: 1px;
-          border-radius: 1px;
-  -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
-     -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
-          box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
+input.span7, textarea.span7, .uneditable-input.span7 {
+  width: 530px;
 }
-
-.btn-navbar .icon-bar + .icon-bar {
-  margin-top: 3px;
+input.span6, textarea.span6, .uneditable-input.span6 {
+  width: 450px;
 }
-
-.navbar .dropdown-menu:before {
-  position: absolute;
-  top: -7px;
-  left: 9px;
-  display: inline-block;
-  border-right: 7px solid transparent;
-  border-bottom: 7px solid #ccc;
-  border-left: 7px solid transparent;
-  border-bottom-color: rgba(0, 0, 0, 0.2);
-  content: '';
+input.span5, textarea.span5, .uneditable-input.span5 {
+  width: 370px;
 }
-
-.navbar .dropdown-menu:after {
-  position: absolute;
-  top: -6px;
-  left: 10px;
-  display: inline-block;
-  border-right: 6px solid transparent;
-  border-bottom: 6px solid #ffffff;
-  border-left: 6px solid transparent;
-  content: '';
+input.span4, textarea.span4, .uneditable-input.span4 {
+  width: 290px;
 }
-
-.navbar-fixed-bottom .dropdown-menu:before {
-  top: auto;
-  bottom: -7px;
-  border-top: 7px solid #ccc;
-  border-bottom: 0;
-  border-top-color: rgba(0, 0, 0, 0.2);
+input.span3, textarea.span3, .uneditable-input.span3 {
+  width: 210px;
 }
-
-.navbar-fixed-bottom .dropdown-menu:after {
-  top: auto;
-  bottom: -6px;
-  border-top: 6px solid #ffffff;
-  border-bottom: 0;
+input.span2, textarea.span2, .uneditable-input.span2 {
+  width: 130px;
 }
-
-.navbar .nav li.dropdown .dropdown-toggle .caret,
-.navbar .nav li.dropdown.open .caret {
-  border-top-color: #ffffff;
-  border-bottom-color: #ffffff;
+input.span1, textarea.span1, .uneditable-input.span1 {
+  width: 50px;
 }
-
-.navbar .nav li.dropdown.active .caret {
-  opacity: 1;
-  filter: alpha(opacity=100);
+input[disabled],
+select[disabled],
+textarea[disabled],
+input[readonly],
+select[readonly],
+textarea[readonly] {
+  cursor: not-allowed;
+  background-color: #eeeeee;
+  border-color: #ddd;
 }
-
-.navbar .nav li.dropdown.open > .dropdown-toggle,
-.navbar .nav li.dropdown.active > .dropdown-toggle,
-.navbar .nav li.dropdown.open.active > .dropdown-toggle {
+input[type="radio"][disabled],
+input[type="checkbox"][disabled],
+input[type="radio"][readonly],
+input[type="checkbox"][readonly] {
   background-color: transparent;
 }
-
-.navbar .nav li.dropdown.active > .dropdown-toggle:hover {
-  color: #ffffff;
-}
-
-.navbar .pull-right .dropdown-menu,
-.navbar .dropdown-menu.pull-right {
-  right: 0;
-  left: auto;
-}
-
-.navbar .pull-right .dropdown-menu:before,
-.navbar .dropdown-menu.pull-right:before {
-  right: 12px;
-  left: auto;
-}
-
-.navbar .pull-right .dropdown-menu:after,
-.navbar .dropdown-menu.pull-right:after {
-  right: 13px;
-  left: auto;
-}
-
-.breadcrumb {
-  padding: 7px 14px;
-  margin: 0 0 18px;
-  list-style: none;
-  background-color: #fbfbfb;
-  background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5);
-  background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5));
-  background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5);
-  background-image: -o-linear-gradient(top, #ffffff, #f5f5f5);
-  background-image: linear-gradient(top, #ffffff, #f5f5f5);
-  background-repeat: repeat-x;
-  border: 1px solid #ddd;
-  -webkit-border-radius: 3px;
-     -moz-border-radius: 3px;
-          border-radius: 3px;
-  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);
-  -webkit-box-shadow: inset 0 1px 0 #ffffff;
-     -moz-box-shadow: inset 0 1px 0 #ffffff;
-          box-shadow: inset 0 1px 0 #ffffff;
-}
-
-.breadcrumb li {
-  display: inline-block;
-  *display: inline;
-  text-shadow: 0 1px 0 #ffffff;
-  *zoom: 1;
+.control-group.warning > label,
+.control-group.warning .help-block,
+.control-group.warning .help-inline {
+  color: #c09853;
 }
-
-.breadcrumb .divider {
-  padding: 0 5px;
-  color: #999999;
+.control-group.warning .checkbox,
+.control-group.warning .radio,
+.control-group.warning input,
+.control-group.warning select,
+.control-group.warning textarea {
+  color: #c09853;
+  border-color: #c09853;
 }
-
-.breadcrumb .active a {
-  color: #333333;
+.control-group.warning .checkbox:focus,
+.control-group.warning .radio:focus,
+.control-group.warning input:focus,
+.control-group.warning select:focus,
+.control-group.warning textarea:focus {
+  border-color: #a47e3c;
+  -webkit-box-shadow: 0 0 6px #dbc59e;
+  -moz-box-shadow: 0 0 6px #dbc59e;
+  box-shadow: 0 0 6px #dbc59e;
 }
-
-.pagination {
-  height: 36px;
-  margin: 18px 0;
+.control-group.warning .input-prepend .add-on,
+.control-group.warning .input-append .add-on {
+  color: #c09853;
+  background-color: #fcf8e3;
+  border-color: #c09853;
 }
-
-.pagination ul {
-  display: inline-block;
-  *display: inline;
-  margin-bottom: 0;
-  margin-left: 0;
-  -webkit-border-radius: 3px;
-     -moz-border-radius: 3px;
-          border-radius: 3px;
-  *zoom: 1;
-  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
-     -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
-          box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+.control-group.error > label,
+.control-group.error .help-block,
+.control-group.error .help-inline {
+  color: #b94a48;
 }
-
-.pagination li {
-  display: inline;
+.control-group.error .checkbox,
+.control-group.error .radio,
+.control-group.error input,
+.control-group.error select,
+.control-group.error textarea {
+  color: #b94a48;
+  border-color: #b94a48;
 }
-
-.pagination a {
-  float: left;
-  padding: 0 14px;
-  line-height: 34px;
-  text-decoration: none;
-  border: 1px solid #ddd;
-  border-left-width: 0;
+.control-group.error .checkbox:focus,
+.control-group.error .radio:focus,
+.control-group.error input:focus,
+.control-group.error select:focus,
+.control-group.error textarea:focus {
+  border-color: #953b39;
+  -webkit-box-shadow: 0 0 6px #d59392;
+  -moz-box-shadow: 0 0 6px #d59392;
+  box-shadow: 0 0 6px #d59392;
 }
-
-.pagination a:hover,
-.pagination .active a {
-  background-color: #f5f5f5;
+.control-group.error .input-prepend .add-on,
+.control-group.error .input-append .add-on {
+  color: #b94a48;
+  background-color: #f2dede;
+  border-color: #b94a48;
 }
-
-.pagination .active a {
-  color: #999999;
-  cursor: default;
+.control-group.success > label,
+.control-group.success .help-block,
+.control-group.success .help-inline {
+  color: #468847;
 }
-
-.pagination .disabled span,
-.pagination .disabled a,
-.pagination .disabled a:hover {
-  color: #999999;
-  cursor: default;
-  background-color: transparent;
+.control-group.success .checkbox,
+.control-group.success .radio,
+.control-group.success input,
+.control-group.success select,
+.control-group.success textarea {
+  color: #468847;
+  border-color: #468847;
 }
-
-.pagination li:first-child a {
-  border-left-width: 1px;
-  -webkit-border-radius: 3px 0 0 3px;
-     -moz-border-radius: 3px 0 0 3px;
-          border-radius: 3px 0 0 3px;
+.control-group.success .checkbox:focus,
+.control-group.success .radio:focus,
+.control-group.success input:focus,
+.control-group.success select:focus,
+.control-group.success textarea:focus {
+  border-color: #356635;
+  -webkit-box-shadow: 0 0 6px #7aba7b;
+  -moz-box-shadow: 0 0 6px #7aba7b;
+  box-shadow: 0 0 6px #7aba7b;
 }
-
-.pagination li:last-child a {
-  -webkit-border-radius: 0 3px 3px 0;
-     -moz-border-radius: 0 3px 3px 0;
-          border-radius: 0 3px 3px 0;
+.control-group.success .input-prepend .add-on,
+.control-group.success .input-append .add-on {
+  color: #468847;
+  background-color: #dff0d8;
+  border-color: #468847;
 }
-
-.pagination-centered {
-  text-align: center;
+input:focus:required:invalid,
+textarea:focus:required:invalid,
+select:focus:required:invalid {
+  color: #b94a48;
+  border-color: #ee5f5b;
 }
-
-.pagination-right {
-  text-align: right;
+input:focus:required:invalid:focus,
+textarea:focus:required:invalid:focus,
+select:focus:required:invalid:focus {
+  border-color: #e9322d;
+  -webkit-box-shadow: 0 0 6px #f8b9b7;
+  -moz-box-shadow: 0 0 6px #f8b9b7;
+  box-shadow: 0 0 6px #f8b9b7;
 }
-
-.pager {
+.form-actions {
+  padding: 17px 20px 18px;
+  margin-top: 18px;
   margin-bottom: 18px;
-  margin-left: 0;
-  text-align: center;
-  list-style: none;
+  background-color: #f5f5f5;
+  border-top: 1px solid #e5e5e5;
   *zoom: 1;
 }
-
-.pager:before,
-.pager:after {
+.form-actions:before,
+.form-actions:after {
   display: table;
   content: "";
 }
-
-.pager:after {
+.form-actions:after {
   clear: both;
 }
-
-.pager li {
-  display: inline;
+.uneditable-input {
+  overflow: hidden;
+  white-space: nowrap;
+  cursor: not-allowed;
+  background-color: #ffffff;
+  border-color: #eee;
+  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
+  -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
+  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
 }
-
-.pager a {
-  display: inline-block;
-  padding: 5px 14px;
-  background-color: #fff;
-  border: 1px solid #ddd;
-  -webkit-border-radius: 15px;
-     -moz-border-radius: 15px;
-          border-radius: 15px;
+:-moz-placeholder {
+  color: #999999;
 }
-
-.pager a:hover {
-  text-decoration: none;
-  background-color: #f5f5f5;
+:-ms-input-placeholder {
+  color: #999999;
 }
-
-.pager .next a {
-  float: right;
+::-webkit-input-placeholder {
+  color: #999999;
 }
-
-.pager .previous a {
-  float: left;
+.help-block,
+.help-inline {
+  color: #555555;
 }
-
-.pager .disabled a,
-.pager .disabled a:hover {
-  color: #999999;
-  cursor: default;
-  background-color: #fff;
+.help-block {
+  display: block;
+  margin-bottom: 9px;
 }
+.help-inline {
+  display: inline-block;
+  *display: inline;
+  /* IE7 inline-block hack */
 
-.modal-open .dropdown-menu {
-  z-index: 2050;
+  *zoom: 1;
+  vertical-align: middle;
+  padding-left: 5px;
 }
-
-.modal-open .dropdown.open {
-  *z-index: 2050;
+.input-prepend,
+.input-append {
+  margin-bottom: 5px;
 }
-
-.modal-open .popover {
-  z-index: 2060;
+.input-prepend input,
+.input-append input,
+.input-prepend select,
+.input-append select,
+.input-prepend .uneditable-input,
+.input-append .uneditable-input {
+  position: relative;
+  margin-bottom: 0;
+  *margin-left: 0;
+  vertical-align: middle;
+  -webkit-border-radius: 0 3px 3px 0;
+  -moz-border-radius: 0 3px 3px 0;
+  border-radius: 0 3px 3px 0;
 }
-
-.modal-open .tooltip {
-  z-index: 2070;
+.input-prepend input:focus,
+.input-append input:focus,
+.input-prepend select:focus,
+.input-append select:focus,
+.input-prepend .uneditable-input:focus,
+.input-append .uneditable-input:focus {
+  z-index: 2;
 }
-
-.modal-backdrop {
-  position: fixed;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  z-index: 1040;
-  background-color: #000000;
+.input-prepend .uneditable-input,
+.input-append .uneditable-input {
+  border-left-color: #ccc;
 }
-
-.modal-backdrop.fade {
-  opacity: 0;
+.input-prepend .add-on,
+.input-append .add-on {
+  display: inline-block;
+  width: auto;
+  height: 18px;
+  min-width: 16px;
+  padding: 4px 5px;
+  font-weight: normal;
+  line-height: 18px;
+  text-align: center;
+  text-shadow: 0 1px 0 #ffffff;
+  vertical-align: middle;
+  background-color: #eeeeee;
+  border: 1px solid #ccc;
 }
-
-.modal-backdrop,
-.modal-backdrop.fade.in {
-  opacity: 0.8;
-  filter: alpha(opacity=80);
+.input-prepend .add-on,
+.input-append .add-on,
+.input-prepend .btn,
+.input-append .btn {
+  margin-left: -1px;
+  -webkit-border-radius: 0;
+  -moz-border-radius: 0;
+  border-radius: 0;
 }
-
-.modal {
-  position: fixed;
-  top: 50%;
-  left: 50%;
-  z-index: 1050;
-  width: 560px;
-  margin: -250px 0 0 -280px;
-  overflow: auto;
-  background-color: #ffffff;
-  border: 1px solid #999;
-  border: 1px solid rgba(0, 0, 0, 0.3);
-  *border: 1px solid #999;
-  -webkit-border-radius: 6px;
-     -moz-border-radius: 6px;
-          border-radius: 6px;
-  -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
-     -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
-          box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
-  -webkit-background-clip: padding-box;
-     -moz-background-clip: padding-box;
-          background-clip: padding-box;
+.input-prepend .active,
+.input-append .active {
+  background-color: #a9dba9;
+  border-color: #46a546;
 }
-
-.modal.fade {
-  top: -25%;
-  -webkit-transition: opacity 0.3s linear, top 0.3s ease-out;
-     -moz-transition: opacity 0.3s linear, top 0.3s ease-out;
-      -ms-transition: opacity 0.3s linear, top 0.3s ease-out;
-       -o-transition: opacity 0.3s linear, top 0.3s ease-out;
-          transition: opacity 0.3s linear, top 0.3s ease-out;
+.input-prepend .add-on,
+.input-prepend .btn {
+  margin-right: -1px;
 }
-
-.modal.fade.in {
-  top: 50%;
+.input-prepend .add-on:first-child,
+.input-prepend .btn:first-child {
+  -webkit-border-radius: 3px 0 0 3px;
+  -moz-border-radius: 3px 0 0 3px;
+  border-radius: 3px 0 0 3px;
 }
-
-.modal-header {
-  padding: 9px 15px;
-  border-bottom: 1px solid #eee;
+.input-append input,
+.input-append select,
+.input-append .uneditable-input {
+  -webkit-border-radius: 3px 0 0 3px;
+  -moz-border-radius: 3px 0 0 3px;
+  border-radius: 3px 0 0 3px;
 }
-
-.modal-header .close {
-  margin-top: 2px;
+.input-append .uneditable-input {
+  border-right-color: #ccc;
+  border-left-color: #eee;
 }
-
-.modal-body {
-  max-height: 400px;
-  padding: 15px;
-  overflow-y: auto;
+.input-append .add-on:last-child,
+.input-append .btn:last-child {
+  -webkit-border-radius: 0 3px 3px 0;
+  -moz-border-radius: 0 3px 3px 0;
+  border-radius: 0 3px 3px 0;
 }
-
-.modal-form {
-  margin-bottom: 0;
+.input-prepend.input-append input,
+.input-prepend.input-append select,
+.input-prepend.input-append .uneditable-input {
+  -webkit-border-radius: 0;
+  -moz-border-radius: 0;
+  border-radius: 0;
 }
-
-.modal-footer {
-  padding: 14px 15px 15px;
-  margin-bottom: 0;
-  text-align: right;
-  background-color: #f5f5f5;
-  border-top: 1px solid #ddd;
-  -webkit-border-radius: 0 0 6px 6px;
-     -moz-border-radius: 0 0 6px 6px;
-          border-radius: 0 0 6px 6px;
-  *zoom: 1;
-  -webkit-box-shadow: inset 0 1px 0 #ffffff;
-     -moz-box-shadow: inset 0 1px 0 #ffffff;
-          box-shadow: inset 0 1px 0 #ffffff;
+.input-prepend.input-append .add-on:first-child,
+.input-prepend.input-append .btn:first-child {
+  margin-right: -1px;
+  -webkit-border-radius: 3px 0 0 3px;
+  -moz-border-radius: 3px 0 0 3px;
+  border-radius: 3px 0 0 3px;
 }
-
-.modal-footer:before,
-.modal-footer:after {
-  display: table;
-  content: "";
+.input-prepend.input-append .add-on:last-child,
+.input-prepend.input-append .btn:last-child {
+  margin-left: -1px;
+  -webkit-border-radius: 0 3px 3px 0;
+  -moz-border-radius: 0 3px 3px 0;
+  border-radius: 0 3px 3px 0;
 }
+.search-query {
+  padding-right: 14px;
+  padding-right: 4px \9;
+  padding-left: 14px;
+  padding-left: 4px \9;
+  /* IE7-8 doesn't have border-radius, so don't indent the padding */
 
-.modal-footer:after {
-  clear: both;
+  margin-bottom: 0;
+  -webkit-border-radius: 14px;
+  -moz-border-radius: 14px;
+  border-radius: 14px;
 }
+.form-search input,
+.form-inline input,
+.form-horizontal input,
+.form-search textarea,
+.form-inline textarea,
+.form-horizontal textarea,
+.form-search select,
+.form-inline select,
+.form-horizontal select,
+.form-search .help-inline,
+.form-inline .help-inline,
+.form-horizontal .help-inline,
+.form-search .uneditable-input,
+.form-inline .uneditable-input,
+.form-horizontal .uneditable-input,
+.form-search .input-prepend,
+.form-inline .input-prepend,
+.form-horizontal .input-prepend,
+.form-search .input-append,
+.form-inline .input-append,
+.form-horizontal .input-append {
+  display: inline-block;
+  *display: inline;
+  /* IE7 inline-block hack */
 
-.modal-footer .btn + .btn {
+  *zoom: 1;
   margin-bottom: 0;
-  margin-left: 5px;
 }
-
-.modal-footer .btn-group .btn + .btn {
-  margin-left: -1px;
+.form-search .hide,
+.form-inline .hide,
+.form-horizontal .hide {
+  display: none;
 }
-
-.tooltip {
-  position: absolute;
-  z-index: 1020;
-  display: block;
-  padding: 5px;
-  font-size: 11px;
-  opacity: 0;
-  filter: alpha(opacity=0);
-  visibility: visible;
+.form-search label,
+.form-inline label {
+  display: inline-block;
 }
-
-.tooltip.in {
-  opacity: 0.8;
-  filter: alpha(opacity=80);
+.form-search .input-append,
+.form-inline .input-append,
+.form-search .input-prepend,
+.form-inline .input-prepend {
+  margin-bottom: 0;
 }
-
-.tooltip.top {
-  margin-top: -2px;
+.form-search .radio,
+.form-search .checkbox,
+.form-inline .radio,
+.form-inline .checkbox {
+  padding-left: 0;
+  margin-bottom: 0;
+  vertical-align: middle;
 }
-
-.tooltip.right {
-  margin-left: 2px;
+.form-search .radio input[type="radio"],
+.form-search .checkbox input[type="checkbox"],
+.form-inline .radio input[type="radio"],
+.form-inline .checkbox input[type="checkbox"] {
+  float: left;
+  margin-right: 3px;
+  margin-left: 0;
 }
-
-.tooltip.bottom {
-  margin-top: 2px;
+.control-group {
+  margin-bottom: 9px;
 }
-
-.tooltip.left {
-  margin-left: -2px;
+legend + .control-group {
+  margin-top: 18px;
+  -webkit-margin-top-collapse: separate;
 }
-
-.tooltip.top .tooltip-arrow {
-  bottom: 0;
-  left: 50%;
-  margin-left: -5px;
-  border-top: 5px solid #000000;
-  border-right: 5px solid transparent;
-  border-left: 5px solid transparent;
+.form-horizontal .control-group {
+  margin-bottom: 18px;
+  *zoom: 1;
 }
-
-.tooltip.left .tooltip-arrow {
-  top: 50%;
-  right: 0;
-  margin-top: -5px;
-  border-top: 5px solid transparent;
-  border-bottom: 5px solid transparent;
-  border-left: 5px solid #000000;
+.form-horizontal .control-group:before,
+.form-horizontal .control-group:after {
+  display: table;
+  content: "";
 }
-
-.tooltip.bottom .tooltip-arrow {
-  top: 0;
-  left: 50%;
-  margin-left: -5px;
-  border-right: 5px solid transparent;
-  border-bottom: 5px solid #000000;
-  border-left: 5px solid transparent;
+.form-horizontal .control-group:after {
+  clear: both;
 }
-
-.tooltip.right .tooltip-arrow {
-  top: 50%;
-  left: 0;
-  margin-top: -5px;
-  border-top: 5px solid transparent;
-  border-right: 5px solid #000000;
-  border-bottom: 5px solid transparent;
+.form-horizontal .control-label {
+  float: left;
+  width: 140px;
+  padding-top: 5px;
+  text-align: right;
 }
-
-.tooltip-inner {
-  max-width: 200px;
-  padding: 3px 8px;
-  color: #ffffff;
-  text-align: center;
-  text-decoration: none;
-  background-color: #000000;
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
+.form-horizontal .controls {
+  *display: inline-block;
+  *padding-left: 20px;
+  margin-left: 160px;
+  *margin-left: 0;
 }
-
-.tooltip-arrow {
-  position: absolute;
-  width: 0;
-  height: 0;
+.form-horizontal .controls:first-child {
+  *padding-left: 160px;
 }
-
-.popover {
-  position: absolute;
-  top: 0;
-  left: 0;
-  z-index: 1010;
-  display: none;
-  padding: 5px;
+.form-horizontal .help-block {
+  margin-top: 9px;
+  margin-bottom: 0;
 }
-
-.popover.top {
-  margin-top: -5px;
+.form-horizontal .form-actions {
+  padding-left: 160px;
 }
-
-.popover.right {
-  margin-left: 5px;
+.nav {
+  margin-left: 0;
+  margin-bottom: 18px;
+  list-style: none;
 }
-
-.popover.bottom {
-  margin-top: 5px;
+.nav > li > a {
+  display: block;
 }
-
-.popover.left {
-  margin-left: -5px;
+.nav > li > a:hover {
+  text-decoration: none;
+  background-color: #eeeeee;
 }
-
-.popover.top .arrow {
-  bottom: 0;
-  left: 50%;
-  margin-left: -5px;
-  border-top: 5px solid #000000;
-  border-right: 5px solid transparent;
-  border-left: 5px solid transparent;
+.nav > .pull-right {
+  float: right;
 }
-
-.popover.right .arrow {
-  top: 50%;
-  left: 0;
-  margin-top: -5px;
-  border-top: 5px solid transparent;
-  border-right: 5px solid #000000;
-  border-bottom: 5px solid transparent;
+.nav .nav-header {
+  display: block;
+  padding: 3px 15px;
+  font-size: 11px;
+  font-weight: bold;
+  line-height: 18px;
+  color: #999999;
+  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+  text-transform: uppercase;
 }
-
-.popover.bottom .arrow {
-  top: 0;
-  left: 50%;
-  margin-left: -5px;
-  border-right: 5px solid transparent;
-  border-bottom: 5px solid #000000;
-  border-left: 5px solid transparent;
+.nav li + .nav-header {
+  margin-top: 9px;
 }
-
-.popover.left .arrow {
-  top: 50%;
-  right: 0;
-  margin-top: -5px;
-  border-top: 5px solid transparent;
-  border-bottom: 5px solid transparent;
-  border-left: 5px solid #000000;
+.nav-list {
+  padding-left: 15px;
+  padding-right: 15px;
+  margin-bottom: 0;
 }
-
-.popover .arrow {
-  position: absolute;
-  width: 0;
-  height: 0;
+.nav-list > li > a,
+.nav-list .nav-header {
+  margin-left: -15px;
+  margin-right: -15px;
+  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
 }
-
-.popover-inner {
-  width: 280px;
-  padding: 3px;
-  overflow: hidden;
-  background: #000000;
-  background: rgba(0, 0, 0, 0.8);
-  -webkit-border-radius: 6px;
-     -moz-border-radius: 6px;
-          border-radius: 6px;
-  -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
-     -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
-          box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+.nav-list > li > a {
+  padding: 3px 15px;
 }
-
-.popover-title {
-  padding: 9px 15px;
-  line-height: 1;
-  background-color: #f5f5f5;
-  border-bottom: 1px solid #eee;
-  -webkit-border-radius: 3px 3px 0 0;
-     -moz-border-radius: 3px 3px 0 0;
-          border-radius: 3px 3px 0 0;
+.nav-list > .active > a,
+.nav-list > .active > a:hover {
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
+  background-color: #0088cc;
 }
-
-.popover-content {
-  padding: 14px;
-  background-color: #ffffff;
-  -webkit-border-radius: 0 0 3px 3px;
-     -moz-border-radius: 0 0 3px 3px;
-          border-radius: 0 0 3px 3px;
-  -webkit-background-clip: padding-box;
-     -moz-background-clip: padding-box;
-          background-clip: padding-box;
+.nav-list [class^="icon-"] {
+  margin-right: 2px;
 }
-
-.popover-content p,
-.popover-content ul,
-.popover-content ol {
-  margin-bottom: 0;
+.nav-list .divider {
+  *width: 100%;
+  height: 1px;
+  margin: 8px 1px;
+  *margin: -5px 0 5px;
+  overflow: hidden;
+  background-color: #e5e5e5;
+  border-bottom: 1px solid #ffffff;
 }
-
-.thumbnails {
-  margin-left: -20px;
-  list-style: none;
+.nav-tabs,
+.nav-pills {
   *zoom: 1;
 }
-
-.thumbnails:before,
-.thumbnails:after {
+.nav-tabs:before,
+.nav-pills:before,
+.nav-tabs:after,
+.nav-pills:after {
   display: table;
   content: "";
 }
-
-.thumbnails:after {
+.nav-tabs:after,
+.nav-pills:after {
   clear: both;
 }
-
-.row-fluid .thumbnails {
-  margin-left: 0;
-}
-
-.thumbnails > li {
+.nav-tabs > li,
+.nav-pills > li {
   float: left;
-  margin-bottom: 18px;
-  margin-left: 20px;
-}
-
-.thumbnail {
-  display: block;
-  padding: 4px;
-  line-height: 1;
-  border: 1px solid #ddd;
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);
-     -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);
-          box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);
-}
-
-a.thumbnail:hover {
-  border-color: #0088cc;
-  -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
-     -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
-          box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
-}
-
-.thumbnail > img {
-  display: block;
-  max-width: 100%;
-  margin-right: auto;
-  margin-left: auto;
 }
-
-.thumbnail .caption {
-  padding: 9px;
-}
-
-.label,
-.badge {
-  font-size: 10.998px;
-  font-weight: bold;
+.nav-tabs > li > a,
+.nav-pills > li > a {
+  padding-right: 12px;
+  padding-left: 12px;
+  margin-right: 2px;
   line-height: 14px;
-  color: #ffffff;
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
-  white-space: nowrap;
-  vertical-align: baseline;
-  background-color: #999999;
-}
-
-.label {
-  padding: 1px 4px 2px;
-  -webkit-border-radius: 3px;
-     -moz-border-radius: 3px;
-          border-radius: 3px;
 }
-
-.badge {
-  padding: 1px 9px 2px;
-  -webkit-border-radius: 9px;
-     -moz-border-radius: 9px;
-          border-radius: 9px;
+.nav-tabs {
+  border-bottom: 1px solid #ddd;
 }
-
-a.label:hover,
-a.badge:hover {
-  color: #ffffff;
-  text-decoration: none;
-  cursor: pointer;
+.nav-tabs > li {
+  margin-bottom: -1px;
 }
-
-.label-important,
-.badge-important {
-  background-color: #b94a48;
+.nav-tabs > li > a {
+  padding-top: 8px;
+  padding-bottom: 8px;
+  line-height: 18px;
+  border: 1px solid transparent;
+  -webkit-border-radius: 4px 4px 0 0;
+  -moz-border-radius: 4px 4px 0 0;
+  border-radius: 4px 4px 0 0;
 }
-
-.label-important[href],
-.badge-important[href] {
-  background-color: #953b39;
+.nav-tabs > li > a:hover {
+  border-color: #eeeeee #eeeeee #dddddd;
 }
-
-.label-warning,
-.badge-warning {
-  background-color: #f89406;
+.nav-tabs > .active > a,
+.nav-tabs > .active > a:hover {
+  color: #555555;
+  background-color: #ffffff;
+  border: 1px solid #ddd;
+  border-bottom-color: transparent;
+  cursor: default;
 }
-
-.label-warning[href],
-.badge-warning[href] {
-  background-color: #c67605;
+.nav-pills > li > a {
+  padding-top: 8px;
+  padding-bottom: 8px;
+  margin-top: 2px;
+  margin-bottom: 2px;
+  -webkit-border-radius: 5px;
+  -moz-border-radius: 5px;
+  border-radius: 5px;
 }
-
-.label-success,
-.badge-success {
-  background-color: #468847;
+.nav-pills > .active > a,
+.nav-pills > .active > a:hover {
+  color: #ffffff;
+  background-color: #0088cc;
 }
-
-.label-success[href],
-.badge-success[href] {
-  background-color: #356635;
+.nav-stacked > li {
+  float: none;
 }
-
-.label-info,
-.badge-info {
-  background-color: #3a87ad;
+.nav-stacked > li > a {
+  margin-right: 0;
 }
-
-.label-info[href],
-.badge-info[href] {
-  background-color: #2d6987;
+.nav-tabs.nav-stacked {
+  border-bottom: 0;
 }
-
-.label-inverse,
-.badge-inverse {
-  background-color: #333333;
+.nav-tabs.nav-stacked > li > a {
+  border: 1px solid #ddd;
+  -webkit-border-radius: 0;
+  -moz-border-radius: 0;
+  border-radius: 0;
 }
-
-.label-inverse[href],
-.badge-inverse[href] {
-  background-color: #1a1a1a;
+.nav-tabs.nav-stacked > li:first-child > a {
+  -webkit-border-radius: 4px 4px 0 0;
+  -moz-border-radius: 4px 4px 0 0;
+  border-radius: 4px 4px 0 0;
 }
-
-@-webkit-keyframes progress-bar-stripes {
-  from {
-    background-position: 40px 0;
-  }
-  to {
-    background-position: 0 0;
-  }
+.nav-tabs.nav-stacked > li:last-child > a {
+  -webkit-border-radius: 0 0 4px 4px;
+  -moz-border-radius: 0 0 4px 4px;
+  border-radius: 0 0 4px 4px;
 }
-
-@-moz-keyframes progress-bar-stripes {
-  from {
-    background-position: 40px 0;
-  }
-  to {
-    background-position: 0 0;
-  }
+.nav-tabs.nav-stacked > li > a:hover {
+  border-color: #ddd;
+  z-index: 2;
 }
-
-@-ms-keyframes progress-bar-stripes {
-  from {
-    background-position: 40px 0;
-  }
-  to {
-    background-position: 0 0;
-  }
+.nav-pills.nav-stacked > li > a {
+  margin-bottom: 3px;
 }
-
-@-o-keyframes progress-bar-stripes {
-  from {
-    background-position: 0 0;
-  }
-  to {
-    background-position: 40px 0;
-  }
+.nav-pills.nav-stacked > li:last-child > a {
+  margin-bottom: 1px;
 }
-
-@keyframes progress-bar-stripes {
-  from {
-    background-position: 40px 0;
-  }
-  to {
-    background-position: 0 0;
-  }
+.nav-tabs .dropdown-menu {
+  -webkit-border-radius: 0 0 5px 5px;
+  -moz-border-radius: 0 0 5px 5px;
+  border-radius: 0 0 5px 5px;
 }
-
-.progress {
-  height: 18px;
-  margin-bottom: 18px;
-  overflow: hidden;
-  background-color: #f7f7f7;
-  background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9);
-  background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));
-  background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9);
-  background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9);
-  background-image: linear-gradient(top, #f5f5f5, #f9f9f9);
-  background-repeat: repeat-x;
+.nav-pills .dropdown-menu {
   -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
-  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);
-  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
-     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
-          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
-}
-
-.progress .bar {
-  width: 0;
-  height: 18px;
-  font-size: 12px;
-  color: #ffffff;
-  text-align: center;
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
-  background-color: #0e90d2;
-  background-image: -moz-linear-gradient(top, #149bdf, #0480be);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));
-  background-image: -webkit-linear-gradient(top, #149bdf, #0480be);
-  background-image: -o-linear-gradient(top, #149bdf, #0480be);
-  background-image: linear-gradient(top, #149bdf, #0480be);
-  background-image: -ms-linear-gradient(top, #149bdf, #0480be);
-  background-repeat: repeat-x;
-  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);
-  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
-     -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
-          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
-  -webkit-box-sizing: border-box;
-     -moz-box-sizing: border-box;
-      -ms-box-sizing: border-box;
-          box-sizing: border-box;
-  -webkit-transition: width 0.6s ease;
-     -moz-transition: width 0.6s ease;
-      -ms-transition: width 0.6s ease;
-       -o-transition: width 0.6s ease;
-          transition: width 0.6s ease;
-}
-
-.progress-striped .bar {
-  background-color: #149bdf;
-  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
-  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  -webkit-background-size: 40px 40px;
-     -moz-background-size: 40px 40px;
-       -o-background-size: 40px 40px;
-          background-size: 40px 40px;
+  -moz-border-radius: 4px;
+  border-radius: 4px;
 }
-
-.progress.active .bar {
-  -webkit-animation: progress-bar-stripes 2s linear infinite;
-     -moz-animation: progress-bar-stripes 2s linear infinite;
-      -ms-animation: progress-bar-stripes 2s linear infinite;
-       -o-animation: progress-bar-stripes 2s linear infinite;
-          animation: progress-bar-stripes 2s linear infinite;
+.nav-tabs .dropdown-toggle .caret,
+.nav-pills .dropdown-toggle .caret {
+  border-top-color: #0088cc;
+  border-bottom-color: #0088cc;
+  margin-top: 6px;
 }
-
-.progress-danger .bar {
-  background-color: #dd514c;
-  background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
-  background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));
-  background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
-  background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
-  background-image: linear-gradient(top, #ee5f5b, #c43c35);
-  background-repeat: repeat-x;
-  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);
+.nav-tabs .dropdown-toggle:hover .caret,
+.nav-pills .dropdown-toggle:hover .caret {
+  border-top-color: #005580;
+  border-bottom-color: #005580;
 }
-
-.progress-danger.progress-striped .bar {
-  background-color: #ee5f5b;
-  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
-  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+.nav-tabs .active .dropdown-toggle .caret,
+.nav-pills .active .dropdown-toggle .caret {
+  border-top-color: #333333;
+  border-bottom-color: #333333;
 }
-
-.progress-success .bar {
-  background-color: #5eb95e;
-  background-image: -moz-linear-gradient(top, #62c462, #57a957);
-  background-image: -ms-linear-gradient(top, #62c462, #57a957);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));
-  background-image: -webkit-linear-gradient(top, #62c462, #57a957);
-  background-image: -o-linear-gradient(top, #62c462, #57a957);
-  background-image: linear-gradient(top, #62c462, #57a957);
-  background-repeat: repeat-x;
-  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);
+.nav > .dropdown.active > a:hover {
+  color: #000000;
+  cursor: pointer;
 }
-
-.progress-success.progress-striped .bar {
-  background-color: #62c462;
-  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
-  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+.nav-tabs .open .dropdown-toggle,
+.nav-pills .open .dropdown-toggle,
+.nav > li.dropdown.open.active > a:hover {
+  color: #ffffff;
+  background-color: #999999;
+  border-color: #999999;
 }
-
-.progress-info .bar {
-  background-color: #4bb1cf;
-  background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
-  background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));
-  background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
-  background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
-  background-image: linear-gradient(top, #5bc0de, #339bb9);
-  background-repeat: repeat-x;
-  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);
+.nav li.dropdown.open .caret,
+.nav li.dropdown.open.active .caret,
+.nav li.dropdown.open a:hover .caret {
+  border-top-color: #ffffff;
+  border-bottom-color: #ffffff;
+  opacity: 1;
+  filter: alpha(opacity=100);
 }
-
-.progress-info.progress-striped .bar {
-  background-color: #5bc0de;
-  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
-  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+.tabs-stacked .open > a:hover {
+  border-color: #999999;
 }
-
-.progress-warning .bar {
-  background-color: #faa732;
-  background-image: -moz-linear-gradient(top, #fbb450, #f89406);
-  background-image: -ms-linear-gradient(top, #fbb450, #f89406);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));
-  background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
-  background-image: -o-linear-gradient(top, #fbb450, #f89406);
-  background-image: linear-gradient(top, #fbb450, #f89406);
-  background-repeat: repeat-x;
-  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);
+.tabbable {
+  *zoom: 1;
 }
-
-.progress-warning.progress-striped .bar {
-  background-color: #fbb450;
-  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
-  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+.tabbable:before,
+.tabbable:after {
+  display: table;
+  content: "";
 }
-
-.accordion {
-  margin-bottom: 18px;
+.tabbable:after {
+  clear: both;
 }
-
-.accordion-group {
-  margin-bottom: 2px;
-  border: 1px solid #e5e5e5;
-  -webkit-border-radius: 4px;
-     -moz-border-radius: 4px;
-          border-radius: 4px;
+.tab-content {
+  overflow: auto;
 }
-
-.accordion-heading {
+.tabs-below > .nav-tabs,
+.tabs-right > .nav-tabs,
+.tabs-left > .nav-tabs {
   border-bottom: 0;
 }
-
-.accordion-heading .accordion-toggle {
+.tab-content > .tab-pane,
+.pill-content > .pill-pane {
+  display: none;
+}
+.tab-content > .active,
+.pill-content > .active {
   display: block;
-  padding: 8px 15px;
 }
-
-.accordion-toggle {
-  cursor: pointer;
+.tabs-below > .nav-tabs {
+  border-top: 1px solid #ddd;
 }
-
-.accordion-inner {
-  padding: 9px 15px;
-  border-top: 1px solid #e5e5e5;
+.tabs-below > .nav-tabs > li {
+  margin-top: -1px;
+  margin-bottom: 0;
 }
-
-.carousel {
-  position: relative;
-  margin-bottom: 18px;
-  line-height: 1;
+.tabs-below > .nav-tabs > li > a {
+  -webkit-border-radius: 0 0 4px 4px;
+  -moz-border-radius: 0 0 4px 4px;
+  border-radius: 0 0 4px 4px;
 }
-
-.carousel-inner {
-  position: relative;
-  width: 100%;
-  overflow: hidden;
+.tabs-below > .nav-tabs > li > a:hover {
+  border-bottom-color: transparent;
+  border-top-color: #ddd;
 }
-
-.carousel .item {
-  position: relative;
-  display: none;
-  -webkit-transition: 0.6s ease-in-out left;
-     -moz-transition: 0.6s ease-in-out left;
-      -ms-transition: 0.6s ease-in-out left;
-       -o-transition: 0.6s ease-in-out left;
-          transition: 0.6s ease-in-out left;
+.tabs-below > .nav-tabs > .active > a,
+.tabs-below > .nav-tabs > .active > a:hover {
+  border-color: transparent #ddd #ddd #ddd;
 }
-
-.carousel .item > img {
-  display: block;
-  line-height: 1;
+.tabs-left > .nav-tabs > li,
+.tabs-right > .nav-tabs > li {
+  float: none;
 }
-
-.carousel .active,
-.carousel .next,
-.carousel .prev {
-  display: block;
+.tabs-left > .nav-tabs > li > a,
+.tabs-right > .nav-tabs > li > a {
+  min-width: 74px;
+  margin-right: 0;
+  margin-bottom: 3px;
 }
-
-.carousel .active {
-  left: 0;
+.tabs-left > .nav-tabs {
+  float: left;
+  margin-right: 19px;
+  border-right: 1px solid #ddd;
 }
-
-.carousel .next,
-.carousel .prev {
-  position: absolute;
-  top: 0;
-  width: 100%;
+.tabs-left > .nav-tabs > li > a {
+  margin-right: -1px;
+  -webkit-border-radius: 4px 0 0 4px;
+  -moz-border-radius: 4px 0 0 4px;
+  border-radius: 4px 0 0 4px;
 }
-
-.carousel .next {
-  left: 100%;
+.tabs-left > .nav-tabs > li > a:hover {
+  border-color: #eeeeee #dddddd #eeeeee #eeeeee;
 }
-
-.carousel .prev {
-  left: -100%;
+.tabs-left > .nav-tabs .active > a,
+.tabs-left > .nav-tabs .active > a:hover {
+  border-color: #ddd transparent #ddd #ddd;
+  *border-right-color: #ffffff;
 }
-
-.carousel .next.left,
-.carousel .prev.right {
-  left: 0;
+.tabs-right > .nav-tabs {
+  float: right;
+  margin-left: 19px;
+  border-left: 1px solid #ddd;
 }
-
-.carousel .active.left {
-  left: -100%;
+.tabs-right > .nav-tabs > li > a {
+  margin-left: -1px;
+  -webkit-border-radius: 0 4px 4px 0;
+  -moz-border-radius: 0 4px 4px 0;
+  border-radius: 0 4px 4px 0;
 }
-
-.carousel .active.right {
-  left: 100%;
+.tabs-right > .nav-tabs > li > a:hover {
+  border-color: #eeeeee #eeeeee #eeeeee #dddddd;
 }
-
-.carousel-control {
-  position: absolute;
-  top: 40%;
-  left: 15px;
-  width: 40px;
-  height: 40px;
-  margin-top: -20px;
-  font-size: 60px;
-  font-weight: 100;
-  line-height: 30px;
-  color: #ffffff;
-  text-align: center;
-  background: #222222;
-  border: 3px solid #ffffff;
-  -webkit-border-radius: 23px;
-     -moz-border-radius: 23px;
-          border-radius: 23px;
-  opacity: 0.5;
-  filter: alpha(opacity=50);
+.tabs-right > .nav-tabs .active > a,
+.tabs-right > .nav-tabs .active > a:hover {
+  border-color: #ddd #ddd #ddd transparent;
+  *border-left-color: #ffffff;
 }
-
-.carousel-control.right {
-  right: 15px;
-  left: auto;
+.pagination {
+  height: 36px;
+  margin: 18px 0;
 }
+.pagination ul {
+  display: inline-block;
+  *display: inline;
+  /* IE7 inline-block hack */
 
-.carousel-control:hover {
-  color: #ffffff;
+  *zoom: 1;
+  margin-left: 0;
+  margin-bottom: 0;
+  -webkit-border-radius: 3px;
+  -moz-border-radius: 3px;
+  border-radius: 3px;
+  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+  -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+.pagination li {
+  display: inline;
+}
+.pagination a {
+  float: left;
+  padding: 0 14px;
+  line-height: 34px;
   text-decoration: none;
-  opacity: 0.9;
-  filter: alpha(opacity=90);
+  border: 1px solid #ddd;
+  border-left-width: 0;
 }
-
-.carousel-caption {
-  position: absolute;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  padding: 10px 15px 5px;
-  background: #333333;
-  background: rgba(0, 0, 0, 0.75);
+.pagination a:hover,
+.pagination .active a {
+  background-color: #f5f5f5;
 }
-
-.carousel-caption h4,
-.carousel-caption p {
-  color: #ffffff;
+.pagination .active a {
+  color: #999999;
+  cursor: default;
 }
-
-.hero-unit {
-  padding: 60px;
-  margin-bottom: 30px;
-  background-color: #eeeeee;
-  -webkit-border-radius: 6px;
-     -moz-border-radius: 6px;
-          border-radius: 6px;
+.pagination .disabled span,
+.pagination .disabled a,
+.pagination .disabled a:hover {
+  color: #999999;
+  background-color: transparent;
+  cursor: default;
 }
-
-.hero-unit h1 {
-  margin-bottom: 0;
-  font-size: 60px;
-  line-height: 1;
-  letter-spacing: -1px;
-  color: inherit;
+.pagination li:first-child a {
+  border-left-width: 1px;
+  -webkit-border-radius: 3px 0 0 3px;
+  -moz-border-radius: 3px 0 0 3px;
+  border-radius: 3px 0 0 3px;
 }
-
-.hero-unit p {
-  font-size: 18px;
-  font-weight: 200;
-  line-height: 27px;
-  color: inherit;
+.pagination li:last-child a {
+  -webkit-border-radius: 0 3px 3px 0;
+  -moz-border-radius: 0 3px 3px 0;
+  border-radius: 0 3px 3px 0;
 }
-
-.pull-right {
-  float: right;
+.pagination-centered {
+  text-align: center;
 }
-
-.pull-left {
-  float: left;
+.pagination-right {
+  text-align: right;
 }
-
-.hide {
-  display: none;
+.well {
+  min-height: 20px;
+  padding: 19px;
+  margin-bottom: 20px;
+  background-color: #f5f5f5;
+  border: 1px solid #eee;
+  border: 1px solid rgba(0, 0, 0, 0.05);
+  -webkit-border-radius: 4px;
+  -moz-border-radius: 4px;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+  -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
 }
-
-.show {
-  display: block;
+.well blockquote {
+  border-color: #ddd;
+  border-color: rgba(0, 0, 0, 0.15);
 }
-
-.invisible {
-  visibility: hidden;
+.well-large {
+  padding: 24px;
+  -webkit-border-radius: 6px;
+  -moz-border-radius: 6px;
+  border-radius: 6px;
+}
+.well-small {
+  padding: 9px;
+  -webkit-border-radius: 3px;
+  -moz-border-radius: 3px;
+  border-radius: 3px;
 }
diff --git a/scp/css/dashboard.css b/scp/css/dashboard.css
new file mode 100644
index 0000000000000000000000000000000000000000..43ec338890ac6bcce9d7647f85841657d362fe88
--- /dev/null
+++ b/scp/css/dashboard.css
@@ -0,0 +1,46 @@
+#line-chart-here {
+    padding: 0.4em;
+    margin-bottom: 1em;
+    border-radius: 0.3em;
+    border: 0.2em solid #ccc;
+    background: rgb(246,248,249); /* Old browsers */
+    background: -moz-linear-gradient(top, rgba(246,248,249,1) 0%, rgba(229,235,238,1) 50%, rgba(215,222,227,1) 51%, rgba(245,247,249,1) 100%); /* FF3.6+ */
+    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(246,248,249,1)), color-stop(50%,rgba(229,235,238,1)), color-stop(51%,rgba(215,222,227,1)), color-stop(100%,rgba(245,247,249,1))); /* Chrome,Safari4+ */
+    background: -webkit-linear-gradient(top, rgba(246,248,249,1) 0%,rgba(229,235,238,1) 50%,rgba(215,222,227,1) 51%,rgba(245,247,249,1) 100%); /* Chrome10+,Safari5.1+ */
+    background: -o-linear-gradient(top, rgba(246,248,249,1) 0%,rgba(229,235,238,1) 50%,rgba(215,222,227,1) 51%,rgba(245,247,249,1) 100%); /* Opera 11.10+ */
+    background: -ms-linear-gradient(top, rgba(246,248,249,1) 0%,rgba(229,235,238,1) 50%,rgba(215,222,227,1) 51%,rgba(245,247,249,1) 100%); /* IE10+ */
+    background: linear-gradient(top, rgba(246,248,249,1) 0%,rgba(229,235,238,1) 50%,rgba(215,222,227,1) 51%,rgba(245,247,249,1) 100%); /* W3C */
+    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f6f8f9', endColorstr='#f5f7f9',GradientType=0 ); /* IE6-9 */
+}
+#line-chart-here tspan {
+    font-family: Monaco, Calibri, Sans Serif;
+    font-size: 8pt;
+}
+#line-chart-legend {
+    margin: 0.6em;
+    line-height: 140%;
+}
+span.label.disabled {
+    opacity: 0.5;
+    background-color: #555 !important;
+}
+span.label {
+    cursor: pointer;
+}
+#table-here tr :not(:first-child) {
+    text-align: right;
+    padding-right: 2.3em;
+    width: 12%;
+}
+#table-here tr :not(:first-child) div {
+    position: relative;
+    margin-right: -1em;
+}
+#table-here tr :not(:first-child) div div {
+    position: absolute;
+    -moz-border-radius: 1em;
+    -webkit-border-radius: 1em;
+    border-radius: 1em;
+}
+
+
diff --git a/scp/css/scp.css b/scp/css/scp.css
index aa6ca4782492783d221fef0c6b18fe412f3cbcd5..3c7b83e12f3fc85001b1fd451c6fcc3e586e2752 100644
--- a/scp/css/scp.css
+++ b/scp/css/scp.css
@@ -16,6 +16,10 @@ a {
     text-align:center;
 }
 
+.full-width {
+    width: 100%;
+}
+
 .clear {
     clear:both;
 }
@@ -26,7 +30,8 @@ a {
 
 .strike { text-decoration:line-through; color:red; }
 
-#canned_attachments label { padding:3px; padding-right:10px; }
+.canned_attachments label, .canned_attachments span .uploads label { padding:3px; padding-right:10px; }
+.canned_attachments label { padding-right:3px; }
 
 
 #breadcrumbs {
@@ -1140,22 +1145,22 @@ time {
     margin-right:20px;
 }
 
-/* Advanced Ticket Search */
+/* Advanced Search & Ticket print options */
 
-#overlay {
+#search_overlay {
     background:#000;
     position:absolute;
     display:none;
     z-index:1000;
 }
 
-#advanced-search, #advanced-search * {
+#advanced-search, #advanced-search *, #print-options, #print-options * {
     box-sizing: border-box;
     -moz-box-sizing: border-box;
     -webkit-box-sizing: border-box;
 }
 
-#advanced-search {
+#advanced-search, #print-options {
     position:absolute;
     padding:1em;
     width:640px;
@@ -1166,7 +1171,24 @@ time {
     z-index:1200;
 }
 
-#advanced-search h3 {
+#print-options {
+    width:500px;
+    height:250px;
+}
+
+#print-options hr {
+    height: 1px;
+    border: 0;
+    background: #aaa;
+    background: -moz-linear-gradient(left, rgba(170,170,170,0) 0%, rgba(170,170,170,1) 10%, rgba(170,170,170,1) 90%, rgba(170,170,170,0) 100%); /* FF3.6+ */
+    background: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(170,170,170,0)), color-stop(10%,rgba(170,170,170,1)), color-stop(90%,rgba(170,170,170,1)), color-stop(100%,rgba(170,170,170,0))); /* Chrome,Safari4+ */
+    background: -o-linear-gradient(left, rgba(170,170,170,0) 0%,rgba(170,170,170,1) 10%,rgba(170,170,170,1) 90%,rgba(170,170,170,0) 100%); /* Opera 11.10+ */
+    background: -ms-linear-gradient(left, rgba(170,170,170,0) 0%,rgba(170,170,170,1) 10%,rgba(170,170,170,1) 90%,rgba(170,170,170,0) 100%); /* IE10+ */
+    background: linear-gradient(to right, rgba(170,170,170,0) 0%,rgba(170,170,170,1) 10%,rgba(170,170,170,1) 90%,rgba(170,170,170,0) 100%); /* W3C */
+    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00aaaaaa', endColorstr='#00aaaaaa',GradientType=1 ); /* IE6-9 */
+}
+
+#advanced-search h3, #print-options h3 {
     color:#2a67ac;
     font-size:20px;
     margin:0;
@@ -1174,16 +1196,16 @@ time {
     display:inline-block;
 }
 
-#advanced-search a.close {
+#advanced-search a.close, #print-options a.close {
     display:inline-block;
     float:right;
     font-size:16px;
     color:#777;
 }
 
-#advanced-search form {
+#advanced-search form, #print-options form {
     clear:both;
-    padding:2em 0 1em 0;
+    padding-top:2em;
     width:100%;
 }
 
@@ -1191,31 +1213,31 @@ time {
     display:none;
 }
 
-#advanced-search fieldset {
+#advanced-search fieldset, #print-options fieldset {
     margin:0;
-    padding:0.25em 0;
+    padding:0 0;
     border:none;
     overflow:hidden;
 }
 
-#advanced-search label {
+#advanced-search label, #print-options label {
     width:100px;
     display:inline-block;
     text-align:right;
     padding:10px;
 }
 
-#advanced-search fieldset input {
+#advanced-search fieldset input, #print-options fieldset input {
     border:1px solid #ccc;
     background:#fff;
 }
 
-#advanced-search fieldset select {
+#advanced-search fieldset select, #print-options fieldset select {
     width:170px;
     display:inline-block;
 }
 
-#advanced-search fieldset span {
+#advanced-search fieldset span, #print-options fieldset span {
     width:50px;
     display:inline-block;
     text-align:center;
@@ -1251,7 +1273,10 @@ time {
 
 #advanced-search input[type="submit"],
 #advanced-search input[type="reset"],
-#advanced-search input[type="button"]
+#advanced-search input[type="button"],
+#print-options input[type="submit"],
+#print-options input[type="reset"],
+#print-options input[type="button"]
 {
     display:inline-block;
     margin:0;
@@ -1264,7 +1289,10 @@ time {
     color: #333;
 }
 
-#advanced-search input[type="reset"], #advanced-search input[type="button"] {
+#advanced-search input[type="reset"],
+#advanced-search input[type="button"],
+#print-options input[type="reset"],
+#print-options input[type="button"] { 
     opacity:0.7;
 }
 
@@ -1303,3 +1331,37 @@ time {
     height:16px;
     background:inherit;
 }
+
+/* Upgrader */
+#upgrader { width: 100%; height: auto; clear: both;}
+#upgrader #sidebar { width: 220px; padding: 10px; border: 1px solid #C8DDFA; float: right; background: #F7FBFE; }
+#upgrader #sidebar h3 { font-size: 10pt; margin: 0 0 5px 0; padding: 0; text-indent: 32px; background: url('../images/cog.png?1312913866') top left no-repeat; line-height: 24px; color: #2a67ac; }
+
+#upgrader #main { width: 680px; float: left;}
+#upgrader #main h1 { margin: 0; padding: 0; font-size: 21pt; font-weight: normal; }
+#upgrader #main h2 { font-size: 12pt; margin: 0; padding: 0; color:#E65524; }
+#upgrader #main h3 { font-size: 10pt; margin: 0; padding: 0; }
+#upgrader #main div#intro { padding-bottom: 5px; margin-bottom:10px; border-bottom: 1px solid #aaaaaa; }
+#upgrader #main  { padding-bottom: 20px; }
+
+ul.progress { margin: 10px 0 20px 20px; padding: 0; }
+ul.progress li { list-style: none; margin: 0; padding: 0 0 2px 24px; background: url('../images/incomplete.png?1312910844'); background-repeat: no-repeat; background-position: 0 50%; }
+ul.progress li.yes { background-image: url('../images/yes.png?1312906296'); }
+ul.progress li.no { background-image: url('../images/no.png?1312906277'); }
+
+ul.progress li.yes small {color:green; }
+ul.progress li.no small {color:red;}
+
+#bar { clear: both; padding-top: 10px; height: 24px; line-height: 24px; text-align: center; border-top: 1px solid #aaaaaa; }
+#bar a, #bar .btn { display: inline-block; margin: 0; height: 24px; line-height: 24px; font-weight: bold; border: 1px solid #666666; text-decoration: none; padding: 0 10px; background: url('../images/grey_btn_bg.png?1312910883') top left repeat-x; color: #333; }
+#bar a:hover, #bar .btn:hover, #bar .btnover { background-position: bottom left; }
+#bar a.unstyled, #bar a.unstyled:hover { font-weight: normal; background: none; border: none; text-decoration: underline; color: #2a67ac; }
+
+#bar.error { background: #ffd; text-align: center; color: #a00; font-weight: bold; }
+
+/* Overlay */
+#overlay { display: none; position: fixed; background: #000; z-index: 1000; }
+
+#loading { padding: 10px 10px 10px 60px; width: 300px; height: 100px; background: url('../images/ajax-loader.gif?1312925608') 10px 50% no-repeat white; position: fixed; display: none; z-index: 3000; }
+#loading h4 { margin: 3px 0 0 0; padding: 0; color: #d80; }
+
diff --git a/scp/dashboard.php b/scp/dashboard.php
index 5284c901c7a5a86a9415619c805cb8a2dd0f9900..8756ca1ea86522eb77c8a7b8ee381f3928de27f9 100644
--- a/scp/dashboard.php
+++ b/scp/dashboard.php
@@ -16,7 +16,6 @@
 require('staff.inc.php');
 $nav->setTabActive('dashboard');
 require(STAFFINC_DIR.'header.inc.php');
-//require(STAFFINC_DIR.$page);
 ?>
 
 <script type="text/javascript" src="js/raphael-min.js"></script>
@@ -24,71 +23,12 @@ require(STAFFINC_DIR.'header.inc.php');
 <script type="text/javascript" src="js/g.line-min.js"></script>
 <script type="text/javascript" src="js/g.dot-min.js"></script>
 <script type="text/javascript" src="js/bootstrap-tab.js"></script>
+<script type="text/javascript" src="js/dashboard.inc.js"></script>
 
 <link rel="stylesheet" type="text/css" href="css/bootstrap.css"/>
+<link rel="stylesheet" type="text/css" href="css/dashboard.css"/>
 
-<style type="text/css">
-#line-chart-here {
-  padding: 0.4em;
-  margin-bottom: 1em;
-  border-radius: 0.3em;
-  border: 0.2em solid #ccc;
-background: rgb(246,248,249); /* Old browsers */
-background: -moz-linear-gradient(top, rgba(246,248,249,1) 0%,
-rgba(229,235,238,1) 50%, rgba(215,222,227,1) 51%, rgba(245,247,249,1) 100%);
-/* FF3.6+ */
-background: -webkit-gradient(linear, left top, left bottom,
-color-stop(0%,rgba(246,248,249,1)), color-stop(50%,rgba(229,235,238,1)),
-color-stop(51%,rgba(215,222,227,1)), color-stop(100%,rgba(245,247,249,1)));
-/* Chrome,Safari4+ */
-background: -webkit-linear-gradient(top, rgba(246,248,249,1)
-0%,rgba(229,235,238,1) 50%,rgba(215,222,227,1) 51%,rgba(245,247,249,1)
-100%); /* Chrome10+,Safari5.1+ */
-background: -o-linear-gradient(top, rgba(246,248,249,1)
-0%,rgba(229,235,238,1) 50%,rgba(215,222,227,1) 51%,rgba(245,247,249,1)
-100%); /* Opera 11.10+ */
-background: -ms-linear-gradient(top, rgba(246,248,249,1)
-0%,rgba(229,235,238,1) 50%,rgba(215,222,227,1) 51%,rgba(245,247,249,1)
-100%); /* IE10+ */
-background: linear-gradient(top, rgba(246,248,249,1) 0%,rgba(229,235,238,1)
-50%,rgba(215,222,227,1) 51%,rgba(245,247,249,1) 100%); /* W3C */
-filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f6f8f9',
-endColorstr='#f5f7f9',GradientType=0 ); /* IE6-9 */
-}
-#line-chart-here tspan {
-    font-family: Monaco, Calibri, Sans Serif;
-    font-size: 8pt;
-}
-#line-chart-legend {
-    margin: 0.6em;
-    line-height: 140%;
-}
-span.label.disabled {
-    opacity: 0.5;
-    background-color: #555 !important;
-}
-span.label {
-    cursor: pointer;
-}
-#table-here tr :not(:first-child) {
-    text-align: right;
-    padding-right: 2.3em;
-    width: 10%;
-}
-#table-here tr :not(:first-child) div {
-    position: relative;
-    margin-right: -1em;
-}
-#table-here tr :not(:first-child) div div {
-    position: absolute;
-    -moz-border-radius: 1em;
-    -webkit-border-radius: 1em;
-    border-radius: 1em;
-}
-
-</style>
-
-<h1>Ticket Activity</h1>
+<h2>Ticket Activity</h2>
 <p>Select the starting time and period for the system activity graph</p>
 <form class="well form-inline" id="timeframe-form">
     <label>
@@ -115,272 +55,14 @@ span.label {
     <div style="position:absolute;right:0;top:0" id="line-chart-legend"></div>
 </div>
 
-<script type="text/javascript">
-    var r, previous_data;
-
-    function refresh() {
-        $('#line-chart-here').empty();
-        $('#line-chart-legend').empty();
-        var r = new Raphael('line-chart-here'),
-            width = $('#line-chart-here').width(),
-            height = $('#line-chart-here').height();
-        $.ajax({
-            method:     'GET',
-            url:        'ajax.php/report/overview/graph',
-            data:       ((this.start && this.start.value) ? {
-                'start': this.start.value,
-                'stop': this.period.value} : {}),
-            dataType:   'json',
-            success:    function(json) {
-                var previous_data = json,
-                    times = [],
-                    smtimes = Array.prototype.concat.apply([], json.times),
-                    plots = [],
-                    max = 0,
-                    primes = [2,3,5,7,9];
-
-                // Convert the timestamp to number of whole days after the
-                // unix epoch, and try and find an exact multiple of the
-                // number of days across the query that is less than 13 for
-                // the number of dates to place across the bottom.
-                for (key in smtimes) {
-                    smtimes[key] = Math.floor(smtimes[key] / 86400);
-                }
-                for (key in json.events) {
-                    e = json.events[key];
-                    if (json.plots[e] === undefined) continue;
-                    $('<span>').append(e)
-                        .attr({class:'label','style':'margin-left:0.5em'})
-                        .appendTo($('#line-chart-legend'));
-                    $('<br>').appendTo('#line-chart-legend');
-                    times.push(smtimes);
-                    plots.push(json.plots[e]);
-                    max = Math.max(max, Math.max.apply(Math, json.plots[e]));
-                }
-                m = r.linechart(10, 10, width - 80, height - 20,
-                    times, plots, { 
-                    gutter: 10,
-                    width: 1.6,
-                    nostroke: false, 
-                    shade: false,
-                    axis: "0 0 1 1",
-                    axisxstep: 8,
-                    axisystep: max,
-                    symbol: "circle",
-                    smooth: false
-                }).hoverColumn(function () {
-                    this.tags = r.set();
-                    var slots = [];
-
-                    for (var i = 0, ii = this.y.length; i < ii; i++) {
-                        if (this.values[i] === 0) continue;
-                        if (this.symbols[i].node.style.display == "none") continue;
-                        var angle = 160;
-                        for (var j = 0, jj = slots.length; j < jj; j++) {
-                            if (slots[j][0] == this.x && slots[j][1] == this.y[i]) {
-                                angle = 20;
-                                break;
-                            }
-                        }
-                        slots.push([this.x, this.y[i]]);
-                        this.tags.push(r.tag(this.x, this.y[i],
-                            this.values[i], angle,
-                            10).insertBefore(this).attr([
-                                { fill: '#eee' },
-                                { fill: this.symbols[i].attr('fill') }]));
-                    }
-                }, function () {
-                    this.tags && this.tags.remove();
-                });
-                // Change axis labels from Unix epoch
-                $('tspan', $('#line-chart-here')).each(function(e) {
-                    var text = this.firstChild.textContent;
-                    if (parseInt(text) > 10000)
-                        this.firstChild.textContent =
-                            $.datepicker.formatDate('mm-dd-yy',
-                            new Date(parseInt(text) * 86400000));
-                });
-                // Dear aspiring API writers, please consider making [easy]
-                // things simpler than this...
-                $('span.label').each(function(i, e) {
-                    e = $(e);
-                    e.click(function() {
-                        e.toggleClass('disabled');
-                        if (e.hasClass('disabled')) {
-                            m.symbols[i].hide();
-                            m.lines[i].hide();
-                        } else {
-                            m.symbols[i].show();
-                            m.lines[i].show();
-                        }
-                    });
-                });
-                $('span.label', '#line-chart-legend').css(
-                    'background-color', function(i) {
-                        return Raphael.color(m.symbols[i][0].attr('fill')).hex; 
-                });
-            }
-        });
-        return false;
-    }
-    $(refresh);
-    $('#timeframe-form').submit(refresh);
-</script>
-
-<h1>Current statistics</h1>
+<hr/>
+<h2>Statistics</h2>
+<p>Statistics of tickets organized by department, help topic, and staff
+member.</p>
 <ul class="nav nav-tabs" id="tabular-navigation"></ul>
 
 <div id="table-here"></div>
 
-<script type="text/javascript">
-
-    $(function() { $('tabular-navigation').tab(); });
-
-    // Add tabs for the tabular display
-    $(function() {
-        $.ajax({
-            url:        'ajax.php/report/overview/table/groups',
-            dataType:   'json',
-            success:    function(json) {
-                var first=true;
-                for (key in json) {
-                    $('#tabular-navigation')
-                        .append($('<li>').attr((first) ? {class:"active"} : {})
-                        .append($('<a>')
-                            .click(build_table)
-                            .attr({'table-group':key,'href':'#'})
-                            .append(json[key])));
-                    first=false;
-                }
-                build_table.apply($('#tabular-navigation li:first-child a'))
-            }
-        });
-    });
-
-    function build_table(e) {
-        $('#table-here').empty();
-        $(this).tab('show');
-        var group = $(this).attr('table-group')
-        $.ajax({
-            method:     'GET',
-            dataType:   'json',
-            url:        'ajax.php/report/overview/table',
-            data:       {group: group},
-            success:    function(json) {
-                var q = $('<table>').attr({class:'table table-condensed table-striped'});
-                var h = $('<tr>').appendTo($('<thead>').appendTo(q));
-                var pagesize = 25;
-                var min = [], max = [], range = [];
-                for (var c in json.columns) {
-                    h.append($('<th>').append(json.columns[c]));
-                    min.push(1e8); max.push(0);
-                }
-                for (y in json.data) {
-                    row = json.data[y];
-                    for (x in row) {
-                        min[x] = Math.min(min[x], parseFloat(row[x]||0));
-                        max[x] = Math.max(max[x], parseFloat(row[x]||0));
-                    }
-                }
-                for (i=1; i<min.length; i++)
-                    range[i] = max[i] - min[i]   
-                for (var i in json.data) {
-                    if (i % pagesize === 0)
-                        b = $('<tbody>').attr({'page':i/pagesize+1}).appendTo(q);
-                    row = json.data[i];
-                    tr = $('<tr>').appendTo(b);
-                    for (var j in row) {
-                        if (j == 0) 
-                            tr.append($('<th>').append(row[j]));
-                        else {
-                            val = parseFloat(row[j])||0;
-                            if (val && max[j] && json.data.length > 1) {
-                                scale = val / max[j];
-                                color = Raphael.hsb(
-                                    Math.min((1 - scale) * .4, 1),
-                                    .75, .75);
-                                size = 16 * scale;
-                            }
-                            tr.append($('<td>')
-                                .append($('<div>').append(
-                                    $('<div>').css(val && range[j] ? {
-                                        'background-color': color,
-                                        'width': size,
-                                        'height': size,
-                                        'top': 9 - (size / 2),
-                                        'right': 10 - (size / 2)
-                                    } : {})
-                                    .append("&nbsp;")))
-                                .append(row[j]));
-                        }
-                    }
-                }
-                $('#table-here').append(q);
-
-                // ----------------------> Pagination <---------------------
-                function goabs(e) {
-                    $('tbody', q).addClass('hide');
-                    if (e.target) {
-                        page = e.target.text;
-                        $('tbody[page='+page+']', q).removeClass('hide');
-                    } else {
-                        e.removeClass('hide');
-                        page = e.attr('page')
-                    }
-                    enable_next_prev(page);
-                }
-                function goprev() {
-                    current = $('tbody:not(.hide)', q).attr('page');
-                    page = Math.max(1, parseInt(current) - 1);
-                    goabs($('tbody[page='+page+']', q));
-                }
-                function gonext() {
-                    current = $('tbody:not(.hide)', q).attr('page');
-                    page = Math.min(Math.floor(json.data.length / pagesize) + 1,
-                        parseInt(current) + 1);
-                    goabs($('tbody[page='+page+']', q));
-                }
-                function enable_next_prev(page) {
-                    $('#table-here div.pagination li[page]').removeClass('active');
-                    $('#table-here div.pagination li[page='+page+']').addClass('active');
-
-                    if (page == 1)  $('#report-page-prev').addClass('disabled');
-                    else            $('#report-page-prev').removeClass('disabled');
-
-                    if (page == Math.floor(json.data.length / pagesize) + 1)
-                                    $('#report-page-next').addClass('disabled');
-                    else            $('#report-page-next').removeClass('disabled');
-                }
-
-                var p = $('<ul>')
-                    .appendTo($('<div>').attr({'class':'pagination'})
-                    .appendTo($('#table-here')));
-                $('<a>').click(goprev).attr({'href':'#'})
-                    .append('&laquo;').appendTo($('<li>').attr({'id':'report-page-prev'})
-                    .appendTo(p));
-                $('tbody', q).each(function() {
-                    page = $(this).attr('page');
-                    $('<a>').click(goabs).attr({'href':'#'}).append(page)
-                        .appendTo($('<li>').attr({'page':page})
-                        .appendTo(p));
-                });
-                $('<a>').click(gonext).attr({'href':'#'})
-                    .append('&raquo;').appendTo($('<li>').attr({'id':'report-page-next'})
-                    .appendTo(p));
-
-                // ------------------------> Export <-----------------------
-                $('<a>').attr({'href':'ajax.php/report/overview/table/export?group='
-                        +group}).append('Export')
-                    .appendTo($('<li>')
-                    .appendTo(p));
-
-                gonext();
-            }
-        });
-        return false;
-    }
-</script>
-
 <?
 include(STAFFINC_DIR.'footer.inc.php');
 ?>
diff --git a/scp/departments.php b/scp/departments.php
index d0869cdf7302cafc8fb8fff071b28291833e4120..ef1acb12d62adcaa3c6285a210e7aa9d3f57fc29 100644
--- a/scp/departments.php
+++ b/scp/departments.php
@@ -45,7 +45,8 @@ if($_POST){
             }else{
                 $count=count($_POST['ids']);
                 if($_POST['public']){
-                    $sql='UPDATE '.DEPT_TABLE.' SET ispublic=1 WHERE dept_id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.DEPT_TABLE.' SET ispublic=1 WHERE dept_id IN ('
+                        .implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())){
                         if($num==$count)
                             $msg='Selected departments made public';
@@ -56,7 +57,9 @@ if($_POST){
                     }
                 }elseif($_POST['private']){
                     $sql='UPDATE '.DEPT_TABLE.' SET ispublic=0  '.
-                         'WHERE dept_id IN ('.implode(',',$_POST['ids']).') AND dept_id!='.db_input($cfg->getDefaultDeptId());
+                         'WHERE dept_id IN ('
+                            .implode(',', db_input($_POST['ids']))
+                        .') AND dept_id!='.db_input($cfg->getDefaultDeptId());
                     if(db_query($sql) && ($num=db_affected_rows())) {
                         if($num==$count)
                             $msg='Selected departments made private';
@@ -68,7 +71,8 @@ if($_POST){
 
                 }elseif($_POST['delete']){
                     //Deny all deletes if one of the selections has members in it.
-                    $sql='SELECT count(staff_id) FROM '.STAFF_TABLE.' WHERE dept_id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='SELECT count(staff_id) FROM '.STAFF_TABLE.' WHERE dept_id IN ('
+                        .implode(',', db_input($_POST['ids'])).')';
                     list($members)=db_fetch_row(db_query($sql));
                     if($members)
                         $errors['err']='Dept. with users can not be deleted. Move staff first.';
diff --git a/scp/emails.php b/scp/emails.php
index ddc626fb36dc9265b41835a95dbc6bf7c676e96b..b0d32bb59bf9d415275aaada58c96cf3df892629 100644
--- a/scp/emails.php
+++ b/scp/emails.php
@@ -46,7 +46,10 @@ if($_POST){
                 $count=count($_POST['ids']);
 
                 $sql='SELECT count(dept_id) FROM '.DEPT_TABLE.' dept '.
-                     'WHERE email_id IN ('.implode(',',$_POST['ids']).') OR autoresp_email_id IN ('.implode(',',$_POST['ids']).')';
+                     'WHERE email_id IN ('.
+                        implode(',', db_input($_POST['ids'])).
+                     ') OR autoresp_email_id IN ('.
+                        implode(',', db_input($_POST['ids'])).')';
                 list($depts)=db_fetch_row(db_query($sql));
                 if($depts>0){
                     $errors['err']='One or more of the selected emails is being used by a department. Remove association first!';
diff --git a/scp/emailtest.php b/scp/emailtest.php
index 9f9b2decb0a3b5e4cde81b3b4ca1ce4ec853a0f5..0ca1d7308cc8c62f0f9852a57f45d4e8802e805a 100644
--- a/scp/emailtest.php
+++ b/scp/emailtest.php
@@ -15,6 +15,7 @@
 **********************************************************************/
 require('admin.inc.php');
 include_once(INCLUDE_DIR.'class.email.php');
+include_once(INCLUDE_DIR.'class.csrf.php');
 $info=array();
 $info['subj']='osTicket test email';
 
@@ -47,6 +48,7 @@ $nav->setTabActive('emails');
 require(STAFFINC_DIR.'header.inc.php');
 ?>
 <form action="emailtest.php" method="post" id="emailtest">
+ <?php csrf_token(); ?>
  <input type="hidden" name="do" value="<?php echo $action; ?>">
  <h2>Test Outgoing Email</h2>
  <table class="form_table" width="940" border="0" cellspacing="0" cellpadding="2">
diff --git a/scp/faq.php b/scp/faq.php
index f668be9f233fe5f2678bebceda1f6fda94dfdd13..6e3d422a1669d8b09c02735d3115879e0fb3edbd 100644
--- a/scp/faq.php
+++ b/scp/faq.php
@@ -40,19 +40,7 @@ if($_POST):
             elseif($faq->update($_POST,$errors)) {
                 $msg='FAQ updated successfully';
                 $_REQUEST['a']=null; //Go back to view
-                //Delete removed attachments.
-                $keepers = $_POST['files']?$_POST['files']:array();
-                if(($attachments = $faq->getAttachments())) {
-                    foreach($attachments as $k=>$file) {
-                        if($file['id'] && !in_array($file['id'], $keepers)) {
-                            $faq->deleteAttachment($file['id']);
-                        }
-                    }
-                }
-                //Upload NEW attachments IF ANY - TODO: validate attachment types??
-                if($_FILES['attachments'] && ($files=Format::files($_FILES['attachments'])))
-                    $faq->uploadAttachments($files);
-
+                $faq->reload();
             } elseif(!$errors['err'])
                 $errors['err'] = 'Unable to update FAQ. Try again!';     
             break;
diff --git a/scp/filters.php b/scp/filters.php
index f39b794d047a1f4fa756c320346dae26ed8b9623..4ce0f30765f5192617f22345c00571f26d206af2 100644
--- a/scp/filters.php
+++ b/scp/filters.php
@@ -15,6 +15,7 @@
 **********************************************************************/
 require('admin.inc.php');
 include_once(INCLUDE_DIR.'class.filter.php');
+require_once(INCLUDE_DIR.'class.canned.php');
 $filter=null;
 if($_REQUEST['id'] && !($filter=Filter::lookup($_REQUEST['id'])))
     $errors['err']='Unknown or invalid filter.';
@@ -48,7 +49,8 @@ if($_POST){
             }else{
                 $count=count($_POST['ids']);
                 if($_POST['enable']){
-                    $sql='UPDATE '.EMAIL_FILTER_TABLE.' SET isactive=1 WHERE id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.EMAIL_FILTER_TABLE.' SET isactive=1 WHERE id IN ('.
+                        implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())){
                         if($num==$count)
                             $msg='Selected filters enabled';
@@ -58,7 +60,8 @@ if($_POST){
                         $errors['err']='Unable to enable selected filters';
                     }
                 }elseif($_POST['disable']){
-                    $sql='UPDATE '.EMAIL_FILTER_TABLE.' SET isactive=0  WHERE id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.EMAIL_FILTER_TABLE.' SET isactive=0  WHERE id IN ('.
+                        implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())) {
                         if($num==$count)
                             $msg='Selected filters disabled';
diff --git a/scp/groups.php b/scp/groups.php
index 7a4f959169160f6f41f0ebce70db6c6ced266695..22b1bae0acb36959fff05ec3f75323a691053920 100644
--- a/scp/groups.php
+++ b/scp/groups.php
@@ -43,7 +43,8 @@ if($_POST){
             }else{
                 $count=count($_POST['ids']);
                 if($_POST['enable']){
-                    $sql='UPDATE '.GROUP_TABLE.' SET group_enabled=1, updated=NOW() WHERE group_id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.GROUP_TABLE.' SET group_enabled=1, updated=NOW() WHERE group_id IN ('.
+                        implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())){
                         if($num==$count)
                             $msg='Selected groups activated';
@@ -53,7 +54,8 @@ if($_POST){
                         $errors['err']='Unable to activate selected groups';
                     }
                 }elseif($_POST['disable']){
-                    $sql='UPDATE '.GROUP_TABLE.' SET group_enabled=0, updated=NOW() WHERE group_id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.GROUP_TABLE.' SET group_enabled=0, updated=NOW() WHERE group_id IN ('.
+                        implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())) {
                         if($num==$count)
                             $msg='Selected groups disabled';
@@ -64,7 +66,7 @@ if($_POST){
                     }
                 }elseif($_POST['delete']){
                     foreach($_POST['ids'] as $k=>$v) {
-                        if(($t=Group::lookup($v)) && $t->delete())
+                        if(($g=Group::lookup($v)) && $g->delete())
                             $i++;
                     }
 
diff --git a/scp/helptopics.php b/scp/helptopics.php
index 18c34393e9b89a67c91661b516f0f045273d34da..5bd1ded7048f26307f2cd18d09d6b3a946f13f65 100644
--- a/scp/helptopics.php
+++ b/scp/helptopics.php
@@ -45,7 +45,8 @@ if($_POST){
             }else{
                 $count=count($_POST['ids']);
                 if($_POST['enable']){
-                    $sql='UPDATE '.TOPIC_TABLE.' SET isactive=1 WHERE topic_id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.TOPIC_TABLE.' SET isactive=1 WHERE topic_id IN ('.
+                        implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())){
                         if($num==$count)
                             $msg='Selected help topics enabled';
@@ -55,7 +56,8 @@ if($_POST){
                         $errors['err']='Unable to enable selected help topics.';
                     }
                 }elseif($_POST['disable']){
-                    $sql='UPDATE '.TOPIC_TABLE.' SET isactive=0  WHERE topic_id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.TOPIC_TABLE.' SET isactive=0  WHERE topic_id IN ('.
+                        implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())) {
                         if($num==$count)
                             $msg='Selected help topics disabled';
diff --git a/scp/images/cog.png b/scp/images/cog.png
new file mode 100755
index 0000000000000000000000000000000000000000..20171bc655e21cb8df4b800230f7b2867d2f0ca2
Binary files /dev/null and b/scp/images/cog.png differ
diff --git a/scp/images/no.png b/scp/images/no.png
new file mode 100644
index 0000000000000000000000000000000000000000..7fc50c6bc73a1a93754306483dd15aaa45e188dd
Binary files /dev/null and b/scp/images/no.png differ
diff --git a/scp/images/yes.png b/scp/images/yes.png
new file mode 100644
index 0000000000000000000000000000000000000000..8ccfa4569a5fcdc4a9de556dba0c19a20d807233
Binary files /dev/null and b/scp/images/yes.png differ
diff --git a/scp/js/dashboard.inc.js b/scp/js/dashboard.inc.js
new file mode 100644
index 0000000000000000000000000000000000000000..cc84661cf2ce393934fa5b0f43a28c222bbe9935
--- /dev/null
+++ b/scp/js/dashboard.inc.js
@@ -0,0 +1,264 @@
+(function ($) {
+    var current_tab;
+    function refresh(e) {
+        $('#line-chart-here').empty();
+        $('#line-chart-legend').empty();
+        var r = new Raphael('line-chart-here'),
+            width = $('#line-chart-here').width(),
+            height = $('#line-chart-here').height();
+        $.ajax({
+            method:     'GET',
+            url:        'ajax.php/report/overview/graph',
+            data:       ((this.start && this.start.value) ? {
+                'start': this.start.value,
+                'stop': this.period.value} : {}),
+            dataType:   'json',
+            success:    function(json) {
+                var times = [],
+                    smtimes = Array.prototype.concat.apply([], json.times),
+                    plots = [],
+                    max = 0;
+
+                // Convert the timestamp to number of whole days after the
+                // unix epoch.
+                for (key in smtimes) {
+                    smtimes[key] = Math.floor(smtimes[key] / 86400);
+                }
+                for (key in json.events) {
+                    e = json.events[key];
+                    if (json.plots[e] === undefined) continue;
+                    $('<span>').append(e)
+                        .attr({'class':'label','style':'margin-left:0.5em'})
+                        .appendTo($('#line-chart-legend'));
+                    $('<br>').appendTo('#line-chart-legend');
+                    times.push(smtimes);
+                    plots.push(json.plots[e]);
+                    // Keep track of max value from any plot
+                    max = Math.max(max, Math.max.apply(Math, json.plots[e]));
+                }
+                m = r.linechart(20, 0, width - 70, height,
+                    times, plots, { 
+                    gutter: 20,
+                    width: 1.6,
+                    nostroke: false, 
+                    shade: false,
+                    axis: "0 0 1 1",
+                    axisxstep: 8,
+                    axisystep: Math.min(12, max),
+                    symbol: "circle",
+                    smooth: false
+                }).hoverColumn(function () {
+                    this.tags = r.set();
+                    var slots = [];
+
+                    for (var i = 0, ii = this.y.length; i < ii; i++) {
+                        if (this.values[i] === 0) continue;
+                        if (this.symbols[i].node.style.display == "none") continue;
+                        var angle = 160;
+                        for (var j = 0, jj = slots.length; j < jj; j++) {
+                            if (slots[j][0] == this.x
+                                    && Math.abs(slots[j][1] - this.y[i]) < 20) {
+                                angle = 20;
+                                break;
+                            }
+                        }
+                        slots.push([this.x, this.y[i]]);
+                        this.tags.push(r.tag(this.x, this.y[i],
+                            this.values[i], angle,
+                            10).insertBefore(this).attr([
+                                { fill: '#eee' },
+                                { fill: this.symbols[i].attr('fill') }]));
+                    }
+                }, function () {
+                    this.tags && this.tags.remove();
+                });
+                // Change axis labels from Unix epoch
+                $('tspan', $('#line-chart-here')).each(function(e) {
+                    var text = this.firstChild.textContent;
+                    if (parseInt(text) > 10000)
+                        this.firstChild.textContent =
+                            $.datepicker.formatDate('mm-dd-yy',
+                            new Date(parseInt(text) * 86400000));
+                });
+                $('span.label').each(function(i, e) {
+                    e = $(e);
+                    e.click(function() {
+                        e.toggleClass('disabled');
+                        if (e.hasClass('disabled')) {
+                            m.symbols[i].hide();
+                            m.lines[i].hide();
+                        } else {
+                            m.symbols[i].show();
+                            m.lines[i].show();
+                        }
+                    });
+                });
+                // Dear aspiring API writers, please consider making [easy]
+                // things simpler than this...
+                $('span.label', '#line-chart-legend').css(
+                    'background-color', function(i) {
+                        return Raphael.color(m.symbols[i][0].attr('fill')).hex; 
+                });
+            }
+        });
+        if (this.start) build_table.apply(this);
+        return false;
+    }
+    $(function() { $('tabular-navigation').tab(); });
+
+    // Add tabs for the tabular display
+    $(function() {
+        $.ajax({
+            url:        'ajax.php/report/overview/table/groups',
+            dataType:   'json',
+            success:    function(json) {
+                var first=true;
+                for (key in json) {
+                    $('#tabular-navigation')
+                        .append($('<li>').attr((first) ? {class:"active"} : {})
+                        .append($('<a>')
+                            .click(build_table)
+                            .attr({'table-group':key,'href':'#'})
+                            .append(json[key])));
+                    first=false;
+                }
+                build_table.apply($('#tabular-navigation li:first-child a')[0])
+            }
+        });
+    });
+
+    var start, stop;
+    function build_table() {
+        if (this.tagName == 'A') {
+            current_tab = $(this).tab('show');
+        }
+        else if (this.start) {
+            start = this.start.value || 'last month';
+            stop = this.period.value || 'now';
+        }
+        var group = current_tab.attr('table-group');
+        $.ajax({
+            method:     'GET',
+            dataType:   'json',
+            url:        'ajax.php/report/overview/table',
+            data:       {group: group, start: start, stop: stop},
+            success:    function(json) {
+                var q = $('<table>').attr({'class':'table table-condensed table-striped'}),
+                    h = $('<tr>').appendTo($('<thead>').appendTo(q)),
+                    pagesize = 25,
+                    max = [];
+                for (var c in json.columns) {
+                    h.append($('<th>').append(json.columns[c]));
+                    max.push(0);
+                }
+                for (y in json.data) {
+                    row = json.data[y];
+                    for (x in row) {
+                        max[x] = Math.max(max[x], parseFloat(row[x]||0));
+                    }
+                }
+                for (var i in json.data) {
+                    if (i % pagesize === 0)
+                        b = $('<tbody>').attr({'page':i/pagesize+1}).appendTo(q);
+                    row = json.data[i];
+                    tr = $('<tr>').appendTo(b);
+                    for (var j in row) {
+                        if (j == 0) 
+                            tr.append($('<th>').append(row[j]));
+                        else {
+                            val = parseFloat(row[j])||0;
+                            color = 'black';
+                            size = 0;
+                            if (val && max[j] && json.data.length > 1) {
+                                scale = val / max[j];
+                                color = Raphael.hsb(
+                                    Math.min((1 - scale) * .4, 1),
+                                    .75, .75);
+                                size = 16 * scale;
+                            }
+                            tr.append($('<td>')
+                                .append($('<div>').append(
+                                    $('<div>').css(val ? {
+                                        'background-color': color,
+                                        'width': size,
+                                        'height': size,
+                                        'top': 9 - (size / 2),
+                                        'right': 10 - (size / 2)
+                                    } : {})
+                                    .append("&nbsp;")))
+                                .append(row[j]));
+                        }
+                    }
+                }
+                if (json.data.length == 0) {
+                    $('<tbody>').attr('page','1').append($('<tr>').append(
+                        $('<td>').attr('colspan','8').append(
+                            'No data for this timeframe found'))).appendTo(q);
+                }
+                $('#table-here').empty().append(q);
+
+                // ----------------------> Pagination <---------------------
+                function goabs(e) {
+                    $('tbody', q).addClass('hide');
+                    if (e.target) {
+                        page = e.target.text;
+                        $('tbody[page='+page+']', q).removeClass('hide');
+                    } else {
+                        e.removeClass('hide');
+                        page = e.attr('page')
+                    }
+                    enable_next_prev(page);
+                }
+                function goprev() {
+                    current = $('tbody:not(.hide)', q).attr('page');
+                    page = Math.max(1, parseInt(current) - 1);
+                    goabs($('tbody[page='+page+']', q));
+                }
+                function gonext() {
+                    current = $('tbody:not(.hide)', q).attr('page');
+                    page = Math.min(Math.floor(json.data.length / pagesize) + 1,
+                        parseInt(current) + 1);
+                    goabs($('tbody[page='+page+']', q));
+                }
+                function enable_next_prev(page) {
+                    $('#table-here div.pagination li[page]').removeClass('active');
+                    $('#table-here div.pagination li[page='+page+']').addClass('active');
+
+                    if (page == 1)  $('#report-page-prev').addClass('disabled');
+                    else            $('#report-page-prev').removeClass('disabled');
+
+                    if (page == Math.floor(json.data.length / pagesize) + 1)
+                                    $('#report-page-next').addClass('disabled');
+                    else            $('#report-page-next').removeClass('disabled');
+                }
+
+                var p = $('<ul>')
+                    .appendTo($('<div>').attr({'class':'pagination'})
+                    .appendTo($('#table-here')));
+                $('<a>').click(goprev).attr({'href':'#'})
+                    .append('&laquo;').appendTo($('<li>').attr({'id':'report-page-prev'})
+                    .appendTo(p));
+                $('tbody', q).each(function() {
+                    page = $(this).attr('page');
+                    $('<a>').click(goabs).attr({'href':'#'}).append(page)
+                        .appendTo($('<li>').attr({'page':page})
+                        .appendTo(p));
+                });
+                $('<a>').click(gonext).attr({'href':'#'})
+                    .append('&raquo;').appendTo($('<li>').attr({'id':'report-page-next'})
+                    .appendTo(p));
+
+                // ------------------------> Export <-----------------------
+                $('<a>').attr({'href':'ajax.php/report/overview/table/export?group='
+                        +group}).append('Export')
+                    .appendTo($('<li>')
+                    .appendTo(p));
+
+                gonext();
+            }
+        });
+        return false;
+    }
+    $(refresh);
+    $(function() { $('#timeframe-form').submit(refresh); });
+})(window.jQuery);
diff --git a/scp/js/scp.js b/scp/js/scp.js
index b31f673f0d9f7119768846bae078d11770ed18fc..8730685c0e2134d18d6a29e9f9f74cf66daaffa8 100644
--- a/scp/js/scp.js
+++ b/scp/js/scp.js
@@ -121,7 +121,7 @@ $(document).ready(function(){
 
 
     //Canned attachments.
-    $('#canned_attachments, #faq_attachments').delegate('input:checkbox', 'click', function(e) {
+    $('.canned_attachments, .faq_attachments').delegate('input:checkbox', 'click', function(e) {
         var elem = $(this);
         if(!$(this).is(':checked') && confirm("Are you sure you want to remove this attachment?")==true) {
             elem.parent().addClass('strike');
@@ -154,12 +154,13 @@ $(document).ready(function(){
                             $('#response',fObj).val(canned.response);
                     }
                     //Canned attachments.
-                    if(canned.files && $('#canned_attachments',fObj).length) {
+                    if(canned.files && $('.canned_attachments',fObj).length) {
                         $.each(canned.files,function(i, j) {
-                            if(!$('#canned_attachments #f'+j.id,fObj).length) {
-                                var file='<label><input type="checkbox" name="cannedattachments[]" value="' + j.id+'" id="f'+j.id+'" checked="checked">';
-                                    file+= '<a href="file.php?h=' + j.hash + j.key+ '">'+ j.name +'</a></label>';
-                                $('#canned_attachments', fObj).append(file);
+                            if(!$('.canned_attachments #f'+j.id,fObj).length) {
+                                var file='<span><label><input type="checkbox" name="cannedattachments[]" value="' + j.id+'" id="f'+j.id+'" checked="checked">';
+                                    file+= ' '+ j.name + '</label>';
+                                    file+= ' (<a href="file.php?h=' + j.hash + j.key+ '">view</a>) </span>';
+                                $('.canned_attachments', fObj).append(file);
                             }
 
                          });
@@ -173,20 +174,54 @@ $(document).ready(function(){
 
 
 
-    /* global inits */
+    /************ global inits *****************/
+
+    //Add CSRF token to the ajax requests.
+    // Many thanks to https://docs.djangoproject.com/en/dev/ref/contrib/csrf/ + jared.
+    $(document).ajaxSend(function(event, xhr, settings) {
+
+        function sameOrigin(url) {
+            // url could be relative or scheme relative or absolute
+            var host = document.location.host; // host + port
+            var protocol = document.location.protocol;
+            var sr_origin = '//' + host;
+            var origin = protocol + sr_origin;
+            // Allow absolute or scheme relative URLs to same origin
+            return (url == origin || url.slice(0, origin.length + 1) == origin + '/') || 
+                (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
+                // or any other URL that isn't scheme relative or absolute i.e
+                // relative.
+                !(/^(\/\/|http:|https:).*/.test(url));    
+        }
+
+        function safeMethod(method) {
+            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
+        }
+        if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
+            xhr.setRequestHeader("X-CSRFToken", $("meta[name=csrf_token]").attr("content"));
+        }
+
+       });
 
     /* Get config settings from the backend */
-    $.get('ajax.php/config/ui.json',
-        function(config){
-            /*
-            if(config && config.max_attachments)
-                alert(config.max_attachments);
-            */
-        },
-        'json')
-        .error( function() {});
-    /* Datepicker */
+    var $config = null;
+    $.ajax({
+        url: "ajax.php/config/scp",
+        dataType: 'json',
+        async: false,
+        success: function (config) {
+            $config = config;
+            }
+        });
+     
+    /* Multifile uploads */
+     $('.multifile').multifile({
+        container:   '.uploads',
+        max_uploads: ($config && $config.max_file_uploads)?$config.max_file_uploads:1,
+        file_types:  ($config && $config.file_types)?$config.file_types:".*"
+        });
 
+    /* Datepicker */
     $('.dp').datepicker({
         numberOfMonths: 2,
         showButtonPanel: true,
@@ -245,7 +280,7 @@ $(document).ready(function(){
     });
 
     /* advanced search */
-    $("#overlay").css({
+    $("#overlay, #search_overlay").css({
         opacity : 0.3,
         top     : 0,
         left    : 0,
@@ -261,14 +296,14 @@ $(document).ready(function(){
     $('#go-advanced').click(function(e) {
         e.preventDefault();
         $('#result-count').html('');
-        $('#overlay').show();
+        $('#search_overlay').show();
         $('#advanced-search').show();
     });
 
     $('#advanced-search').delegate('a.close, input.close', 'click', function(e) {
         e.preventDefault();
         $('#advanced-search').hide()
-        $('#overlay').hide();
+        $('#search_overlay').hide();
     }).delegate('#status', 'change', function() {
         switch($(this).val()) {
             case 'closed':
@@ -323,5 +358,4 @@ $(document).ready(function(){
                 $('.buttons', elem).show();
              });
     });
-
 });
diff --git a/scp/js/ticket.js b/scp/js/ticket.js
index 22a97d623bd34d0ef664b012c1cd040e9f55c15e..2913c225cf0579f3587442831a135bb3464b53f8 100644
--- a/scp/js/ticket.js
+++ b/scp/js/ticket.js
@@ -152,7 +152,7 @@ var autoLock = {
             autoLock.renewLock(e);
         } else {
             $.ajax({
-                type: "GET",
+                type: "POST",
                 url: 'ajax.php/tickets/'+autoLock.tid+'/lock',
                 dataType: 'json',
                 cache: false,
@@ -316,6 +316,25 @@ jQuery(function($) {
             }
         }
      });
+    
+    //Ticket print options
+    $("#print-options").css({
+        top  : ($(window).height() /5),
+        left : ($(window).width() / 2 - 300)
+    });
+
+    $('a#ticket-print').click(function(e) {
+        e.preventDefault();
+        $('#overlay').show();
+        $('#print-options').show();
+        return false;
+    });
+
+    $('#print-options').delegate('a.close, input.close', 'click', function(e) {
+        e.preventDefault();
+        $('#print-options').hide()
+        $('#overlay').hide();
+    });
 
     //Start watching the form for activity.
     autoLock.Init();
diff --git a/scp/js/upgrader.js b/scp/js/upgrader.js
new file mode 100644
index 0000000000000000000000000000000000000000..09bde7766c6f39e9f95e0b50ccf3c0efc3bbb2fb
--- /dev/null
+++ b/scp/js/upgrader.js
@@ -0,0 +1,58 @@
+jQuery(function($) {
+            
+    $("#overlay").css({
+        opacity : 0.3,
+        top     : 0,
+        left    : 0,
+        width   : $(window).width(),
+        height  : $(window).height()
+        });
+
+    $("#loading").css({
+        top  : ($(window).height() / 3),
+        left : ($(window).width() / 2 - 160)
+        });
+        
+    $('form#upgrade').submit(function(e) {
+        e.preventDefault();
+        var form = $(this);
+        $('input[type=submit]', this).attr('disabled', 'disabled');
+        $('#overlay, #loading').show();
+        doTasks('upgrade.php',form.serialize());
+
+        return false;
+        });
+
+    function doTasks(url, data) {
+        function _lp(count) {
+            $.ajax({
+                type: 'POST',
+                url: 'ajax.php/upgrader',
+                async: true,
+                cache: false,
+                data: data,
+                dataType: 'text',
+                success: function(res) {
+                    if (res) { 
+                        $('#loading #msg').html(res);
+                    }
+                },
+                statusCode: {
+                    200: function() {
+                        setTimeout(function() { _lp(count+1); }, 2);
+                    },
+
+                    201: function() {
+                        $('#loading #msg').html("We're done... cleaning up!");
+                        setTimeout(function() { location.href =url+'?c='+count+'&r='+Math.floor((Math.random()*100)+1); }, 3000);
+                    }
+                },
+                error: function() {
+                    $('#loading #msg').html("Something went wrong");
+                    setTimeout(function() { location.href =url+'?c='+count+'&r='+Math.floor((Math.random()*100)+1); }, 1000);
+                }
+            });
+        };
+        _lp(0);
+    }
+});
diff --git a/scp/login.php b/scp/login.php
index 2af73c318b45ddb15438d3ab8966ea76d11c6576..6a28e0f45130f26f733f8eca82066565f5e2d9dc 100644
--- a/scp/login.php
+++ b/scp/login.php
@@ -17,6 +17,7 @@ require_once('../main.inc.php');
 if(!defined('INCLUDE_DIR')) die('Fatal Error. Kwaheri!');
 
 require_once(INCLUDE_DIR.'class.staff.php');
+require_once(INCLUDE_DIR.'class.csrf.php');
 
 $msg=$_SESSION['_staff']['auth']['msg'];
 $msg=$msg?$msg:'Authentication Required';
@@ -24,7 +25,7 @@ if($_POST && (!empty($_POST['username']) && !empty($_POST['passwd']))){
     //$_SESSION['_staff']=array(); #Uncomment to disable login strikes.
     $msg='Invalid login';
     if(($user=Staff::login($_POST['username'],$_POST['passwd'],$errors))){
-        $dest=$_SESSION['_user']['auth']['dest'];
+        $dest=$_SESSION['_staff']['auth']['dest'];
         $dest=($dest && (!strstr($dest,'login.php') && !strstr($dest,'ajax.php')))?$dest:'index.php';
         @header("Location: $dest");
         require_once('index.php'); //Just incase header is messed up.
diff --git a/scp/logout.php b/scp/logout.php
index 32d62d14abb29363df9a7da033a1f0873821cbc9..8f3b980d5e86f65d2569ade250f3437b38c072bf 100644
--- a/scp/logout.php
+++ b/scp/logout.php
@@ -15,13 +15,16 @@
     vim: expandtab sw=4 ts=4 sts=4:
 **********************************************************************/
 require('staff.inc.php');
+//CSRF Check: Make sure the user actually clicked on the link to logout.
+if(!$_GET['auth'] || $_GET['auth']!=md5($ost->getCSRFToken().SECRET_SALT.session_id()))
+   @header('Location: index.php');
+
 $ost->logDebug('Staff logout',
         sprintf("%s logged out [%s]", 
             $thisstaff->getUserName(), $_SERVER['REMOTE_ADDR'])); //Debug.
 $_SESSION['_staff']=array();
 session_unset();
 session_destroy();
-session_write_close();
 @header('Location: login.php');
 require('login.php');
 ?>
diff --git a/scp/syslogs.php b/scp/logs.php
similarity index 94%
rename from scp/syslogs.php
rename to scp/logs.php
index 843fecd842cf49e3d3622338aec78777755ba544..e29ef3702a50cd8949cc355b99b5a12dcb0ceadd 100644
--- a/scp/syslogs.php
+++ b/scp/logs.php
@@ -1,6 +1,6 @@
 <?php
 /*********************************************************************
-    syslogs.php
+    logs.php
 
     System Logs
 
@@ -23,7 +23,8 @@ if($_POST){
             }else{
                 $count=count($_POST['ids']);
                 if($_POST['delete']){
-                    $sql='DELETE FROM '.SYSLOG_TABLE.' WHERE log_id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='DELETE FROM '.SYSLOG_TABLE.' WHERE log_id IN ('
+                        .implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())){
                         if($num==$count)
                             $msg='Selected logs deleted successfully';
@@ -42,8 +43,6 @@ if($_POST){
     }
 }
 
-
-  
 $page='syslogs.inc.php';
 $nav->setTabActive('dashboard');
 require(STAFFINC_DIR.'header.inc.php');
diff --git a/scp/profile.php b/scp/profile.php
index e6506fa6ece8bd0686550cae4810e17a2c76cd6f..96e1b7e29af59bb03fa929600a02c66c60fde4ff 100644
--- a/scp/profile.php
+++ b/scp/profile.php
@@ -19,8 +19,7 @@ $msg='';
 $staff=Staff::lookup($thisstaff->getId());
 if($_POST && $_POST['id']!=$thisstaff->getId()) { //Check dummy ID used on the form.
  $errors['err']='Internal Error. Action Denied';
-}
-if(!$errors && $_POST) { //Handle post
+} elseif(!$errors && $_POST) { //Handle post
 
     if(!$staff)
         $errors['err']='Unknown or invalid staff';
diff --git a/scp/slas.php b/scp/slas.php
index c67a4d8cd007f7811b3aead54d67280388c33ed5..8f3b0f75ca331381beb6a348f46c2a703853b229 100644
--- a/scp/slas.php
+++ b/scp/slas.php
@@ -45,7 +45,8 @@ if($_POST){
             }else{
                 $count=count($_POST['ids']);
                 if($_POST['enable']){
-                    $sql='UPDATE '.SLA_TABLE.' SET isactive=1 WHERE id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.SLA_TABLE.' SET isactive=1 WHERE id IN ('.
+                        implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())){
                         if($num==$count)
                             $msg='Selected SLA plans enabled';
@@ -55,7 +56,8 @@ if($_POST){
                         $errors['err']='Unable to enable selected SLA plans.';
                     }
                 }elseif($_POST['disable']){
-                    $sql='UPDATE '.SLA_TABLE.' SET isactive=0  WHERE id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.SLA_TABLE.' SET isactive=0  WHERE id IN ('.
+                        implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())) {
                         if($num==$count)
                             $msg='Selected SLA plans disabled';
diff --git a/scp/staff.inc.php b/scp/staff.inc.php
index a8310f5edc6ef9bbddf9bf088095f98337746614..5dcf6045042397c1ee806a8df9f0f2b0f28725a3 100644
--- a/scp/staff.inc.php
+++ b/scp/staff.inc.php
@@ -13,7 +13,7 @@
 
     vim: expandtab sw=4 ts=4 sts=4:
 **********************************************************************/
-if(basename($_SERVER['SCRIPT_NAME'])==basename(__FILE__)) die('Kwaheri rafiki!'); //Say hi to our friend..
+if(basename($_SERVER['SCRIPT_NAME'])==basename(__FILE__)) die('Access denied'); //Say hi to our friend..
 
 if(!file_exists('../main.inc.php')) die('Fatal error... get technical support');
 
@@ -39,6 +39,7 @@ define('KB_PREMADE_TABLE',TABLE_PREFIX.'kb_premade');
 require_once(INCLUDE_DIR.'class.staff.php');
 require_once(INCLUDE_DIR.'class.group.php');
 require_once(INCLUDE_DIR.'class.nav.php');
+require_once(INCLUDE_DIR.'class.csrf.php');
 
 /* First order of the day is see if the user is logged in and with a valid session.
     * User must be valid staff beyond this point 
@@ -80,6 +81,16 @@ if(!$thisstaff->isAdmin()) {
 //Keep the session activity alive
 $thisstaff->refreshSession();
 
+/******* CSRF Protectin *************/
+// Enforce CSRF protection for POSTS
+if ($_POST  && !$ost->checkCSRFToken()) {
+    Http::response(400, 'Valid CSRF Token Required');
+    exit;
+}
+
+//Add token to the header - used on ajax calls [DO NOT CHANGE THE NAME] 
+$ost->addExtraHeader('<meta name="csrf_token" content="'.$ost->getCSRFToken().'" />');
+
 /******* SET STAFF DEFAULTS **********/
 //Set staff's timezone offset.
 $_SESSION['TZ_OFFSET']=$thisstaff->getTZoffset();
@@ -92,8 +103,12 @@ $errors=array();
 $msg=$warn=$sysnotice='';
 $tabs=array();
 $submenu=array();
-if($ost->isUpgradePending()) {
-    $errors['err']=$sysnotice='System upgrade is pending <a href="../setup/upgrade.php">Upgrade Now</a>';
+$exempt = in_array(basename($_SERVER['SCRIPT_NAME']), array('logout.php', 'ajax.php', 'logs.php', 'upgrade.php'));
+
+if($ost->isUpgradePending() && !$exempt) {
+    $errors['err']=$sysnotice='System upgrade is pending <a href="upgrade.php">Upgrade Now</a>';
+    require('upgrade.php');
+    exit;
 } elseif($cfg->isHelpDeskOffline()) {
     $sysnotice='<strong>System is set to offline mode</strong> - Client interface is disabled and ONLY admins can access staff control panel.';
     $sysnotice.=' <a href="settings.php">Enable</a>.';
@@ -101,7 +116,7 @@ if($ost->isUpgradePending()) {
 
 $nav = new StaffNav($thisstaff);
 //Check for forced password change.
-if($thisstaff->forcePasswdChange()){
+if($thisstaff->forcePasswdChange() && !$exempt) {
     # XXX: Call staffLoginPage() for AJAX and API requests _not_ to honor
     #      the request
     require('profile.php'); //profile.php must request this file as require_once to avoid problems.
diff --git a/scp/staff.php b/scp/staff.php
index 863a348c9f37f547f5a8b57ddf0f162cc5257b1f..88c8949f9908542067bf0ebc03e64781c5ce0b08 100644
--- a/scp/staff.php
+++ b/scp/staff.php
@@ -45,7 +45,8 @@ if($_POST){
             }else{
                 $count=count($_POST['ids']);
                 if($_POST['enable']){
-                    $sql='UPDATE '.STAFF_TABLE.' SET isactive=1 WHERE staff_id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.STAFF_TABLE.' SET isactive=1 WHERE staff_id IN ('.
+                        implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())){
                         if($num==$count)
                             $msg='Selected staff activated';
diff --git a/scp/teams.php b/scp/teams.php
index c579372197995e4fd3811eddf338d457817aadb0..50d7ca1cae022dd328189b9d8ffdaaad1727c533 100644
--- a/scp/teams.php
+++ b/scp/teams.php
@@ -43,7 +43,8 @@ if($_POST){
             }else{
                 $count=count($_POST['ids']);
                 if($_POST['enable']){
-                    $sql='UPDATE '.TEAM_TABLE.' SET isenabled=1 WHERE team_id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.TEAM_TABLE.' SET isenabled=1 WHERE team_id IN ('.
+                        implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())){
                         if($num==$count)
                             $msg='Selected teams activated';
@@ -53,7 +54,8 @@ if($_POST){
                         $errors['err']='Unable to activate selected teams';
                     }
                 }elseif($_POST['disable']){
-                    $sql='UPDATE '.TEAM_TABLE.' SET isenabled=0 WHERE team_id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.TEAM_TABLE.' SET isenabled=0 WHERE team_id IN ('.
+                        implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())) {
                         if($num==$count)
                             $msg='Selected teams disabled';
diff --git a/scp/templates.php b/scp/templates.php
index 47e24dd6e4a4d06d6e35cf8d0ccae290b99dbd24..4ba95d70a8a707422bf011781b6df9ab292a5f9f 100644
--- a/scp/templates.php
+++ b/scp/templates.php
@@ -54,7 +54,8 @@ if($_POST){
             }else{
                 $count=count($_POST['ids']);
                 if($_POST['enable']){
-                    $sql='UPDATE '.EMAIL_TEMPLATE_TABLE.' SET isactive=1 WHERE tpl_id IN ('.implode(',',$_POST['ids']).')';
+                    $sql='UPDATE '.EMAIL_TEMPLATE_TABLE.' SET isactive=1 WHERE tpl_id IN ('.
+                        implode(',', db_input($_POST['ids'])).')';
                     if(db_query($sql) && ($num=db_affected_rows())){
                         if($num==$count)
                             $msg='Selected templates enabled';
diff --git a/scp/tickets.php b/scp/tickets.php
index 7cc7740bb677eeff2bddd177697a661c7da2996d..66af215ea732a492b5f9e99cf5b0d99c16ebdb6c 100644
--- a/scp/tickets.php
+++ b/scp/tickets.php
@@ -57,7 +57,7 @@ if($_POST && !$errors):
 
             $wasOpen =($ticket->isOpen());
             //If no error...do the do.
-            if(!$errors && ($respId=$ticket->postReply($_POST,$_FILES['attachments'],$errors))) {
+            if(!$errors && ($respId=$ticket->postReply($_POST, $errors))) {
                 $msg='Reply posted successfully';
                 $ticket->reload();
                 if($ticket->isClosed() && $wasOpen)
@@ -360,7 +360,7 @@ if($_POST && !$errors):
                 $ticket=null;
                 if(!$thisstaff || !$thisstaff->canCreateTickets()) {
                      $errors['err']='You do not have permission to create tickets. Contact admin for such access';
-                }elseif(($ticket=Ticket::open($_POST, $_FILES['attachments'], $errors))) {
+                }elseif(($ticket=Ticket::open($_POST, $errors))) {
                     $msg='Ticket created successfully';
                     $_REQUEST['a']=null;
                     if(!$ticket->checkStaffAccess($thisstaff) || $ticket->isClosed())
@@ -456,7 +456,7 @@ if($ticket) {
     $inc = 'ticket-view.inc.php';
     if($_REQUEST['a']=='edit' && $thisstaff->canEditTickets()) 
         $inc = 'ticket-edit.inc.php';
-    elseif($_REQUEST['a'] == 'print' && !$ticket->pdfExport())
+    elseif($_REQUEST['a'] == 'print' && !$ticket->pdfExport($_REQUEST['psize'], $_REQUEST['notes']))
         $errors['err'] = 'Internal error: Unable to export the ticket to PDF for print.';
 } else {
     $inc = 'tickets.inc.php';
diff --git a/setup/upgrade.php b/scp/upgrade.php
similarity index 58%
rename from setup/upgrade.php
rename to scp/upgrade.php
index e5fd21084ccb534167d681ee6288793d5a683296..4ca5f71561e06abaeee8fb2b4e2bb69960c1cf80 100644
--- a/setup/upgrade.php
+++ b/scp/upgrade.php
@@ -13,49 +13,26 @@
 
     vim: expandtab sw=4 ts=4 sts=4:
 **********************************************************************/
-function staffLoginPage($msg) {
-        
-    $_SESSION['_staff']['auth']['dest']=THISPAGE;
-    $_SESSION['_staff']['auth']['msg']=$msg;
-    header('Location: ../scp/login.php');
-    exit;
-}
-
-require '../scp/staff.inc.php';
-if(!$thisstaff or !$thisstaff->isAdmin()) {
-    staffLoginPage('Admin Access Required!');
-    exit;
-}
-
-define('SETUPINC', true);
-define('INC_DIR', './inc/');
-define('SQL_DIR', INC_DIR.'sql/');
-
-require_once INC_DIR.'class.upgrader.php';
+require_once 'admin.inc.php';
+require_once INCLUDE_DIR.'class.upgrader.php';
 
 //$_SESSION['ost_upgrader']=null;
 $upgrader = new Upgrader($cfg->getSchemaSignature(), TABLE_PREFIX, SQL_DIR);
-
-
-$wizard=array();
-$wizard['title']='osTicket Upgrade Wizard';
-$wizard['tagline']='Upgrading osTicket to v'.$upgrader->getVersionVerbose();
-$wizard['logo']='logo-upgrade.png';
-$wizard['menu']=array('Upgrade Guide'=>'http://osticket.com/wiki/Upgrade_and_Migration',
-                      'Get Professional Help'=>'http://osticket.com/support');
 $errors=array();
 if($_POST && $_POST['s'] && !$upgrader->isAborted()) {
     switch(strtolower($_POST['s'])) {
         case 'prereq':
-            //XXX: check if it's upgradable version??
-            if(!$ost->isUpgradePending())
+            if(!$ost->isUpgradePending()) {
                 $errors['err']=' Nothing to do! System already upgraded to the current version';
-            elseif(!$upgrader->isUpgradable())
+            } elseif(!$upgrader->isUpgradable()) {
                 $errors['err']='The upgrader does NOT support upgrading from the current vesion!';
-            elseif($upgrader->check_prereq())
+            } elseif(!$upgrader->check_prereq()) {
+                $errors['prereq']='Minimum requirements not met! Refer to Release Notes for more information';
+            } elseif(!strcasecmp(basename(CONFIG_FILE), 'settings.php')) {
+                $errors['err']='Config file rename required to continue!';
+            } else {
                 $upgrader->setState('upgrade');
-            else
-                $errors['prereq']='Minimum requirements not met!';
+            } 
             break;
         case 'upgrade': //Manual upgrade.... when JS (ajax) is not supported.
             if($upgrader->getNumPendingTasks()) {
@@ -77,25 +54,36 @@ if($_POST && $_POST['s'] && !$upgrader->isAborted()) {
 
 switch(strtolower($upgrader->getState())) {
     case 'aborted':
-        $inc='upgrade-aborted.inc.php';
+        $inc='aborted.inc.php';
         break;
     case 'upgrade':
         $inc='upgrade.inc.php';
         break;
     case 'done':
-        $inc='upgrade-done.inc.php';
+        $inc='done.inc.php';
         break;
     default:
-        $inc='upgrade-prereq.inc.php';
+        $inc='prereq.inc.php';
         if($upgrader->isAborted())
-            $inc='upgrade-aborted.inc.php';
+            $inc='aborted.inc.php';
+        elseif(!strcasecmp(basename(CONFIG_FILE), 'settings.php'))
+            $inc='rename.inc.php';
         elseif(!$ost->isUpgradePending())
-            $errors['err']='Nothing to do! System already upgraded to the latest version';
+            $errors['err']='Nothing to do! System already upgraded to <b>'.$ost->getVersion().'</b> with no pending patches to apply.';
         elseif(!$upgrader->isUpgradable())
-            $errors['err']='The upgrader does NOT support upgrading from the current vesion!';
+            $errors['err']=sprintf('The upgrader does NOT support upgrading from the current patch [%s]!', $cfg->getSchemaSignature());
+
 }
 
-require(INC_DIR.'header.inc.php');
-require(INC_DIR.$inc);
-require(INC_DIR.'footer.inc.php');
+$nav = new AdminNav($thisstaff);
+$nav->setTabActive('dashboard');
+$nav->addSubMenu(array('desc'=>'Upgrader',
+                           'title'=>'Upgrader',
+                           'href'=>'upgrade.php',
+                           'iconclass'=>'preferences'),
+                        true);
+$ost->addExtraHeader('<script type="text/javascript" src="./js/upgrader.js"></script>');
+require(STAFFINC_DIR.'header.inc.php');
+require(UPGRADE_DIR.$inc);
+require(STAFFINC_DIR.'footer.inc.php');
 ?>
diff --git a/secure.inc.php b/secure.inc.php
index 3096b3503036e8746a58cea56aa2e85f977b4896..45010979855f9f377e802b569a1d9edc8eb2af91 100644
--- a/secure.inc.php
+++ b/secure.inc.php
@@ -16,9 +16,18 @@
 if(!strcasecmp(basename($_SERVER['SCRIPT_NAME']),basename(__FILE__))) die('Kwaheri!');
 if(!file_exists('client.inc.php')) die('Fatal Error.');
 require_once('client.inc.php');
+
+//Client Login page: Ajax interface can pre-declare the function to trap logins.
+if(!function_exists('clientLoginPage')) {
+    function clientLoginPage($msg ='') {
+        require('./login.php');
+        exit;
+    }
+}
+
 //User must be logged in!
 if(!$thisclient || !$thisclient->getId() || !$thisclient->isValid()){
-    require('./login.php');
+    clientLoginPage();
     exit;
 }
 $thisclient->refreshSession();
diff --git a/setup/cleanup-codebase.sh b/setup/cleanup-codebase.sh
new file mode 100644
index 0000000000000000000000000000000000000000..d9209b91738f3cb8b1f690bdd1d0db6fdf45a481
--- /dev/null
+++ b/setup/cleanup-codebase.sh
@@ -0,0 +1,100 @@
+#!/bin/bash
+
+find_root() {
+    local root=".";
+    while [[ ${#root} < 20 ]]; do
+        [[ -f "$root/main.inc.php" ]] && break
+        root="$root/.."
+    done
+
+    [[ ! -f "$root/main.inc.php" ]] && exit 1;
+
+    pushd . > /dev/null
+    cd $root
+    pwd -P
+    popd > /dev/null
+}
+
+root="$(find_root)"
+if [[ ! -f "$root/main.inc.php" ]]; then
+    echo "!!! Unable to determing codebase root."
+    echo "!!! Try running this inside the codebase path."
+    exit 1;
+fi
+
+while read file; do
+    if [[ -n "$file" && "${file[0]}" != "\x23" && -f "$root/$file" ]]; then
+        echo "Cleaning $file";
+        rm "$root/$file";
+    fi
+done <<< "
+# Removed in 1.6-rc5
+ostconfig.php
+
+# Removed in 1.6.0
+images/button.jpg
+images/logo.jpg
+images/new_ticket_title.jpg
+images/ticket_status_title.jpg
+include/settings.php
+
+# Removed in 1.7.0
+images/bg.gif
+images/fibres.png
+images/home.gif
+images/icons
+images/lipsum.png
+images/logo2.jpg
+images/logout.gif
+images/my_tickets.gif
+images/new_ticket.gif
+images/new_ticket_icon.jpg
+images/poweredby.jpg
+images/rainbow.png
+images/refresh_btn.gif
+images/ticket_status.gif
+images/ticket_status_icon.jpg
+images/verticalbar.jpg
+images/view_closed_btn.gif
+images/view_open_btn.gif
+include/class.msgtpl.php
+include/class.sys.php
+include/client/index.php
+include/client/viewticket.inc.php
+include/ost-config.sameple.php
+include/staff/api.inc.php
+include/staff/changepasswd.inc.php
+include/staff/dept.inc.php
+include/staff/depts.inc.php
+include/staff/editticket.inc.php
+include/staff/mypref.inc.php
+include/staff/myprofile.inc.php
+include/staff/newticket.inc.php
+include/staff/premade.inc.php
+include/staff/reply.inc.php
+include/staff/smtp.inc.php
+include/staff/viewticket.inc.php
+scp/css/autosuggest_inquisitor.css
+scp/css/datepicker.css
+scp/css/main.css
+scp/css/style.css
+scp/css/tabs.css
+scp/images/alert.png
+scp/images/bg-login-box.gif
+scp/images/icons/email_settings.gif
+scp/images/logo-support.gif
+scp/images/minus.gif
+scp/images/ostlogo.jpg
+scp/images/pagebg.jpg
+scp/images/plus.gif
+scp/images/refresh.gif
+scp/images/tab.jpg
+scp/images/view_closed.gif
+scp/images/view_open.gif
+scp/js/ajax.js
+scp/js/autolock.js
+scp/js/bsn.AutoSuggest_2.1.3.js
+scp/js/calendar.js
+scp/js/datepicker.js
+scp/js/tabber.js
+"
diff --git a/setup/images/.DS_Store b/setup/images/.DS_Store
deleted file mode 100644
index 0781e8368c16159126b95903f523919883384c09..0000000000000000000000000000000000000000
Binary files a/setup/images/.DS_Store and /dev/null differ
diff --git a/setup/inc/class.attachment.migrate.php b/setup/inc/class.attachment.migrate.php
deleted file mode 100644
index 20385fd936439fbe868c2069b4fde0601a80b0ac..0000000000000000000000000000000000000000
--- a/setup/inc/class.attachment.migrate.php
+++ /dev/null
@@ -1,162 +0,0 @@
-<?php
-/*********************************************************************
-    class.attachment.migrate.php
-
-    Attachment migration from file-based attachments in pre-1.7 to
-    database-backed attachments in osTicket v1.7. This class provides the
-    hardware to find and retrieve old attachments and move them into the new
-    database scheme with the data in the actual database.
-
-    Copyright (c)  2006-2012 osTicket
-    http://www.osticket.com
-
-    Released under the GNU General Public License WITHOUT ANY WARRANTY.
-    See LICENSE.TXT for details.
-
-    vim: expandtab sw=4 ts=4 sts=4:
-**********************************************************************/
-include_once(INCLUDE_DIR.'class.file.php');
-
-class AttachmentMigrater {
-    function AttachmentMigrater() {
-        $this->queue = array();
-        $this->current = 0;
-        $this->errors = 0;
-        $this->errorList = array();
-    }
-    /**
-     * Identifies attachments in need of migration and queues them for
-     * migration to the new database schema.
-     * 
-     * @see ::next() for output along the way
-     *
-     * Returns:
-     * TRUE/FALSE to indicate if migration finished without any errors
-     */
-    function start_migration() {
-        $this->findAttachments();
-        $this->total = count($this->queue);
-    }
-    /**
-     * Process the migration for a unit of time. This will be used to
-     * overcome the execution time restriction of PHP. This instance can be
-     * stashed in a session and have this method called periodically to
-     * process another batch of attachments
-     */
-    function do_batch($max, $time=20) {
-        $start = time();
-        $this->errors = 0;
-        while (count($this->queue) && $count++ < $max && time()-$start < $time)
-            $this->next();
-        # TODO: Log success/error indication of migration of attachments
-        return (!$this->errors);
-    }
-
-    function queue($fileinfo) {
-        $this->queue[] = $fileinfo;
-    }
-    function getQueueLength() { return count($this->queue); }
-    /**
-     * Processes the next item on the work queue. Emits a JSON messages to
-     * indicate current progress.
-     *
-     * Returns:
-     * TRUE/NULL if the migration was successful
-     */
-    function next() {
-        # Fetch next item -- use the last item so the array indices don't
-        # need to be recalculated for every shift() operation.
-        $info = array_pop($this->queue);
-        # Attach file to the ticket
-        if (!($info['data'] = @file_get_contents($info['path']))) {
-            # Continue with next file
-            return $this->error(
-                sprintf('%s: Cannot read file contents', $info['path']));
-        }
-        # Get the mime/type of each file
-        # XXX: Use finfo_buffer for PHP 5.3+
-        $info['type'] = mime_content_type($info['path']);
-        if (!($fileId = AttachmentFile::save($info))) {
-            return $this->error(
-                sprintf('%s: Unable to migrate attachment', $info['path']));
-        }
-        # Update the ATTACHMENT_TABLE record to set file_id
-        db_query('update '.TICKET_ATTACHMENT_TABLE
-                .' set file_id='.db_input($fileId)
-                .' where attach_id='.db_input($info['attachId']));
-        # Remove disk image of the file. If this fails, the migration for
-        # this file would not be retried, because the file_id in the
-        # TICKET_ATTACHMENT_TABLE has a nonzero value now
-        if (!@unlink($info['path']))
-            $this->error(
-                sprintf('%s: Unable to remove file from disk',
-                $info['path']));
-        # TODO: Log an internal note to the ticket?
-        return true;
-    }
-    /**
-     * From (class Ticket::fixAttachments), used to detect the locations of
-     * attachment files
-     */
-    /* static */ function findAttachments(){
-        global $cfg;
-
-        $res=db_query('SELECT attach_id, file_name, file_key, Ti.created'
-            .' FROM '.TICKET_ATTACHMENT_TABLE.' TA'
-            .' JOIN '.TICKET_TABLE.' Ti ON Ti.ticket_id=TA.ticket_id'
-            .' WHERE NOT file_id');
-        if (!$res) {
-            return $this->error('Unable to query for attached files');
-        } elseif (!db_num_rows($res)) {
-            return true;
-        }
-        $dir=$cfg->getUploadDir();
-        while (list($id,$name,$key,$created)=db_fetch_row($res)) {
-            $month=date('my',strtotime($created));
-            $info=array(
-                'name'=>        $name,
-                'attachId'=>    $id,
-            );
-            $filename15=sprintf("%s/%s_%s",rtrim($dir,'/'),$key,$name);
-            $filename16=sprintf("%s/%s/%s_%s",rtrim($dir,'/'),$month,$key,$name); //new destination.
-            if (file_exists($filename15)) { 
-                $info['path'] = $filename15;
-            } elseif (file_exists($filename16)) {  
-                $info['path'] = $filename16;
-            } else {
-                # XXX Cannot find file for attachment
-                $this->error(sprintf('%s: Unable to locate attachment file',
-                    $name));
-                # No need to further process this file
-                continue;
-            }
-            # TODO: Get the size and mime/type of each file.
-            #
-            # NOTE: If filesize() fails and file_get_contents() doesn't,
-            # then the AttachmentFile::save() method will automatically
-            # estimate the filesize based on the length of the string data
-            # received in $info['data'] -- ie. no need to do that here.
-            #
-            # NOTE: The size is done here because it should be quick to
-            # lookup out of file inode already loaded. The mime/type may
-            # take a while because it will require a second IO to read the
-            # file data.  To ensure this will finish before the
-            # max_execution_time, perform the type match in the ::next()
-            # method since the entire file content will be read there
-            # anyway.
-            $info['size'] = @filesize($info['path']);
-            # Coroutines would be nice ..
-            $this->queue($info);
-        }
-    }
-
-    function error($what) {
-        $this->errors++;
-        $this->errorList[] = $what;
-        # Assist in returning FALSE for inline returns with this method
-        return false;
-    }
-    function getErrors() {
-        return $this->errorList;
-    }
-}
diff --git a/setup/inc/class.installer.php b/setup/inc/class.installer.php
index 7b3dbe534eb0af30f13f27223f555849d30a6bb1..2d284ecedca1e48b25a2fdfd25ad912ec449912a 100644
--- a/setup/inc/class.installer.php
+++ b/setup/inc/class.installer.php
@@ -13,7 +13,7 @@
 
     vim: expandtab sw=4 ts=4 sts=4:
 **********************************************************************/
-require_once INC_DIR.'class.setup.php';
+require_once INCLUDE_DIR.'class.setup.php';
 
 class Installer extends SetupWizard {
 
@@ -99,7 +99,7 @@ class Installer extends SetupWizard {
         define('ADMIN_EMAIL',$vars['admin_email']); //Needed to report SQL errors during install.
         define('PREFIX',$vars['prefix']); //Table prefix
 
-        $schemaFile =INC_DIR.'sql/osticket-v1.7-mysql.sql'; //DB dump.
+        $schemaFile =INC_DIR.'sql/osTicket-mysql.sql'; //DB dump.
         $debug = true; //XXX:Change it to true to show SQL errors.
 
         //Last minute checks.
diff --git a/setup/inc/class.migrater.php b/setup/inc/class.migrater.php
deleted file mode 100644
index de8a3d9590e97b9d78ecb905528bcbc1bc2c03a5..0000000000000000000000000000000000000000
--- a/setup/inc/class.migrater.php
+++ /dev/null
@@ -1,67 +0,0 @@
-<?php
-/*********************************************************************
-    class.migrater.php
-
-    SQL database migrater. This provides the engine capable of rolling the
-    database for an osTicket installation forward (and perhaps even
-    backward) in time using a set of included migration scripts. Each script
-    will roll the database between two database checkpoints. Where possible,
-    the migrater will roll several checkpoint scripts into one to be applied
-    together.
-
-    Jared Hancock <jared@osticket.com>
-    Copyright (c)  2006-2012 osTicket
-    http://www.osticket.com
-
-    Released under the GNU General Public License WITHOUT ANY WARRANTY.
-    See LICENSE.TXT for details.
-
-    vim: expandtab sw=4 ts=4 sts=4:
-**********************************************************************/
-
-class DatabaseMigrater {
-
-    var $start;
-    var $end;
-    var $sqldir;
-
-    function DatabaseMigrater($start, $end, $sqldir) {
-       
-        $this->start = $start;
-        $this->end = $end;
-        $this->sqldir = $sqldir;
-       
-    }
-
-    function getPatches($stop=null) {
-
-        $start= $this->start;
-        $stop = $stop?$stop:$this->end;
-
-        $patches = array();
-        while (true) {
-            $next = glob($this->sqldir . substr($start, 0, 8)
-                         . '-*.patch.sql');
-            if (count($next) == 1) {
-                $patches[] = $next[0];
-                $start = substr(basename($next[0]), 9, 8);
-            } elseif (count($next) == 0) {
-                # There are no patches leaving the current signature. We
-                # have to assume that we've applied all the available
-                # patches.
-                break;
-            } else {
-                # Problem -- more than one patch exists from this snapshot.
-                # We probably need a graph approach to solve this.
-                break;
-            }
-
-            # Break if we've reached our target stop.
-            if(!$start || !strncasecmp($start, $stop, 8))
-                break;
-        }
-
-        return $patches;
-    }
-}
-?>
diff --git a/setup/inc/file-unclean.inc.php b/setup/inc/file-unclean.inc.php
index 1de4607e82bb5a2db8b7aea204fc6c57ba390c26..309fad10bc150d3beac23c937df1ebd448d42238 100644
--- a/setup/inc/file-unclean.inc.php
+++ b/setup/inc/file-unclean.inc.php
@@ -4,7 +4,7 @@ if(!defined('SETUPINC')) die('Kwaheri!');
     <div id="main">
             <h1 style="color:#FF7700;">osTicket is already installed?</h1>
             <div id="intro">
-             <p>Configuration file already changed - which could mean osTicket is already installed or the config file is currupted. If you are trying to upgrade osTicket, then <a href="upgrade.php" >click here</a>.</p>
+             <p>Configuration file already changed - which could mean osTicket is already installed or the config file is currupted. If you are trying to upgrade osTicket, then go to <a href="../scp/" >Admin Panel</a>.</p>
 
              <p>If you believe this is in error, please try replacing the config file with a unchanged template copy and try again or get technical help.</p>
              <p>Refer to the <a target="_blank" href="http://osticket.com/wiki/Installation">Installation Guide</a> on the wiki for more information.</p>
diff --git a/setup/inc/sql/60fcbee1-f8856d56.patch.sql b/setup/inc/sql/60fcbee1-f8856d56.patch.sql
deleted file mode 100644
index 2b7e48599816e88702f709f50557189b160a727e..0000000000000000000000000000000000000000
--- a/setup/inc/sql/60fcbee1-f8856d56.patch.sql
+++ /dev/null
@@ -1,19 +0,0 @@
-DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_event`;
-CREATE TABLE `%TABLE_PREFIX%ticket_event` (
-  `ticket_id` int(11) unsigned NOT NULL default '0',
-  `staff_id` int(11) unsigned NOT NULL,
-  `team_id` int(11) unsigned NOT NULL,
-  `dept_id` int(11) unsigned NOT NULL,
-  `topic_id` int(11) unsigned NOT NULL,
-  `state` enum('created','closed','reopened','assigned','transferred','overdue') NOT NULL,
-  `staff` varchar(255) NOT NULL default 'SYSTEM',
-  `timestamp` datetime NOT NULL,
-  KEY `ticket_state` (`ticket_id`, `state`, `timestamp`),
-  KEY `ticket_stats` (`timestamp`, `state`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_history`;
-DROP TABLE IF EXISTS `%TABLE_PREFIX%history`;
-
-UPDATE `%TABLE_PREFIX%config`
-    SET `schema_signature`='f8856d56e51c5cc3416389de78b54515';
diff --git a/setup/inc/sql/7be60a84-522e5b78.patch.sql b/setup/inc/sql/7be60a84-522e5b78.patch.sql
deleted file mode 100644
index acdaf7d0d3c1f8baaedd40bd68e33b01b97e72c9..0000000000000000000000000000000000000000
--- a/setup/inc/sql/7be60a84-522e5b78.patch.sql
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * @version v1.7-DPR1 (P1)
- */ 
-UPDATE `%TABLE_PREFIX%email_template`
-    SET `ticket_overlimit_subj` = 'Open Tickets Limit Reached'
-    WHERE `tpl_id` = 1 AND `cfg_id` = 1;
-
-UPDATE `%TABLE_PREFIX%config`
-    SET `schema_signature`='522e5b783c2824c67222260ee22baa93';
diff --git a/setup/inc/sql/osticket-v1.7-mysql.sql b/setup/inc/sql/osTicket-mysql.sql
similarity index 96%
rename from setup/inc/sql/osticket-v1.7-mysql.sql
rename to setup/inc/sql/osTicket-mysql.sql
index b8bb7ce263dfbcb7442fda8b2e15b9edebdbb48c..21acfcfe83efe5b52d9ba5d9b153a87a25cc7eb9 100644
--- a/setup/inc/sql/osticket-v1.7-mysql.sql
+++ b/setup/inc/sql/osTicket-mysql.sql
@@ -3,7 +3,7 @@ DROP TABLE IF EXISTS `%TABLE_PREFIX%api_key`;
 CREATE TABLE `%TABLE_PREFIX%api_key` (
   `id` int(10) unsigned NOT NULL auto_increment,
   `isactive` tinyint(1) NOT NULL default '1',
-  `ipaddr` varchar(16) NOT NULL,
+  `ipaddr` varchar(64) NOT NULL,
   `apikey` varchar(255) NOT NULL,
   `notes` text,
   `updated` datetime NOT NULL,
@@ -175,6 +175,7 @@ CREATE TABLE `%TABLE_PREFIX%department` (
   `dept_name` varchar(32) NOT NULL default '',
   `dept_signature` tinytext NOT NULL,
   `ispublic` tinyint(1) unsigned NOT NULL default '1',
+  `group_membership` tinyint(1) NOT NULL default '0',
   `ticket_auto_response` tinyint(1) NOT NULL default '1',
   `message_auto_response` tinyint(1) NOT NULL default '0',
   `updated` datetime NOT NULL,
@@ -237,6 +238,7 @@ CREATE TABLE `%TABLE_PREFIX%email_filter` (
   `reject_email` tinyint(1) unsigned NOT NULL default '0',
   `use_replyto_email` tinyint(1) unsigned NOT NULL default '0',
   `disable_autoresponder` tinyint(1) unsigned NOT NULL default '0',
+  `canned_response_id` int(11) unsigned NOT NULL default '0',
   `email_id` int(10) unsigned NOT NULL default '0',
   `priority_id` int(10) unsigned NOT NULL default '0',
   `dept_id` int(10) unsigned NOT NULL default '0',
@@ -338,7 +340,6 @@ CREATE TABLE `%TABLE_PREFIX%groups` (
   `group_id` int(10) unsigned NOT NULL auto_increment,
   `group_enabled` tinyint(1) unsigned NOT NULL default '1',
   `group_name` varchar(50) NOT NULL default '',
-  `dept_access` varchar(255) NOT NULL default '',
   `can_create_tickets` tinyint(1) unsigned NOT NULL default '1',
   `can_edit_tickets` tinyint(1) unsigned NOT NULL default '1',
   `can_delete_tickets` tinyint(1) unsigned NOT NULL default '0',
@@ -355,10 +356,21 @@ CREATE TABLE `%TABLE_PREFIX%groups` (
   KEY `group_active` (`group_enabled`)
 ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
 
-INSERT INTO `%TABLE_PREFIX%groups` (`group_id`, `group_enabled`, `group_name`, `dept_access`, `can_create_tickets`, `can_edit_tickets`, `can_delete_tickets`, `can_close_tickets`, `can_assign_tickets`, `can_transfer_tickets`, `can_ban_emails`, `can_manage_premade`, `can_manage_faq`, `notes`) VALUES
-    (1, 1, 'Admins', '2,1', 1, 1, 1, 1, 1, 1, 1, 1, 1, 'overlords'),
-    (2, 1, 'Managers', '2,1', 1, 1, 1, 1, 1, 1, 1, 1, 1, ''),
-    (3, 1, 'Staff', '2,1', 1, 1, 0, 1, 1, 1, 0, 0, 0, '');
+INSERT INTO `%TABLE_PREFIX%groups` (`group_id`, `group_enabled`, `group_name`, `can_create_tickets`, `can_edit_tickets`, `can_delete_tickets`, `can_close_tickets`, `can_assign_tickets`, `can_transfer_tickets`, `can_ban_emails`, `can_manage_premade`, `can_manage_faq`, `notes`, `created`, `updated`) VALUES
+    (1, 1, 'Admins', 1, 1, 1, 1, 1, 1, 1, 1, 1, 'overlords', NOW(), NOW()),
+    (2, 1, 'Managers', 1, 1, 1, 1, 1, 1, 1, 1, 1, '', NOW(), NOW()),
+    (3, 1, 'Staff', 1, 1, 0, 1, 1, 1, 0, 0, 0, '', NOW(), NOW());
+
+DROP TABLE IF EXISTS `%TABLE_PREFIX%group_dept_access`;
+CREATE TABLE `%TABLE_PREFIX%group_dept_access` (
+  `group_id` int(10) unsigned NOT NULL default '0',
+  `dept_id` int(10) unsigned NOT NULL default '0',
+  UNIQUE KEY `group_dept` (`group_id`,`dept_id`),
+  KEY `dept_id`  (`dept_id`)
+) ENGINE=MyISAM;
+
+INSERT INTO `%TABLE_PREFIX%group_dept_access` (`group_id`, `dept_id`) VALUES
+    (1, 1), (1, 2), (2, 1), (2, 2), (3, 1), (3, 2);
 
 DROP TABLE IF EXISTS `%TABLE_PREFIX%help_topic`;
 CREATE TABLE `%TABLE_PREFIX%help_topic` (
@@ -423,9 +435,8 @@ CREATE TABLE `%TABLE_PREFIX%session` (
   `session_data` longtext collate utf8_unicode_ci,
   `session_expire` datetime default NULL,
   `session_updated` datetime default NULL,
-  `user_id` int(10) unsigned NOT NULL default '0' COMMENT 'osTicket staff
-ID',
-  `user_ip` varchar(32) collate utf8_unicode_ci NOT NULL,
+  `user_id` int(10) unsigned NOT NULL default '0' COMMENT 'osTicket staff ID',
+  `user_ip` varchar(64) NOT NULL,
   `user_agent` varchar(255) collate utf8_unicode_ci NOT NULL,
   PRIMARY KEY  (`session_id`),
   KEY `updated` (`session_updated`),
@@ -497,7 +508,7 @@ CREATE TABLE `%TABLE_PREFIX%syslog` (
   `title` varchar(255) NOT NULL,
   `log` text NOT NULL,
   `logger` varchar(64) NOT NULL,
-  `ip_address` varchar(16) NOT NULL,
+  `ip_address` varchar(64) NOT NULL,
   `created` datetime NOT NULL,
   `updated` datetime NOT NULL,
   PRIMARY KEY  (`log_id`),
@@ -520,8 +531,8 @@ CREATE TABLE `%TABLE_PREFIX%team` (
   KEY `lead_id` (`lead_id`)
 ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
 
-INSERT INTO `%TABLE_PREFIX%team` (`lead_id`, `isenabled`, `noalerts`, `name`, `notes`)
-    VALUES (0, 1, 0, 'Level I Support', '');
+INSERT INTO `%TABLE_PREFIX%team` (`lead_id`, `isenabled`, `noalerts`, `name`, `notes`, `created`, `updated`)
+    VALUES (0, 1, 0, 'Level I Support', '', NOW(), NOW());
 
 DROP TABLE IF EXISTS `%TABLE_PREFIX%team_member`;
 CREATE TABLE `%TABLE_PREFIX%team_member` (
@@ -546,7 +557,7 @@ CREATE TABLE `%TABLE_PREFIX%ticket` (
   `subject` varchar(64) NOT NULL default '[no subject]',
   `phone` varchar(16) default NULL,
   `phone_ext` varchar(8) default NULL,
-  `ip_address` varchar(16) NOT NULL default '',
+  `ip_address` varchar(64) NOT NULL default '',
   `status` enum('open','closed') NOT NULL default 'open',
   `source` enum('Web','Email','Phone','API','Other') NOT NULL default
 'Other',
@@ -660,6 +671,7 @@ CREATE TABLE `%TABLE_PREFIX%ticket_thread` (
   PRIMARY KEY  (`id`),
   KEY `ticket_id` (`ticket_id`),
   KEY `staff_id` (`staff_id`),
+  KEY `pid` (`pid`),
   FULLTEXT KEY `body` (`body`)
 ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
 
diff --git a/setup/inc/sql/osTicket-mysql.sql.md5 b/setup/inc/sql/osTicket-mysql.sql.md5
new file mode 100644
index 0000000000000000000000000000000000000000..ad088e947dfe5eac019e5860c29e776bfabe60b1
--- /dev/null
+++ b/setup/inc/sql/osTicket-mysql.sql.md5
@@ -0,0 +1 @@
+2e7531a201b5b8650dcd43681a832ebd
diff --git a/setup/inc/sql/osticket-v1.6.sql b/setup/inc/sql/osticket-v1.6.sql
deleted file mode 100644
index 7dcf180bb27f53f9a1b1a8cccae94604848140d0..0000000000000000000000000000000000000000
--- a/setup/inc/sql/osticket-v1.6.sql
+++ /dev/null
@@ -1,509 +0,0 @@
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%api_key`;
-CREATE TABLE `%TABLE_PREFIX%api_key` (
-  `id` int(10) unsigned NOT NULL auto_increment,
-  `isactive` tinyint(1) NOT NULL default '1',
-  `ipaddr` varchar(16) NOT NULL,
-  `apikey` varchar(255) NOT NULL,
-  `updated` datetime NOT NULL default '0000-00-00 00:00:00',
-  `created` datetime NOT NULL default '0000-00-00 00:00:00',
-  PRIMARY KEY  (`id`),
-  UNIQUE KEY `ipaddr` (`ipaddr`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%api_key` (`id`, `isactive`, `ipaddr`, `apikey`, `updated`, `created`) VALUES (1, 1, '192.168.1.5', 'siri!', NOW(), NOW());
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%config`;
-CREATE TABLE `%TABLE_PREFIX%config` (
-  `id` tinyint(1) unsigned NOT NULL auto_increment,
-  `isonline` tinyint(1) unsigned NOT NULL default '0',
-  `timezone_offset` float(3,1) NOT NULL default '0.0',
-  `enable_daylight_saving` tinyint(1) unsigned NOT NULL default '0',
-  `staff_ip_binding` tinyint(1) unsigned NOT NULL default '1',
-  `staff_max_logins` tinyint(3) unsigned NOT NULL default '4',
-  `staff_login_timeout` int(10) unsigned NOT NULL default '2',
-  `staff_session_timeout` int(10) unsigned NOT NULL default '30',
-  `client_max_logins` tinyint(3) unsigned NOT NULL default '4',
-  `client_login_timeout` int(10) unsigned NOT NULL default '2',
-  `client_session_timeout` int(10) unsigned NOT NULL default '30',
-  `max_page_size` tinyint(3) unsigned NOT NULL default '25',
-  `max_open_tickets` tinyint(3) unsigned NOT NULL default '0',
-  `max_file_size` int(11) unsigned NOT NULL default '1048576',
-  `autolock_minutes` tinyint(3) unsigned NOT NULL default '3',
-  `overdue_grace_period` int(10) unsigned NOT NULL default '0',
-  `alert_email_id` tinyint(4) unsigned NOT NULL default '0',
-  `default_email_id` tinyint(4) unsigned NOT NULL default '0',
-  `default_dept_id` tinyint(3) unsigned NOT NULL default '0',
-  `default_priority_id` tinyint(2) unsigned NOT NULL default '2',
-  `default_template_id` tinyint(4) unsigned NOT NULL default '1',
-  `default_smtp_id` tinyint(4) unsigned NOT NULL default '0',
-  `spoof_default_smtp` tinyint(1) unsigned NOT NULL default '0',
-  `clickable_urls` tinyint(1) unsigned NOT NULL default '1',
-  `allow_priority_change` tinyint(1) unsigned NOT NULL default '0',
-  `use_email_priority` tinyint(1) unsigned NOT NULL default '0',
-  `enable_captcha` tinyint(1) unsigned NOT NULL default '0',
-  `enable_auto_cron` tinyint(1) unsigned NOT NULL default '0',
-  `enable_mail_fetch` tinyint(1) unsigned NOT NULL default '0',
-  `enable_email_piping` tinyint(1) unsigned NOT NULL default '0',
-  `send_sql_errors` tinyint(1) unsigned NOT NULL default '1',
-  `send_mailparse_errors` tinyint(1) unsigned NOT NULL default '1',
-  `send_login_errors` tinyint(1) unsigned NOT NULL default '1',
-  `save_email_headers` tinyint(1) unsigned NOT NULL default '1',
-  `strip_quoted_reply` tinyint(1) unsigned NOT NULL default '1',
-  `log_ticket_activity` tinyint(1) unsigned NOT NULL default '1',
-  `ticket_autoresponder` tinyint(1) unsigned NOT NULL default '0',
-  `message_autoresponder` tinyint(1) unsigned NOT NULL default '0',
-  `ticket_notice_active` tinyint(1) unsigned NOT NULL default '0',
-  `ticket_alert_active` tinyint(1) unsigned NOT NULL default '0',
-  `ticket_alert_admin` tinyint(1) unsigned NOT NULL default '1',
-  `ticket_alert_dept_manager` tinyint(1) unsigned NOT NULL default '1',
-  `ticket_alert_dept_members` tinyint(1) unsigned NOT NULL default '0',
-  `message_alert_active` tinyint(1) unsigned NOT NULL default '0',
-  `message_alert_laststaff` tinyint(1) unsigned NOT NULL default '1',
-  `message_alert_assigned` tinyint(1) unsigned NOT NULL default '1',
-  `message_alert_dept_manager` tinyint(1) unsigned NOT NULL default '0',
-  `note_alert_active` tinyint(1) unsigned NOT NULL default '0',
-  `note_alert_laststaff` tinyint(1) unsigned NOT NULL default '1',
-  `note_alert_assigned` tinyint(1) unsigned NOT NULL default '1',
-  `note_alert_dept_manager` tinyint(1) unsigned NOT NULL default '0',
-  `overdue_alert_active` tinyint(1) unsigned NOT NULL default '0',
-  `overdue_alert_assigned` tinyint(1) unsigned NOT NULL default '1',
-  `overdue_alert_dept_manager` tinyint(1) unsigned NOT NULL default '1',
-  `overdue_alert_dept_members` tinyint(1) unsigned NOT NULL default '0',
-  `auto_assign_reopened_tickets` tinyint(1) unsigned NOT NULL default '1',
-  `show_assigned_tickets` tinyint(1) unsigned NOT NULL default '0',
-  `show_answered_tickets` tinyint(1) NOT NULL default '0',
-  `hide_staff_name` tinyint(1) unsigned NOT NULL default '0',
-  `overlimit_notice_active` tinyint(1) unsigned NOT NULL default '0',
-  `email_attachments` tinyint(1) unsigned NOT NULL default '1',
-  `allow_attachments` tinyint(1) unsigned NOT NULL default '0',
-  `allow_email_attachments` tinyint(1) unsigned NOT NULL default '0',
-  `allow_online_attachments` tinyint(1) unsigned NOT NULL default '0',
-  `allow_online_attachments_onlogin` tinyint(1) unsigned NOT NULL default '0',
-  `random_ticket_ids` tinyint(1) unsigned NOT NULL default '1',
-  `log_level` tinyint(1) unsigned NOT NULL default '2',
-  `log_graceperiod` int(10) unsigned NOT NULL default '12',
-  `upload_dir` varchar(255) NOT NULL default '',
-  `allowed_filetypes` varchar(255) NOT NULL default '.doc, .pdf',
-  `time_format` varchar(32) NOT NULL default ' h:i A',
-  `date_format` varchar(32) NOT NULL default 'm/d/Y',
-  `datetime_format` varchar(60) NOT NULL default 'm/d/Y g:i a',
-  `daydatetime_format` varchar(60) NOT NULL default 'D, M j Y g:ia',
-  `reply_separator` varchar(60) NOT NULL default '-- do not edit --',
-  `admin_email` varchar(125) NOT NULL default '',
-  `helpdesk_title` varchar(255) NOT NULL default 'osTicket Support Ticket System',
-  `helpdesk_url` varchar(255) NOT NULL default '',
-  `api_passphrase` varchar(125) NOT NULL default '',
-  `ostversion` varchar(16) NOT NULL default '',
-  `updated` timestamp NOT NULL default CURRENT_TIMESTAMP,
-  PRIMARY KEY  (`id`),
-  KEY `isoffline` (`isonline`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%department`;
-CREATE TABLE `%TABLE_PREFIX%department` (
-  `dept_id` int(11) unsigned NOT NULL auto_increment,
-  `tpl_id` int(10) unsigned NOT NULL default '0',
-  `email_id` int(10) unsigned NOT NULL default '0',
-  `autoresp_email_id` int(10) unsigned NOT NULL default '0',
-  `manager_id` int(10) unsigned NOT NULL default '0',
-  `dept_name` varchar(32) NOT NULL default '',
-  `dept_signature` tinytext NOT NULL,
-  `ispublic` tinyint(1) unsigned NOT NULL default '1',
-  `ticket_auto_response` tinyint(1) NOT NULL default '1',
-  `message_auto_response` tinyint(1) NOT NULL default '0',
-  `can_append_signature` tinyint(1) NOT NULL default '1',
-  `updated` datetime NOT NULL default '0000-00-00 00:00:00',
-  `created` datetime NOT NULL default '0000-00-00 00:00:00',
-  PRIMARY KEY  (`dept_id`),
-  UNIQUE KEY `dept_name` (`dept_name`),
-  KEY `manager_id` (`manager_id`),
-  KEY `autoresp_email_id` (`autoresp_email_id`),
-  KEY `tpl_id` (`tpl_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%department` (`dept_id`, `tpl_id`, `email_id`, `autoresp_email_id`, `manager_id`, `dept_name`, `dept_signature`, `ispublic`, `ticket_auto_response`, `message_auto_response`, `can_append_signature`, `updated`, `created`) VALUES
-(1, 0, 1, 0, 0, 'Support', 'Support Dept', 1, 1, 1, 1, NOW(), NOW()),
-(2, 0, 1, 0, 0, 'Billing', 'Billing Dept', 1, 1, 1, 1, NOW(), NOW());
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%email`;
-CREATE TABLE `%TABLE_PREFIX%email` (
-  `email_id` int(11) unsigned NOT NULL auto_increment,
-  `noautoresp` tinyint(1) unsigned NOT NULL default '0',
-  `priority_id` tinyint(3) unsigned NOT NULL default '2',
-  `dept_id` tinyint(3) unsigned NOT NULL default '0',
-  `email` varchar(125) NOT NULL default '',
-  `name` varchar(32) NOT NULL default '',
-  `userid` varchar(125) NOT NULL,
-  `userpass` varchar(125) NOT NULL,
-  `mail_active` tinyint(1) NOT NULL default '0',
-  `mail_host` varchar(125) NOT NULL,
-  `mail_protocol` enum('POP','IMAP') NOT NULL default 'POP',
-  `mail_encryption` enum('NONE','SSL') NOT NULL,
-  `mail_port` int(6) default NULL,
-  `mail_fetchfreq` tinyint(3) NOT NULL default '5',
-  `mail_fetchmax` tinyint(4) NOT NULL default '30',
-  `mail_delete` tinyint(1) NOT NULL default '0',
-  `mail_errors` tinyint(3) NOT NULL default '0',
-  `mail_lasterror` datetime default NULL,
-  `mail_lastfetch` datetime default NULL,
-  `smtp_active` tinyint(1) default '0',
-  `smtp_host` varchar(125) NOT NULL,
-  `smtp_port` int(6) default NULL,
-  `smtp_secure` tinyint(1) NOT NULL default '1',
-  `smtp_auth` tinyint(1) NOT NULL default '1',
-  `created` datetime NOT NULL default '0000-00-00 00:00:00',
-  `updated` datetime NOT NULL default '0000-00-00 00:00:00',
-  PRIMARY KEY  (`email_id`),
-  UNIQUE KEY `email` (`email`),
-  KEY `priority_id` (`priority_id`),
-  KEY `dept_id` (`dept_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%email_banlist`;
-CREATE TABLE `%TABLE_PREFIX%email_banlist` (
-  `id` int(11) NOT NULL auto_increment,
-  `email` varchar(255) NOT NULL default '',
-  `submitter` varchar(126) NOT NULL default '',
-  `added` datetime NOT NULL default '0000-00-00 00:00:00',
-  PRIMARY KEY  (`id`),
-  UNIQUE KEY `email` (`email`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%email_banlist` (`id`, `email`, `submitter`, `added`) VALUES
-(1, 'test@example.com', 'System', NOW());
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%email_template`;
-CREATE TABLE `%TABLE_PREFIX%email_template` (
-  `tpl_id` int(11) NOT NULL auto_increment,
-  `cfg_id` int(10) unsigned NOT NULL default '0',
-  `name` varchar(32) NOT NULL default '',
-  `notes` text,
-  `ticket_autoresp_subj` varchar(255) NOT NULL default '',
-  `ticket_autoresp_body` text NOT NULL,
-  `ticket_notice_subj` varchar(255) NOT NULL,
-  `ticket_notice_body` text NOT NULL,
-  `ticket_alert_subj` varchar(255) NOT NULL default '',
-  `ticket_alert_body` text NOT NULL,
-  `message_autoresp_subj` varchar(255) NOT NULL default '',
-  `message_autoresp_body` text NOT NULL,
-  `message_alert_subj` varchar(255) NOT NULL default '',
-  `message_alert_body` text NOT NULL,
-  `note_alert_subj` varchar(255) NOT NULL,
-  `note_alert_body` text NOT NULL,
-  `assigned_alert_subj` varchar(255) NOT NULL default '',
-  `assigned_alert_body` text NOT NULL,
-  `ticket_overdue_subj` varchar(255) NOT NULL default '',
-  `ticket_overdue_body` text NOT NULL,
-  `ticket_overlimit_subj` varchar(255) NOT NULL default '',
-  `ticket_overlimit_body` text NOT NULL,
-  `ticket_reply_subj` varchar(255) NOT NULL default '',
-  `ticket_reply_body` text NOT NULL,
-  `created` datetime NOT NULL default '0000-00-00 00:00:00',
-  `updated` datetime NOT NULL default '0000-00-00 00:00:00',
-  PRIMARY KEY  (`tpl_id`),
-  KEY `cfg_id` (`cfg_id`),
-  FULLTEXT KEY `message_subj` (`ticket_reply_subj`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-
-INSERT INTO `%TABLE_PREFIX%email_template` (`tpl_id`, `cfg_id`, `name`, `notes`, `ticket_autoresp_subj`, `ticket_autoresp_body`, `ticket_notice_subj`, `ticket_notice_body`, `ticket_alert_subj`, `ticket_alert_body`, `message_autoresp_subj`, `message_autoresp_body`, `message_alert_subj`, `message_alert_body`, `note_alert_subj`, `note_alert_body`, `assigned_alert_subj`, `assigned_alert_body`, `ticket_overdue_subj`, `ticket_overdue_body`, `ticket_overlimit_subj`, `ticket_overlimit_body`, `ticket_reply_subj`, `ticket_reply_body`, `created`, `updated`) VALUES
-(1, 1, 'osTicket Default Template', 'Default osTicket templates', 'Support Ticket Opened [#%ticket]', '%name,\r\n\r\nA request for support has been created and assigned ticket #%ticket. A representative will follow-up with you as soon as possible.\r\n\r\nYou can view this ticket''s progress online here: %url/view.php?e=%email&t=%ticket.\r\n\r\nIf you wish to send additional comments or information regarding this issue, please don''t open a new ticket. Simply login using the link above and update the ticket.\r\n\r\n%signature', '[#%ticket] %subject', '%name,\r\n\r\nOur customer care team has created a ticket, #%ticket on your behalf, with the following message.\r\n\r\n%message\r\n\r\nIf you wish to provide additional comments or information regarding this issue, please don''t open a new ticket. You can update or view this ticket''s progress online here: %url/view.php?e=%email&t=%ticket.\r\n\r\n%signature', 'New Ticket Alert', '%staff,\r\n\r\nNew ticket #%ticket created.\r\n-------------------\r\nName: %name\r\nEmail: %email\r\nDept: %dept\r\n\r\n%message\r\n-------------------\r\n\r\nTo view/respond to the ticket, please login to the support ticket system.\r\n\r\n- Your friendly Customer Support System - powered by osTicket.', '[#%ticket] Message Added', '%name,\r\n\r\nYour reply to support request #%ticket has been noted.\r\n\r\nYou can view this support request progress online here: %url/view.php?e=%email&t=%ticket.\r\n\r\n%signature', 'New Message Alert', '%staff,\r\n\r\nNew message appended to ticket #%ticket\r\n\r\n----------------------\r\nName: %name\r\nEmail: %email\r\nDept: %dept\r\n\r\n%message\r\n-------------------\r\n\r\nTo view/respond to the ticket, please login to the support ticket system.\r\n\r\n- Your friendly Customer Support System - powered by osTicket.', 'New Internal Note Alert', '%staff,\r\n\r\nInternal note appended to ticket #%ticket\r\n\r\n----------------------\r\nName: %name\r\n\r\n%note\r\n-------------------\r\n\r\nTo view/respond to the ticket, please login to the support ticket system.\r\n\r\n- Your friendly Customer Support System - powered by osTicket.', 'Ticket #%ticket Assigned to you', '%assignee,\r\n\r\n%assigner has assigned ticket #%ticket to you!\r\n\r\n%message\r\n\r\nTo view complete details, simply login to the support system.\r\n\r\n- Your friendly Support Ticket System - powered by osTicket.', 'Stale Ticket Alert', '%staff,\r\n\r\nA ticket, #%ticket assigned to you or in your department is seriously overdue.\r\n\r\n%url/scp/tickets.php?id=%id\r\n\r\nWe should all work hard to guarantee that all tickets are being addressed in a timely manner. Enough baby talk...please address the issue or you will hear from me again.\r\n\r\n\r\n- Your friendly (although with limited patience) Support Ticket System - powered by osTicket.', 'Support Ticket Denied', '%name\r\n\r\nNo support ticket has been created. You''ve exceeded maximum number of open tickets allowed.\r\n\r\nThis is a temporary block. To be able to open another ticket, one of your pending tickets must be closed. To update or add comments to an open ticket simply login using the link below.\r\n\r\n%url/view.php?e=%email\r\n\r\nThank you.\r\n\r\nSupport Ticket System', '[#%ticket] %subject', '%name,\r\n\r\nA customer support staff member has replied to your support request, #%ticket with the following response:\r\n\r\n%response\r\n\r\nWe hope this response has sufficiently answered your questions. If not, please do not send another email. Instead, reply to this email or login to your account for a complete archive of all your support requests and responses.\r\n\r\n%url/view.php?e=%email&t=%ticket\r\n\r\n%signature', NOW(), NOW());
-
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%groups`;
-CREATE TABLE `%TABLE_PREFIX%groups` (
-  `group_id` int(10) unsigned NOT NULL auto_increment,
-  `group_enabled` tinyint(1) unsigned NOT NULL default '1',
-  `group_name` varchar(50) NOT NULL default '',
-  `dept_access` varchar(255) NOT NULL default '',
-  `can_create_tickets` tinyint(1) unsigned NOT NULL default '1',
-  `can_edit_tickets` tinyint(1) unsigned NOT NULL default '1',
-  `can_delete_tickets` tinyint(1) unsigned NOT NULL default '0',
-  `can_close_tickets` tinyint(1) unsigned NOT NULL default '0',
-  `can_transfer_tickets` tinyint(1) unsigned NOT NULL default '1',
-  `can_ban_emails` tinyint(1) unsigned NOT NULL default '0',
-  `can_manage_kb` tinyint(1) unsigned NOT NULL default '0',
-  `created` datetime NOT NULL default '0000-00-00 00:00:00',
-  `updated` datetime NOT NULL default '0000-00-00 00:00:00',
-  PRIMARY KEY  (`group_id`),
-  KEY `group_active` (`group_enabled`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%groups` (`group_id`, `group_enabled`, `group_name`, `dept_access`, `can_create_tickets`, `can_edit_tickets`, `can_delete_tickets`, `can_close_tickets`, `can_transfer_tickets`, `can_ban_emails`, `can_manage_kb`, `created`, `updated`) VALUES
-(1, 1, 'Admins', '1', 1, 1, 1, 1, 1, 1, 1, NOW(), NOW()),
-(2, 1, 'Managers', '1', 1, 1, 0, 1, 1, 1, 1, NOW(),NOW()),
-(3, 1, 'Staff', '1', 1, 0, 0, 0, 0, 0, 0, NOW(), NOW());
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%help_topic`;
-CREATE TABLE `%TABLE_PREFIX%help_topic` (
-  `topic_id` int(11) unsigned NOT NULL auto_increment,
-  `isactive` tinyint(1) unsigned NOT NULL default '1',
-  `noautoresp` tinyint(3) unsigned NOT NULL default '0',
-  `priority_id` tinyint(3) unsigned NOT NULL default '0',
-  `dept_id` tinyint(3) unsigned NOT NULL default '0',
-  `topic` varchar(32) NOT NULL default '',
-  `created` datetime NOT NULL default '0000-00-00 00:00:00',
-  `updated` datetime NOT NULL default '0000-00-00 00:00:00',
-  PRIMARY KEY  (`topic_id`),
-  UNIQUE KEY `topic` (`topic`),
-  KEY `priority_id` (`priority_id`),
-  KEY `dept_id` (`dept_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-
-INSERT INTO `%TABLE_PREFIX%help_topic` (`topic_id`, `isactive`, `noautoresp`, `priority_id`, `dept_id`, `topic`, `created`, `updated`) VALUES
-(1, 1, 0, 2, 1, 'Support', NOW(), NOW()),
-(2, 1, 0, 3, 1, 'Billing', NOW(), NOW());
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%kb_premade`;
-CREATE TABLE `%TABLE_PREFIX%kb_premade` (
-  `premade_id` int(10) unsigned NOT NULL auto_increment,
-  `dept_id` int(10) unsigned NOT NULL default '0',
-  `isenabled` tinyint(1) unsigned NOT NULL default '1',
-  `title` varchar(125) NOT NULL default '',
-  `answer` text NOT NULL,
-  `created` datetime NOT NULL default '0000-00-00 00:00:00',
-  `updated` datetime NOT NULL default '0000-00-00 00:00:00',
-  PRIMARY KEY  (`premade_id`),
-  UNIQUE KEY `title_2` (`title`),
-  KEY `dept_id` (`dept_id`),
-  KEY `active` (`isenabled`),
-  FULLTEXT KEY `title` (`title`,`answer`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%kb_premade` (`premade_id`, `dept_id`, `isenabled`, `title`, `answer`, `created`, `updated`) VALUES
-(1, 0, 1, 'What is osTicket (sample)?', '\r\nosTicket is a widely-used open source support ticket system, an attractive alternative to higher-cost and complex customer support systems - simple, lightweight, reliable, open source, web-based and easy to setup and use.', NOW(), NOW()),
-(2, 0, 1, 'Sample (with variables)', '\r\n%name,\r\n\r\nYour ticket #%ticket created on %createdate is in %dept department.\r\n\r\n', NOW(), NOW());
-
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%staff`;
-CREATE TABLE `%TABLE_PREFIX%staff` (
-  `staff_id` int(11) unsigned NOT NULL auto_increment,
-  `group_id` int(10) unsigned NOT NULL default '0',
-  `dept_id` int(10) unsigned NOT NULL default '0',
-  `username` varchar(32) NOT NULL default '',
-  `firstname` varchar(32) default NULL,
-  `lastname` varchar(32) default NULL,
-  `passwd` varchar(128) default NULL,
-  `email` varchar(128) default NULL,
-  `phone` varchar(24) NOT NULL default '',
-  `phone_ext` varchar(6) default NULL,
-  `mobile` varchar(24) NOT NULL default '',
-  `signature` tinytext NOT NULL,
-  `isactive` tinyint(1) NOT NULL default '1',
-  `isadmin` tinyint(1) NOT NULL default '0',
-  `isvisible` tinyint(1) unsigned NOT NULL default '1',
-  `onvacation` tinyint(1) unsigned NOT NULL default '0',
-  `daylight_saving` tinyint(1) unsigned NOT NULL default '0',
-  `append_signature` tinyint(1) unsigned NOT NULL default '0',
-  `change_passwd` tinyint(1) unsigned NOT NULL default '0',
-  `timezone_offset` float(3,1) NOT NULL default '0.0',
-  `max_page_size` int(11) unsigned NOT NULL default '0',
-  `auto_refresh_rate` int(10) unsigned NOT NULL default '0',
-  `created` datetime NOT NULL default '0000-00-00 00:00:00',
-  `lastlogin` datetime default NULL,
-  `updated` datetime NOT NULL default '0000-00-00 00:00:00',
-  PRIMARY KEY  (`staff_id`),
-  UNIQUE KEY `username` (`username`),
-  KEY `dept_id` (`dept_id`),
-  KEY `issuperuser` (`isadmin`),
-  KEY `group_id` (`group_id`,`staff_id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%syslog`;
-CREATE TABLE `%TABLE_PREFIX%syslog` (
-  `log_id` int(11) unsigned NOT NULL auto_increment,
-  `log_type` enum('Debug','Warning','Error') NOT NULL,
-  `title` varchar(255) NOT NULL,
-  `log` text NOT NULL,
-  `logger` varchar(64) NOT NULL,
-  `ip_address` varchar(16) NOT NULL,
-  `created` datetime NOT NULL default '0000-00-00 00:00:00',
-  `updated` datetime NOT NULL default '0000-00-00 00:00:00',
-  PRIMARY KEY  (`log_id`),
-  KEY `log_type` (`log_type`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket`;
-CREATE TABLE `%TABLE_PREFIX%ticket` (
-  `ticket_id` int(11) unsigned NOT NULL auto_increment,
-  `ticketID` int(11) unsigned NOT NULL default '0',
-  `dept_id` int(10) unsigned NOT NULL default '1',
-  `priority_id` int(10) unsigned NOT NULL default '2',
-  `topic_id` int(10) unsigned NOT NULL default '0',
-  `staff_id` int(10) unsigned NOT NULL default '0',
-  `email` varchar(120) NOT NULL default '',
-  `name` varchar(32) NOT NULL default '',
-  `subject` varchar(64) NOT NULL default '[no subject]',
-  `helptopic` varchar(255) default NULL,
-  `phone` varchar(16) default NULL,
-  `phone_ext` varchar(8) default NULL,
-  `ip_address` varchar(16) NOT NULL default '',
-  `status` enum('open','closed') NOT NULL default 'open',
-  `source` enum('Web','Email','Phone','Other') NOT NULL default 'Other',
-  `isoverdue` tinyint(1) unsigned NOT NULL default '0',
-  `isanswered` tinyint(1) unsigned NOT NULL default '0',
-  `duedate` datetime default NULL,
-  `reopened` datetime default NULL,
-  `closed` datetime default NULL,
-  `lastmessage` datetime default NULL,
-  `lastresponse` datetime default NULL,
-  `created` datetime NOT NULL default '0000-00-00 00:00:00',
-  `updated` datetime NOT NULL default '0000-00-00 00:00:00',
-  PRIMARY KEY  (`ticket_id`),
-  UNIQUE KEY `email_extid` (`ticketID`,`email`),
-  KEY `dept_id` (`dept_id`),
-  KEY `staff_id` (`staff_id`),
-  KEY `status` (`status`),
-  KEY `priority_id` (`priority_id`),
-  KEY `created` (`created`),
-  KEY `closed` (`closed`),
-  KEY `duedate` (`duedate`),
-  KEY `topic_id` (`topic_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_attachment`;
-CREATE TABLE `%TABLE_PREFIX%ticket_attachment` (
-  `attach_id` int(11) unsigned NOT NULL auto_increment,
-  `ticket_id` int(11) unsigned NOT NULL default '0',
-  `ref_id` int(11) unsigned NOT NULL default '0',
-  `ref_type` enum('M','R') NOT NULL default 'M',
-  `file_size` varchar(32) NOT NULL default '',
-  `file_name` varchar(128) NOT NULL default '',
-  `file_key` varchar(128) NOT NULL default '',
-  `deleted` tinyint(1) unsigned NOT NULL default '0',
-  `created` datetime NOT NULL default '0000-00-00 00:00:00',
-  `updated` datetime default NULL,
-  PRIMARY KEY  (`attach_id`),
-  KEY `ticket_id` (`ticket_id`),
-  KEY `ref_type` (`ref_type`),
-  KEY `ref_id` (`ref_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_lock`;
-CREATE TABLE `%TABLE_PREFIX%ticket_lock` (
-  `lock_id` int(11) unsigned NOT NULL auto_increment,
-  `ticket_id` int(11) unsigned NOT NULL default '0',
-  `staff_id` int(10) unsigned NOT NULL default '0',
-  `expire` datetime default NULL,
-  `created` datetime NOT NULL default '0000-00-00 00:00:00',
-  PRIMARY KEY  (`lock_id`),
-  UNIQUE KEY `ticket_id` (`ticket_id`),
-  KEY `staff_id` (`staff_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_message`;
-CREATE TABLE `%TABLE_PREFIX%ticket_message` (
-  `msg_id` int(11) unsigned NOT NULL auto_increment,
-  `ticket_id` int(11) unsigned NOT NULL default '0',
-  `messageId` varchar(255) default NULL,
-  `message` text NOT NULL,
-  `headers` text,
-  `source` varchar(16) default NULL,
-  `ip_address` varchar(16) default NULL,
-  `created` datetime NOT NULL default '0000-00-00 00:00:00',
-  `updated` datetime default NULL,
-  PRIMARY KEY  (`msg_id`),
-  KEY `ticket_id` (`ticket_id`),
-  KEY `msgId` (`messageId`),
-  FULLTEXT KEY `message` (`message`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_note`;
-CREATE TABLE `%TABLE_PREFIX%ticket_note` (
-  `note_id` int(11) unsigned NOT NULL auto_increment,
-  `ticket_id` int(11) unsigned NOT NULL default '0',
-  `staff_id` int(10) unsigned NOT NULL default '0',
-  `source` varchar(32) NOT NULL default '',
-  `title` varchar(255) NOT NULL default 'Generic Intermal Notes',
-  `note` text NOT NULL,
-  `created` datetime NOT NULL default '0000-00-00 00:00:00',
-  PRIMARY KEY  (`note_id`),
-  KEY `ticket_id` (`ticket_id`),
-  KEY `staff_id` (`staff_id`),
-  FULLTEXT KEY `note` (`note`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_priority`;
-CREATE TABLE `%TABLE_PREFIX%ticket_priority` (
-  `priority_id` tinyint(4) NOT NULL auto_increment,
-  `priority` varchar(60) NOT NULL default '',
-  `priority_desc` varchar(30) NOT NULL default '',
-  `priority_color` varchar(7) NOT NULL default '',
-  `priority_urgency` tinyint(1) unsigned NOT NULL default '0',
-  `ispublic` tinyint(1) NOT NULL default '1',
-  PRIMARY KEY  (`priority_id`),
-  UNIQUE KEY `priority` (`priority`),
-  KEY `priority_urgency` (`priority_urgency`),
-  KEY `ispublic` (`ispublic`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%ticket_priority` (`priority_id`, `priority`, `priority_desc`, `priority_color`, `priority_urgency`, `ispublic`) VALUES
-(1, 'low', 'Low', '#DDFFDD', 4, 1),
-(2, 'normal', 'Normal', '#FFFFF0', 3, 1),
-(3, 'high', 'High', '#FEE7E7', 2, 1),
-(4, 'emergency', 'Emergency', '#FEE7E7', 1, 0);
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_response`;
-CREATE TABLE `%TABLE_PREFIX%ticket_response` (
-  `response_id` int(11) unsigned NOT NULL auto_increment,
-  `msg_id` int(11) unsigned NOT NULL default '0',
-  `ticket_id` int(11) unsigned NOT NULL default '0',
-  `staff_id` int(11) unsigned NOT NULL default '0',
-  `staff_name` varchar(32) NOT NULL default '',
-  `response` text NOT NULL,
-  `ip_address` varchar(16) NOT NULL default '',
-  `created` datetime NOT NULL default '0000-00-00 00:00:00',
-  `updated` datetime NOT NULL default '0000-00-00 00:00:00',
-  PRIMARY KEY  (`response_id`),
-  KEY `ticket_id` (`ticket_id`),
-  KEY `msg_id` (`msg_id`),
-  KEY `staff_id` (`staff_id`),
-  FULLTEXT KEY `response` (`response`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%timezone`;
-CREATE TABLE `%TABLE_PREFIX%timezone` (
-  `id` int(11) unsigned NOT NULL auto_increment,
-  `offset` float(3,1) NOT NULL default '0.0',
-  `timezone` varchar(255) NOT NULL default '',
-  PRIMARY KEY  (`id`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-INSERT INTO `%TABLE_PREFIX%timezone` (`id`, `offset`, `timezone`) VALUES
-(1, -12.0, 'Eniwetok, Kwajalein'),
-(2, -11.0, 'Midway Island, Samoa'),
-(3, -10.0, 'Hawaii'),
-(4, -9.0, 'Alaska'),
-(5, -8.0, 'Pacific Time (US & Canada)'),
-(6, -7.0, 'Mountain Time (US & Canada)'),
-(7, -6.0, 'Central Time (US & Canada), Mexico City'),
-(8, -5.0, 'Eastern Time (US & Canada), Bogota, Lima'),
-(9, -4.0, 'Atlantic Time (Canada), Caracas, La Paz'),
-(10, -3.5, 'Newfoundland'),
-(11, -3.0, 'Brazil, Buenos Aires, Georgetown'),
-(12, -2.0, 'Mid-Atlantic'),
-(13, -1.0, 'Azores, Cape Verde Islands'),
-(14, 0.0, 'Western Europe Time, London, Lisbon, Casablanca'),
-(15, 1.0, 'Brussels, Copenhagen, Madrid, Paris'),
-(16, 2.0, 'Kaliningrad, South Africa'),
-(17, 3.0, 'Baghdad, Riyadh, Moscow, St. Petersburg'),
-(18, 3.5, 'Tehran'),
-(19, 4.0, 'Abu Dhabi, Muscat, Baku, Tbilisi'),
-(20, 4.5, 'Kabul'),
-(21, 5.0, 'Ekaterinburg, Islamabad, Karachi, Tashkent'),
-(22, 5.5, 'Bombay, Calcutta, Madras, New Delhi'),
-(23, 6.0, 'Almaty, Dhaka, Colombo'),
-(24, 7.0, 'Bangkok, Hanoi, Jakarta'),
-(25, 8.0, 'Beijing, Perth, Singapore, Hong Kong'),
-(26, 9.0, 'Tokyo, Seoul, Osaka, Sapporo, Yakutsk'),
-(27, 9.5, 'Adelaide, Darwin'),
-(28, 10.0, 'Eastern Australia, Guam, Vladivostok'),
-(29, 11.0, 'Magadan, Solomon Islands, New Caledonia'),
-(30, 12.0, 'Auckland, Wellington, Fiji, Kamchatka');
diff --git a/setup/inc/sql/osticket-v1.7-mysql.sql.md5 b/setup/inc/sql/osticket-v1.7-mysql.sql.md5
deleted file mode 100644
index 4bdfcd1ce270c2ca67c9c9f461bef15d010936f6..0000000000000000000000000000000000000000
--- a/setup/inc/sql/osticket-v1.7-mysql.sql.md5
+++ /dev/null
@@ -1 +0,0 @@
-aa4664afc3b43d4068eb2e82684fc28e
diff --git a/setup/inc/sql/v1.6rc5-upgrade.sql b/setup/inc/sql/v1.6rc5-upgrade.sql
deleted file mode 100644
index 9f44710fe3bb1c4523433619c59e31e01bd94f73..0000000000000000000000000000000000000000
--- a/setup/inc/sql/v1.6rc5-upgrade.sql
+++ /dev/null
@@ -1,128 +0,0 @@
-ALTER TABLE `%TABLE_PREFIX%email` 
-ADD `userid` VARCHAR( 125 ) NOT NULL AFTER `name` ,
-ADD `userpass` VARCHAR( 125 ) NOT NULL AFTER `userid`,
-ADD `mail_active` TINYINT( 1 ) NOT NULL DEFAULT '0' AFTER `userpass` ,
-ADD `mail_host` VARCHAR( 125 ) NOT NULL AFTER `mail_active` ,
-ADD `mail_protocol` ENUM( 'POP', 'IMAP' ) NOT NULL AFTER `mail_host` ,
-ADD `mail_encryption` ENUM( 'NONE', 'SSL' ) NOT NULL AFTER `mail_protocol` ,
-ADD `mail_port` INT( 6 ) NULL AFTER `mail_encryption` ,
-ADD `mail_fetchfreq` TINYINT( 3 ) NOT NULL DEFAULT '5' AFTER `mail_port` ,
-ADD `mail_fetchmax` TINYINT( 4 ) NOT NULL DEFAULT '30' AFTER `mail_fetchfreq` ,
-ADD `mail_delete` TINYINT( 1 ) NOT NULL DEFAULT '0' AFTER `mail_fetchmax` ,
-ADD `mail_errors` TINYINT( 3 ) NOT NULL DEFAULT '0' AFTER `mail_delete` ,
-ADD `mail_lasterror` DATETIME NULL AFTER `mail_errors` ,
-ADD `mail_lastfetch` DATETIME NULL AFTER `mail_lasterror` ,
-ADD `smtp_active` TINYINT( 1 ) NOT NULL AFTER `mail_lastfetch` ,
-ADD `smtp_host` VARCHAR( 125 ) NOT NULL AFTER `smtp_active` ,
-ADD `smtp_port` INT( 6 ) NULL AFTER `smtp_host` ,
-ADD `smtp_auth` TINYINT( 1 ) NOT NULL DEFAULT '1' AFTER `smtp_port` ;
-
-ALTER TABLE `%TABLE_PREFIX%groups` ADD `can_edit_tickets` TINYINT UNSIGNED NOT NULL DEFAULT '0' AFTER `dept_access` ;
-
-UPDATE `%TABLE_PREFIX%groups`  SET `can_edit_tickets`=1 WHERE `can_delete_tickets`=1;
-
-ALTER TABLE `%TABLE_PREFIX%ticket` ADD `duedate` DATETIME NULL AFTER `isoverdue` ;
-
-ALTER TABLE `%TABLE_PREFIX%ticket` ADD INDEX ( `duedate` ) ;
-
-ALTER TABLE `%TABLE_PREFIX%ticket` CHANGE `source` `source` ENUM( 'Web', 'Email', 'Phone', 'Other' ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT 'Other' ;
- 
-ALTER TABLE `%TABLE_PREFIX%email_template` 
-ADD `note_alert_subj` VARCHAR( 255 ) NOT NULL AFTER `message_alert_body` ,
-ADD `note_alert_body` TEXT NOT NULL AFTER `note_alert_subj` ;
-
-UPDATE `%TABLE_PREFIX%email_template`  SET  `note_alert_subj` = 'New Internal Note Alert',`note_alert_body` = '%staff,\r\n\r\nInternal note appended to ticket #%ticket\r\n\r\n----------------------\r\nName: %name\r\n\r\n%note\r\n-------------------\r\n\r\nTo view/respond to the ticket, please login to the support ticket system.\r\n\r\nYour friendly,\r\n\r\nCustomer Support System - powered by osTicket.';
-
-ALTER TABLE `%TABLE_PREFIX%ticket_message` ADD `messageId` VARCHAR( 255 ) NULL AFTER `ticket_id` ;
-ALTER TABLE `%TABLE_PREFIX%ticket_message` ADD INDEX ( `messageId` ) ;
-
-ALTER TABLE `%TABLE_PREFIX%config` 
-ADD `note_alert_active` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `message_alert_dept_manager` ,
-ADD `note_alert_laststaff` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '1' AFTER `note_alert_active` ,
-ADD `note_alert_assigned` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '1' AFTER `note_alert_laststaff` ,
-ADD `note_alert_dept_manager` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `note_alert_assigned` ;
-
-ALTER TABLE `%TABLE_PREFIX%department` ADD `autoresp_email_id` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `email_id` ;
-
-ALTER TABLE `%TABLE_PREFIX%department` ADD INDEX ( `autoresp_email_id` ) ;
-
-ALTER TABLE `%TABLE_PREFIX%config` CHANGE `default_priority` `default_priority_id` TINYINT( 2 ) UNSIGNED NOT NULL DEFAULT '2';
-
-ALTER TABLE `%TABLE_PREFIX%config` CHANGE `default_template` `default_template_id` TINYINT( 4 ) UNSIGNED NOT NULL DEFAULT '1';
-
-ALTER TABLE `%TABLE_PREFIX%config` CHANGE `default_email` `default_email_id` TINYINT( 4 ) UNSIGNED NOT NULL DEFAULT '0';
-
-ALTER TABLE `%TABLE_PREFIX%config` CHANGE `default_dept` `default_dept_id` TINYINT( 3 ) UNSIGNED NOT NULL DEFAULT '0';
-
-ALTER TABLE `%TABLE_PREFIX%config` CHANGE `enable_pop3_fetch` `enable_mail_fetch` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0';
-
-ALTER TABLE `%TABLE_PREFIX%config` ADD `alert_email_id` TINYINT( 4 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `overdue_grace_period` ;
-
-ALTER TABLE `%TABLE_PREFIX%config`
-ADD `default_smtp_id` TINYINT( 4 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `default_template_id` ,
-ADD `spoof_default_smtp` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `default_smtp_id` ;
-
-ALTER TABLE `%TABLE_PREFIX%config` ADD `log_level` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '2' AFTER `random_ticket_ids` ;
-
-ALTER TABLE `%TABLE_PREFIX%config` 
-ADD `staff_max_logins` TINYINT UNSIGNED NOT NULL DEFAULT '4' AFTER `enable_daylight_saving` ,
-ADD `staff_login_timeout` INT UNSIGNED NOT NULL DEFAULT '2' AFTER `staff_max_logins` ;
-
-ALTER TABLE `%TABLE_PREFIX%config` 
-ADD `client_max_logins` TINYINT UNSIGNED NOT NULL DEFAULT '4' AFTER `staff_session_timeout` ,
-ADD `client_login_timeout` INT UNSIGNED NOT NULL DEFAULT '2' AFTER `client_max_logins` ;
-
-ALTER TABLE `%TABLE_PREFIX%config` ADD `show_answered_tickets` TINYINT( 1 ) NOT NULL DEFAULT '0' AFTER `show_assigned_tickets` ;
-
-ALTER TABLE `%TABLE_PREFIX%ticket` ADD `isanswered` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `isoverdue` ;
-
-ALTER TABLE `%TABLE_PREFIX%ticket` ADD `lastmessage` DATETIME NULL AFTER `closed` , ADD `lastresponse` DATETIME NULL AFTER `lastmessage` ;
-
-ALTER TABLE `%TABLE_PREFIX%config` ADD `hide_staff_name` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `show_answered_tickets` ;
-
-ALTER TABLE `%TABLE_PREFIX%config` ADD `log_graceperiod` INT UNSIGNED NOT NULL DEFAULT '12' AFTER `log_level` ;
-
-ALTER TABLE `%TABLE_PREFIX%ticket` ADD `phone_ext` VARCHAR( 8 ) NULL DEFAULT NULL AFTER `phone` ;
-
-ALTER TABLE `%TABLE_PREFIX%ticket` ADD `topic`  VARCHAR(64) NULL DEFAULT NULL AFTER `subject` ;
-
-ALTER TABLE `%TABLE_PREFIX%ticket_message` ADD FULLTEXT (`message`);
-
-ALTER TABLE `%TABLE_PREFIX%ticket_response` ADD FULLTEXT (`response`);
-
-ALTER TABLE `%TABLE_PREFIX%ticket_note` ADD FULLTEXT (`note`);
-  
-ALTER TABLE `%TABLE_PREFIX%department` ADD `tpl_id` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `dept_id` ;
-
-ALTER TABLE `%TABLE_PREFIX%department` ADD INDEX ( `tpl_id` ) ;
-
-ALTER TABLE `%TABLE_PREFIX%email_template` ADD `notes` TEXT NULL AFTER `name` ;
-
-ALTER TABLE `%TABLE_PREFIX%config` CHANGE `api_key` `api_passphrase` VARCHAR( 125 ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%api_key`;
-CREATE TABLE `%TABLE_PREFIX%api_key` (
-  `id` int(10) unsigned NOT NULL auto_increment,
-  `isactive` tinyint(1) NOT NULL default '1',
-  `ipaddr` varchar(16) NOT NULL,
-  `apikey` varchar(255) NOT NULL,
-  `updated` datetime NOT NULL default '0000-00-00 00:00:00',
-  `created` datetime NOT NULL default '0000-00-00 00:00:00',
-  PRIMARY KEY  (`id`),
-  UNIQUE KEY `ipaddr` (`ipaddr`)
-) ENGINE=MyISAM;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%syslog`;
-CREATE TABLE `%TABLE_PREFIX%syslog` (
-  `log_id` int(11) unsigned NOT NULL auto_increment,
-  `log_type` enum('Debug','Warning','Error') NOT NULL,
-  `title` varchar(255) NOT NULL,
-  `log` text NOT NULL,
-  `logger` varchar(64) NOT NULL,
-  `ip_address` varchar(16) NOT NULL,
-  `created` datetime NOT NULL default '0000-00-00 00:00:00',
-  `updated` datetime NOT NULL default '0000-00-00 00:00:00',
-  PRIMARY KEY  (`log_id`),
-  KEY `log_type` (`log_type`)
-) ENGINE=MyISAM;
-
diff --git a/setup/inc/sql/v1.6st-upgrade.sql b/setup/inc/sql/v1.6st-upgrade.sql
deleted file mode 100644
index 571620fb1beddc9137ea77c133b7bc47cc7a6960..0000000000000000000000000000000000000000
--- a/setup/inc/sql/v1.6st-upgrade.sql
+++ /dev/null
@@ -1,28 +0,0 @@
-ALTER TABLE `%TABLE_PREFIX%ticket` ADD `topic_id` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `priority_id`;
-
-ALTER TABLE `%TABLE_PREFIX%ticket` ADD INDEX ( `topic_id` );
-
-ALTER TABLE `%TABLE_PREFIX%ticket` CHANGE `topic` `helptopic` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;
-
-ALTER TABLE `%TABLE_PREFIX%groups` ADD `can_create_tickets` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '1' AFTER `dept_access`;
-
-ALTER TABLE `%TABLE_PREFIX%staff` ADD `auto_refresh_rate` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `max_page_size`;
-
-ALTER TABLE `%TABLE_PREFIX%config` ADD `ticket_notice_active` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `message_autoresponder`;
-
-ALTER TABLE `%TABLE_PREFIX%config` ADD `enable_captcha` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `use_email_priority`;
-
-ALTER TABLE `%TABLE_PREFIX%config` ADD `log_ticket_activity` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '1' AFTER `strip_quoted_reply`;
-
-ALTER TABLE `%TABLE_PREFIX%config` ADD `staff_ip_binding` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '1' AFTER `enable_daylight_saving`;
-
-ALTER TABLE `%TABLE_PREFIX%staff` CHANGE `signature` `signature` TINYTEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
-
-ALTER TABLE `%TABLE_PREFIX%department` CHANGE `dept_signature` `dept_signature` TINYTEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
-
-ALTER TABLE `%TABLE_PREFIX%email_template`
-ADD `ticket_notice_subj` VARCHAR( 255 ) NOT NULL AFTER `ticket_autoresp_body` ,
-ADD `ticket_notice_body` TEXT NOT NULL AFTER `ticket_notice_subj`;
-
-INSERT INTO `%TABLE_PREFIX%kb_premade` (`premade_id`, `dept_id`, `isenabled`, `title`, `answer`, `created`, `updated`) VALUES
-    ('', 0, 1, 'Sample (with variables)', '\r\n%name,\r\n\r\nYour ticket #%ticket created on %createdate is in %dept department.\r\n\r\n', NOW(), NOW());
diff --git a/setup/inc/upgrade-done.inc.php b/setup/inc/upgrade-done.inc.php
deleted file mode 100644
index 0ec75c31a8099d5c0877231a00e274400a97f049..0000000000000000000000000000000000000000
--- a/setup/inc/upgrade-done.inc.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php if(!defined('SETUPINC')) die('Kwaheri!');
-$url=URL;
-
-?>    
-    <div id="main">
-        <h1 style="color:green;">Upgrade Completed!</h1>
-        <div id="intro">
-        <p>Congratulations osTicket upgrade has been completed successfully. Please refer to Release Notes for more information about changes and/or new features.</p>
-        <h3 style="color:#FF7700;">Post-upgrade manual cleanup</h3>
-        Please take a minute to cleanup!
-        <ul>
-            <li><b>Delete setup directory</b>:<br> After verifying that the upgrade completed correctly please delete setup folder.</li>
-            <li><b>Enable the helpdesk</b>:<br> You can now enable osTicket, be sure to take some time to explore changes and new features</li>
-        </ul>
-        </div>
-        <p>Once again, thank you for choosing osTicket. Your feedback is welcomed!</p>
-        <p>We take user feedback seriously and are dedicated to making changes based on your input. Feel free to let us know of any other improvements you would like to see in osTicket, so that we may add them in the future as we continue to develop better and better versions of osTicket.</p>
-        <p>Good luck.<p>
-        <p>osTicket Team.</p>
-        <br>
-        <p><b>PS</b>: Don't just make customers happy, make happy customers!</p>
-    </div>
-    <div id="sidebar">
-            <h3>What's Next?</h3>
-            <p><b>Post-upgrade</b>: You can now log in to <a href="../scp/admin.php" target="_blank">Admin Panel</a> and explore the new features. For complete and upto date release notes see <a href="http://osticket.com/wiki/Post-Install_Setup_Guide" target="_blank">osTicket wiki</a></p>
-          
-            <p><b>Stay up to date</b>: It's important to keep your osTicket installation up to date. Get announcements, security updates and alerts delivered directly to you! 
-            <a target="_blank" href="http://osticket.com/support/subscribe.php">Subcribe today</a> and be in the loop!</p>
-            <p><b>Commercial support available</b>: Get guidance and hands-on expertise to address unique challenges and make sure your osTicket runs smoothly, efficiently, and securely. <a target="_blank" href="http://osticket.com/support/commercial_support.php.php">Learn More!</a></p>
-   </div>
diff --git a/setup/js/setup.js b/setup/js/setup.js
index b1f8e08c3aa48397206c43ad854fc3bf4815473c..7dd4c81aa5887c7388538e9dadd9f06927d1ac4b 100644
--- a/setup/js/setup.js
+++ b/setup/js/setup.js
@@ -18,47 +18,4 @@ jQuery(function($) {
         $('#overlay, #loading').show();
         return true;
         });
-
-    $('form#upgrade').submit(function(e) {
-        e.preventDefault();
-        var form = $(this);
-        $('input[type=submit]', this).attr('disabled', 'disabled');
-        $('#overlay, #loading').show();
-        doTasks('upgrade.php',form.serialize());
-
-        return false;
-        });
-
-    function doTasks(url, data) {
-        function _lp(count) {
-            $.ajax({
-                type: 'GET',
-                url: 'p.php',
-                async: true,
-                cache: false,
-                data: data,
-                dataType: 'text',
-                success: function(res) {
-                    if (res) { 
-                        $('#loading #msg').html(res);
-                    }
-                },
-                statusCode: {
-                    200: function() {
-                        setTimeout(function() { _lp(count+1); }, 2);
-                    },
-
-                    304: function() {
-                        $('#loading #msg').html("We're done... cleaning up!");
-                        setTimeout(function() { location.href =url;}, 3000);
-                    }
-                },
-                error: function() {
-                    $('#loading #msg').html("Something went wrong");
-                    setTimeout(function() { location.href =url;}, 1000);
-                }
-            });
-        };
-        _lp(0);
-    }
 });
diff --git a/setup/p.php b/setup/p.php
deleted file mode 100644
index 51c7055f257559099fd600ef12c31e882605873d..0000000000000000000000000000000000000000
--- a/setup/p.php
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-/*********************************************************************
-    upgrader.php
-
-    osTicket Upgrader Helper - called via ajax.
-
-    Peter Rotich <peter@osticket.com>
-    Copyright (c)  2006-2012 osTicket
-    http://www.osticket.com
-
-    Released under the GNU General Public License WITHOUT ANY WARRANTY.
-    See LICENSE.TXT for details.
-
-    vim: expandtab sw=4 ts=4 sts=4:
-**********************************************************************/
-function staffLoginPage($msg) {
-    Http::response(403, $msg?$msg:'Access Denied');
-    exit;
-}
-
-require '../scp/staff.inc.php';
-if(!$thisstaff or !$thisstaff->isAdmin()) {
-    staffLoginPage('Admin Access Required!');
-    exit;
-}
-
-define('SETUPINC', true);
-define('INC_DIR', './inc/');
-define('SQL_DIR', INC_DIR.'sql/');
-
-require_once INC_DIR.'class.upgrader.php';
-
-
-$upgrader = new Upgrader($cfg->getSchemaSignature(), TABLE_PREFIX, SQL_DIR);
-
-//Just report the next action on the first call.
-if(!$_SESSION['ost_upgrader'][$upgrader->getShash()]['progress']) {
-    $_SESSION['ost_upgrader'][$upgrader->getShash()]['progress'] = $upgrader->getNextAction();
-    Http::response(200, $upgrader->getNextAction());
-    exit;
-}
-
-if($upgrader->getNumPendingTasks()) {
-    if($upgrader->doTasks() && !$upgrader->getNumPendingTasks() && $ost->isUpgradePending()) {
-        //Just reporting done...with tasks - break in between patches!
-        header("HTTP/1.1 304 Not Modified");
-        exit;
-    }
-} elseif($ost->isUpgradePending() && $upgrader->isUpgradable()) {
-    $version = $upgrader->getNextVersion();
-    if($upgrader->upgrade()) {
-        //We're simply reporting progress here - call back will report next action'
-        Http::response(200, "Upgraded to $version ... post-upgrade checks!");
-        exit;
-    }
-} elseif(!$ost->isUpgradePending()) {
-    $upgrader->setState('done');
-    session_write_close();
-    header("HTTP/1.1 304 Not Modified");
-    exit;
-}
-
-if($upgrader->isAborted() || $upgrader->getErrors()) {
-    Http::response(416, "We have a problem ... wait a sec.");
-    exit;
-}
-
-Http::response(200, $upgrader->getNextAction());
-?>
diff --git a/setup/setup.inc.php b/setup/setup.inc.php
index c2b404c74a68aeb346e091c4cd900e141464a135..d6f54ca268c784e471dc756d228ff888763d4730 100644
--- a/setup/setup.inc.php
+++ b/setup/setup.inc.php
@@ -14,6 +14,9 @@
     vim: expandtab sw=4 ts=4 sts=4:
 **********************************************************************/
 
+#This  version - changed on every release
+define('THIS_VERSION', '1.7-RC1');
+
 #inits
 error_reporting(E_ALL ^ E_NOTICE); //turn on errors??
 ini_set('magic_quotes_gpc', 0);
@@ -52,6 +55,7 @@ ini_set('include_path', './'.PATH_SEPARATOR.INC_DIR.PATH_SEPARATOR.INCLUDE_DIR.P
 endif;
 
 #required files
+require_once(INCLUDE_DIR.'class.setup.php');
 require_once(INCLUDE_DIR.'class.validator.php');
 require_once(INCLUDE_DIR.'class.passwd.php');
 require_once(INCLUDE_DIR.'class.format.php');
diff --git a/tickets.php b/tickets.php
index 81b8ed68f153b551c4b063d2fa6860ea84070ac1..4ee69a8ef51f5b2b274df224fac4ed195330da5a 100644
--- a/tickets.php
+++ b/tickets.php
@@ -38,26 +38,15 @@ if($_POST && is_object($ticket) && $ticket->getId()):
         if(!$_POST['message'])
             $errors['message']='Message required';
 
-        //check attachment..if any is set
-        $files=($cfg->allowOnlineAttachments() && $_FILES['attachments'])?Format::files($_FILES['attachments']):array();
-        if($files) {
-
-            foreach($files as $file) {
-                if(!$file['name']) continue;
-
-                if(!$cfg->canUploadFileType($file['name']))
-                    $errors['attachment']='Invalid file type [ '.$file['name'].' ]';
-                elseif($file['size']>$cfg->getMaxFileSize())
-                    $errors['attachment']='File '.$file['name'].'is too big. Max '.$cfg->getMaxFileSize().' bytes allowed';
-            }
-        }
-                    
         if(!$errors) {
             //Everything checked out...do the magic.
             if(($msgid=$ticket->postMessage($_POST['message'],'Web'))) {
-                if($files && $cfg->allowOnlineAttachments())
-                    $ticket->uploadAttachments($files,$msgid,'M');
-
+                if($cfg->allowOnlineAttachments() 
+                        && $_FILES['attachments']
+                        && ($files=Format::files($_FILES['attachments']))) {
+                    $ost->validateFileUploads($files); //Validator sets errors - if any.
+                    $ticket->uploadAttachments($files, $msgid, 'M');
+                }
                 $msg='Message Posted Successfully';
             } else {
                 $errors['err']='Unable to post the message. Try again';
@@ -68,7 +57,7 @@ if($_POST && is_object($ticket) && $ticket->getId()):
         }
         break;
     default:
-        $errors['err']='Uknown action';
+        $errors['err']='Unknown action';
     }
     $ticket->reload();
 endif;