Index: trunk/lib/App.inc.php
===================================================================
--- trunk/lib/App.inc.php	(revision 14)
+++ trunk/lib/App.inc.php	(revision 15)
@@ -441,8 +441,4 @@
             $this =& App::getInstance();
         }
-
-        if (!$this->running) {
-            return false;
-        }
         
         // If priority is not specified, assume the worst.
@@ -452,9 +448,8 @@
         }
     
-        // If log file is not specified, create one in the codebase root.
-        if ($this->getParam('log_directory') === null || !is_dir($this->getParam('log_directory')) || !is_writable($this->getParam('log_directory'))) {
-            // If log file is not specified, don't log to a file.
+        // If log file is not specified, don't log to a file.
+        if (!$this->getParam('log_directory') || !$this->getParam('log_filename') || !is_dir($this->getParam('log_directory')) || !is_writable($this->getParam('log_directory'))) {
             $this->setParam(array('log_file_priority' => false));
-            // We must use trigger_error rather than calling App::logMsg, which might lead to an infinite loop.
+            // We must use trigger_error to report this problem rather than calling App::logMsg, which might lead to an infinite loop.
             trigger_error(sprintf('Codebase error: log directory (%s) not found or writable.', $this->getParam('log_directory')), E_USER_NOTICE);
         }
Index: trunk/lib/Auth_SQL.inc.php
===================================================================
--- trunk/lib/Auth_SQL.inc.php	(revision 14)
+++ trunk/lib/Auth_SQL.inc.php	(revision 15)
@@ -123,4 +123,5 @@
             }
 
+            // The minimal columns for a table compatable with the Auth_SQL class.
             DB::query("CREATE TABLE IF NOT EXISTS " . $this->getParam('db_table') . " (
                 " . $this->getParam('db_primary_key') . " smallint(11) NOT NULL auto_increment,
@@ -306,8 +307,8 @@
         // Return user data if found.
         if ($user_data = mysql_fetch_assoc($qid)) {
-            App::logMsg(sprintf('Authentication successful for user: %s', $username), LOG_DEBUG, __FILE__, __LINE__);
+            App::logMsg(sprintf('Authentication successful for %s %s (%s)', $this->_auth, $user_data['user_id'], $username), LOG_DEBUG, __FILE__, __LINE__);
             return $user_data;
         } else {
-            App::logMsg(sprintf('Authentication failed for user: %s', $username), LOG_DEBUG, __FILE__, __LINE__);
+            App::logMsg(sprintf('Authentication failed for %s %s (encrypted attempted password: %s)', $this->_auth, $username, $this->encryptPassword($password)), LOG_NOTICE, __FILE__, __LINE__);
             return false;
         }
@@ -352,5 +353,5 @@
             if (!empty($user_data['blocked'])) {
                 
-                App::logMsg(sprintf('Login failed, blocked account. User: %s (%s) Reason: %s', $user_data['user_id'], $username, $user_data['blocked_reason']), LOG_NOTICE, __FILE__, __LINE__);
+                App::logMsg(sprintf('%s %s (%s) login failed due to blocked account: %s', ucfirst($this->_auth), $this->getVal('user_id'), $this->getVal('username'), $this->getVal('blocked_reason')), LOG_NOTICE, __FILE__, __LINE__);
                 
                 switch ($user_data['blocked_reason']) {
@@ -385,12 +386,12 @@
                 if ($this->getVal('abuse_warning_level') < $this->_params['login_abuse_warnings']) {
                     // Warn the user with a password reset.
-                    $this->resetPassword(null, _("This is a security precaution. We have detected this account has been accessed from multiple computers simultaneously. It is against policy to share your login information with others. If further account abuse is detected your account will be blocked."));
+                    $this->resetPassword(null, _("This is a security precaution. We have detected this account has been accessed from multiple computers simultaneously. It is against policy to share login information with others. If further account abuse is detected this account will be blocked."));
                     App::raiseMsg(_("Your password has been reset as a security precaution. Please check your email for more information."), MSG_NOTICE, __FILE__, __LINE__);
-                    App::logMsg(sprintf('Account abuse detected for user %s from IP %s', $this->getVal('username'), $this->getVal('remote_ip')), LOG_WARNING, __FILE__, __LINE__);
+                    App::logMsg(sprintf('Account abuse detected for %s %s (%s) from IP %s', $this->_auth, $this->getVal('user_id'), $this->getVal('username'), $this->getVal('remote_ip')), LOG_WARNING, __FILE__, __LINE__);
                 } else {
                     // Block the account with the reason of account abuse.
                     $this->blockAccount(null, 'account abuse');
                     App::raiseMsg(_("Your account has been blocked as a security precaution. Please contact us for more information."), MSG_NOTICE, __FILE__, __LINE__);
-                    App::logMsg(sprintf('Account blocked for user %s from IP %s', $this->getVal('username'), $this->getVal('remote_ip')), LOG_ALERT, __FILE__, __LINE__);
+                    App::logMsg(sprintf('Account blocked for %s %s (%s) from IP %s', $this->_auth, $this->getVal('user_id'), $this->getVal('username'), $this->getVal('remote_ip')), LOG_ALERT, __FILE__, __LINE__);
                 }
                 // Increment user's warning level.
@@ -608,5 +609,9 @@
         $this->initDB();
         
-        $qid = DB::query("SELECT 1 FROM " . $this->_params['db_table'] . " WHERE " . $this->_params['db_username_column'] . " = '" . addslashes($username) . "'");
+        $qid = DB::query("
+            SELECT 1 
+            FROM " . $this->_params['db_table'] . "
+            WHERE " . $this->_params['db_username_column'] . " = '" . addslashes($username) . "'
+        ");
         return (mysql_num_rows($qid) > 0);
     }
@@ -622,5 +627,9 @@
         $this->initDB();
         
-        $qid = DB::query("SELECT " . $this->_params['db_username_column'] . " FROM " . $this->_params['db_table'] . " WHERE " . $this->_params['db_primary_key'] . " = '" . addslashes($user_id) . "'");
+        $qid = DB::query("
+            SELECT " . $this->_params['db_username_column'] . "
+            FROM " . $this->_params['db_table'] . "
+            WHERE " . $this->_params['db_primary_key'] . " = '" . addslashes($user_id) . "'
+        ");
         if (list($username) = mysql_fetch_row($qid)) {
             return $username;
@@ -677,8 +686,6 @@
             
         case AUTH_ENCRYPT_SHA1 :
-            if (function_exists('sha1')) { // Only in PHP 4.3.0+
-                return sha1($password);
-                break;
-            }
+            return sha1($password);
+            break;
             
         case AUTH_ENCRYPT_MD5 :
@@ -726,5 +733,13 @@
             WHERE " . $this->_params['db_primary_key'] . " = '" . addslashes($user_id) . "'
         ");
-        $user_data = mysql_fetch_assoc($qid);
+        if (!$user_data = mysql_fetch_assoc($qid)) {
+            App::logMsg(sprintf('Reset password failed. %s %s not found.', ucfirst($this->_auth), $user_id), LOG_NOTICE, __FILE__, __LINE__);
+            return false;
+        }
+        
+        // Make sure user has an email on record.
+        if (!isset($user_data['email']) || '' == trim($user_data['email'])) {
+            App::logMsg(sprintf('Password reset but notification failed, no email address for %s %s (%s).', $this->_auth, $user_data[$this->_params['db_primary_key']], $user_data[$this->_params['db_username_column']]), LOG_NOTICE, __FILE__, __LINE__);
+        }
 
         // Get new password.
@@ -755,8 +770,8 @@
 EOF;
         $email_body = wordwrap(sprintf($email_body, 
-            $user_data['username'],
+            $user_data[$this->_params['db_username_column']],
             App::getParam('site_name'),
             $reason,
-            $user_data['username'],
+            $user_data[$this->_params['db_username_column']],
             $password,
             App::getParam('site_name'),
@@ -767,5 +782,8 @@
         mail($user_data['email'], $email_subject, $email_body, sprintf("From: %s <%s>\r\n", App::getParam('site_name'), App::getParam('site_email')), App::getParam('envelope_sender_address'));
     
-        return array('username'=>$user_data['username'], 'userpass'=>$password);
+        return array(
+            'username' => $user_data[$this->_params['db_username_column']], 
+            'userpass' => $password
+        );
     }
     
Index: trunk/lib/DB.inc.php
===================================================================
--- trunk/lib/DB.inc.php	(revision 14)
+++ trunk/lib/DB.inc.php	(revision 15)
@@ -7,5 +7,5 @@
  *
  * @author  Quinn Comendant <quinn@strangecode.com>
- * @version 1.0
+ * @version 1.0.1
  */
  
@@ -144,7 +144,10 @@
         }
         
-        // Connection errors.
+        // Test for connection errors.
         if (!$this->dbh || mysql_error($this->dbh)) {
             $mysql_error_msg = $this->dbh ? 'Codebase MySQL error: (' . mysql_errno($this->dbh) . ') ' . mysql_error($this->dbh) : 'Codebase MySQL error: Could not connect to server.';
+            App::logMsg($mysql_error_msg, LOG_EMERG, __FILE__, __LINE__);
+
+            // Print helpful or pretty error?
             if ($this->getParam('db_debug')) {
                 echo $mysql_error_msg . "\n";
@@ -152,7 +155,12 @@
                 echo _("This page is temporarily unavailable. It should be back up in a few minutes.");
             }
-            App::logMsg($mysql_error_msg, LOG_EMERG, __FILE__, __LINE__);
-            echo "\n\n<!-- Script execution stopped out of embarrassment. -->";
-            die;
+
+            // Die or continue without connection?
+            if ($this->getParam('db_die_on_failure')) {
+                echo "\n\n<!-- Script execution stopped out of embarrassment. -->";
+                die;
+            } else {
+                return false;
+            }
         }
         
Index: trunk/lib/DBSessionHandler.inc.php
===================================================================
--- trunk/lib/DBSessionHandler.inc.php	(revision 14)
+++ trunk/lib/DBSessionHandler.inc.php	(revision 15)
@@ -38,7 +38,11 @@
             $this->db =& $db;
             
+        } else if (isset($db) && is_a($db, 'DB')) {
+            // Not a DB object.
+            App::logMsg(sprintf('Provided DB object is not connected. %s', mysql_error($db->dbh)), LOG_ERR, __FILE__, __LINE__);
+            
         } else if (isset($db)) {
             // Not a DB object.
-            App::logMsg(sprintf('Argument one is not a valid DB object: %s', gettype($db)), LOG_ERR, __FILE__, __LINE__);
+            App::logMsg(sprintf('Provided DB object is not valid. %s', gettype($db)), LOG_ERR, __FILE__, __LINE__);
             
         } else {
@@ -59,5 +63,4 @@
             // Connect to database.
             $this->db->connect();
-            
         }
 
Index: trunk/lib/FormValidator.inc.php
===================================================================
--- trunk/lib/FormValidator.inc.php	(revision 14)
+++ trunk/lib/FormValidator.inc.php	(revision 15)
@@ -390,10 +390,10 @@
         // Test email address format.
         if ($allow_fullname) {
-            if (!$this->checkRegex($form_name, '/^[\w\s]*<?php[A-Za-z0-9._-]{1,}\@[A-Za-z0-9.-]{1,}\.[A-Za-z]{2,5}>?$/i', true, sprintf(_("<strong>%s</strong> is not a valid email address."), $email))) {
+            if (!$this->checkRegex($form_name, '/^[\w\s]*<?[^\s@\[\]<>]{1,}\@[A-Za-z0-9.-]{1,}\.[A-Za-z]{2,5}>?$/i', true, sprintf(_("<strong>%s</strong> is not a valid email address."), $email))) {
                 App::logMsg(sprintf('The email address %s is not valid.', getFormData($form_name)), LOG_DEBUG, __FILE__, __LINE__);
                 return false;
             }
         } else {
-            if (!$this->checkRegex($form_name, '/^[A-Za-z0-9._-]{1,}\@[A-Za-z0-9.-]{1,}\.[A-Za-z]{2,5}$/i', true, sprintf(_("<strong>%s</strong> is not a valid email address."), $email))) {
+            if (!$this->checkRegex($form_name, '/^[^\s@\[\]<>]{1,}\@[A-Za-z0-9.-]{1,}\.[A-Za-z]{2,5}$/i', true, sprintf(_("<strong>%s</strong> is not a valid email address."), $email))) {
                 App::logMsg(sprintf('The email address %s is not valid.', getFormData($form_name)), LOG_DEBUG, __FILE__, __LINE__);
                 return false;
@@ -402,11 +402,11 @@
         
         // Test length.
-        if (!$this->stringLength($form_name, 0, 128, sprintf(_("<strong>Email address</strong> must contain less than 128 characters."), $email))) {
-            App::logMsg(sprintf('The email address %s must contain less than 128 characters.', getFormData($form_name)), LOG_DEBUG, __FILE__, __LINE__);
+        if (!$this->stringLength($form_name, 0, 255, sprintf(_("<strong>Email address</strong> must contain less than 256 characters."), $email))) {
+            App::logMsg(sprintf('The email address %s must contain less than 256 characters.', getFormData($form_name)), LOG_DEBUG, __FILE__, __LINE__);
             return false;
         }
         
         // Check domain exists and has valid MX record.
-        preg_match('/^[\w\s]*<?php[A-Za-z0-9._-]{1,}\@([A-Za-z0-9.-]{1,}\.[A-Za-z]{2,5})>?$/i', $email, $matches);
+        preg_match('/^[\w\s]*<?[^\s@\[\]<>]{1,}\@([A-Za-z0-9.-]{1,}\.[A-Za-z]{2,5})>?$/i', $email, $matches);
         if (!empty($matches[1])) {
             if (!checkdnsrr($matches[1] . '.', 'MX') && gethostbyname($matches[1]) == $matches[1]) {
Index: trunk/lib/RecordVersion.inc.php
===================================================================
--- trunk/lib/RecordVersion.inc.php	(revision 14)
+++ trunk/lib/RecordVersion.inc.php	(revision 15)
@@ -338,5 +338,5 @@
             AND record_val = '" . addslashes($record_val) . "'
             ORDER BY version_datetime DESC
-        ", 1); die;///
+        ");
         $versions = array();
         while ($row = mysql_fetch_assoc($qid)) {
Index: trunk/lib/SpellCheck.inc.php
===================================================================
--- trunk/lib/SpellCheck.inc.php	(revision 14)
+++ trunk/lib/SpellCheck.inc.php	(revision 15)
@@ -7,23 +7,26 @@
  *
  * @author  Quinn Comendant <quinn@strangecode.com>
- * @version 1.0
+ * @version 1.1
  */
  
 /* Implementation example:
 --------------------------------------------------------------------------------
-include '_config.inc.php';
+include_once dirname(__FILE__) . '/_config.inc.php';
 include 'codebase/lib/SpellCheck.inc.php';
 
-// Instantiate with language and optionally the path to the custom wordlist file.
-$spell = new SpellCheck('en', '/tmp/my_custom_dict');
+// Instantiate with parameters. In this example we'll set the language and the path to the personal wordlist file.
+$spell = new SpellCheck(array(
+    'language' => 'en', 
+    'personal_wordlist' => '/tmp/my_custom_dict'
+));
+
+// Just for the heck of it add a new word to persistent personal wordlist file.
+$spell->add('mealworm');
 
 $text_to_check = 'donky rinds taste like mealworm paste';
-
-// Add new word to persistent custom wordlist file.
-$spell->add('mealworm');
 
 if (!$spell->checkString($text_to_check)) {
     $suggestions = $spell->getStringSuggestions($text_to_check);
-    echo 'Spelling errors:';
+    echo 'Spelling errors! Here are suggested alternatives:';
     print_r($suggestions);
 } else {
@@ -39,6 +42,7 @@
 
     var $_params = array(
-        'personal_wordlist' => '',
-        'skip_len' => 3,
+        'language' => 'en',
+        'personal_wordlist' => '', // Text file to save custom words to.
+        'skip_length' => 3, // Words with this many chars or less will not be checked.
         'mode' => PSPELL_NORMAL, // PSPELL_FAST, PSPELL_NORMAL, or PSPELL_BAD_SPELLERS.
         'highlight_start' => '<strong style="color:red;">',
@@ -53,20 +57,27 @@
     /**
      * Constructor.
-     */
-    function SpellCheck($lang='en', $personal_wordlist=null)
-    {
-        $this->_pspell_cfg_handle = pspell_config_create($lang);
-
-        pspell_config_ignore($this->_pspell_cfg_handle, $skip_len);
-        pspell_config_mode($this->_pspell_cfg_handle, $mode);
-
-        if (isset($personal_wordlist)) {
-            if (!is_writable(dirname($personal_wordlist)) && !is_writable($personal_wordlist)) {
-                App::logMsg(sprintf('Personal wordlist file not writable: %s', $personal_wordlist), LOG_NOTICE, __FILE__, __LINE__);
+	 *
+     * @param  array    $params     Array of parameters (key => val pairs).
+     */
+    function SpellCheck($params)
+    {
+		if (!is_array($params) || empty($params)) {
+			trigger_error('SpellCheck parameters not set properly', E_USER_ERROR);
+		}
+
+		$this->setParam($params);
+
+        $this->_pspell_cfg_handle = pspell_config_create($this->getParam('language'));
+
+        pspell_config_ignore($this->_pspell_cfg_handle, $this->getParam('skip_length'));
+        pspell_config_mode($this->_pspell_cfg_handle, $this->getParam('mode'));
+
+        if ('' != $this->getParam('personal_wordlist')) {
+            if (!is_writable(dirname($this->getParam('personal_wordlist'))) || !is_writable($this->getParam('personal_wordlist'))) {
+            	App::logMsg(sprintf('Personal wordlist file not writable: %s', $this->getParam('personal_wordlist')), LOG_WARNING, __FILE__, __LINE__);
             } else {
-                $this->setParam(array('personal_wordlist' => $personal_wordlist));
-                pspell_config_personal($this->_pspell_cfg_handle, $personal_wordlist);
+                pspell_config_personal($this->_pspell_cfg_handle, $this->getParam('personal_wordlist'));
                 $this->_use_personal_wordlist = true;
-                App::logMsg(sprintf('Using personal wordlist: %s', $personal_wordlist), LOG_DEBUG, __FILE__, __LINE__);
+                App::logMsg(sprintf('Using personal wordlist: %s', $this->getParam('personal_wordlist')), LOG_DEBUG, __FILE__, __LINE__);
             }
         }
@@ -174,6 +185,11 @@
     {
         if ($this->_use_personal_wordlist) {
-            App::logMsg(sprintf('Added "%s" to personal wordlist: %s', $word, $this->getParam('personal_wordlist')), LOG_DEBUG, __FILE__, __LINE__);
-            return pspell_add_to_personal($this->_pspell_handle, $word);
+            if (pspell_add_to_personal($this->_pspell_handle, $word)) {
+				App::logMsg(sprintf('Added "%s" to personal wordlist: %s', $word, $this->getParam('personal_wordlist')), LOG_DEBUG, __FILE__, __LINE__);
+				return true;			
+			} else {
+				App::logMsg(sprintf('Failed adding "%s" to personal wordlist: %s', $word, $this->getParam('personal_wordlist')), LOG_ERR, __FILE__, __LINE__);
+				return false;
+			}
         }
     }
Index: trunk/tests/Auth_SQLTest.php
===================================================================
--- trunk/tests/Auth_SQLTest.php	(revision 14)
+++ trunk/tests/Auth_SQLTest.php	(revision 15)
@@ -106,5 +106,8 @@
         $true = $this->Auth_SQL->authenticate('testuser', 'testpass');
         $this->assertTrue($true, 'User login failed, but should have succeeded.');
+
+        echo "Testing wrong password...\n";
         $false = $this->Auth_SQL->authenticate('testuser', 'wrongpass');
+
         $this->assertfalse($false, 'User login succeeded, but should have failed.');
     }
@@ -120,4 +123,5 @@
         $this->assertFalse($after_logged_in, '3. User is still logged in but should not be.');
 
+        echo "Testing wrong password...\n";
         $login2 = $this->Auth_SQL->login('testuser', 'wrongpass');
         $this->assertFalse($login2, '4. User login succeeded, but should have failed.');
Index: trunk/tests/_config.inc.php
===================================================================
--- trunk/tests/_config.inc.php	(revision 14)
+++ trunk/tests/_config.inc.php	(revision 15)
@@ -19,5 +19,5 @@
     'db_name' => 'test',
     'db_user' => 'root',
-    'db_pass' => getenv('DB_PASS'),        
+    'db_pass' => getenv('DB_PASS'),
     'display_errors' => true,
     'db_always_debug' => false, // TRUE = display all SQL queries.
@@ -32,4 +32,3 @@
 
 $app->start();
-
 ?>
Index: trunk/tests/run_tests.sh
===================================================================
--- trunk/tests/run_tests.sh	(revision 14)
+++ trunk/tests/run_tests.sh	(revision 15)
@@ -1,4 +1,9 @@
 #!/bin/sh
-for foo in `dirname $0`/*Test.php; 
+
+# Be in the directory with all the tests.
+cd `dirname $0`;
+
+# Run tests sequentially.
+for foo in *Test.php; 
 do
     php $foo;
