diff --git a/include/class.client.php b/include/class.client.php
index 5c5f3035ee6b485d6862950b35924f00e0f90b97..087215ce7919e45331e5f6f813a7a56bd8e24156 100644
--- a/include/class.client.php
+++ b/include/class.client.php
@@ -4,7 +4,7 @@
 
     Handles everything about client
 
-    NOTE: Please note that osTicket uses email address and ticket ID to authenticate the user*!
+    XXX: 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>
@@ -134,72 +134,94 @@ class Client {
         return (($id=self::getLastTicketIdByEmail($email)))?self::lookup($id, $email):null;
     }
 
-    /* static */ function tryLogin($ticketID, $email, $auth=null) {
+    /* static */ function login($ticketID, $email, $auth=null, &$errors=array()) {
         global $ost;
+
+
         $cfg = $ost->getConfig();
+        $auth = trim($auth);
+        $email = trim($email);
+        $ticketID = trim($ticketID);
 
         # Only consider auth token for GET requests, and for GET requests,
         # REQUIRE the auth token
-        $auto_login = $_SERVER['REQUEST_METHOD'] == 'GET';
+        $auto_login = ($_SERVER['REQUEST_METHOD'] == 'GET');
 
         //Check time for last max failed login attempt strike.
-        $loginmsg='Invalid login';
-        # XXX: SECURITY: Max attempts is enforced client-side via the PHP
-        #      session cookie.
         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.
+                $errors['login'] = '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>';
+                $_SESSION['_client']['laststrike'] = time(); //renew the strike.
+            } else { //Timeout is over.
                 //Reset the counter for next round of attempts after the timeout.
-                $_SESSION['_client']['laststrike']=null;
-                $_SESSION['_client']['strikes']=0;
+                $_SESSION['_client']['laststrike'] = null;
+                $_SESSION['_client']['strikes'] = 0;
             }
         }
+
+        if($auto_login && !$auth)
+            $errors['login'] = 'Invalid method';
+        elseif(!$ticketID || !Validator::is_email($email))
+            $errors['login'] = 'Valid email and ticket number required';
+
+        //Bail out on error.
+        if($errors) return false;
+
         //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.
+        if(($ticket=Ticket::lookupByExtId($ticketID, $email)) && $ticket->getId()) {
+            //At this point we know the ticket ID is valid.
             //TODO: 1) Check how old the ticket is...3 months max?? 2) Must be the latest 5 tickets?? 
             //Check the email given.
-            # Require auth token for automatic logins
-            if (!$auto_login || $auth === $ticket->getAuthToken()) {
-                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['TZ_DST']=$cfg->observeDaylightSaving();
-                    //Log login info...
-                    $msg=sprintf("%s/%s logged in [%s]",$ticket->getEmail(),$ticket->getExtId(),$_SERVER['REMOTE_ADDR']);
-                    $ost->logDebug('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;
-                }
-            }
+
+            # Require auth token for automatic logins (GET METHOD).
+            if (!strcasecmp($ticket->getEmail(), $email) && (!$auto_login || $auth === $ticket->getAuthToken())) {
+                    
+                //valid match...create session goodies for the client.
+                $user = new ClientSession($email,$ticket->getExtId());
+                $_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['TZ_DST'] = $cfg->observeDaylightSaving();
+                
+                //Log login info...
+                $msg=sprintf('%s/%s logged in [%s]', $ticket->getEmail(), $ticket->getExtId(), $_SERVER['REMOTE_ADDR']);
+                $ost->logDebug('User login', $msg);
+        
+                //Regenerate session ID.
+                $sid=session_id(); //Current session id.
+                session_regenerate_id(TRUE); //get new ID.
+                if(($session=$ost->getSession()) && is_object($session) && $sid)
+                    $session->destroy($sid);
+
+                session_write_close();
+
+                return $user;
+
+            } 
         }
+
         //If we get to this point we know the login failed.
+        $errors['login'] = 'Invalid login';
         $_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".
+            $errors['login'] = '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 user.'."\n".
+                    'Email: '.$email."\n".'Ticket#: '.$ticketID."\n".
                     'IP: '.$_SERVER['REMOTE_ADDR']."\n".'Time:'.date('M j, Y, g:i a T')."\n\n".
                     'Attempts #'.$_SESSION['_client']['strikes'];
-            $ost->logError('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'].
+            $ost->logError('Excessive login attempts (user)', $alert, ($cfg->alertONLoginError()));
+        } elseif($_SESSION['_client']['strikes']%2==0) { //Log every other failed login attempt as a warning.
+            $alert='Email: '.$email."\n".'Ticket #: '.$ticketID."\n".'IP: '.$_SERVER['REMOTE_ADDR'].
                    "\n".'TIME: '.date('M j, Y, g:i a T')."\n\n".'Attempts #'.$_SESSION['_client']['strikes'];
-            $ost->logWarning('Failed login attempt (client)', $alert);
+            $ost->logWarning('Failed login attempt (user)', $alert);
         }
+
+        return false;
     }
 }
 ?>
diff --git a/include/class.staff.php b/include/class.staff.php
index ace8f2a0b785c2b31d6fc0d490d0f21113fad9a4..778041e7ca6fd707d16b91b5f3a9a4669fe3076a 100644
--- a/include/class.staff.php
+++ b/include/class.staff.php
@@ -558,15 +558,21 @@ class Staff {
 
         if($_SESSION['_staff']['laststrike']) {
             if((time()-$_SESSION['_staff']['laststrike'])<$cfg->getStaffLoginTimeout()) {
-                $errors['err']='You\'ve reached maximum failed login attempts allowed.';
+                $errors['err']='Max. failed login attempts reached';
+                $_SESSION['_staff']['laststrike'] = time(); //reset timer.
             } else { //Timeout is over.
                 //Reset the counter for next round of attempts after the timeout.
                 $_SESSION['_staff']['laststrike']=null;
                 $_SESSION['_staff']['strikes']=0;
             }
         }
+
+        if(!$username || !$passwd)
+            $errors['err'] = 'Username and password required';
+
+        if($errors) return false;
    
-        if(!$errors && ($user=new StaffSession($username)) && $user->getId() && $user->check_passwd($passwd)) {
+        if(($user=new StaffSession(trim($username))) && $user->getId() && $user->check_passwd($passwd)) {
             //update last login && password reset stuff.
             $sql='UPDATE '.STAFF_TABLE.' SET lastlogin=NOW() ';
             if($user->isPasswdResetDue() && !$user->isAdmin())
@@ -574,15 +580,18 @@ class Staff {
             $sql.=' WHERE staff_id='.db_input($user->getId());
             db_query($sql);
             //Now set session crap and lets roll baby!
-            $_SESSION['_staff']=array(); //clear.
-            $_SESSION['_staff']['userID']=$username;
+            $_SESSION['_staff'] = array(); //clear.
+            $_SESSION['_staff']['userID'] = $username;
             $user->refreshSession(); //set the hash.
-            $_SESSION['TZ_OFFSET']=$user->getTZoffset();
-            $_SESSION['TZ_DST']=$user->observeDaylight();
+            $_SESSION['TZ_OFFSET'] = $user->getTZoffset();
+            $_SESSION['TZ_DST'] = $user->observeDaylight();
 
+            //Log debug info.
             $ost->logDebug('Staff login', 
                     sprintf("%s logged in [%s]", $user->getUserName(), $_SERVER['REMOTE_ADDR'])); //Debug.
-            $sid=session_id(); //Current ID
+
+            //Regenerate session id.
+            $sid=session_id(); //Current id
             session_regenerate_id(TRUE);
             //Destroy old session ID - needed for PHP version < 5.1.0 TODO: remove when we move to php 5.3 as min. requirement.
             if(($session=$ost->getSession()) && is_object($session) && $sid)
@@ -599,14 +608,14 @@ class Staff {
             $errors['err']='Forgot your login info? Contact Admin.';
             $_SESSION['_staff']['laststrike']=time();
             $alert='Excessive login attempts by a staff member?'."\n".
-                   'Username: '.$_POST['username']."\n".'IP: '.$_SERVER['REMOTE_ADDR']."\n".'TIME: '.date('M j, Y, g:i a T')."\n\n".
+                   'Username: '.$username."\n".'IP: '.$_SERVER['REMOTE_ADDR']."\n".'TIME: '.date('M j, Y, g:i a T')."\n\n".
                    'Attempts #'.$_SESSION['_staff']['strikes']."\n".'Timeout: '.($cfg->getStaffLoginTimeout()/60)." minutes \n\n";
-            $ost->logWarning('Excessive login attempts ('.$_POST['username'].')', $alert, ($cfg->alertONLoginError()));
+            $ost->logWarning('Excessive login attempts ('.$username.')', $alert, ($cfg->alertONLoginError()));
     
         } elseif($_SESSION['_staff']['strikes']%2==0) { //Log every other failed login attempt as a warning.
-            $alert='Username: '.$_POST['username']."\n".'IP: '.$_SERVER['REMOTE_ADDR'].
+            $alert='Username: '.$username."\n".'IP: '.$_SERVER['REMOTE_ADDR'].
                    "\n".'TIME: '.date('M j, Y, g:i a T')."\n\n".'Attempts #'.$_SESSION['_staff']['strikes'];
-            $ost->logWarning('Failed staff login attempt ('.$_POST['username'].')', $alert, false);
+            $ost->logWarning('Failed staff login attempt ('.$username.')', $alert, false);
         }
 
         return false;
diff --git a/include/class.ticket.php b/include/class.ticket.php
index ec3dcdd1e54e6e075e071b5cc94e2092417bfb92..9f8ce96d5649c75c9a9035aad404e9aef39fdeb8 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -1766,8 +1766,17 @@ class Ticket {
 
    
    /*============== Static functions. Use Ticket::function(params); ==================*/
-    function getIdByExtId($extid) {
-        $sql ='SELECT  ticket_id FROM '.TICKET_TABLE.' ticket WHERE ticketID='.db_input($extid);
+    function getIdByExtId($extId, $email=null) {
+        
+        if(!$extId || !is_numeric($extId)) 
+            return 0;
+
+        $sql ='SELECT  ticket_id FROM '.TICKET_TABLE.' ticket '
+             .' WHERE ticketID='.db_input($extId);
+        
+        if($email)
+            $sql.=' AND email='.db_input($email);
+
         if(($res=db_query($sql)) && db_num_rows($res))
             list($id)=db_fetch_row($res);
 
@@ -1780,8 +1789,8 @@ class Ticket {
         return ($id && is_numeric($id) && ($ticket= new Ticket($id)) && $ticket->getId()==$id)?$ticket:null;    
     }
 
-    function lookupByExtId($id) {
-        return self::lookup(self:: getIdByExtId($id));
+    function lookupByExtId($id, $email=null) {
+        return self::lookup(self:: getIdByExtId($id, $email));
     }
 
     function genExtRandID() {
diff --git a/include/client/login.inc.php b/include/client/login.inc.php
index e1e52e9d454e7a1a4f62fdfec39c5625e496c5d2..7e46c2eb30598e2220128654b0232cd08d81ac62 100644
--- a/include/client/login.inc.php
+++ b/include/client/login.inc.php
@@ -1,5 +1,5 @@
 <?php
-if(!defined('OSTCLIENTINC')) die('Kwaheri');
+if(!defined('OSTCLIENTINC')) die('Access Denied');
 
 $email=Format::input($_POST['lemail']?$_POST['lemail']:$_GET['e']);
 $ticketid=Format::input($_POST['lticket']?$_POST['lticket']:$_GET['t']);
@@ -8,7 +8,8 @@ $ticketid=Format::input($_POST['lticket']?$_POST['lticket']:$_GET['t']);
 <p>To view the status of a ticket, provide us with the login details below.</p>
 <form action="login.php" method="post" id="clientLogin">
     <?php csrf_token(); ?>
-    <strong>Authentication Required</strong>
+    <strong><?php echo Format::htmlchars($errors['login']); ?></strong>
+    <br>
     <div>
         <label for="email">E-Mail Address:</label>
         <input id="email" type="text" name="lemail" size="30" value="<?php echo $email; ?>">
diff --git a/include/staff/login.tpl.php b/include/staff/login.tpl.php
index 2b4d21ad015f1e2d6124c8a3422572bcce53d91e..b8b136eb56d01282e8b15dbd4c0f11085e437eaa 100644
--- a/include/staff/login.tpl.php
+++ b/include/staff/login.tpl.php
@@ -1,4 +1,8 @@
-<?php defined('OSTSCPINC') or die('Invalid path'); ?>
+<?php 
+defined('OSTSCPINC') or die('Invalid path');
+
+$info = ($_POST && $errors)?Format::htmlchars($_POST):array();
+?>
 <!DOCTYPE html>
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 <head>
@@ -22,9 +26,9 @@
     <h3><?php echo Format::htmlchars($msg); ?></h3>
     <form action="login.php" method="post">
         <?php csrf_token(); ?>
-        <input type="hidden" name="d"o value="scplogin">
+        <input type="hidden" name="do" value="scplogin">
         <fieldset>
-            <input type="text" name="username" id="name" value="" placeholder="username" autocorrect="off" autocapitalize="off">
+            <input type="text" name="username" id="name" value="<?php echo $info['username']; ?>" placeholder="username" autocorrect="off" autocapitalize="off">
             <input type="password" name="passwd" id="pass" placeholder="password" autocorrect="off" autocapitalize="off">
         </fieldset>
         <input class="submit" type="submit" name="submit" value="Log In">
diff --git a/login.php b/login.php
index f35693fd4083401a1aea72125e8cb1cc116710c7..834f00ddf72410de113271462f272ef38a4b9737 100644
--- a/login.php
+++ b/login.php
@@ -21,8 +21,17 @@ define('OSTCLIENTINC',TRUE); //make includes happy
 require_once(INCLUDE_DIR.'class.client.php');
 require_once(INCLUDE_DIR.'class.ticket.php');
 
-if ($_POST) ClientSession::tryLogin($_POST['lticket'], $_POST['lemail']);
-else ClientSession::tryLogin($_GET['t'], $_GET['e'], $_GET['a']);
+if($_POST) {
+
+    if(($user=Client::login(trim($_POST['lticket']), trim($_POST['lemail']), null, $errors))) {
+        //XXX: Ticket owner is assumed.
+        @header('Location: tickets.php?id='.$user->getTicketID());
+        require_once('tickets.php'); //Just in case of 'header already sent' error.
+        exit;
+    } elseif(!$errors['err']) {
+        $errors['err'] = 'Authentication error - try again!';
+    }
+}
 
 $nav = new UserNav();
 $nav->setActiveNav('status');
diff --git a/main.inc.php b/main.inc.php
index 872f56758854a2d84ba78251dcce13c25cc00a42..b007a5a4b53fbe43cb20967c323da94721311a4b 100644
--- a/main.inc.php
+++ b/main.inc.php
@@ -112,7 +112,8 @@
     require(INCLUDE_DIR.'mysql.php');
 
     #CURRENT EXECUTING SCRIPT.
-    define('THISPAGE',Misc::currentURL());
+    define('THISPAGE', Misc::currentURL());
+    define('THISURI', $_SERVER['REQUEST_URI']);
 
     # This is to support old installations. with no secret salt.
     if(!defined('SECRET_SALT')) define('SECRET_SALT',md5(TABLE_PREFIX.ADMIN_EMAIL));
diff --git a/scp/login.php b/scp/login.php
index 6a28e0f45130f26f733f8eca82066565f5e2d9dc..5ba5e28e0568afb7626001cc00d76d35b02f2f93 100644
--- a/scp/login.php
+++ b/scp/login.php
@@ -19,20 +19,19 @@ if(!defined('INCLUDE_DIR')) die('Fatal Error. Kwaheri!');
 require_once(INCLUDE_DIR.'class.staff.php');
 require_once(INCLUDE_DIR.'class.csrf.php');
 
-$msg=$_SESSION['_staff']['auth']['msg'];
-$msg=$msg?$msg:'Authentication Required';
-if($_POST && (!empty($_POST['username']) && !empty($_POST['passwd']))){
+$dest = $_SESSION['_staff']['auth']['dest'];
+$msg = $_SESSION['_staff']['auth']['msg'];
+$msg = $msg?$msg:'Authentication Required';
+if($_POST) {
     //$_SESSION['_staff']=array(); #Uncomment to disable login strikes.
-    $msg='Invalid login';
-    if(($user=Staff::login($_POST['username'],$_POST['passwd'],$errors))){
-        $dest=$_SESSION['_staff']['auth']['dest'];
+    if(($user=Staff::login($_POST['username'], $_POST['passwd'], $errors))){
         $dest=($dest && (!strstr($dest,'login.php') && !strstr($dest,'ajax.php')))?$dest:'index.php';
         @header("Location: $dest");
         require_once('index.php'); //Just incase header is messed up.
         exit;
-    }elseif(!$errors['err']){
-        $errors['err']='Login error - try again';
     }
+
+    $msg = $errors['err']?$errors['err']:'Invalid login';
 }
 define("OSTSCPINC",TRUE); //Make includes happy!
 include_once(INCLUDE_DIR.'staff/login.tpl.php');
diff --git a/scp/staff.inc.php b/scp/staff.inc.php
index 5dcf6045042397c1ee806a8df9f0f2b0f28725a3..decf2c5cd624a719f718d5e53e92770fc502ae4c 100644
--- a/scp/staff.inc.php
+++ b/scp/staff.inc.php
@@ -49,7 +49,7 @@ require_once(INCLUDE_DIR.'class.csrf.php');
 
 if(!function_exists('staffLoginPage')) { //Ajax interface can pre-declare the function to  trap expired sessions.
     function staffLoginPage($msg) {
-        $_SESSION['_staff']['auth']['dest']=THISPAGE;
+        $_SESSION['_staff']['auth']['dest']=THISURI;
         $_SESSION['_staff']['auth']['msg']=$msg;
         require(SCP_DIR.'login.php');
         exit;
diff --git a/view.php b/view.php
index 984b04c3019645c6ca1d075bbab0aac8460e4094..10e5374fe71b8dcf3551c0ee922ac5b4800e961a 100644
--- a/view.php
+++ b/view.php
@@ -3,6 +3,7 @@
     view.php
 
     Ticket View.
+    TODO: Support different views based on auth_token - e.g for BCC'ed users vs. Ticket owner.
 
     Peter Rotich <peter@osticket.com>
     Copyright (c)  2006-2010 osTicket
@@ -14,8 +15,22 @@
     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_once('client.inc.php');
+
+//If the user is NOT logged in - try auto-login (if params exists).
+if(!$thisclient || !$thisclient->isValid()) {
+    // * On login Client::login will redirect the user to tickets.php view.
+    // * See TODO above for planned multi-view.
+    $user = null;
+    if($_GET['t'] && $_GET['e'] && $_GET['a'])
+        $user = Client::login($_GET['t'], $_GET['e'], $_GET['a'], $errors);
+
+    //XXX: For now we're assuming the user is the ticket owner
+    // (multi-view based on auth token will come later).
+    if($user && $user->getTicketID()==trim($_GET['t']))
+        @header('Location: tickets.php?id='.$user->getTicketID());
+}
+
+//Simply redirecting to tickets.php until multiview is implemented.
 require('tickets.php');
 ?>