diff --git a/WHATSNEW.md b/WHATSNEW.md
new file mode 100644
index 0000000000000000000000000000000000000000..d194837fe8d7c7444121a4ea6e7710402ca63abf
--- /dev/null
+++ b/WHATSNEW.md
@@ -0,0 +1,14 @@
+osTicket v1.7
+=============
+
+New Features
+============
+Version 1.7 includes several new features
+
+API
+---
+Interface with osTicket via HTTP requests. Starting with version 1.7,
+tickets are createable by submitting an HTTP POST request to either
+
+    /api/tickets.xml
+    /api/tickets.json
diff --git a/api/.htaccess b/api/.htaccess
new file mode 100644
index 0000000000000000000000000000000000000000..e230ac6e186f66ada37cca3809396e32b98473e1
--- /dev/null
+++ b/api/.htaccess
@@ -0,0 +1,9 @@
+Options +FollowSymLinks
+RewriteEngine On
+
+RewriteBase /api/
+
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteCond %{REQUEST_FILENAME} !-d
+
+RewriteRule ^(.*)$ http.php/$1 [L]
diff --git a/assets/default/css/theme.css b/assets/default/css/theme.css
index dde40189e88227edaa3f1c18e4aec6b7e1bb67db..c6a6242df3d461805e06d366f451d3abf34a29ff 100644
--- a/assets/default/css/theme.css
+++ b/assets/default/css/theme.css
@@ -495,7 +495,7 @@ body {
 #ticketForm div.error label, #clientLogin div.error label {
   color: #a00;
 }
-#ticketForm p, #clientLogin p {
+#clientLogin p {
   clear: both;
   text-align: center;
 }
@@ -646,7 +646,7 @@ a.refresh {
 #ticketThread table th {
   text-align: left;
   border-bottom: 1px solid #aaa;
-  font-size: 11pt;
+  font-size: 12px;
   padding: 5px;
 }
 #ticketThread table td {
@@ -659,7 +659,7 @@ a.refresh {
   background: #ddd;
 }
 #ticketThread .info {
-  padding: 5px;
+  padding: 2px;
   background: #f9f9f9;
   border-top: 1px solid #ddd;
   height: 16px;
@@ -667,16 +667,13 @@ a.refresh {
 }
 #ticketThread .info a {
   display: inline-block;
-  margin: 5px 20px 5px 0;
+  margin: 5px 10px 5px 0;
   padding-left: 24px;
   height: 16px;
   line-height: 16px;
   background-position: 0 50%;
   background-repeat: no-repeat;
 }
-#ticketThread .info .pdf {
-  background-image: url('../images/filetypes/pdf.png?1319636863');
-}
 
 #reply {
   margin-top: 20px;
diff --git a/attachment.php b/attachment.php
new file mode 100644
index 0000000000000000000000000000000000000000..819ff5863b559522f70a65fd1c2fc56846e37d8a
--- /dev/null
+++ b/attachment.php
@@ -0,0 +1,36 @@
+<?php
+/*********************************************************************
+    attachment.php
+
+    Attachments interface for clients.
+    Clients should never see the dir paths.
+    
+    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:
+**********************************************************************/
+require('secure.inc.php');
+require_once(INCLUDE_DIR.'class.attachment.php');
+//Basic checks
+if(!$thisclient 
+        || !$_GET['id'] 
+        || !$_GET['h']
+        || !($attachment=Attachment::lookup($_GET['id']))
+        || !($file=$attachment->getFile()))
+    die('Unknown attachment!');
+
+//Validate session access hash - we want to make sure the link is FRESH! and the user has access to the parent ticket!!
+$vhash=md5($attachment->getFileId().session_id().$file->getHash());
+if(strcasecmp(trim($_GET['h']),$vhash) 
+        || !($ticket=$attachment->getTicket()) 
+        || !$ticket->checkClientAccess($thisclient)) 
+    die('Unknown or invalid attachment');
+//Download the file..
+$file->download();
+
+?>
diff --git a/captcha.php b/captcha.php
new file mode 100644
index 0000000000000000000000000000000000000000..3ab68f746ddb378da077cac80b616caf6f69b129
--- /dev/null
+++ b/captcha.php
@@ -0,0 +1,20 @@
+<?php
+/*********************************************************************
+    captcha.php
+
+    Simply returns captcha image.
+    
+    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:
+**********************************************************************/
+require_once('main.inc.php');
+require(INCLUDE_DIR.'class.captcha.php');
+$captcha = new Captcha(5,12,ROOT_DIR.'images/captcha/');
+echo $captcha->getImage();
+?>
diff --git a/client.inc.php b/client.inc.php
index 5461bd2f75246f57b710f74312eb45b9c4cfba9a..b714e93b44bd587f4d10a2f292b2d4890bc63a3f 100644
--- a/client.inc.php
+++ b/client.inc.php
@@ -51,7 +51,7 @@ require_once(INCLUDE_DIR.'class.dept.php');
 //clear some vars
 $errors=array();
 $msg='';
-$thisclient=null;
+$thisclient=$nav=null;
 //Make sure the user is valid..before doing anything else.
 if($_SESSION['_client']['userID'] && $_SESSION['_client']['key'])
     $thisclient = new ClientSession($_SESSION['_client']['userID'],$_SESSION['_client']['key']);
@@ -60,6 +60,8 @@ if($_SESSION['_client']['userID'] && $_SESSION['_client']['key'])
 if($thisclient && $thisclient->getId() && $thisclient->isValid()){
      $thisclient->refreshSession();
 }
+/* Client specific defaults */
+define('PAGE_LIMIT',DEFAULT_PAGE_LIMIT);
 
 $nav = new UserNav($thisclient, 'home');
 ?>
diff --git a/images/bg.gif b/images/bg.gif
deleted file mode 100644
index e20f31775822d9b0a7a01ddaf38cb1f48a60e6f2..0000000000000000000000000000000000000000
Binary files a/images/bg.gif and /dev/null differ
diff --git a/images/fibres.png b/images/fibres.png
deleted file mode 100644
index 7ad3ac27f71bdf17f637ffae3d86d36e24359764..0000000000000000000000000000000000000000
Binary files a/images/fibres.png and /dev/null differ
diff --git a/images/home.gif b/images/home.gif
deleted file mode 100644
index b25c0781dd0b8f66d4a9271b662061b54d7a9c4d..0000000000000000000000000000000000000000
Binary files a/images/home.gif and /dev/null differ
diff --git a/images/icons/attachment.gif b/images/icons/attachment.gif
deleted file mode 100644
index 4400e61e9812a3b2a070c89fc6fce7489c104e17..0000000000000000000000000000000000000000
Binary files a/images/icons/attachment.gif and /dev/null differ
diff --git a/images/icons/refresh.gif b/images/icons/refresh.gif
deleted file mode 100644
index 8268958a19e016741fffb8309b1174e548f5ce19..0000000000000000000000000000000000000000
Binary files a/images/icons/refresh.gif and /dev/null differ
diff --git a/images/icons/thread.gif b/images/icons/thread.gif
deleted file mode 100644
index bffd6b0b3cf5ce0cadfc38683ee7fb3fa0a5c82a..0000000000000000000000000000000000000000
Binary files a/images/icons/thread.gif and /dev/null differ
diff --git a/images/icons/ticket.gif b/images/icons/ticket.gif
deleted file mode 100644
index 4304ea7955091c46d9fe570faefc643773a5c1de..0000000000000000000000000000000000000000
Binary files a/images/icons/ticket.gif and /dev/null differ
diff --git a/images/icons/ticket_source_email.gif b/images/icons/ticket_source_email.gif
deleted file mode 100644
index 6b57605d47b7fc2e4729b5a6602bdf4768ad749f..0000000000000000000000000000000000000000
Binary files a/images/icons/ticket_source_email.gif and /dev/null differ
diff --git a/images/icons/ticket_source_other.gif b/images/icons/ticket_source_other.gif
deleted file mode 100644
index 4304ea7955091c46d9fe570faefc643773a5c1de..0000000000000000000000000000000000000000
Binary files a/images/icons/ticket_source_other.gif and /dev/null differ
diff --git a/images/icons/ticket_source_phone.gif b/images/icons/ticket_source_phone.gif
deleted file mode 100644
index b9aa8ed58a2993eab69a1c83fba78bb627e9004f..0000000000000000000000000000000000000000
Binary files a/images/icons/ticket_source_phone.gif and /dev/null differ
diff --git a/images/icons/ticket_source_web.gif b/images/icons/ticket_source_web.gif
deleted file mode 100644
index 1b7a5b909075fb879056d15468e407df21e0507d..0000000000000000000000000000000000000000
Binary files a/images/icons/ticket_source_web.gif and /dev/null differ
diff --git a/images/lipsum.png b/images/lipsum.png
deleted file mode 100644
index feb6a95fba027cb3d54883fc64ade1294c74bd09..0000000000000000000000000000000000000000
Binary files a/images/lipsum.png and /dev/null differ
diff --git a/images/logo.png b/images/logo.png
deleted file mode 100644
index 256344139522f7f8bc65b36e1ef0890e0fa3cf52..0000000000000000000000000000000000000000
Binary files a/images/logo.png and /dev/null differ
diff --git a/images/logo2.jpg b/images/logo2.jpg
deleted file mode 100644
index 16bc12ed36e707ace9d2d9e5443cc6d3a895711b..0000000000000000000000000000000000000000
Binary files a/images/logo2.jpg and /dev/null differ
diff --git a/images/logout.gif b/images/logout.gif
deleted file mode 100644
index 6dd774f09e48292379250ac0f1be17ccdb30baec..0000000000000000000000000000000000000000
Binary files a/images/logout.gif and /dev/null differ
diff --git a/images/my_tickets.gif b/images/my_tickets.gif
deleted file mode 100644
index ee2d25bbedd01ba5a64e9a66f5fc72b7b876f10c..0000000000000000000000000000000000000000
Binary files a/images/my_tickets.gif and /dev/null differ
diff --git a/images/new_ticket.gif b/images/new_ticket.gif
deleted file mode 100644
index 32d9636e71fa848c3b7d0f0d8eb559b78465ef22..0000000000000000000000000000000000000000
Binary files a/images/new_ticket.gif and /dev/null differ
diff --git a/images/new_ticket_icon.jpg b/images/new_ticket_icon.jpg
deleted file mode 100644
index 855eef0644245185b7b2f700d35d6a953aa65cd1..0000000000000000000000000000000000000000
Binary files a/images/new_ticket_icon.jpg and /dev/null differ
diff --git a/images/poweredby.jpg b/images/poweredby.jpg
deleted file mode 100644
index c98eb7d679b09975599711643cfcd3549c0540f6..0000000000000000000000000000000000000000
Binary files a/images/poweredby.jpg and /dev/null differ
diff --git a/images/rainbow.png b/images/rainbow.png
deleted file mode 100644
index c08f52edb522e5ec42c237994622f3b8520b428b..0000000000000000000000000000000000000000
Binary files a/images/rainbow.png and /dev/null differ
diff --git a/images/refresh_btn.gif b/images/refresh_btn.gif
deleted file mode 100644
index 8a33b22d9a9b026391e38a8bbb0d6834eb789a93..0000000000000000000000000000000000000000
Binary files a/images/refresh_btn.gif and /dev/null differ
diff --git a/images/ticket_status.gif b/images/ticket_status.gif
deleted file mode 100644
index 0775549996b70c79816e455e6850d1abf0e376ab..0000000000000000000000000000000000000000
Binary files a/images/ticket_status.gif and /dev/null differ
diff --git a/images/ticket_status_icon.jpg b/images/ticket_status_icon.jpg
deleted file mode 100644
index bf27b1f904418c311f05b27f118a55622be51b47..0000000000000000000000000000000000000000
Binary files a/images/ticket_status_icon.jpg and /dev/null differ
diff --git a/images/verticalbar.jpg b/images/verticalbar.jpg
deleted file mode 100644
index 2678913d2cdb9b8ec861e71396fcb92a552ff13a..0000000000000000000000000000000000000000
Binary files a/images/verticalbar.jpg and /dev/null differ
diff --git a/images/view_closed_btn.gif b/images/view_closed_btn.gif
deleted file mode 100644
index 6cd8f080a9007a85a2c0f08a6133f54a0253d6e8..0000000000000000000000000000000000000000
Binary files a/images/view_closed_btn.gif and /dev/null differ
diff --git a/images/view_open_btn.gif b/images/view_open_btn.gif
deleted file mode 100644
index 8ed6be9ce8159b20abfb0c9ea69b5235a4903b33..0000000000000000000000000000000000000000
Binary files a/images/view_open_btn.gif and /dev/null differ
diff --git a/include/class.canned.php b/include/class.canned.php
index 00c46de3365e92fef38fe29e154c56fafacb622b..6c6c1ac1c75bcbc25b7c288c2e49909e30b4876a 100644
--- a/include/class.canned.php
+++ b/include/class.canned.php
@@ -143,30 +143,13 @@ class Canned {
         return $i;
     }
 
-    function deleteAttachment($fileId) {
-        
-        $sql='DELETE FROM '.CANNED_ATTACHMENT_TABLE
-             .' WHERE canned_id='.db_input($this->getId())
-             .' AND file_id='.db_input($fileId)
-             .' LIMIT 1';
-       
-        if(!db_query($sql) || !db_affected_rows())
-            return false;
-
-
-        if(($file=AttachmentFile::lookup($fileId)) && !$file->isInuse())
-            $file->delete();
-
-        return true;
-    }
-
     function deleteAttachments(){
 
         $deleted=0;
-        if(($attachments = $this->getAttachments())) {
-            foreach($attachments as $attachment)
-                if($attachment['id'] && $this->deleteAttachment($attachment['id']))
-                    $deleted++;
+        $sql='DELETE FROM '.CANNED_ATTACHMENT_TABLE
+            .' WHERE canned_id='.db_input($this->getId());
+        if(db_query($sql) && db_affected_rows()) {
+            $deleted = AttachmentFile::deleteOrphans();
         }
 
         return $deleted;
diff --git a/include/class.client.php b/include/class.client.php
index f7ede15c52fe33b0a1a99dfdecb8081c64407d0d..e1057afa651472052589c0629fed129475d0e45e 100644
--- a/include/class.client.php
+++ b/include/class.client.php
@@ -4,8 +4,8 @@
 
     Handles everything about client
 
-    The class will undergo major changes one client's accounts are used. 
-    At the moment we will play off the email + ticket ID authentication.
+    NOTE: Please note that osTicket uses email address and ticket ID to authenticate the user*!
+          Client is modeled on the info of the ticket used to login .
 
     Peter Rotich <peter@osticket.com>
     Copyright (c)  2006-2012 osTicket
@@ -19,75 +19,104 @@
 
 class Client {
 
-
     var $id;
     var $fullname;
     var $username;
-    var $passwd;
     var $email;
 
-    
-    var $udata;
     var $ticket_id;
     var $ticketID;
 
-    function Client($email,$id){
+    var $ht;
+
+
+    function Client($email,$id) {
         $this->id =0;
         $this->load($id,$email);
     }
 
-    function isClient(){
-        return TRUE;
-    }
+    function load($id=0, $email='') {
 
-    function load($id,$email=''){
+        if(!$id && !($id=$this->getId()))
+            return false;
 
-        $sql='SELECT ticket_id,ticketID,name,email FROM '.TICKET_TABLE.' WHERE ticketID='.db_input($id);
-        if($email){ //don't validate...using whatever is entered.
+        $sql='SELECT ticket_id, ticketID, name, email, phone, phone_ext '
+            .' FROM '.TICKET_TABLE
+            .' WHERE ticketID='.db_input($id);
+        if($email)
             $sql.=' AND email='.db_input($email);
-        }
-        $res=db_query($sql);
-        if(!$res || !db_num_rows($res))
+
+        if(!($res=db_query($sql)) || !db_num_rows($res))
             return NULL;
 
-        $row=db_fetch_array($res);
-        $this->udata=$row;
-        $this->id         = $row['ticketID']; //placeholder
-        $this->ticket_id  = $row['ticket_id'];
-        $this->ticketID   = $row['ticketID'];
-        $this->fullname   = ucfirst($row['name']);
-        $this->username   = $row['email'];
-        $this->email      = $row['email'];
+        $this->ht = db_fetch_array($res);
+        $this->id         = $this->ht['ticketID']; //placeholder
+        $this->ticket_id  = $this->ht['ticket_id'];
+        $this->ticketID   = $this->ht['ticketID'];
+        $this->fullname   = ucfirst($this->ht['name']);
+        $this->username   = $this->ht['email'];
+        $this->email      = $this->ht['email'];
+
+        $this->stats = array();
       
         return($this->id);
     }
 
+    function reload() {
+        return $this->load();
+    }
+
+    function isClient() {
+        return TRUE;
+    }
 
-    function getId(){
+    function getId() {
         return $this->id;
     }
 
-    function getEmail(){
+    function getEmail() {
         return $this->email;
     }
 
-    function getUserName(){
+    function getUserName() {
         return $this->username;
     }
 
-    function getName(){
+    function getName() {
         return $this->fullname;
     }
+
+    function getPhone() {
+        return $this->ht['phone'];
+    }
+
+    function getPhoneExt() {
+        return $this->ht['phone_ext'];
+    }
     
     function getTicketID() {
         return $this->ticketID;
     }
 
+    function getTicketStats() {
+
+        if(!$this->stats['tickets'])
+            $this->stats['tickets'] = Ticket::getClientStats($this->getEmail());
+
+        return $this->stats['tickets'];
+    }
+
+    function getNumTickets() {
+        return ($stats=$this->getTicketStats())?($stats['open']+$stats['closed']):0;
+    }
+
+    function getNumOpenTickets() {
+        return ($stats=$this->getTicketStats())?$stats['open']:0;
+    }
+
     /* ------------- Static ---------------*/
     function lookup($id, $email) {
         return ($id && is_numeric($id) && ($c=new Client($id,$email)) && $c->getId()==$id)?$c:null;
     }
-
 }
-
 ?>
diff --git a/include/class.config.php b/include/class.config.php
index 1e3d7745ffaf9788715308564bcc676fc28ac845..37040ebca4372e993870537bb248e9fb48685a5a 100644
--- a/include/class.config.php
+++ b/include/class.config.php
@@ -32,17 +32,20 @@ class Config {
         $this->load($id);
     }
 
-    function load($id) {
+    function load($id=0) {
+        if(!$id && !($id=$this->getId()))
+            return false;
 
-        $sql='SELECT * FROM '.CONFIG_TABLE.' WHERE id='.db_input($id);
-        if($id && ($res=db_query($sql)) && db_num_rows($res)) {
-            $this->config=db_fetch_array($res);
-            $this->id=$this->config['id'];
+        $sql='SELECT * FROM '.CONFIG_TABLE
+            .' WHERE id='.db_input($id);
+        if(!($res=db_query($sql)) || !db_num_rows($res))
+            return false;
 
-            return true;
-        }
+            
+        $this->config=db_fetch_array($res);
+        $this->id=$this->config['id'];
 
-        return false;
+        return true;
     }
 
     //Initialize some default values.
@@ -52,10 +55,13 @@ class Config {
     }
     
     function reload() {
-        if($this->load($this->id))
-            $this->init();
-    }
+        if(!$this->load($this->getId()))
+            return false;
+
+        $this->init();
 
+        return true;
+    }
 
     function isHelpDeskOffline() {
         return !$this->isSystemOnline();
@@ -75,7 +81,7 @@ class Config {
         return '1.7 DPR';
     }
 
-    function getSchemaVersion() {
+    function getSchemaSignature() {
         return $this->config['schema_signature'];
     }
 
@@ -111,7 +117,7 @@ class Config {
     }
 
     function getId() {
-        return $this->config['id'];
+        return $this->id;
     }
    
     function getTitle() {
@@ -145,6 +151,10 @@ class Config {
     function getPasswdResetPeriod() {
         return $this->config['passwd_reset_period'];
     }
+
+    function showRelatedTickets() {
+        return $this->config['show_related_tickets'];
+    }
         
     function getClientTimeout() {
         return $this->getClientSessionTimeout();
diff --git a/include/class.cron.php b/include/class.cron.php
index 3fd2d652cad8551ffa9852cd3d1f8984f060d542..ddc4d2973e77ff93f6f83a4a3fefd6b4b9b82814 100644
--- a/include/class.cron.php
+++ b/include/class.cron.php
@@ -34,10 +34,16 @@ class Cron {
         Sys::purgeLogs();
     }
 
+    function CleanOrphanedFiles() {
+        require_once(INCLUDE_DIR.'class.file.php');
+        AttachmentFile::deleteOrphans();
+    }
+
     function run(){ //called by outside cron NOT autocron
-        Cron::MailFetcher();
-        Cron::TicketMonitor();
-        cron::PurgeLogs();
+        self::MailFetcher();
+        self::TicketMonitor();
+        self::PurgeLogs();
+        self::CleanOrphanedFiles();
     }
 }
 ?>
diff --git a/include/class.faq.php b/include/class.faq.php
index 63b0848e469c7b3b1df6dbb9d61e27fca2c28118..7e23803dc458272ed7f81184c190213ddabd0e85 100644
--- a/include/class.faq.php
+++ b/include/class.faq.php
@@ -192,7 +192,7 @@ class FAQ {
             /* The h key must match validation in file.php */
             $hash=$attachment['hash'].md5($attachment['id'].session_id().$attachment['hash']);
             if($attachment['size'])
-                $size=sprintf('(<i>%s</i>)',Format::file_size($attachment['size']));
+                $size=sprintf('&nbsp;<small>(<i>%s</i>)</small>',Format::file_size($attachment['size']));
 
             $str.=sprintf('<a class="Icon file" href="file.php?h=%s" target="%s">%s</a>%s&nbsp;%s',
                     $hash, $target, Format::htmlchars($attachment['name']), $size, $separator);
@@ -217,29 +217,13 @@ class FAQ {
         return $i;
     }
 
-    function deleteAttachment($fileId) {
-
-        $sql='DELETE FROM '.FAQ_ATTACHMENT_TABLE
-             .' WHERE faq_id='.db_input($this->getId())
-             .' AND file_id='.db_input($fileId)
-             .' LIMIT 1';
-
-        if(!db_query($sql) || !db_affected_rows())
-            return false;
-
-        if(($file=AttachmentFile::lookup($fileId)) && !$file->isInuse())
-            $file->delete();
-
-        return true;
-    }
-
     function deleteAttachments(){
 
         $deleted=0;
-        if(($attachments = $this->getAttachments())) {
-            foreach($attachments as $attachment)
-                if($attachment['id'] && $this->deleteAttachment($attachment['id']))
-                    $deleted++;
+        $sql='DELETE FROM '.FAQ_ATTACHMENT_TABLE
+            .' WHERE faq_id='.db_input($this->getId());
+        if(db_query($sql) && db_affected_rows()) {
+            $deleted = AttachmentFile::deleteOrphans();
         }
 
         return $deleted;
diff --git a/include/class.file.php b/include/class.file.php
index af38bfd59e43b45471dc35d8e1a256678c05588a..b9bfbe1b7d2975ebdcc467bfb826ed35b8f1ec75 100644
--- a/include/class.file.php
+++ b/include/class.file.php
@@ -138,6 +138,7 @@ class AttachmentFile {
         exit();
     }
 
+    /* Function assumes the files types have been validated */
     function upload($file) {
         
         if(!$file['name'] || !is_uploaded_file($file['tmp_name']))
@@ -193,6 +194,24 @@ class AttachmentFile {
         
         return ($id && ($file = new AttachmentFile($id)) && $file->getId()==$id)?$file:null;
     }
+    /**
+     * Removes files and associated meta-data for files which no ticket,
+     * canned-response, or faq point to any more.
+     */
+    /* static */ function deleteOrphans() {
+        $res=db_query(
+            'DELETE FROM '.FILE_TABLE.' WHERE id NOT IN ('
+                # DISTINCT implies sort and may not be necessary
+                .'SELECT DISTINCT(file_id) FROM ('
+                    .'SELECT file_id FROM '.TICKET_ATTACHMENT_TABLE
+                    .' UNION ALL '
+                    .'SELECT file_id FROM '.CANNED_ATTACHMENT_TABLE
+                    .' UNION ALL '
+                    .'SELECT file_id FROM '.FAQ_ATTACHMENT_TABLE
+                .') still_loved'
+            .')');
+        return db_affected_rows();
+    }
 }
 
 class AttachmentList {
diff --git a/include/class.filter.php b/include/class.filter.php
index 9a1caf2b1b0792c9cea14d9cbf28cf4a458ea0ce..4f18e96514c307077b7300a02674f8ad1698039e 100644
--- a/include/class.filter.php
+++ b/include/class.filter.php
@@ -38,7 +38,7 @@ class Filter {
             return false;
         
         $this->ht=db_fetch_array($res);
-        $this->id=$info['id'];
+        $this->id=$this->ht['id'];
         
         return true;
     }
@@ -260,7 +260,7 @@ class Filter {
         #       Set owning department (?)
         if ($this->getDeptId())     $ticket['deptId']=$this->getDeptId();
         #       Set ticket priority (?)
-        if ($this->getPriorityId()) $ticket['pri']=$this->getPriorityId();
+        if ($this->getPriorityId()) $ticket['priorityId']=$this->getPriorityId();
         #       Set SLA plan (?)
         if ($this->getSLAId())      $ticket['slaId']=$this->getSLAId();
         #       Auto-assign to (?)
@@ -589,16 +589,46 @@ class EmailFilter {
             array_push($this->filters, new Filter($id));
         return $this->filters;
     }
+    /**
+     * Fetches the short list of filters that match the email received in the
+     * constructor. This function is memoized so subsequent calls will
+     * return immediately.
+     */
+    function getMatchingFilterList() {
+        if (!isset($this->short_list)) {
+            $this->short_list = array();
+            foreach ($this->filters as $filter)
+                if ($filter->matches($this->email))
+                    $this->short_list[] = $filter;
+        }
+        return $this->short_list;
+    }
+    /**
+     * Determine if the filters that match the received email indicate that
+     * the email should be rejected
+     *
+     * Returns FALSE if the email should be acceptable. If the email should
+     * be rejected, the first filter that matches and has rejectEmail set is
+     * returned.
+     */
+    function shouldReject() {
+        foreach ($this->getMatchingFilterList() as $filter) {
+            # Set reject if this filter indicates that the email should
+            # be blocked; however, don't unset $reject, because if it
+            # was set by another rule that did not set stopOnMatch(), we
+            # should still honor its configuration
+            if ($filter->rejectEmail()) return $filter;
+        }
+        return false;
+    }
     /**
      * Determine if any filters match the received email, and if so, apply
      * actions defined in those filters to the ticket-to-be-created.
      */
     function apply(&$ticket) {
-        foreach ($this->filters as $filter) {
-            if ($filter->matches($this->email)) {
-                $filter->apply($ticket, $this->email);
-                if ($filter->stopOnMatch()) break;
-            }
+        foreach ($this->getMatchingFilterList() as $filter) {
+            $filter->apply($ticket, $this->email);
+            if ($filter->stopOnMatch()) break;
         }
     }
     
diff --git a/include/class.format.php b/include/class.format.php
index 0dbd9e1432215d57b92661e99acfe761fa96b522..45f4301913072fa49d93d7dc3a10019b82536563 100644
--- a/include/class.format.php
+++ b/include/class.format.php
@@ -117,10 +117,12 @@ class Format {
     function clickableurls($text) {
 
         //Not perfect but it works - please help improve it. 
-        $text=preg_replace('/(((f|ht){1}tp(s?):\/\/)[-a-zA-Z0-9@:%_\+.~#?&;\/\/=]+)/','<a href="\\1" target="_blank">\\1</a>', $text);
+        $text=preg_replace('/(((f|ht){1}tp(s?):\/\/)[-a-zA-Z0-9@:%_\+.~#?&;\/\/=]+)/',
+            '<a href="l.php?url=\\1" target="_blank">\\1</a>', $text);
         $text=preg_replace("/(^|[ \\n\\r\\t])(www\.([a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+)(\/[^\/ \\n\\r]*)*)/",
-                '\\1<a href="http://\\2" target="_blank">\\2</a>', $text);
-        $text=preg_replace("/(^|[ \\n\\r\\t])([_\.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,4})/",'\\1<a href="mailto:\\2" target="_blank">\\2</a>', $text);
+            '\\1<a href="l.php?url=http://\\2" target="_blank">\\2</a>', $text);
+        $text=preg_replace("/(^|[ \\n\\r\\t])([_\.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,4})/",
+            '\\1<a href="l.php?url=mailto:\\2" target="_blank">\\2</a>', $text);
 
         return $text;
     }
diff --git a/include/class.misc.php b/include/class.misc.php
index c9a5db034865db1ac621948aacd3a03b9a919b1b..d9f59f47858b23c9c47c2de6ea6c3cedfda61df1 100644
--- a/include/class.misc.php
+++ b/include/class.misc.php
@@ -139,6 +139,22 @@ class Misc {
         return $output;
     }
 
-   
+    function siteBaseUrl() {
+        # Detects Alias-ing
+        $paths = explode('/', $_SERVER['REQUEST_URI']);
+        # Drop the last item -- it will be the php page we're on
+        array_pop($paths);
+        $leading = array();
+        while (count($paths)) {
+            if (in_array($paths[0], array('scp','client')))
+                break;
+            $leading[] = array_shift($paths);
+        }
+        if (count($leading) > 1)
+            return implode('/', $leading);
+        else
+            return '';
+    }
+
 }
 ?>
diff --git a/include/class.nav.php b/include/class.nav.php
index 561fc963dcd80165bc755fd96588907a3e06a1ac..a3b719f08d6bec16f6a2a7bb3fb264b1730c2f13 100644
--- a/include/class.nav.php
+++ b/include/class.nav.php
@@ -263,15 +263,24 @@ class UserNav {
 
             $navs = array();
             $user = $this->user;
-            $navs['home']=array('desc'=>'Support Center Home','href'=>'index.php','title'=>'');
+            $navs['home']=array('desc'=>'Support&nbsp;Center&nbsp;Home','href'=>'index.php','title'=>'');
             if($cfg && $cfg->isKnowledgebaseEnabled())
                 $navs['kb']=array('desc'=>'Knowledgebase','href'=>'kb/index.php','title'=>'');
 
-            $navs['new']=array('desc'=>'Open New Ticket','href'=>'open.php','title'=>'');
-            if($user && $user->isValid())
-                $navs['tickets']=array('desc'=>'My Tickets','href'=>'tickets.php','title'=>'');
-            else
+            $navs['new']=array('desc'=>'Open&nbsp;New&nbsp;Ticket','href'=>'open.php','title'=>'');
+            if($user && $user->isValid()) {
+                if($cfg && $cfg->showRelatedTickets()) {
+                    $navs['tickets']=array('desc'=>sprintf('My&nbsp;Tickets&nbsp;(%d)',$user->getNumTickets()),
+                                           'href'=>'tickets.php',
+                                            'title'=>'Show all tickets');
+                } else {
+                    $navs['tickets']=array('desc'=>'View&nbsp;Ticket&nbsp;Thread',
+                                           'href'=>sprintf('tickets.php?id=%d',$user->getTicketID()),
+                                           'title'=>'View ticket status');
+                }
+            } else {
                 $navs['status']=array('desc'=>'Check Ticket Status','href'=>'view.php','title'=>'');
+            }
             $this->navs=$navs;
         }
 
diff --git a/include/class.staff.php b/include/class.staff.php
index bfb0b79d2735c32b2410845fba1f0f89490bf0ba..9968965991fc024caa326747da423a01d0202eb8 100644
--- a/include/class.staff.php
+++ b/include/class.staff.php
@@ -37,15 +37,18 @@ 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 '.
-             '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) ';
+        $sql='SELECT staff.*, grp.*, tz.offset as tz_offset '
+            .' ,TIME_TO_SEC(TIMEDIFF(NOW(),IFNULL(staff.passwdreset,staff.created))) as passwd_change_sec '
+            .' 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) ';
+
         $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;
 
+        
         $this->ht=db_fetch_array($res);
         $this->id  = $this->ht['staff_id'];
         $this->teams =$this->ht['teams']=$this->getTeams();
diff --git a/include/class.ticket.php b/include/class.ticket.php
index edb9ac4608cd6df114bebd62c798d4b205b443aa..4801f1625594d030dd137861cfb4e4db7d9896e9 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -175,6 +175,18 @@ class Ticket{
                  || $staff->getId()==$this->getStaffId());
     }
 
+    function checkClientAccess($client) {
+        global $cfg;
+
+        if(!is_object($client) && !($client=Client::lookup($client)))
+            return false;
+
+        if(!strcasecmp($client->getEmail(),$this->getEmail()))
+            return true;
+
+        return ($cfg && $cfg->showRelatedTickets() && $client->getTicketId()==$ticket->getExtId());
+    }
+
     //Getters
     function getId(){
         return  $this->id;
@@ -437,8 +449,10 @@ class Ticket{
 
     function getRelatedTicketsCount(){
 
-        $sql='SELECT count(*)  FROM '.TICKET_TABLE.' WHERE email='.db_input($this->getEmail());
-        return db_count($sql);
+        $sql='SELECT count(*)  FROM '.TICKET_TABLE
+            .' WHERE email='.db_input($this->getEmail());
+
+        return db_result(db_query($sql));
     }
 
     function getThreadCount() {
@@ -488,7 +502,7 @@ class Ticket{
                 ON (msg.ticket_id=attach.ticket_id AND msg.msg_id=attach.ref_id AND ref_type="M") '
             .' WHERE  msg.ticket_id='.db_input($this->getId())
             .' GROUP BY msg.msg_id '
-            .' ORDER BY msg.created DESC ';
+            .' ORDER BY msg.created ASC ';
 
         $messages=array();
         if(($res=db_query($sql)) && db_num_rows($res))
@@ -1193,7 +1207,9 @@ class Ticket{
 
         $this->onMessage($autorespond); //must be called b4 sending alerts to staff.
 
-        if(!($tpl = $dept->getTemplate()))
+        $dept = $this->getDept();
+
+        if(!$dept || !($tpl = $dept->getTemplate()))
             $tpl= $cfg->getDefaultTemplate();
 
         if(!($email=$cfg->getAlertEmail()))
@@ -1424,15 +1440,10 @@ class Ticket{
         global $cfg;
 
         $deleted=0;
-        if(($attachments = $this->getAttachments())) {
-            //Clear reference table - XXX: some attachments might be orphaned
-            db_query('DELETE FROM '.TICKET_ATTACHMENT_TABLE.' WHERE ticket_id='.db_input($this->getId()));
-            //Delete file from DB IF NOT inuse.
-            foreach($attachments as $attachment) {
-                if(($file=AttachmentFile::lookup($attachment['file_id'])) && !$file->isInuse() && $file->delete())
-                    $deleted++;
-            }
-        }
+        // Clear reference table
+        $res=db_query('DELETE FROM '.TICKET_ATTACHMENT_TABLE.' WHERE ticket_id='.db_input($this->getId()));
+        if ($res && db_affected_rows())
+            $deleted = AttachmentFile::deleteOrphans();
 
         return $deleted;
     }
@@ -1463,10 +1474,14 @@ class Ticket{
 
 
    
-    function lookup($id){ //Assuming local ID is the only lookup used!
+    function lookup($id) { //Assuming local ID is the only lookup used!
         return ($id && is_numeric($id) && ($ticket= new Ticket($id)) && $ticket->getId()==$id)?$ticket:null;    
     }
 
+    function lookupByExtId($id) {
+        return self::lookup(self:: getIdByExtId($id));
+    }
+
     function genExtRandID() {
         global $cfg;
 
@@ -1542,6 +1557,27 @@ class Ticket{
         return db_fetch_array(db_query($sql));
     }
 
+
+    /* Quick client's tickets stats 
+       @email - valid email. 
+     */
+    function getClientStats($email) {
+
+        if(!$email || !Validator::is_email($email))
+            return null;
+
+        $sql='SELECT count(open.ticket_id) as open, count(closed.ticket_id) as closed '
+            .' FROM '.TICKET_TABLE.' ticket '
+            .' LEFT JOIN '.TICKET_TABLE.' open
+                ON (open.ticket_id=ticket.ticket_id AND open.status=\'open\') '
+            .' LEFT JOIN '.TICKET_TABLE.' closed
+                ON (closed.ticket_id=ticket.ticket_id AND closed.status=\'closed\')'
+            .' WHERE ticket.email='.db_input($email);
+
+        return db_fetch_array(db_query($sql));
+    }
+
+    //FIXME: Refactor the code for version 1.7
     function update($var,&$errors) {
          global $cfg,$thisstaff;
 
@@ -1627,12 +1663,21 @@ class Ticket{
     function create($vars,&$errors, $origin, $autorespond=true, $alertstaff=true) {
         global $cfg,$thisclient,$_FILES;
 
-        //Make sure the email is not banned
+        //Make sure the email address is not banned
         if ($vars['email'] && EmailFilter::isBanned($vars['email'])) {
             $errors['err']='Ticket denied. Error #403';
             Sys::log(LOG_WARNING,'Ticket denied','Banned email - '.$vars['email']);
             return 0;
-         }
+        }
+        // Make sure email contents should not be rejected
+        if (($email_filter=new EmailFilter($vars))
+                && ($filter=$email_filter->shouldReject())) {
+            $errors['err']='Ticket denied. Error #403';
+            Sys::log(LOG_WARNING,'Ticket denied',
+                sprintf('Banned email - %s by filter "%s"', $vars['email'],
+                    $filter->getName()));
+            return 0;
+        }
 
         $id=0;
         $fields=array();
@@ -1646,7 +1691,7 @@ class Ticket{
                 break;
             case 'staff':
                 $fields['deptId']   = array('type'=>'int',  'required'=>1, 'error'=>'Dept. required');
-                $fields['topicId']   = array('type'=>'int',  'required'=>1, 'error'=>'Topic required');
+                $fields['topicId']  = array('type'=>'int',  'required'=>1, 'error'=>'Topic required');
                 $fields['duedate']  = array('type'=>'date', 'required'=>0, 'error'=>'Invalid date - must be MM/DD/YY');
             case 'api':
                 $fields['source']   = array('type'=>'string', 'required'=>1, 'error'=>'Indicate source');
@@ -1656,10 +1701,10 @@ class Ticket{
                 break;
             default:
                 # TODO: Return error message
-                $errors['origin'] = 'Invalid origin given';
+                $errors['err']=$errors['origin'] = 'Invalid origin given';
         }
-        $fields['pri']      = array('type'=>'int',      'required'=>0, 'error'=>'Invalid Priority');
-        $fields['phone']    = array('type'=>'phone',    'required'=>0, 'error'=>'Valid phone # required');
+        $fields['priorityId']   = array('type'=>'int',      'required'=>0, 'error'=>'Invalid Priority');
+        $fields['phone']        = array('type'=>'phone',    'required'=>0, 'error'=>'Valid phone # required');
         
         if(!Validator::process($fields, $vars, $errors) && !$errors['err'])
             $errors['err'] ='Missing or invalid data - check the errors and try again';
@@ -1692,14 +1737,15 @@ class Ticket{
         }
 
         # Perform email filter actions on the new ticket arguments XXX: Move filter to the top and check for reject...
-        if (!$errors && $ef = new EmailFilter($vars)) $ef->apply($vars);
+        if (!$errors && $email_filter) $email_filter->apply($vars);
 
         # Some things will need to be unpacked back into the scope of this
         # function
         if (isset($vars['autorespond'])) $autorespond=$vars['autorespond'];
 
         //check ticket limits..if limit set is >0 
-        //TODO: Base ticket limits on SLA... XXX: move it elsewhere??
+        //TODO:  XXX: move it elsewhere?? Client::checkMaxOpenTickets($email,$vars)
+
         if($vars['email'] && !$errors && $cfg->getMaxOpenTickets()>0 && strcasecmp($origin,'staff')){
             $openTickets=Ticket::getOpenTicketsByEmail($vars['email']);
             if($openTickets>=$cfg->getMaxOpenTickets()) {
@@ -1800,14 +1846,6 @@ class Ticket{
 
         //post the message.
         $msgid=$ticket->postMessage($vars['message'],$source,$vars['mid'],$vars['header'],true);
-        //TODO: recover from postMessage error??
-
-        //Upload attachments...web based. - XXX: Assumes user uploaded attachments!! XXX: move it to client interface.
-        if($_FILES['attachment']['name'] && $cfg->allowOnlineAttachments() && $msgid) {    
-            if(!$cfg->allowAttachmentsOnlogin() || ($cfg->allowAttachmentsOnlogin() && ($thisuser && $thisuser->isValid()))) {
-                $ticket->uploadAttachment($_FILES['attachment'],$msgid,'M');
-            }
-        }
 
         // Configure service-level-agreement for this ticket
         $ticket->selectSLAId($vars['slaId']);
diff --git a/include/class.topic.php b/include/class.topic.php
index 59159c8c90a5501150f22342fdf886ed5a729330..40ab8096bc1831b821ea37754b18e3d1a1a22e3e 100644
--- a/include/class.topic.php
+++ b/include/class.topic.php
@@ -135,6 +135,10 @@ class Topic {
         return $topics;
     }
 
+    function getPublicHelpTopics() {
+        return self::getHelpTopics(true);
+    }
+
 
     function getIdByName($topic){
         $sql='SELECT topic_id FROM '.TOPIC_TABLE.' WHERE topic='.db_input($topic);
diff --git a/include/client/header.inc.php b/include/client/header.inc.php
index ad88a0c80d13cb9655a5b113d28c5de94943b102..65966c838279f9174536bba87f01d5f5c3526cd4 100644
--- a/include/client/header.inc.php
+++ b/include/client/header.inc.php
@@ -21,8 +21,14 @@ header("Content-Type: text/html; charset=UTF-8\r\n");
             <a id="logo" href="<?php echo ROOT_PATH; ?>index.php" title="Support Center"><img src="<?php echo ASSETS_PATH; ?>images/logo.png" border=0 alt="Support Center"></a>
             <p>
              <?php
-             if($thisclient && is_object($thisclient) && $thisclient->isValid()) { ?>
-                <a href="<?php echo ROOT_PATH; ?>tickets.php">My Tickets</a> - 
+             if($thisclient && is_object($thisclient) && $thisclient->isValid()) { 
+                 echo $thisclient->getName().'&nbsp;-&nbsp;';
+                 ?>
+                <?php
+                if($cfg->showRelatedTickets()) {?>
+                <a href="<?php echo ROOT_PATH; ?>tickets.php">My Tickets <b>(<?php echo $thisclient->getNumTickets(); ?>)</b></a> - 
+                <?php
+                } ?>
                 <a href="<?php echo ROOT_PATH; ?>logout.php">Log Out</a>
              <?php 
              }elseif($nav){ ?>
diff --git a/include/client/kb-category.inc.php b/include/client/kb-category.inc.php
index f166fb5bdf8a1f528e56b965c5c32dca3e16dd8f..50a51782f214b8fc28b78f54afdd005c3f1a71df 100644
--- a/include/client/kb-category.inc.php
+++ b/include/client/kb-category.inc.php
@@ -1,34 +1,31 @@
 <?php
 if(!defined('OSTCLIENTINC') || !$category || !$category->isPublic()) die('Access Denied');
-
 ?>
-<div style="width:700;padding-top:10px; float:left;">
-  <h2>Frequently Asked Questions</h2>
-</div>
-<div style="float:right;text-align:right;padding-top:5px;padding-right:5px;">&nbsp;</div>
-<div class="clear"></div>
-<br>
-<div><strong><?php echo $category->getName() ?></strong></div>
+<h1><strong><?php echo $category->getName() ?></strong></h1>
 <p>
 <?php echo Format::safe_html($category->getDescription()); ?>
 </p>
 <hr>
 <?php
-$sql='SELECT faq.faq_id, question '
+$sql='SELECT faq.faq_id, question, count(attach.file_id) as attachments '
     .' FROM '.FAQ_TABLE.' faq '
     .' LEFT JOIN '.FAQ_ATTACHMENT_TABLE.' attach ON(attach.faq_id=faq.faq_id) '
     .' WHERE faq.ispublished=1 AND faq.category_id='.db_input($category->getId())
     .' GROUP BY faq.faq_id';
 if(($res=db_query($sql)) && db_num_rows($res)) {
-    echo '<div id="faq">
+    echo '
+         <h2>Frequently Asked Questions</h2>
+         <div id="faq">
             <ol>';
     while($row=db_fetch_array($res)) {
+        $attachments=$row['attachments']?'<span class="Icon file"></span>':'';
         echo sprintf('
-            <li><a href="faq.php?id=%d" >%s</a></li>',
-            $row['faq_id'],Format::htmlchars($row['question']));
+            <li><a href="faq.php?id=%d" >%s &nbsp;%s</a></li>',
+            $row['faq_id'],Format::htmlchars($row['question']), $attachments);
     }
     echo '  </ol>
-         </div>';
+         </div>
+         <p><a class="back" href="index.php">&laquo; Go Back</a></p>';
 }else {
     echo '<strong>Category does not have any FAQs. <a href="index.php">Back To Index</a></strong>';
 }
diff --git a/include/client/knowledgebase.inc.php b/include/client/knowledgebase.inc.php
index 0af99ba21b1d92532a6063e175e9cf0fdc69c2c9..83484e95de818d732a67fed39b980fd5e9262e95 100644
--- a/include/client/knowledgebase.inc.php
+++ b/include/client/knowledgebase.inc.php
@@ -1,5 +1,6 @@
 <?php
 if(!defined('OSTCLIENTINC')) die('Access Denied');
+
 ?>
 <h1>Frequently Asked Questions</h1>
 <form action="index.php" method="get" style="padding-top:15px;">
@@ -14,6 +15,7 @@ if(!defined('OSTCLIENTINC')) die('Access Denied');
                     $sql='SELECT category_id, name, count(faq.category_id) as faqs '
                         .' FROM '.FAQ_CATEGORY_TABLE.' cat '
                         .' LEFT JOIN '.FAQ_TABLE.' faq USING(category_id) '
+                        .' WHERE cat.ispublic=1 AND faq.ispublished=1 '
                         .' GROUP BY cat.category_id '
                         .' HAVING faqs>0 '
                         .' ORDER BY cat.name DESC ';
@@ -40,6 +42,7 @@ if(!defined('OSTCLIENTINC')) die('Access Denied');
                     $sql='SELECT ht.topic_id, ht.topic, count(faq.topic_id) as faqs '
                         .' FROM '.TOPIC_TABLE.' ht '
                         .' LEFT JOIN '.FAQ_TOPIC_TABLE.' faq USING(topic_id) '
+                        .' WHERE ht.ispublic=1 '
                         .' GROUP BY ht.topic_id '
                         .' HAVING faqs>0 '
                         .' ORDER BY ht.topic DESC ';
@@ -88,7 +91,7 @@ if($_REQUEST['q'] || $_REQUEST['cid'] || $_REQUEST['topicId']) { //Search.
 } else { //Category Listing.
     $sql='SELECT cat.category_id, cat.name, cat.description, cat.ispublic, count(faq.faq_id) as faqs '
         .' FROM '.FAQ_CATEGORY_TABLE.' cat '
-        .' LEFT JOIN '.FAQ_TABLE.' faq ON(faq.category_id=cat.category_id) '
+        .' LEFT JOIN '.FAQ_TABLE.' faq ON(faq.category_id=cat.category_id AND faq.ispublished=1) '
         .' WHERE cat.ispublic=1 '
         .' GROUP BY cat.category_id '
         .' HAVING faqs>0 '
diff --git a/include/client/open.inc.php b/include/client/open.inc.php
index fd31bc9b81f907204134114e1aed59d3fc728cb6..9c2a82b4706e1fc83253471eea8224e47cd7b382 100644
--- a/include/client/open.inc.php
+++ b/include/client/open.inc.php
@@ -1,21 +1,40 @@
 <?php
-if(!defined('OSTCLIENTINC')) die('Access Denied'); //Say bye to our friend..
+if(!defined('OSTCLIENTINC')) die('Access Denied!');
+$info=array();
+if($thisclient && $thisclient->isValid()) {
+    $info=array('name'=>$thisclient->getName(),
+                'email'=>$thisclient->getEmail(),
+                'phone'=>$thisclient->getPhone(),
+                'phone_ext'=>$thisclient->getPhoneExt());
+}
 
-$info=($_POST && $errors)?Format::htmlchars($_POST):array();
+$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">E-Mail Address:</label>
+        <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>
@@ -30,16 +49,14 @@ $info=($_POST && $errors)?Format::htmlchars($_POST):array();
         <select id="topicId" name="topicId">
             <option value="" selected="selected">&mdash; Select a Help Topics &mdash;</option>
             <?php
-                $sql='SELECT topic_id,topic FROM '.TOPIC_TABLE.' WHERE isactive=1 ORDER BY topic';
-                 if(($res=db_query($sql)) && db_num_rows($res)) {
-                     while (list($topicId,$topic) = db_fetch_row($res)){
-                        $selected = ($info['topicId']==$topicId)?'selected="selected"':''; ?>
-                        <option value="<?php echo $topicId; ?>"<?php echo $selected; ?>><?php echo $topic; ?></option>
-                        <?php
-                     }
-                 }else{ ?>
-                    <option value="0" >General Inquiry</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>
     </div>
@@ -58,35 +75,41 @@ $info=($_POST && $errors)?Format::htmlchars($_POST):array();
         <textarea id="message" cols="60" rows="8" name="message"><?php echo $info['message']; ?></textarea>
     </div>
     <?php if(($cfg->allowOnlineAttachments() && !$cfg->allowAttachmentsOnlogin())
-            || ($cfg->allowAttachmentsOnlogin() && ($thisuser && $thisuser->isValid()))) { ?>
+            || ($cfg->allowAttachmentsOnlogin() && ($thisclient && $thisclient->isValid()))) { ?>
      <div>
-        <label for="attachment">Attachments:</label>
-        <input id="attachment" type="file" name="attachment"><font class="error">&nbsp;<?php echo $errors['attachment']; ?></font>
+        <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>                                                                
     <?php } ?>
     <?php
-    if($cfg && $cfg->allowPriorityChange()) {
-      $sql='SELECT priority_id,priority_desc FROM '.TICKET_PRIORITY_TABLE.' WHERE ispublic=1 ORDER BY priority_urgency DESC';
-      if(($res=db_query($sql)) && db_num_rows($res)) {?>
-      <div>
+    if($cfg->allowPriorityChange() && ($priorities=Priority::getPriorities())) { ?>
+    <div>
         <label for="priority">Ticket Priority:</label>
         <select id="priority" name="priorityId">
-              <?php
+            <?php
                 if(!$info['priorityId'])
-                    $info['priorityId']=$cfg->getDefaultPriorityId(); //use system's default priority.
-                while($row=db_fetch_array($res)){ 
-                    $selected=$info['priorityId']==$row['priority_id']?'selected="selected"':'';
-                    ?>
-                    <option value="<?php echo $row['priority_id']; ?>" <?php echo $selected; ?> ><?php echo $row['priority_desc']; ?></option>
-              <?php } ?>
+                    $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>
+        
+    </div>
     <?php
-      }
-    } ?>
+    }
+    ?>
     <?php
-    if($cfg && $cfg->enableCaptcha() && (!$thisuser || !$thisuser->isValid())) {
+    if($cfg && $cfg->enableCaptcha() && (!$thisclient || !$thisclient->isValid())) {
         if($_POST && $errors && !$errors['captcha'])
             $errors['captcha']='Please re-enter the text again';
         ?>
@@ -101,7 +124,7 @@ $info=($_POST && $errors)?Format::htmlchars($_POST):array();
     <?php
     } ?>
     <br>
-    <p>
+    <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"'>
diff --git a/include/client/tickets.inc.php b/include/client/tickets.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..a360217167bde83dedcb4decb339677e3c5370d6
--- /dev/null
+++ b/include/client/tickets.inc.php
@@ -0,0 +1,172 @@
+<?php
+if(!defined('OSTCLIENTINC') || !is_object($thisclient) || !$thisclient->isValid() || !$cfg->showRelatedTickets()) die('Access Denied');
+
+$qstr='&'; //Query string collector
+$status=null;
+if(isset($_REQUEST['status'])) { //Query string status has nothing to do with the real status used below.
+    $qstr.='status='.urlencode($_REQUEST['status']);
+    //Status we are actually going to use on the query...making sure it is clean!
+    switch(strtolower($_REQUEST['status'])) {
+     case 'open':
+     case 'closed':
+        $status=strtolower($_REQUEST['status']);
+        break;
+     default:
+        $status=''; //ignore
+    }
+} elseif($thisclient->getNumOpenTickets()) {
+    $status='open'; //Defaulting to open
+}
+
+$sortOptions=array('id'=>'ticketID', 'name'=>'ticket.name', 'subject'=>'ticket.subject',
+                    'email'=>'ticket.email', 'status'=>'ticket.status', 'dept'=>'dept_name','date'=>'ticket.created');
+$orderWays=array('DESC'=>'DESC','ASC'=>'ASC');
+//Sorting options...
+$order_by=$order=null;
+$sort=($_REQUEST['sort'] && $sortOptions[strtolower($_REQUEST['sort'])])?strtolower($_REQUEST['sort']):'date';
+if($sort && $sortOptions[$sort])
+    $order_by =$sortOptions[$sort];
+
+$order_by=$order_by?$order_by:'ticket_created';
+if($_REQUEST['order'] && $orderWays[strtoupper($_REQUEST['order'])]) 
+    $order=$orderWays[strtoupper($_REQUEST['order'])];
+
+$order=$order?$order:'ASC';
+if($order_by && strpos($order_by,','))
+    $order_by=str_replace(','," $order,",$order_by);
+
+$x=$sort.'_sort';
+$$x=' class="'.strtolower($order).'" ';
+
+$qselect='SELECT ticket.ticket_id,ticket.ticketID,ticket.dept_id,isanswered, dept.ispublic, ticket.subject, ticket.name, ticket.email '.
+           ',dept_name,ticket. status, ticket.source, ticket.created ';
+
+$qfrom='FROM '.TICKET_TABLE.' ticket '
+      .' LEFT JOIN '.DEPT_TABLE.' dept ON (ticket.dept_id=dept.dept_id) ';
+
+$qwhere =' WHERE ticket.email='.db_input($thisclient->getEmail());
+
+if($status){
+    $qwhere.=' AND ticket.status='.db_input($status);
+}
+
+$search=($_REQUEST['a']=='search' && $_REQUEST['q']);
+if($search) {
+    $qstr.='&a='.urlencode($_REQUEST['a']).'&q='.urlencode($_REQUEST['q']);
+    if(is_numeric($_REQUEST['q'])) {
+        $qwhere.=" AND ticket.ticketID LIKE '$queryterm%'";
+    } else {//Deep search!
+        $queryterm=db_real_escape($_REQUEST['q'],false); //escape the term ONLY...no quotes.
+        $qwhere.=' AND ( '
+                ." ticket.subject LIKE '%$queryterm%'"
+                ." OR message.message LIKE '%$queryterm%'"
+                ." OR response.response LIKE '%$queryterm%'"
+                .' ) ';
+        $deep_search=true;
+        //Joins needed for search
+        $qfrom.=' LEFT JOIN '.TICKET_MESSAGE_TABLE.' message ON (ticket.ticket_id=message.ticket_id )'
+               .' LEFT JOIN '.TICKET_RESPONSE_TABLE.' response ON (ticket.ticket_id=response.ticket_id )';
+    }
+}
+
+$total=db_count('SELECT count(DISTINCT ticket.ticket_id) '.$qfrom.' '.$qwhere);
+$pageNav=new Pagenate($total,$page, PAGE_LIMIT);
+$pageNav->setURL('tickets.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
+
+//more stuff...
+$qselect.=' ,count(attach_id) as attachments ';
+$qfrom.=' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ON  ticket.ticket_id=attach.ticket_id ';
+$qgroup=' GROUP BY ticket.ticket_id';
+
+$query="$qselect $qfrom $qwhere $qgroup ORDER BY $order_by $order LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
+//echo $query;
+$res = db_query($query);
+$showing=($res && db_num_rows($res))?$pageNav->showing():"";
+$showing.=($status)?(' '.ucfirst($status).' Tickets'):' All Tickets';
+if($search)
+    $showing="Search Results: $showing";
+
+$negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting
+
+?>
+<h1>My Tickets</h1>
+<br>
+<form action="tickets.php" method="get" id="ticketSearchForm">
+    <input type="hidden" name="a"  value="search">
+    <input type="text" name="q" size="20" value="<?php echo Format::htmlchars($_REQUEST['q']); ?>">
+    <select name="status">
+        <option value="">&mdash; Any Status &mdash;</option>
+        <option value="open" <?php echo ($status=='open')?'selected="selected"':'';?>>Open</option>
+        <option value="closed" <?php echo ($status=='closed')?'selected="selected"':'';?>>Closed</option>
+    </select>
+    <input type="submit" value="Go">
+</form>
+<a class="refresh" href="<?php echo $_SERVER['REQUEST_URI']; ?>">Refresh</a>
+<table id="ticketTable" width="800" border="0" cellspacing="0" cellpadding="0">
+    <caption><?php echo $showing; ?></caption>
+    <thead>
+        <tr>
+            <th width="70" nowrap>
+                <a href="tickets.php?sort=ID&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Ticket ID">Ticket #</a>
+            </th>
+            <th width="100">
+                <a href="tickets.php?sort=date&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Date">Create Date</a>
+            </th>
+            <th width="80">
+                <a href="tickets.php?sort=status&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Status">Status</a>
+            </th>
+            <th width="240">
+                <a href="tickets.php?sort=subj&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Subject">Subject</a>
+            </th>
+            <th width="150">
+                <a href="tickets.php?sort=dept&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Department">Department</a>
+            </th>
+            <th width="150">Phone Number</th>
+        </tr>
+    </thead>
+    <tbody>
+    <?php
+     if($res && ($num=db_num_rows($res))) {
+        $defaultDept=Dept::getDefaultDeptName(); //Default public dept.
+        while ($row = db_fetch_array($res)) {
+            $dept=$row['ispublic']?$row['dept_name']:$defaultDept;
+            $subject=Format::htmlchars(Format::truncate($row['subject'],40));
+            if($row['attachments'])
+                $subject.='  &nbsp;&nbsp;<span class="Icon file"></span>';
+
+            $ticketID=$row['ticketID'];
+            if($row['isanswered'] && !strcasecmp($row['status'],'open')) {
+                $subject="<b>$subject</b>";
+                $ticketID="<b>$ticketID</b>";
+            }
+            $phone=Format::phone($row['phone']);
+            if($row['phone_ext'])
+                $phone.=' '.$row['phone_ext'];
+            ?>
+            <tr id="<?php echo $row['ticketID']; ?>">
+                <td class="centered">
+                <a class="Icon <?php echo strtolower($row['source']); ?>Ticket" title="<?php echo $row['email']; ?>" 
+                    href="tickets.php?id=<?php echo $row['ticketID']; ?>"><?php echo $ticketID; ?></a>
+                </td>
+                <td>&nbsp;<?=Format::db_date($row['created'])?></td>
+                <td>&nbsp;<?=ucfirst($row['status'])?></td>
+                <td>
+                    <a href="tickets.php?id=<?php echo $row['ticketID']; ?>"><?php echo $subject; ?></a>
+                </td>
+                <td>&nbsp;<?=Format::truncate($dept,30)?></td>
+                <td><?php echo $phone; ?></td>
+            </tr>
+        <?php
+        }
+
+     } else {
+         echo '<tr><td colspan="7">Your query did not match any records</td></tr>';
+     }
+    ?>
+    </tbody>
+</table>
+<?php
+if($res && $num>0) { 
+    echo '<div>&nbsp;Page:'.$pageNav->getPageLinks().'&nbsp;</div>';
+}
+?>
diff --git a/include/client/view.inc.php b/include/client/view.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..e720ed96bffa58c5d7321e7fe2544c7829a86678
--- /dev/null
+++ b/include/client/view.inc.php
@@ -0,0 +1,157 @@
+<?php
+if(!defined('OSTCLIENTINC') || !$thisclient || !$ticket || !$ticket->checkClientAccess($thisclient)) die('Access Denied!');
+
+$info=($_POST && $errors)?Format::htmlchars($_POST):array();
+
+$dept = $ticket->getDept();
+//Making sure we don't leak out internal dept names
+if(!$dept || !$dept->isPublic())
+    $dept = $cfg->getDefaultDept();
+
+?>
+<table width="800" cellpadding="1" cellspacing="0" border="0" id="ticketInfo">
+    <tr>
+        <td colspan="2" width="100%">
+            <h1>
+                Ticket #<?php echo $ticket->getExtId(); ?> &nbsp;
+                <a href="view.php?id=<?php echo $ticket->getExtId(); ?>" title="Reload"><span class="Icon refresh">&nbsp;</span></a>
+            </h1>
+        </td>
+    </tr> 
+    <tr>
+        <td width="50%">   
+            <table class="infoTable" cellspacing="1" cellpadding="3" width="100%" border="0">
+                <tr>
+                    <th width="100">Ticket Status:</th>
+                    <td><?php echo ucfirst($ticket->getStatus()); ?></td>
+                </tr>
+                <tr>
+                    <th>Department:</th>
+                    <td><?php echo Format::htmlchars($dept->getName()); ?></td>
+                </tr>
+                <tr>
+                    <th>Create Date:</th>
+                    <td><?php echo Format::db_datetime($ticket->getCreateDate()); ?></td>
+                </tr>
+           </table>
+       </td>
+       <td width="50%">
+           <table class="infoTable" cellspacing="1" cellpadding="3" width="100%" border="0">
+               <tr>
+                   <th width="100">Name:</th>
+                   <td><?php echo ucfirst($ticket->getName()); ?></td>
+               </tr>
+               <tr>
+                   <th width="100">Email:</th>
+                   <td><?php echo Format::htmlchars($ticket->getEmail()); ?></td>
+               </tr>
+               <tr>
+                   <th>Phone:</th>
+                   <td><?php echo $ticket->getPhoneNumber(); ?></td>
+               </tr>
+            </table>
+       </td>
+    </tr>
+</table>
+<br>
+<h2>Subject:<?php echo Format::htmlchars($ticket->getSubject()); ?></h2>
+<br>
+<span class="Icon thread">Ticket Thread</span>
+<div id="ticketThread">
+<?php    
+if($ticket->getThreadCount() && ($messages = $ticket->getMessages())) {
+     
+    foreach($messages as $message) {?>
+    
+        <table class="message" cellspacing="0" cellpadding="1" width="800" border="0">
+        
+            <tr><th><?php echo Format::db_datetime($message['created']); ?></th></tr>
+            
+            <tr><td><?php echo Format::display($message['message']); ?></td></tr>
+            
+            <?php
+            
+            if($message['attachments'] && ($links=$ticket->getAttachmentsLinks($message['msg_id'],'M'))) { ?>
+            
+                <tr><td class="info"><?php echo $links; ?></td></tr>
+                
+            <?php
+            
+            } ?>
+            
+        </table>
+        <?php
+        if($message['responses'] && ($responses=$ticket->getResponses($message['msg_id']))) {
+           foreach($responses as $resp) {
+               $staff=$cfg->hideStaffName()?'staff':Format::htmlchars($resp['staff_name']);
+               ?>
+               <table class="response" cellspacing="0" cellpadding="1" width="100%" border="0">
+                <tr>
+                    <th><?php echo Format::db_datetime($resp['created']);?>&nbsp;-&nbsp;<?php echo $staff; ?></th>
+                </tr>
+                <tr><td><?php echo Format::display($resp['response']); ?></td></tr>
+                <?php
+                if($resp['attachments'] && ($links=$ticket->getAttachmentsLinks($resp['response_id'],'R'))) {?>
+                 <tr><td class="info"><?php echo $links; ?></td></tr>
+                <?php
+                 }?>
+                </table>
+            <?
+           }
+       }
+    }
+}
+?>
+</div>
+<div class="clear" style="padding-bottom:10px;"></div>
+<?php if($errors['err']) { ?>
+    <div id="msg_error"><?php echo $errors['err']; ?></div>
+<?php }elseif($msg) { ?>
+    <div id="msg_notice"><?php echo $msg; ?></div>
+<?php }elseif($warn) { ?>
+    <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">
+    <h2>Post a Reply</h2>
+    <input type="hidden" name="id" value="<?php echo $ticket->getExtId(); ?>">
+    <input type="hidden" name="a" value="reply">
+    <table border="0" cellspacing="0" cellpadding="3" width="800">
+        <tr>
+            <td width="160">
+                <label>Message:</label>
+            </td>
+            <td width="640">
+                <?php
+                if($ticket->isClosed()) {
+                    $msg='<b>Ticket will be reopened on message post</b>';
+                } else {
+                    $msg='To best assist you, please be specific and detailed';
+                }
+                ?>
+                <span id="msg"><em><?php echo $msg; ?> </em></span><font class="error">*&nbsp;<?php echo $errors['message']; ?></font><br/>
+                <textarea name="message" id="message" cols="50" rows="9" wrap="soft"><?php echo $info['message']; ?></textarea>
+            </td>
+        </tr>
+        <?php
+        if($cfg->allowOnlineAttachments()) { ?>
+        <tr>
+            <td width="160">
+                <label for="attachment">Attachments:</label>
+            </td>
+            <td width="640" id="reply_form_attachments" class="attachments">
+                <div class="uploads">
+                </div>
+                <div class="file_input">
+                    <input type="file" name="attachments[]" size="30" value="" />
+                </div>
+            </td>
+        </tr>
+        <?php
+        } ?>
+    </table>
+    <p style="padding-left:165px;">
+        <input type="submit" value="Post Reply">
+        <input type="reset" value="Reset">
+        <input type="button" value="Cancel" onClick="history.go(-1)">
+    </p>
+</form>
diff --git a/include/staff/api.inc.php b/include/staff/api.inc.php
index 7463ad0956cbfbb02d2e4d3faa82cfa0cd6da35e..21eac469162af3d2cc9652d8e8255f230ee18460 100644
--- a/include/staff/api.inc.php
+++ b/include/staff/api.inc.php
@@ -1,146 +1,147 @@
-<?php
-if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied');
-
-
-$info['phrase']=($errors && $_POST['phrase'])?Format::htmlchars($_POST['phrase']):$cfg->getAPIPassphrase();
-$select='SELECT * ';
-$from='FROM '.API_KEY_TABLE;
-$where='';
-$sortOptions=array('date'=>'created','ip'=>'ipaddr');
-$orderWays=array('DESC'=>'DESC','ASC'=>'ASC');
-//Sorting options...
-if($_REQUEST['sort']) {
-    $order_column =$sortOptions[$_REQUEST['sort']];
-}
-
-if($_REQUEST['order']) {
-    $order=$orderWays[$_REQUEST['order']];
-}
-$order_column=$order_column?$order_column:'ipaddr';
-$order=$order?$order:'ASC';
-$order_by=" ORDER BY $order_column $order ";
-
-$total=db_count('SELECT count(*) '.$from.' '.$where);
-$pagelimit=1000;//No limit.
-$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
-$pageNav=new Pagenate($total,$page,$pagelimit);
-$pageNav->setURL('admin.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
-$query="$select $from $where $order_by";
-//echo $query;
-$result = db_query($query);
-$showing=db_num_rows($result)?$pageNav->showing():'';
-$negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting..
-$deletable=0;
-?>
-<div class="msg">API Keys</div>
-<hr>
-<div><b><?php echo $showing; ?></b></div>
- <table width="100%" border="0" cellspacing=1 cellpadding=2>
-   <form action="admin.php?t=api" method="POST" name="api" onSubmit="return checkbox_checker(document.forms['api'],1,0);">
-   <input type=hidden name='t' value='api'>
-   <input type=hidden name='do' value='mass_process'>
-   <tr><td>
-    <table border="0" cellspacing=0 cellpadding=2 class="dtable" align="center" width="100%">
-        <tr>
-	        <th width="7px">&nbsp;</th>
-	        <th>API Key</th>
-            <th width="10" nowrap>Active</th>
-            <th width="100" nowrap>&nbsp;&nbsp;IP Address</th>
-	        <th width="150" nowrap>&nbsp;&nbsp;
-                <a href="admin.php?t=api&sort=date&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Create Date <?php echo $negorder; ?>">Created</a></th>
-        </tr>
+<?php
+if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied');
+
+
+$info['phrase']=($errors && $_POST['phrase'])?Format::htmlchars($_POST['phrase']):$cfg->getAPIPassphrase();
+$select='SELECT * ';
+$from='FROM '.API_KEY_TABLE;
+$where='';
+$sortOptions=array('date'=>'created','ip'=>'ipaddr');
+$orderWays=array('DESC'=>'DESC','ASC'=>'ASC');
+//Sorting options...
+if($_REQUEST['sort']) {
+    $order_column =$sortOptions[$_REQUEST['sort']];
+}
+
+if($_REQUEST['order']) {
+    $order=$orderWays[$_REQUEST['order']];
+}
+$order_column=$order_column?$order_column:'ipaddr';
+$order=$order?$order:'ASC';
+$order_by=" ORDER BY $order_column $order ";
+
+$total=db_count('SELECT count(*) '.$from.' '.$where);
+$pagelimit=1000;//No limit. TODO: Add limit.
+$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
+$pageNav=new Pagenate($total,$page,$pagelimit);
+$pageNav->setURL('admin.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
+$query="$select $from $where $order_by";
+//echo $query;
+$result = db_query($query);
+$showing=db_num_rows($result)?$pageNav->showing():'';
+$negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting..
+$deletable=0;
+?>
+<div class="msg">API Keys</div>
+<hr>
+<div><b><?php echo $showing; ?></b></div>
+ <table width="100%" border="0" cellspacing=1 cellpadding=2>
+   <form action="admin.php?t=api" method="POST" name="api" onSubmit="return checkbox_checker(document.forms['api'],1,0);">
+   <input type=hidden name='t' value='api'>
+   <input type=hidden name='do' value='mass_process'>
+   <tr><td>
+    <table border="0" cellspacing=0 cellpadding=2 class="dtable" align="center" width="100%">
+        <tr>
+	        <th width="7px">&nbsp;</th>
+	        <th>API Key</th>
+            <th width="10" nowrap>Active</th>
+            <th width="100" nowrap>&nbsp;&nbsp;IP Address</th>
+	        <th width="150" nowrap>&nbsp;&nbsp;
+                <a href="admin.php?t=api&sort=date&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Create Date <?php echo $negorder; ?>">Created</a></th>
+        </tr>
         <?php
-        $class = 'row1';
-        $total=0;
-        $active=$inactive=0;
-        $sids=($errors && is_array($_POST['ids']))?$_POST['ids']:null;
-        if($result && db_num_rows($result)):
-            $dtpl=$cfg->getDefaultTemplateId();
-            while ($row = db_fetch_array($result)) {
-                $sel=false;
-                $disabled='';
-                if($row['isactive'])
-                    $active++;
-                else
-                    $inactive++;
-                    
-                if($sids && in_array($row['id'],$sids)){
-                    $class="$class highlight";
-                    $sel=true;
-                }
-                ?>
-            <tr class="<?php echo $class; ?>" id="<?php echo $row['id']; ?>">
-                <td width=7px>
-                  <input type="checkbox" name="ids[]" value="<?php echo $row['id']; ?>" <?php echo $sel?'checked':''; ?>
-                        onClick="highLight(this.value,this.checked);">
-                <td>&nbsp;<?php echo $row['apikey']; ?></td>
-                <td><?php echo $row['isactive']?'<b>Yes</b>':'No'; ?></td>
-                <td>&nbsp;<?php echo $row['ipaddr']; ?></td>
-                <td>&nbsp;<?php echo Format::db_datetime($row['created']); ?></td>
-            </tr>
+        $class = 'row1';
+        $total=0;
+        $active=$inactive=0;
+        $sids=($errors && is_array($_POST['ids']))?$_POST['ids']:null;
+        if($result && db_num_rows($result)):
+            $dtpl=$cfg->getDefaultTemplateId();
+            while ($row = db_fetch_array($result)) {
+                $sel=false;
+                $disabled='';
+                if($row['isactive'])
+                    $active++;
+                else
+                    $inactive++;
+                    
+                if($sids && in_array($row['id'],$sids)){
+                    $class="$class highlight";
+                    $sel=true;
+                }
+                ?>
+            <tr class="<?php echo $class; ?>" id="<?php echo $row['id']; ?>">
+                <td width=7px>
+                  <input type="checkbox" name="ids[]" value="<?php echo $row['id']; ?>" <?php echo $sel?'checked':''; ?>
+                        onClick="highLight(this.value,this.checked);">
+                <td>&nbsp;<?php echo $row['apikey']; ?></td>
+                <td><?php echo $row['isactive']?'<b>Yes</b>':'No'; ?></td>
+                <td>&nbsp;<?php echo $row['ipaddr']; ?></td>
+                <td>&nbsp;<?php echo Format::db_datetime($row['created']); ?></td>
+            </tr>
             <?php
-            $class = ($class =='row2') ?'row1':'row2';
-            } //end of while.
-        else: //nothin' found!! ?> 
-            <tr class="<?php echo $class; ?>"><td colspan=5><b>Query returned 0 results</b>&nbsp;&nbsp;<a href="admin.php?t=templates">Index list</a></td></tr>
+            $class = ($class =='row2') ?'row1':'row2';
+            } //end of while.
+        else: //nothin' found!! ?> 
+            <tr class="<?php echo $class; ?>"><td colspan=5><b>Query returned 0 results</b>&nbsp;&nbsp;<a href="admin.php?t=templates">Index list</a></td></tr>
         <?php
-        endif; ?>
-     
-     </table>
-    </td></tr>
+        endif; ?>
+     
+     </table>
+    </td></tr>
     <?php
-    if(db_num_rows($result)>0): //Show options..
-     ?>
-    <tr>
-        <td align="center">
-            <?php
-            if($inactive) { ?>
-                <input class="button" type="submit" name="enable" value="Enable"
-                     onClick='return confirm("Are you sure you want to ENABLE selected keys?");'>
-            <?php
-            }
-            if($active){ ?>
-            &nbsp;&nbsp;
-                <input class="button" type="submit" name="disable" value="Disable"
-                     onClick='return confirm("Are you sure you want to DISABLE selected keys?");'>
-            <?php } ?>
-            &nbsp;&nbsp;
-            <input class="button" type="submit" name="delete" value="Delete" 
-                     onClick='return confirm("Are you sure you want to DELETE selected keys?");'>
-        </td>
-    </tr>
+    if(db_num_rows($result)>0): //Show options..
+     ?>
+    <tr>
+        <td align="center">
+            <?php
+            if($inactive) { ?>
+                <input class="button" type="submit" name="enable" value="Enable"
+                     onClick='return confirm("Are you sure you want to ENABLE selected keys?");'>
+            <?php
+            }
+            if($active){ ?>
+            &nbsp;&nbsp;
+                <input class="button" type="submit" name="disable" value="Disable"
+                     onClick='return confirm("Are you sure you want to DISABLE selected keys?");'>
+            <?php } ?>
+            &nbsp;&nbsp;
+            <input class="button" type="submit" name="delete" value="Delete" 
+                     onClick='return confirm("Are you sure you want to DELETE selected keys?");'>
+        </td>
+    </tr>
     <?php
-    endif;
-    ?>
-    </form>
- </table>
- <br/>
- <div class="msg">Add New IP</div>
- <hr>
- <div>
-   Add a new IP address.&nbsp;&nbsp;<font class="error"><?php echo $errors['ip']; ?></font>
-   <form action="admin.php?t=api" method="POST" >
-    <input type=hidden name='t' value='api'>
-    <input type=hidden name='do' value='add'>
-    New IP:
-    <input name="ip" size=30 value="<?php echo ($errors['ip'])?Format::htmlchars($_REQUEST['ip']):''; ?>" />
-    <font class="error">*&nbsp;</font>&nbsp;&nbsp;
-     &nbsp;&nbsp; <input class="button" type="submit" name="add" value="Add">
-    </form>
- </div>
- <br/>
- <div class="msg">API Passphrase</div>
- <hr>
- <div>
-   Passphrase must be at least 3 words. Required to generate the api keys.<br/>
-   <form action="admin.php?t=api" method="POST" >
-    <input type=hidden name='t' value='api'>
-    <input type=hidden name='do' value='update_phrase'>
-    Phrase:
-    <input name="phrase" size=50 value="<?php echo Format::htmlchars($info['phrase']); ?>" />
-    <font class="error">*&nbsp;<?php echo $errors['phrase']; ?></font>&nbsp;&nbsp;
-     &nbsp;&nbsp; <input class="button" type="submit" name="update" value="Submit">
-    </form>
-    <br/><br/>
-    <div><i>Please note that changing the passprase does NOT invalidate existing keys. To regerate a key you need to delete and readd it.</i></div>
- </div>
+    endif;
+    ?>
+    </form>
+ </table>
+ <br/>
+ <div class="msg">Add New IP</div>
+ <hr>
+ <div>
+   Add a new IP address.&nbsp;&nbsp;<font class="error"><?php echo $errors['ip']; ?></font>
+   <form action="admin.php?t=api" method="POST" >
+    <input type=hidden name='t' value='api'>
+    <input type=hidden name='do' value='add'>
+    New IP:
+    <input name="ip" size=30 value="<?php echo ($errors['ip'])?Format::htmlchars($_REQUEST['ip']):''; ?>" />
+    <font class="error">*&nbsp;</font>&nbsp;&nbsp;
+     &nbsp;&nbsp; <input class="button" type="submit" name="add" value="Add">
+    </form>
+ </div>
+ <br/>
+ <div class="msg">API Passphrase</div>
+ <hr>
+ <div>
+   Passphrase must be at least 3 words. Required to generate the api keys.<br/>
+   <form action="admin.php?t=api" method="POST" >
+    <input type=hidden name='t' value='api'>
+    <input type=hidden name='do' value='update_phrase'>
+    Phrase:
+    <input name="phrase" size=50 value="<?php echo Format::htmlchars($info['phrase']); ?>" />
+    <font class="error">*&nbsp;<?php echo $errors['phrase']; ?></font>&nbsp;&nbsp;
+     &nbsp;&nbsp; <input class="button" type="submit" name="update" value="Submit">
+    </form>
+    <br/><br/>
+    <div><i>Please note that changing the passprase does NOT invalidate existing keys. To regerate a key you need to delete and readd it.</i></div>
+ </div>
+
diff --git a/include/staff/apikeys.inc.php b/include/staff/apikeys.inc.php
index 26468089d56016c34e8dfd1dfefc972f33854b29..d7063c749ce92c04cddc36f20902b88181ab51d4 100644
--- a/include/staff/apikeys.inc.php
+++ b/include/staff/apikeys.inc.php
@@ -25,10 +25,8 @@ $$x=' class="'.strtolower($order).'" ';
 $order_by="$order_column $order ";
 
 $total=db_count('SELECT count(*) FROM '.API_KEY_TABLE.' ');
-$pagelimit=$thisstaff->getPageLimit();
-$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails.
 $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
-$pageNav=new Pagenate($total,$page,$pagelimit);
+$pageNav=new Pagenate($total,$page,PAGE_LIMIT);
 $pageNav->setURL('apikeys.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
 //Ok..lets roll...create the actual query
 $qstr.='&order='.($order=='DESC'?'ASC':'DESC');
diff --git a/include/staff/banlist.inc.php b/include/staff/banlist.inc.php
index 5978964273ed573ca42fa817ed7eaf348ae143cb..ecef00ba4325e18339b4f733d82a34b38466b950 100644
--- a/include/staff/banlist.inc.php
+++ b/include/staff/banlist.inc.php
@@ -41,10 +41,8 @@ $$x=' class="'.strtolower($order).'" ';
 $order_by="$order_column $order ";
 
 $total=db_count('SELECT count(DISTINCT rule.id) '.$from.' '.$where);
-$pagelimit=$thisstaff->getPageLimit();
-$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails.
 $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
-$pageNav=new Pagenate($total,$page,$pagelimit);
+$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
 $pageNav->setURL('banlist.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
 $qstr.='&order='.($order=='DESC'?'ASC':'DESC');
 $query="$select $from $where ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
diff --git a/include/staff/cannedreplies.inc.php b/include/staff/cannedreplies.inc.php
index db44a79f3cc9470cdbdbd0746bd589a5bc16b44f..601e27d37f49646b4043b57a717abb64cb626b96 100644
--- a/include/staff/cannedreplies.inc.php
+++ b/include/staff/cannedreplies.inc.php
@@ -33,10 +33,8 @@ $$x=' class="'.strtolower($order).'" ';
 $order_by="$order_column $order ";
 
 $total=db_count('SELECT count(*) FROM '.CANNED_TABLE.' canned ');
-$pagelimit=$thisstaff->getPageLimit();
-$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails.
 $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
-$pageNav=new Pagenate($total,$page,$pagelimit);
+$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
 $pageNav->setURL('canned.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
 //Ok..lets roll...create the actual query
 $qstr.='&order='.($order=='DESC'?'ASC':'DESC');
diff --git a/include/staff/categories.inc.php b/include/staff/categories.inc.php
index bba679898b0c5b8891486faa657eb73114f50f1f..a437338c20a156550487faf891324e2a16406562 100644
--- a/include/staff/categories.inc.php
+++ b/include/staff/categories.inc.php
@@ -28,10 +28,8 @@ $$x=' class="'.strtolower($order).'" ';
 $order_by="$order_column $order ";
 
 $total=db_count('SELECT count(*) FROM '.FAQ_CATEGORY_TABLE.' cat ');
-$pagelimit=$thisstaff->getPageLimit();
-$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails.
 $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
-$pageNav=new Pagenate($total,$page,$pagelimit);
+$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
 $pageNav->setURL('categories.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
 $qstr.='&order='.($order=='DESC'?'ASC':'DESC');
 $query="$sql GROUP BY cat.category_id ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
diff --git a/include/staff/directory.inc.php b/include/staff/directory.inc.php
index b687d811f2a8993c7eb8753fadb4efe5fe7668ad..c9d11a3d4bf1d8921b3261fc80d3e9a6a73616ae 100644
--- a/include/staff/directory.inc.php
+++ b/include/staff/directory.inc.php
@@ -52,10 +52,8 @@ $$x=' class="'.strtolower($order).'" ';
 $order_by="$order_column $order ";
 
 $total=db_count('SELECT count(DISTINCT staff.staff_id) '.$from.' '.$where);
-$pagelimit=$thisstaff->getPageLimit();
-$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails.
 $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
-$pageNav=new Pagenate($total,$page,$pagelimit);
+$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
 $pageNav->setURL('directory.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
 //Ok..lets roll...create the actual query
 $qstr.='&order='.($order=='DESC'?'ASC':'DESC');
diff --git a/include/staff/emails.inc.php b/include/staff/emails.inc.php
index 44e277b468ad9879edb7fe528b7ba960e0762858..65d34d7b9bfb0b10acd983bfe41e5671932d3060 100644
--- a/include/staff/emails.inc.php
+++ b/include/staff/emails.inc.php
@@ -29,10 +29,8 @@ $$x=' class="'.strtolower($order).'" ';
 $order_by="$order_column $order ";
 
 $total=db_count('SELECT count(*) FROM '.EMAIL_TABLE.' email ');
-$pagelimit=$thisstaff->getPageLimit();
-$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails.
 $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
-$pageNav=new Pagenate($total,$page,$pagelimit);
+$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
 $pageNav->setURL('emails.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
 //Ok..lets roll...create the actual query
 $qstr.='&order='.($order=='DESC'?'ASC':'DESC');
diff --git a/include/staff/filters.inc.php b/include/staff/filters.inc.php
index 4b9d6f31eb0e04f995ef7ffafde66a6a84bdb618..fb8a48d268a7705d5eb3a49b4076a6dcdb3b0b17 100644
--- a/include/staff/filters.inc.php
+++ b/include/staff/filters.inc.php
@@ -29,10 +29,8 @@ $$x=' class="'.strtolower($order).'" ';
 $order_by="$order_column $order ";
 
 $total=db_count('SELECT count(*) FROM '.EMAIL_FILTER_TABLE.' filter ');
-$pagelimit=$thisstaff->getPageLimit();
-$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails.
 $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
-$pageNav=new Pagenate($total,$page,$pagelimit);
+$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
 $pageNav->setURL('filters.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
 //Ok..lets roll...create the actual query
 $qstr.='&order='.($order=='DESC'?'ASC':'DESC');
diff --git a/include/staff/helptopics.inc.php b/include/staff/helptopics.inc.php
index 51a7666889f562676910351c69edcf8e10f96b91..27ffde9bdacac59c2687b30b5046dde4255b1537 100644
--- a/include/staff/helptopics.inc.php
+++ b/include/staff/helptopics.inc.php
@@ -30,10 +30,8 @@ $$x=' class="'.strtolower($order).'" ';
 $order_by="$order_column $order ";
 
 $total=db_count('SELECT count(*) FROM '.TOPIC_TABLE.' topic ');
-$pagelimit=$thisstaff->getPageLimit();
-$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails.
 $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
-$pageNav=new Pagenate($total,$page,$pagelimit);
+$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
 $pageNav->setURL('helptopics.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
 //Ok..lets roll...create the actual query
 $qstr.='&order='.($order=='DESC'?'ASC':'DESC');
diff --git a/include/staff/settings-general.inc.php b/include/staff/settings-general.inc.php
index ff5e058b1e36bdb2a7b51282201c9b5c3e633412..2e1e347bef5c45eab3826c2b263a59149cb32fc4 100644
--- a/include/staff/settings-general.inc.php
+++ b/include/staff/settings-general.inc.php
@@ -1,196 +1,197 @@
-<form action="settings.php?t=general" method="post" id="save">
-<input type="hidden" name="t" value="general" >
-<table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2">
-    <thead>
-        <tr>
-            <th colspan="2">
-                <h4>General Settings</h4>
-                <em>Offline mode will disable client interface and only allow 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"   <?php echo $config['isonline']?'checked="checked"':''; ?> /><b>Online</b> (Active)
-                <input type="radio" name="isonline"  value="0"   <?php echo !$config['isonline']?'checked="checked"':''; ?> /><b>Offline</b> (Disabled)
-                &nbsp;<font class="error">&nbsp;<?php echo $config['isoffline']?'osTicket offline':''; ?></font>
-            </td>
-        </tr>
-        <tr>
-            <td width="220" class="required">Helpdesk URL:</td>
-            <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>
-            <td width="220" class="required">Helpdesk Name/Title:</td>
-            <td><input type="text" size="40" name="helpdesk_title" value="<?php echo $config['helpdesk_title']; ?>">
-                &nbsp;<font class="error">*&nbsp;<?php echo $errors['helpdesk_title']; ?></font></td>
-        </tr>
-        <tr>
-            <td width="220" class="required">Default Department:</td>
-            <td>
-                <select name="default_dept_id">
-                    <option value="">&mdash; Select Default Department &mdash;</option>
+<form action="settings.php?t=general" method="post" id="save">
+<input type="hidden" name="t" value="general" >
+<table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2">
+    <thead>
+        <tr>
+            <th colspan="2">
+                <h4>General Settings</h4>
+                <em>Offline mode will disable client interface and only allow 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"   <?php echo $config['isonline']?'checked="checked"':''; ?> /><b>Online</b> (Active)
+                <input type="radio" name="isonline"  value="0"   <?php echo !$config['isonline']?'checked="checked"':''; ?> /><b>Offline</b> (Disabled)
+                &nbsp;<font class="error">&nbsp;<?php echo $config['isoffline']?'osTicket offline':''; ?></font>
+            </td>
+        </tr>
+        <tr>
+            <td width="220" class="required">Helpdesk URL:</td>
+            <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>
+            <td width="220" class="required">Helpdesk Name/Title:</td>
+            <td><input type="text" size="40" name="helpdesk_title" value="<?php echo $config['helpdesk_title']; ?>">
+                &nbsp;<font class="error">*&nbsp;<?php echo $errors['helpdesk_title']; ?></font></td>
+        </tr>
+        <tr>
+            <td width="220" class="required">Default Department:</td>
+            <td>
+                <select name="default_dept_id">
+                    <option value="">&mdash; Select Default Department &mdash;</option>
                     <?php
-                    $sql='SELECT dept_id,dept_name FROM '.DEPT_TABLE.' WHERE ispublic=1';
-                    if(($res=db_query($sql)) && db_num_rows($res)){
-                        while (list($id,$name) = db_fetch_row($res)){
-                            $selected = ($config['default_dept_id']==$id)?'selected="selected"':''; ?>
-                            <option value="<?php echo $id; ?>"<?php echo $selected; ?>><?php echo $name; ?> Dept</option>
+                    $sql='SELECT dept_id,dept_name FROM '.DEPT_TABLE.' WHERE ispublic=1';
+                    if(($res=db_query($sql)) && db_num_rows($res)){
+                        while (list($id,$name) = db_fetch_row($res)){
+                            $selected = ($config['default_dept_id']==$id)?'selected="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>
-            <td width="220" class="required">Default Email Templates:</td>
-            <td>
-                <select name="default_template_id">
-                    <option value="">&mdash; Select Default Template &mdash;</option>
+                        }
+                    } ?>
+                </select>&nbsp;<font class="error">*&nbsp;<?php echo $errors['default_dept_id']; ?></font>
+            </td>
+        </tr>
+        <tr>
+            <td width="220" class="required">Default Email Templates:</td>
+            <td>
+                <select name="default_template_id">
+                    <option value="">&mdash; Select Default Template &mdash;</option>
                     <?php
-                    $sql='SELECT tpl_id,name FROM '.EMAIL_TEMPLATE_TABLE.' WHERE isactive=1 AND cfg_id='.db_input($cfg->getId()).' ORDER BY name';
-                    if(($res=db_query($sql)) && db_num_rows($res)){
-                        while (list($id,$name) = db_fetch_row($res)){
-                            $selected = ($config['default_template_id']==$id)?'selected="selected"':''; ?>
-                            <option value="<?php echo $id; ?>"<?php echo $selected; ?>><?php echo $name; ?></option>
+                    $sql='SELECT tpl_id,name FROM '.EMAIL_TEMPLATE_TABLE.' WHERE isactive=1 AND cfg_id='.db_input($cfg->getId()).' ORDER BY name';
+                    if(($res=db_query($sql)) && db_num_rows($res)){
+                        while (list($id,$name) = db_fetch_row($res)){
+                            $selected = ($config['default_template_id']==$id)?'selected="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><td>Default Page Size:</td>
-            <td>
-                <select name="max_page_size">
+                        }
+                    } ?>
+                </select>&nbsp;<font class="error">*&nbsp;<?php echo $errors['default_template_id']; ?></font>
+            </td>
+        </tr>
+
+        <tr><td>Default Page Size:</td>
+            <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="selected"':''; ?> value="<?php echo $i; ?>"><?php echo $i; ?></option>
+                     $pagelimit=$config['max_page_size'];
+                    for ($i = 5; $i <= 50; $i += 5) {
+                        ?>
+                        <option <?php echo $config['max_page_size']==$i?'selected="selected"':''; ?> value="<?php echo $i; ?>"><?php echo $i; ?></option>
                         <?php
-                    } ?>
-                </select>
-            </td>
-        </tr>
-        <tr>
-            <td>Default Log Level:</td>
-            <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>
-                <font class="error">&nbsp;<?php echo $errors['log_level']; ?></font>
-            </td>
-        </tr>
-        <tr>
-            <td>Purge Logs:</td>
-            <td>        
-                <select name="log_graceperiod">
-                    <option value=0 selected>Never Purge Logs</option>
+                    } ?>
+                </select>
+            </td>
+        </tr>
+        <tr>
+            <td>Default Log Level:</td>
+            <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>
+                <font class="error">&nbsp;<?php echo $errors['log_level']; ?></font>
+            </td>
+        </tr>
+        <tr>
+            <td>Purge Logs:</td>
+            <td>        
+                <select name="log_graceperiod">
+                    <option value=0 selected>Never Purge Logs</option>
                     <?php
-                    for ($i = 1; $i <=12; $i++) {
-                        ?>
-                        <option <?php echo $config['log_graceperiod']==$i?'selected="selected"':''; ?> value="<?php echo $i; ?>">
-                            After&nbsp;<?php echo $i; ?>&nbsp;<?php echo ($i>1)?'Months':'Month'; ?></option>
+                    for ($i = 1; $i <=12; $i++) {
+                        ?>
+                        <option <?php echo $config['log_graceperiod']==$i?'selected="selected"':''; ?> value="<?php echo $i; ?>">
+                            After&nbsp;<?php echo $i; ?>&nbsp;<?php echo ($i>1)?'Months':'Month'; ?></option>
                         <?php
-                    } ?>
-                </select>
-            </td>
-        </tr>
-        <tr><td>Password Reset Policy:</th>
-            <td>
-                <select name="passwd_reset_period">
-                   <option value="0"> &mdash; None &mdash;</option>
-                  <?php
-                    for ($i = 1; $i <= 12; $i++) {
-                        echo sprintf('<option value="%d" %s>%s%s</option>',
-                                $i,(($config['passwd_reset_period']==$i)?'selected="selected"':''),$i>1?"Every $i ":'',$i>1?' Months':'Monthly');
-                    }
-                    ?>
-                </select>
-                &nbsp;<font class="error">&nbsp;<?php echo $errors['passwd_reset_period']; ?></font>
-            </td>
-        </tr>
-        <tr><td>Staff Excessive Logins:</td>
-            <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> failed login attempt(s) allowed 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> minute lock-out is enforced.
-            </td>
-        </tr>
-        <tr><td>Staff Session Timeout:</td>
-            <td>
-              <input type="text" name="staff_session_timeout" size=6 value="<?php echo $config['staff_session_timeout']; ?>">
-                Maximum idle time in minutes before a staff member must log in again (enter 0 to disable).
-            </td>
-        </tr>
-       <tr><td>Bind Staff Session to IP:</td>
-            <td>
-              <input type="checkbox" name="staff_ip_binding" <?php echo $config['staff_ip_binding']?'checked="checked"':''; ?>>
-              <em>(binds staff session to originating IP address upon login)</em>
-            </td>
-        </tr>
-        <tr><td>Client Excessive Logins:</td>
-            <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> failed login attempt(s) allowed 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> minute lock-out is enforced. 
-            </td>
-        </tr>
-
-        <tr><td>Client Session Timeout:</td>
-            <td>
-              <input type="text" name="client_session_timeout" size=6 value="<?php echo $config['client_session_timeout']; ?>">
-                &nbsp;Maximum idle time in minutes before a client must log in again (enter 0 to disable).
-            </td>
-        </tr>
-        <tr><td>Clickable URLs:</td>
-            <td>
-              <input type="checkbox" name="clickable_urls" <?php echo $config['clickable_urls']?'checked="checked"':''; ?>>
-               <em>(converts URLs in messages to clickable links)</em>
-            </td>
-        </tr>
-        <tr><td>Enable Auto Cron:</td>
-            <td>
-              <input type="checkbox" name="enable_auto_cron" <?php echo $config['enable_auto_cron']?'checked="checked"':''; ?>>
-                <em>(executes cron jobs based on staff activity - not recommended)</em>
-            </td>
-        </tr>
-    </tbody>
-</table>
-<p style="padding-left:250px;">
-    <input class="button" type="submit" name="submit" value="Save Changes">
-    <input class="button" type="reset" name="reset" value="Reset Changes">
-</p>
-</form>
+                    } ?>
+                </select>
+            </td>
+        </tr>
+        <tr><td>Password Reset Policy:</th>
+            <td>
+                <select name="passwd_reset_period">
+                   <option value="0"> &mdash; None &mdash;</option>
+                  <?php
+                    for ($i = 1; $i <= 12; $i++) {
+                        echo sprintf('<option value="%d" %s>%s%s</option>',
+                                $i,(($config['passwd_reset_period']==$i)?'selected="selected"':''),$i>1?"Every $i ":'',$i>1?' Months':'Monthly');
+                    }
+                    ?>
+                </select>
+                &nbsp;<font class="error">&nbsp;<?php echo $errors['passwd_reset_period']; ?></font>
+            </td>
+        </tr>
+        <tr><td>Staff Excessive Logins:</td>
+            <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> failed login attempt(s) allowed 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> minute lock-out is enforced.
+            </td>
+        </tr>
+        <tr><td>Staff Session Timeout:</td>
+            <td>
+              <input type="text" name="staff_session_timeout" size=6 value="<?php echo $config['staff_session_timeout']; ?>">
+                Maximum idle time in minutes before a staff member must log in again (enter 0 to disable).
+            </td>
+        </tr>
+       <tr><td>Bind Staff Session to IP:</td>
+            <td>
+              <input type="checkbox" name="staff_ip_binding" <?php echo $config['staff_ip_binding']?'checked="checked"':''; ?>>
+              <em>(binds staff session to originating IP address upon login)</em>
+            </td>
+        </tr>
+        <tr><td>Client Excessive Logins:</td>
+            <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> failed login attempt(s) allowed 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> minute lock-out is enforced. 
+            </td>
+        </tr>
+
+        <tr><td>Client Session Timeout:</td>
+            <td>
+              <input type="text" name="client_session_timeout" size=6 value="<?php echo $config['client_session_timeout']; ?>">
+                &nbsp;Maximum idle time in minutes before a client must log in again (enter 0 to disable).
+            </td>
+        </tr>
+        <tr><td>Clickable URLs:</td>
+            <td>
+              <input type="checkbox" name="clickable_urls" <?php echo $config['clickable_urls']?'checked="checked"':''; ?>>
+               <em>(converts URLs in messages to clickable links)</em>
+            </td>
+        </tr>
+        <tr><td>Enable Auto Cron:</td>
+            <td>
+              <input type="checkbox" name="enable_auto_cron" <?php echo $config['enable_auto_cron']?'checked="checked"':''; ?>>
+                <em>(executes cron jobs based on staff activity - not recommended)</em>
+            </td>
+        </tr>
+    </tbody>
+</table>
+<p style="padding-left:250px;">
+    <input class="button" type="submit" name="submit" value="Save Changes">
+    <input class="button" type="reset" name="reset" value="Reset Changes">
+</p>
+</form>
+
diff --git a/include/staff/slaplans.inc.php b/include/staff/slaplans.inc.php
index 4ebb46b334e4e2a15b3f63f163824c03accbca29..5dea61f69b8ccaeaec3b84411185fbe4a26da886 100644
--- a/include/staff/slaplans.inc.php
+++ b/include/staff/slaplans.inc.php
@@ -25,10 +25,8 @@ $$x=' class="'.strtolower($order).'" ';
 $order_by="$order_column $order ";
 
 $total=db_count('SELECT count(*) FROM '.SLA_TABLE.' sla ');
-$pagelimit=$thisstaff->getPageLimit();
-$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails.
 $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
-$pageNav=new Pagenate($total,$page,$pagelimit);
+$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
 $pageNav->setURL('slas.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
 //Ok..lets roll...create the actual query
 $qstr.='&order='.($order=='DESC'?'ASC':'DESC');
diff --git a/include/staff/staffmembers.inc.php b/include/staff/staffmembers.inc.php
index be8497b97c5030009cac3ff099dd8fadffa00ace..aa41b1bbf4a00a6143bb8bd0961d8a8ab4a801b0 100644
--- a/include/staff/staffmembers.inc.php
+++ b/include/staff/staffmembers.inc.php
@@ -46,10 +46,8 @@ $$x=' class="'.strtolower($order).'" ';
 $order_by="$order_column $order ";
 
 $total=db_count('SELECT count(DISTINCT staff.staff_id) '.$from.' '.$where);
-$pagelimit=$thisstaff->getPageLimit();
-$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails.
 $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
-$pageNav=new Pagenate($total,$page,$pagelimit);
+$pageNav=new Pagenate($total,$page,PAGE_LIMIT);
 $pageNav->setURL('staff.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
 //Ok..lets roll...create the actual query
 $qstr.='&order='.($order=='DESC'?'ASC':'DESC');
diff --git a/include/staff/syslogs.inc.php b/include/staff/syslogs.inc.php
index 1cec6aff3f253876a77c11d961ca87cba5b3c91f..482dd429c3738faea83e49df05a09c8dd391a7e2 100644
--- a/include/staff/syslogs.inc.php
+++ b/include/staff/syslogs.inc.php
@@ -71,9 +71,7 @@ $qfrom=' FROM '.SYSLOG_TABLE.' log ';
 $total=db_count("SELECT count(*) $qfrom $qwhere");
 $page = ($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
 //pagenate
-$pagelimit=$thisstaff->getPageLimit();
-$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails.
-$pageNav=new Pagenate($total,$page,$pagelimit);
+$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
 $pageNav->setURL('syslogs.php',$qstr);
 $qstr.='&order='.($order=='DESC'?'ASC':'DESC');
 $query="$qselect $qfrom $qwhere ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
diff --git a/include/staff/templates.inc.php b/include/staff/templates.inc.php
index 8ce8ca8546ed5932fa5788aec5430400b68e6210..7f82f656f12cafe984de35ff205eb62bfef2b1a7 100644
--- a/include/staff/templates.inc.php
+++ b/include/staff/templates.inc.php
@@ -28,10 +28,8 @@ $$x=' class="'.strtolower($order).'" ';
 $order_by="$order_column $order ";
 
 $total=db_count('SELECT count(*) FROM '.EMAIL_TEMPLATE_TABLE.' tpl ');
-$pagelimit=$thisstaff->getPageLimit();
-$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails.
 $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
-$pageNav=new Pagenate($total,$page,$pagelimit);
+$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
 $pageNav->setURL('templates.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
 //Ok..lets roll...create the actual query
 $qstr.='&order='.($order=='DESC'?'ASC':'DESC');
diff --git a/include/staff/tickets.inc.php b/include/staff/tickets.inc.php
index dad492a18f83dd64ed22f94de6a662de5e46ae45..d0b27690e2cf138140c1707e1f3a92809493cc91 100644
--- a/include/staff/tickets.inc.php
+++ b/include/staff/tickets.inc.php
@@ -180,8 +180,8 @@ if(!$order_by && $showanswered) {
 }elseif(!$order_by && !strcasecmp($status,'closed')){
     $order_by='ticket.closed, ticket.created'; //No priority sorting for closed tickets.
 }
-$order_by =$order_by?$order_by:'priority_urgency,effective_date,ticket.created';
-$order=$order?$order:'DESC';
+$order_by =$order_by?$order_by:'priority_urgency, effective_date, ticket.created';
+$order=$order?$order:'ASC';
 
 if($order_by && strpos($order_by,','))
     $order_by=str_replace(','," $order,",$order_by);
@@ -200,6 +200,7 @@ $qselect ='SELECT DISTINCT ticket.ticket_id,lock_id,ticketID,ticket.dept_id,tick
 $qfrom=' FROM '.TICKET_TABLE.' ticket '.
        ' LEFT JOIN '.DEPT_TABLE.' dept ON ticket.dept_id=dept.dept_id ';
 
+$sjoin='';
 if($search && $deep_search) {
     $sjoin=' LEFT JOIN '.TICKET_MESSAGE_TABLE.' message ON (ticket.ticket_id=message.ticket_id )'
           .' LEFT JOIN '.TICKET_RESPONSE_TABLE.' response ON (ticket.ticket_id=response.ticket_id )'
@@ -210,7 +211,7 @@ $qgroup=' GROUP BY ticket.ticket_id';
 //get ticket count based on the query so far..
 $total=db_count("SELECT count(DISTINCT ticket.ticket_id) $qfrom $sjoin $qwhere");
 //pagenate
-$pagelimit=($_GET['limit'] && is_numeric($_GET['limit']))?$_GET['limit']:$thisstaff->getPageLimit();
+$pagelimit=($_GET['limit'] && is_numeric($_GET['limit']))?$_GET['limit']:PAGE_LIMIT;
 $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
 $pageNav=new Pagenate($total,$page,$pagelimit);
 $pageNav->setURL('tickets.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
@@ -350,7 +351,7 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false;
 <div class="clear"></div>
 <div style="margin-bottom:20px">
 <form action="tickets.php" method="POST" name='tickets' onSubmit="return checkbox_checker(this,1,0);">
- <a class="refresh" href="">Refresh</a>
+ <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; ?>" >
  <table class="list" border="0" cellspacing="1" cellpadding="2" width="940">
diff --git a/index.php b/index.php
index 37e5c7f1b2dd3e899d3d7a154d5e074629ed1bfe..ac4fe04a014455d083aacab299fdace3a045e529 100644
--- a/index.php
+++ b/index.php
@@ -13,4 +13,40 @@
 
     vim: expandtab sw=4 ts=4 sts=4:
 **********************************************************************/
-require('offline.php');
+require('client.inc.php');
+$section = 'home';
+require(CLIENTINC_DIR.'header.inc.php');
+?>
+
+<div id="landing_page">
+    <h1>Welcome to the Support Center</h1>
+    <p>
+        In order to streamline support requests and better serve you, we utilize a support ticket system. Every support request is assigned a unique ticket number which you can use to track the progress and responses online. For your reference we provide complete archives and history of all your support requests. A valid email address is required to submit a ticket.
+    </p>
+
+    <div id="new_ticket">
+        <h3>Open A New Ticket</h3>
+        <form method="get" action="open.php">  
+            <div>Please provide as much detail as possible so we can best assist you. To update a previously submitted ticket, please login.</div>
+            <input type="submit" value="Open a New Ticket">
+        </form>
+    </div>
+
+    <div id="check_status">
+        <h3>Check Ticket Status</h3>
+        <form class="status_form" action="view.php" method="get">
+            <div>We provide archives and history of all your current and past support requests complete with responses.</div>
+            <input type="submit" value="Check Ticket Status">
+        </form>
+    </div>
+</div>
+<div class="clear"></div>
+<?php
+if($cfg && $cfg->isKnowledgebaseEnabled()){ 
+    //FIXME: provide ability to feature or select random FAQs ??
+?>
+<p>Be sure to browse our <a href="kb/index.php">Frequently Asked Questions (FAQs)</a>, before opening a ticket.</p>
+</div>
+<?php
+} ?>
+<?php require(CLIENTINC_DIR.'footer.inc.php'); ?>
diff --git a/js/osticket.js b/js/osticket.js
index fd04ff48c809525267ebaacca85ac30cb37dd00a..a809e6f2f794a0534096c69b2a210428424d703d 100644
--- a/js/osticket.js
+++ b/js/osticket.js
@@ -1,79 +1 @@
-jQuery(function($) {
-    var max_uploads = 5;
-    var current_reply_uploads = 0;
-    var current_note_uploads = 0;
-
-    function parse_upload(elem) {
-        var new_input = elem.clone();
-        var filename = elem.val();
-        if(filename != '') {
-            var container = elem.parent().parent();
-            var form_type = container.attr('id');
-            elem.blur().hide();
-            $('.uploads', container).append('<div><label><input type="checkbox" name="uploads[]" value="' + filename + '" checked="checked"> ' + filename.replace('C:\\', '').replace('fakepath\\', '') + '</label></div>');
-            if(form_type=='reply_form_attachments') {
-                current_reply_uploads++;
-                if(current_reply_uploads < max_uploads) {
-                    elem.after(new_input.val('').blur());
-                } 
-            } else {
-                current_note_uploads++;
-                if(current_note_uploads < max_uploads) {
-                    elem.after(new_input.val('').blur());
-                } 
-            }
-        }
-    }
-
-    if($.browser.msie) {
-        $('.attachments').delegate('input[type=file]', 'click', function() {
-            var elem = $(this);
-            setTimeout(function() {
-                parse_upload(elem);
-                elem.blur();
-            }, 0);
-        });
-    } else {
-        $('.attachments').delegate('input[type=file]', 'change', function() {
-            var elem = $(this);
-            parse_upload(elem);
-        });
-    }
-
-    $('.uploads').delegate('.uploads input', 'click', function(e) {
-        e.preventDefault();
-        var elem = $(this);
-        elem.attr('checked', 'checked');
-        if(confirm("Are you sure you want to delete this attachment?")==true) {
-            var container = elem.parent().parent();
-            var cparent = container.parent().parent();
-            var form_type = cparent.attr('id');
-            var filename = elem.val();
-            $('input[type=file]', cparent).each(function() {
-                if($(this).val() == filename) {
-                    $(this).remove();
-                }
-            });
-            container.remove();
-            var new_input = $('input[type=file]:last', cparent).clone();
-            var last_elem = $('input[type=file]:last', cparent);
-            if(form_type=='reply_form_attachments') {
-                current_reply_uploads--;
-                if(current_reply_uploads < max_uploads) {
-                    if(last_elem.css('display')=='none') {
-                        last_elem.after(new_input.val('').show());
-                    }
-                } 
-            } else {
-                current_note_uploads--;
-                if(current_note_uploads < max_uploads) {
-                    if(last_elem.css('display')=='none') {
-                        last_elem.after(new_input.val('').show());
-                    }
-                } 
-            }
-        } else {
-            e.preventDefault();
-        }
-    });    
-});
\ No newline at end of file
+//Nothing for now...
diff --git a/l.php b/l.php
new file mode 100644
index 0000000000000000000000000000000000000000..657952e266f1498846db84c663e135997ecb242f
--- /dev/null
+++ b/l.php
@@ -0,0 +1,29 @@
+<?php
+/*********************************************************************
+    l.php
+
+    Link redirection
+
+    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:
+**********************************************************************/
+require 'secure.inc.php';
+
+global $_GET;
+$url = $_GET['url'];
+if (!$url) exit();
+?>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
+    <meta http-equiv="refresh" content="0;<?php echo $url; ?>"/>
+</head>
+<body/>
+</html>
diff --git a/login.php b/login.php
new file mode 100644
index 0000000000000000000000000000000000000000..044d74644785f32a0f79bae76e6c4309fd473b2a
--- /dev/null
+++ b/login.php
@@ -0,0 +1,91 @@
+<?php
+/*********************************************************************
+    login.php
+
+    Client Login 
+
+    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:
+**********************************************************************/
+require_once('client.inc.php');
+if(!defined('INCLUDE_DIR')) die('Fatal Error');
+define('CLIENTINC_DIR',INCLUDE_DIR.'client/');
+define('OSTCLIENTINC',TRUE); //make includes happy
+
+require_once(INCLUDE_DIR.'class.client.php');
+require_once(INCLUDE_DIR.'class.ticket.php');
+//We are ready baby
+$loginmsg='Authentication Required';
+if($_POST && (!empty($_POST['lemail']) && !empty($_POST['lticket']))):
+    $loginmsg='Authentication Required';
+    $email=trim($_POST['lemail']);
+    $ticketID=trim($_POST['lticket']);
+    //$_SESSION['_client']=array(); #Uncomment to disable login strikes.
+    
+    //Check time for last max failed login attempt strike.
+    $loginmsg='Invalid login';
+    if($_SESSION['_client']['laststrike']) {
+        if((time()-$_SESSION['_client']['laststrike'])<$cfg->getClientLoginTimeout()) {
+            $loginmsg='Excessive failed login attempts';
+            $errors['err']='You\'ve reached maximum failed login attempts allowed. Try again later or <a href="open.php">open a new ticket</a>';
+        }else{ //Timeout is over.
+            //Reset the counter for next round of attempts after the timeout.
+            $_SESSION['_client']['laststrike']=null;
+            $_SESSION['_client']['strikes']=0;
+        }
+    }
+    //See if we can fetch local ticket id associated with the ID given
+    if(!$errors && is_numeric($ticketID) && Validator::is_email($email) && ($ticket=Ticket::lookupByExtId($ticketID))) {
+        //At this point we know the ticket is valid.
+        //TODO: 1) Check how old the ticket is...3 months max?? 2) Must be the latest 5 tickets?? 
+        //Check the email given.
+        if($ticket->getId() && strcasecmp($ticket->getEMail(),$email)==0){
+            //valid match...create session goodies for the client.
+            $user = new ClientSession($email,$ticket->getId());
+            $_SESSION['_client']=array(); //clear.
+            $_SESSION['_client']['userID']   =$ticket->getEmail(); //Email
+            $_SESSION['_client']['key']      =$ticket->getExtId(); //Ticket ID --acts as password when used with email. See above.
+            $_SESSION['_client']['token']    =$user->getSessionToken();
+            $_SESSION['TZ_OFFSET']=$cfg->getTZoffset();
+            $_SESSION['daylight']=$cfg->observeDaylightSaving();
+            //Log login info...
+            $msg=sprintf("%s/%s logged in [%s]",$ticket->getEmail(),$ticket->getExtId(),$_SERVER['REMOTE_ADDR']);
+            Sys::log(LOG_DEBUG,'User login',$msg);
+            //Redirect tickets.php
+            session_write_close();
+            session_regenerate_id();
+            @header("Location: tickets.php?id=".$ticket->getExtId());
+            require_once('tickets.php'); //Just incase. of header already sent error.
+            exit;
+        }
+    }
+    //If we get to this point we know the login failed.
+    $_SESSION['_client']['strikes']+=1;
+    if(!$errors && $_SESSION['_client']['strikes']>$cfg->getClientMaxLogins()) {
+        $loginmsg='Access Denied';
+        $errors['err']='Forgot your login info? Please <a href="open.php">open a new ticket</a>.';
+        $_SESSION['_client']['laststrike']=time();
+        $alert='Excessive login attempts by a client?'."\n".
+                'Email: '.$_POST['lemail']."\n".'Ticket#: '.$_POST['lticket']."\n".
+                'IP: '.$_SERVER['REMOTE_ADDR']."\n".'Time:'.date('M j, Y, g:i a T')."\n\n".
+                'Attempts #'.$_SESSION['_client']['strikes'];
+        Sys::log(LOG_ALERT,'Excessive login attempts (client)',$alert,($cfg->alertONLoginError()));
+    }elseif($_SESSION['_client']['strikes']%2==0){ //Log every other failed login attempt as a warning.
+        $alert='Email: '.$_POST['lemail']."\n".'Ticket #: '.$_POST['lticket']."\n".'IP: '.$_SERVER['REMOTE_ADDR'].
+               "\n".'TIME: '.date('M j, Y, g:i a T')."\n\n".'Attempts #'.$_SESSION['_client']['strikes'];
+        Sys::log(LOG_WARNING,'Failed login attempt (client)',$alert);
+    }
+endif;
+
+$nav = new UserNav();
+$nav->setActiveNav('status');
+require(CLIENTINC_DIR.'header.inc.php');
+require(CLIENTINC_DIR.'login.inc.php');
+require(CLIENTINC_DIR.'footer.inc.php');
+?>
diff --git a/logout.php b/logout.php
new file mode 100644
index 0000000000000000000000000000000000000000..72c3560ecc7f540febb1ea0032c9b6cd39e2d3d6
--- /dev/null
+++ b/logout.php
@@ -0,0 +1,24 @@
+<?php
+/*********************************************************************
+    logout.php
+
+    Destroy clients session.
+
+    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:
+**********************************************************************/
+
+require('client.inc.php');
+//We are checking to make sure the user is logged in before a logout to avoid session reset tricks on excess logins
+$_SESSION['_client']=array();
+session_unset();
+session_destroy();
+header('Location: index.php');
+require('index.php');
+?>
diff --git a/main.inc.php b/main.inc.php
index 6fd211ed3b4505f825dc8869e92e8186d92c1e68..53314c1ba469595a63f30a8e7584e3a10c250ae5 100644
--- a/main.inc.php
+++ b/main.inc.php
@@ -102,9 +102,6 @@
     #CURRENT EXECUTING SCRIPT.
     define('THISPAGE',Misc::currentURL());
 
-    #pagenation default
-    define('PAGE_LIMIT',20);
-
     # This is to support old installations. with no secret salt.
     if(!defined('SECRET_SALT')) define('SECRET_SALT',md5(TABLE_PREFIX.ADMIN_EMAIL));
 
@@ -164,10 +161,7 @@
         $ferror='Unable to connect to the database';
     }elseif(!($cfg=Sys::getConfig())){
         $ferror='Unable to load config info from DB. Get tech support.';
-    }elseif(!ini_get('short_open_tag')) {
-        $ferror='Short open tag disabled! - osTicket requires it turned ON.';
     }
-
     if($ferror){ //Fatal error
         Sys::alertAdmin('osTicket Fatal Error',$ferror); //try alerting admin.
         die("<b>Fatal Error:</b> Contact system administrator."); //Generic error.
@@ -175,6 +169,11 @@
     }
     //Init
     $cfg->init();
+
+    //System defaults we might want to make global//
+    #pagenation default - user can overwrite it!
+    define('DEFAULT_PAGE_LIMIT',$cfg->getPageSize()?$cfg->getPageSize():25);
+
     //Start session handler!
     $session=osTicketSession::start(SESSION_TTL); // start_session 
     //Set default timezone...staff will overwrite it.
diff --git a/offline.php b/offline.php
index 3c3b24a425c78badc335c45cc62a9022fa61d1f6..24f8401a14c9710de2f9bf7af3a13985a47a099d 100644
--- a/offline.php
+++ b/offline.php
@@ -14,6 +14,11 @@
     vim: expandtab sw=4 ts=4 sts=4:
 **********************************************************************/
 require_once('client.inc.php');
+if($cfg && !$cfg->isHelpDeskOffline()) { 
+    @header('Location: index.php'); //Redirect if the system is online.
+    include('index.php');
+    exit;
+}
 $nav=null;
 require(CLIENTINC_DIR.'header.inc.php');
 ?>
diff --git a/open.php b/open.php
new file mode 100644
index 0000000000000000000000000000000000000000..11d3a0a9d3397d64941886169a5fa2892ea663a1
--- /dev/null
+++ b/open.php
@@ -0,0 +1,55 @@
+<?php
+/*********************************************************************
+    open.php
+
+    New tickets handle.
+
+    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:
+**********************************************************************/
+require('client.inc.php');
+define('SOURCE','Web'); //Ticket source.
+$inc='open.inc.php';    //default include.
+$errors=array();
+if($_POST):
+    $_POST['deptId']=$_POST['emailId']=0; //Just Making sure we don't accept crap...only topicId is expected.
+    if($thisclient) {
+        $_POST['name']=$thisclient->getName();
+        $_POST['email']=$thisclient->getEmail();
+    } elseif($cfg->enableCaptcha()) {
+        if(!$_POST['captcha'])
+            $errors['captcha']='Enter text shown on the image';
+        elseif(strcmp($_SESSION['captcha'],md5($_POST['captcha'])))
+            $errors['captcha']='Invalid - try again!';
+    }
+
+    //Ticket::create...checks for errors..
+    if(($ticket=Ticket::create($_POST,$errors,SOURCE))){
+        $msg='Support ticket request created';
+        //Logged in...simply view the newly created ticket.
+        if($thisclient && $thisclient->isValid()) {
+            if(!$cfg->showRelatedTickets())
+                $_SESSION['_client']['key']= $ticket->getExtId(); //Resetting login Key to the current ticket!
+            session_write_close();
+            session_regenerate_id();
+            @header('Location: tickets.php?id='.$ticket->getExtId());
+        }
+        //Thank the user and promise speedy resolution!
+        $inc='thankyou.inc.php';
+    }else{
+        $errors['err']=$errors['err']?$errors['err']:'Unable to create a ticket. Please correct errors below and try again!';
+    }
+endif;
+
+//page
+$nav->setActiveNav('new');
+require(CLIENTINC_DIR.'header.inc.php');
+require(CLIENTINC_DIR.$inc);
+require(CLIENTINC_DIR.'footer.inc.php');
+?>
diff --git a/scp/l.php b/scp/l.php
new file mode 100644
index 0000000000000000000000000000000000000000..2c66c2835eefcafb6711416228fa985878c43428
--- /dev/null
+++ b/scp/l.php
@@ -0,0 +1,29 @@
+<?php
+/*********************************************************************
+    l.php
+
+    Link redirection
+
+    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:
+**********************************************************************/
+require_once 'staff.inc.php';
+
+global $_GET;
+$url = $_GET['url'];
+if (!$url) exit();
+?>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
+    <meta http-equiv="refresh" content="0;<?php echo $url; ?>"/>
+</head>
+<body/>
+</html>
diff --git a/scp/staff.inc.php b/scp/staff.inc.php
index 3c0d328809cbc94b37e9a2fee074ce6dabb08a97..b3ee30a4ec3a555c2fd8c3c86ed6e72b2c6517ca 100644
--- a/scp/staff.inc.php
+++ b/scp/staff.inc.php
@@ -79,11 +79,14 @@ if(!$thisstaff->isadmin()){
 
 //Keep the session activity alive
 $thisstaff->refreshSession();
+
+/******* SET STAFF DEFAULTS **********/
 //Set staff's timezone offset.
 $_SESSION['TZ_OFFSET']=$thisstaff->getTZoffset();
 $_SESSION['daylight']=$thisstaff->observeDaylight();
 
 define('AUTO_REFRESH_RATE',$thisstaff->getRefreshRate()*60);
+define('PAGE_LIMIT',$thisstaff->getPageLimit()?$thisstaff->getPageLimit():DEFAULT_PAGE_LIMIT);
 
 //Clear some vars. we use in all pages.
 $errors=array();
diff --git a/secure.inc.php b/secure.inc.php
new file mode 100644
index 0000000000000000000000000000000000000000..3096b3503036e8746a58cea56aa2e85f977b4896
--- /dev/null
+++ b/secure.inc.php
@@ -0,0 +1,25 @@
+<?php
+/*********************************************************************
+    secure.inc.php
+
+    File included on every client's "secure" pages
+
+    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(!strcasecmp(basename($_SERVER['SCRIPT_NAME']),basename(__FILE__))) die('Kwaheri!');
+if(!file_exists('client.inc.php')) die('Fatal Error.');
+require_once('client.inc.php');
+//User must be logged in!
+if(!$thisclient || !$thisclient->getId() || !$thisclient->isValid()){
+    require('./login.php');
+    exit;
+}
+$thisclient->refreshSession();
+?>
diff --git a/setup/inc/class.setup.php b/setup/inc/class.setup.php
index c4d986c655ad6041591f879f7e4c077ef24ec6b7..c6bf7b6751c9e80236d3cbfe143a37c6d52cf6c5 100644
--- a/setup/inc/class.setup.php
+++ b/setup/inc/class.setup.php
@@ -303,7 +303,7 @@ class Installer extends SetupWizard {
         if(!$this->errors) {
             //Create admin user.
             $sql='INSERT INTO '.PREFIX.'staff SET created=NOW() '
-                .', isactive=1, isadmin=1, group_id=1, dept_id=1, timezone_id=8 '
+                .', isactive=1, isadmin=1, group_id=1, dept_id=1, timezone_id=8, max_page_size=25 '
                 .', email='.db_input($_POST['admin_email'])
                 .', firstname='.db_input($vars['fname'])
                 .', lastname='.db_input($vars['lname'])
diff --git a/setup/js/tips.js b/setup/js/tips.js
index d7214dc6379caabd7b210865bb930bb7f4891a7a..76c20421a28c9301a92497a778de881e1e4f91fe 100644
--- a/setup/js/tips.js
+++ b/setup/js/tips.js
@@ -45,4 +45,3 @@ jQuery(function($) {
         $(this).parent().parent().remove();
     });
 });
-
diff --git a/tickets.php b/tickets.php
new file mode 100644
index 0000000000000000000000000000000000000000..d4759ba522e328911d2e9a494254ce338ea7f905
--- /dev/null
+++ b/tickets.php
@@ -0,0 +1,89 @@
+<?php
+/*********************************************************************
+    tickets.php
+
+    Main client/user interface.
+    Note that we are using external ID. The real (local) ids are hidden from user.
+
+    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:
+**********************************************************************/
+require('secure.inc.php');
+if(!is_object($thisclient) || !$thisclient->isValid()) die('Access denied'); //Double check again.
+require_once(INCLUDE_DIR.'class.ticket.php');
+$ticket=null;
+if($_REQUEST['id']) {
+    if(!($ticket=Ticket::lookupByExtId($_REQUEST['id']))) {
+        $errors['err']='Unknown or invalid ticket ID.';
+    }elseif(!$ticket->checkClientAccess($thisclient)) {
+        $errors['err']='Unknown or invalid ticket ID.'; //Using generic message on purpose!
+        $ticket=null;
+    }
+}
+
+//Process post...depends on $ticket object above.
+if($_POST && is_object($ticket) && $ticket->getId()):
+    $errors=array();
+    switch(strtolower($_POST['a'])){
+    case 'reply':
+        if(!$ticket->checkClientAccess($thisclient)) //double check perm again!
+            $errors['err']='Access Denied. Possibly invalid ticket ID';
+
+        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');
+
+                $msg='Message Posted Successfully';
+            } else {
+                $errors['err']='Unable to post the message. Try again';
+            }
+
+        } elseif(!$errors['err']) {
+            print_r($errors);
+            $errors['err']='Error(s) occurred. Please try again';
+           
+        }
+        break;
+    default:
+        $errors['err']='Uknown action';
+    }
+    $ticket->reload();
+endif;
+$nav->setActiveNav('tickets');
+if($ticket && $ticket->checkClientAccess($thisclient)) {
+    $inc='view.inc.php';
+} elseif($cfg->showRelatedTickets() && $thisclient->getNumTickets()) {
+    $inc='tickets.inc.php';
+} else {
+    $nav->setActiveNav('new');
+    $inc='open.inc.php';
+}
+include(CLIENTINC_DIR.'header.inc.php');
+include(CLIENTINC_DIR.$inc);
+include(CLIENTINC_DIR.'footer.inc.php');
+?>
diff --git a/view.php b/view.php
new file mode 100644
index 0000000000000000000000000000000000000000..984b04c3019645c6ca1d075bbab0aac8460e4094
--- /dev/null
+++ b/view.php
@@ -0,0 +1,21 @@
+<?php
+/*********************************************************************
+    view.php
+
+    Ticket View.
+
+    Peter Rotich <peter@osticket.com>
+    Copyright (c)  2006-2010 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:
+    $Id: $
+**********************************************************************/
+require('secure.inc.php');
+if(!is_object($thisclient) || !$thisclient->isValid()) die('Access denied'); //Double check again.
+//We are now using tickets.php but we need to keep view.php for backward compatibility
+require('tickets.php');
+?>