Index: trunk/lib/App.inc.php
===================================================================
--- trunk/lib/App.inc.php	(revision 494)
+++ trunk/lib/App.inc.php	(revision 497)
@@ -537,20 +537,19 @@
                 switch ($m['type']) {
                 case MSG_ERR:
-                    echo '<div class="sc-msg-error">' . $m['message'] . '</div>';
+                    echo '<div data-alert class="sc-msg-error alert-box alert">' . $m['message'] . '<a href="#" class="close">&times;</a></div>';
                     break;
 
                 case MSG_WARNING:
-                    echo '<div class="sc-msg-warning">' . $m['message'] . '</div>';
+                    echo '<div data-alert class="sc-msg-warning alert-box warning">' . $m['message'] . '<a href="#" class="close">&times;</a></div>';
                     break;
 
                 case MSG_SUCCESS:
-                    echo '<div class="sc-msg-success">' . $m['message'] . '</div>';
+                    echo '<div data-alert class="sc-msg-success alert-box success">' . $m['message'] . '<a href="#" class="close">&times;</a></div>';
                     break;
 
                 case MSG_NOTICE:
                 default:
-                    echo '<div class="sc-msg-notice">' . $m['message'] . '</div>';
+                    echo '<div data-alert class="sc-msg-notice alert-box info">' . $m['message'] . '<a href="#" class="close">&times;</a></div>';
                     break;
-
                 }
             }
Index: trunk/lib/Auth_SQL.inc.php
===================================================================
--- trunk/lib/Auth_SQL.inc.php	(revision 494)
+++ trunk/lib/Auth_SQL.inc.php	(revision 497)
@@ -471,4 +471,7 @@
          * (2) If this number exceeds the login_abuse_max_ips, assume multiple people are logging in under the same account.
         **/
+        // TODO: make this ipv6 compatible. At the moment, ipv6 addresses are converted into zero for remote_ip_binary.
+        // http://www.highonphp.com/5-tips-for-working-with-ipv6-in-php
+        // https://stackoverflow.com/questions/444966/working-with-ipv6-addresses-in-php
         if ($this->getParam('abuse_detection') && !$this->get('login_abuse_exempt')) {
             $qid = $db->query("
Index: trunk/lib/DB.inc.php
===================================================================
--- trunk/lib/DB.inc.php	(revision 494)
+++ trunk/lib/DB.inc.php	(revision 497)
@@ -441,4 +441,31 @@
     }
 
+    /**
+     * Returns the values of an ENUM or SET column, returning them as an array.
+     *
+     * @param  string $db_table   database table to lookup
+     * @param  string $db_col     database column to lookup
+     * @param  bool   $sort          Sort the output.
+     * @return array    Array of the set/enum values on success, false on failure.
+     */
+    public function getEnumValues($db_table, $db_col, $sort=false)
+    {
+        $app =& App::getInstance();
+
+        $qid = $this->query("SHOW COLUMNS FROM " . $this->escapeString($db_table) . " LIKE '" . $this->escapeString($db_col) . "'", false);
+
+        $row = mysql_fetch_row($qid);
+        if (preg_match('/^enum|^set/i', $row[1]) && preg_match_all("/'([^']*)'/", $row[1], $matches)) {
+            if ($sort) {
+                natsort($matches[1]);
+            }
+            return $matches[1];
+        } else {
+            $app->logMsg(sprintf('No set or enum fields found in %s.%s', $db_table, $db_col), LOG_ERR, __FILE__, __LINE__);
+            return false;
+        }
+    }
+
+
 } // End.
 
Index: trunk/lib/FormValidator.inc.php
===================================================================
--- trunk/lib/FormValidator.inc.php	(revision 494)
+++ trunk/lib/FormValidator.inc.php	(revision 497)
@@ -209,18 +209,18 @@
                     switch ($e['type']) {
                     case MSG_ERR:
-                        echo '<div class="sc-msg-error">' . $e['message'] . '</div>';
+                        echo '<div data-alert class="sc-msg-error alert-box alert">' . $e['message'] . '<a href="#" class="close">&times;</a></div>';
                         break;
 
                     case MSG_WARNING:
-                        echo '<div class="sc-msg-warning">' . $e['message'] . '</div>';
+                        echo '<div data-alert class="sc-msg-warning alert-box warning">' . $e['message'] . '<a href="#" class="close">&times;</a></div>';
                         break;
 
                     case MSG_SUCCESS:
-                        echo '<div class="sc-msg-success">' . $e['message'] . '</div>';
+                        echo '<div data-alert class="sc-msg-success alert-box alert">' . $e['message'] . '<a href="#" class="close">&times;</a></div>';
                         break;
 
                     case MSG_NOTICE:
                     default:
-                        echo '<div class="sc-msg-notice">' . $e['message'] . '</div>';
+                        echo '<div data-alert class="sc-msg-notice alert-box info">' . $e['message'] . '<a href="#" class="close">&times;</a></div>';
                         break;
                     }
@@ -304,5 +304,5 @@
     public function isEmpty($form_name, $msg='')
     {
-        $this->notEmpty($form_name, $msg);
+        return $this->notEmpty($form_name, $msg);
     }
 
Index: trunk/lib/HTML.inc.php
===================================================================
--- trunk/lib/HTML.inc.php	(revision 497)
+++ trunk/lib/HTML.inc.php	(revision 497)
@@ -0,0 +1,217 @@
+<?php
+/*
+* The Strangecode Codebase - a general application development framework for PHP
+* For details visit the project site: <http://trac.strangecode.com/>
+* Copyright Â© 2014 Strangecode, LLC
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+* HTML()
+*
+* Tools for building HTML from PHP data.
+*
+* @author   Quinn Comendant <quinn@strangecode.com>
+* @version  1.0
+* @since    11 Sep 2014 21:08:06
+*
+* Example of use:
+---------------------------------------------------------------------
+echo HTML::buttons(array(
+    array('name' => 'submit', 'value' => _("Save changes"), 'class' => 'small button', 'accesskey' => 's'),
+    array('name' => 'reset', 'value' => _("Reset"), 'class' => 'small button secondary', 'accesskey' => 'r'),
+    array('name' => 'cancel', 'value' => _("Cancel"), 'class' => 'small button secondary', 'accesskey' => 'c'),
+));
+---------------------------------------------------------------------
+*/
+
+class HTML {
+
+    /**
+    * Prints submit buttons based on given array of submit button names and titles. If the array includes an 'href' key, the
+    * button is created using a <a> otherwise an <input type="âŠ" /> is used.
+    *
+    * @access  public
+    * @param   array   $buttons     Array of buttons, the key being the button name, and value being the title of the button.
+    * @return  void
+    * @author   Quinn Comendant <quinn@strangecode.com>
+    * @version  1.0
+    * @since    12 Sep 2014 00:17:38
+    */
+    static public function printButtons($buttons=array(), $class='button-group')
+    {
+        if (!isset($buttons[0]) || !is_array($buttons[0])) {
+            $app =& App::getInstance();
+            $app->logMsg(sprintf('Incorrect parameters passed to HTML::buttons(): %s', getDump($buttons)), LOG_DEBUG, __FILE__, __LINE__);
+            return false;
+        }
+        if (empty($buttons)) {
+            return '';
+        }
+        ?><ul class="<?php echo oTxt($class) ?>"><?php
+        foreach ($buttons as $i => $b) {
+            $defaults = array();
+            $defaults['type'] = isset($b['type']) ? $b['type'] : 'submit';
+            $b = array_merge($defaults, $b);
+            if (isset($b['href'])) {
+                echo '<li><a';
+                foreach (array_diff_key($b, array('value' => null)) as $key => $value) {
+                    printf(' %s="%s"', $key, oTxt($value));
+                }
+                echo '>' . oTxt($b['value']) . '</a></li>';
+            } else if (isset($b['name'])) {
+                $defaults['id'] = isset($b['id']) ? $b['id'] : sprintf('sc-%s-button', $b['name']);
+                echo '<li><input';
+                foreach ($b as $key => $value) {
+                    printf(' %s="%s"', $key, oTxt($value));
+                }
+                echo ' /></li>';
+            } else {
+                $app->logMsg(sprintf('Button missing name or href: %s', getDump($b)), LOG_ERR, __FILE__, __LINE__);
+                continue;
+            }
+        }
+        ?></ul><?php
+    }
+
+    /*
+    * Return an array of key-value pairs matching a database query for the given parameters. This is useful for
+    * injecting into HTML::printSelectOptions().
+    *
+    * @access   public
+    * @param  string $db_table         database table to lookup
+    * @param  string $key_column       column containing the human-readable titles for the select menu
+    * @param  string $val_column       column containing the computer values for the select menu
+    * @param  string $preselected      the currently selected value of the menu. compared to the $val_column
+    * @param  bool   $first            Optional first item; set true for a blank item, array for item with name and value.
+    * @param  string $extra_clause     SQL exclude clause. Something like "WHERE girls != 'buckteeth'"
+    * @return array                    Array of options suitable to pass into HTML::printSelectOptions().
+    * @author   Quinn Comendant <quinn@strangecode.com>
+    * @version  1.0
+    * @since    12 Sep 2014 11:43:23
+    */
+    static public function getSelectOptions($db_table, $key_column, $val_column, $preselected, $first=false, $extra_clause='', $sql_format='SELECT %1$s, %2$s FROM %3$s %4$s')
+    {
+        $db =& DB::getInstance();
+
+        // Sometimes preselected comes as a comma list.
+        if (!is_array($preselected)) {
+            $preselected = array($preselected);
+        }
+
+        $options = array();
+        if (true === $first) {
+            // Include a blank first option.
+            $options[] = array(
+                'value' => '',
+                'selected' => in_array('', $preselected),
+                'text' => '',
+            );
+        } else if (is_array($first)) {
+            // When the 'blank' first option needs a specific key->val pair.
+            foreach ($first as $key => $val) {
+                $options[] = array(
+                    'value' => $key,
+                    'selected' => in_array($key, $preselected),
+                    'text' => $val,
+                );
+            }
+        }
+
+        $db =& DB::getInstance();
+        $qid = $db->query(sprintf($sql_format, $key_column, $val_column, $db_table, $extra_clause), false);
+        while ($row = mysql_fetch_assoc($qid)) {
+            $options[] = array(
+                'value' => $row[$val_column],
+                'selected' => in_array($row[$val_column], $preselected),
+                'text' => $row[$key_column],
+            );
+        }
+        return $options;
+    }
+
+    /**
+     * Prints option fields for a select form. Works only with enum or set
+     * data types in table columns.
+     *
+     * @param  string $db_table     Database table to lookup
+     * @param  string $db_col       Database column to lookup
+     * @param  string $preselected  The currently selected value of the menu. compared to the $val_column
+     * @param  bool   $first        Optional first item; set true for a blank item, array for item with name and value.
+     * @param  bool   $sort         Sort the output.
+     */
+    static public function getSelectOptionsEnum($db_table, $db_col, $preselected, $first=false, $sort=false)
+    {
+        // Sometimes preselected comes as a comma list.
+        if (!is_array($preselected)) {
+            $preselected = array($preselected);
+        }
+
+        $options = array();
+        if (true === $first) {
+            // Include a blank first option.
+            $options[] = array(
+                'value' => '',
+                'selected' => in_array('', $preselected),
+                'text' => '',
+            );
+        } else if (is_array($first)) {
+            // When the 'blank' first option needs a specific key->val pair.
+            foreach ($first as $key => $val) {
+                $options[] = array(
+                    'value' => $key,
+                    'selected' => in_array($key, $preselected),
+                    'text' => $val,
+                );
+            }
+        }
+
+        $db =& DB::getInstance();
+        $values = $db->getEnumValues($db_table, $db_col, $sort);
+        foreach ($values as $v) {
+            $options[] = array(
+                'value' => $v,
+                'selected' => in_array($v, $preselected),
+                'text' => $v,
+            );
+        }
+
+        return $options;
+    }
+
+    /**
+     * Prints a select menu containing the specified values and keys of a table.
+     *
+     */
+    static public function printSelectOptions($options)
+    {
+        if (!isset($options) || !is_array($options)) {
+            $app =& App::getInstance();
+            $app->logMsg(sprintf('Incorrect parameters passed to HTML::printSelectOptions(): %s', getDump($options)), LOG_DEBUG, __FILE__, __LINE__);
+            return false;
+        }
+        if (empty($options)) {
+            return '';
+        }
+
+        foreach ($options as $o) {
+            printf('<option value="%s"%s>%s</option>',
+                oTxt($o['value']),
+                ($o['selected'] ? ' selected' : ''),
+                oTxt($o['text'])
+            );
+        }
+    }
+}
Index: trunk/lib/Lock.inc.php
===================================================================
--- trunk/lib/Lock.inc.php	(revision 494)
+++ trunk/lib/Lock.inc.php	(revision 497)
@@ -384,5 +384,4 @@
     {
         $app =& App::getInstance();
-
         ?>
         <form method="post" action="<?php echo oTxt($_SERVER['PHP_SELF']); ?>">
Index: trunk/lib/Navigation.inc.php
===================================================================
--- trunk/lib/Navigation.inc.php	(revision 494)
+++ trunk/lib/Navigation.inc.php	(revision 497)
@@ -254,6 +254,7 @@
                         // A crumb with no link.
                         $breadcrumbs[] = array(
-                            'url' => false,
-                            'title' => sprintf($this->getParam('last_crumb_format'), $page['title'])
+                            'url' => $_SERVER['REQUEST_URI'],
+                            'title' => sprintf($this->getParam('last_crumb_format'), $page['title']),
+                            'class' => 'current'
                         );
                     } else if ($crumb_count > $this->getParam('chop_breadcrumb_links')) {
@@ -261,5 +262,6 @@
                         $breadcrumbs[] = array(
                             'url' => $page['url'],
-                            'title' => sprintf($this->getParam('last_crumb_format'), $page['title'])
+                            'title' => sprintf($this->getParam('last_crumb_format'), $page['title']),
+                            'class' => '',
                         );
                     }
@@ -269,5 +271,6 @@
                         $breadcrumbs[] = array(
                             'url' => false,
-                            'title' => $page['title']
+                            'title' => $page['title'],
+                            'class' => 'unavailable',
                         );
                     } else {
@@ -275,5 +278,6 @@
                         $breadcrumbs[] = array(
                             'url' => $page['url'],
-                            'title' => $page['title']
+                            'title' => $page['title'],
+                            'class' => '',
                         );
                     }
@@ -334,4 +338,28 @@
     }
 
+    /*
+    *
+    *
+    * @access   public
+    * @param
+    * @return
+    * @author   Quinn Comendant <quinn@strangecode.com>
+    * @version  1.0
+    * @since    07 Sep 2014 12:22:19
+    */
+    public function getBreadcrumbsUL()
+    {
+        $breadcrumbs = $this->getBreadcrumbsArray();
+        if (!empty($breadcrumbs)) {
+            ?><ul class="breadcrumbs"><?php
+            foreach ($breadcrumbs as $b) {
+                $printclass = '' != $b['class'] ? sprintf(' class="%s"', $b['class']) : '';
+                printf('<li%s><a href="%s">%s</a></li>', $printclass, $b['url'], $b['title']);
+            }
+            ?></ul><?php
+        }
+        unset($key, $value);
+    }
+
     /**
      * Test if the given URI matches the URL of the current page. By default the URI is tested
Index: trunk/lib/SortOrder.inc.php
===================================================================
--- trunk/lib/SortOrder.inc.php	(revision 494)
+++ trunk/lib/SortOrder.inc.php	(revision 497)
@@ -212,10 +212,10 @@
             if ($this->sort_by == $col) {
                 if (mb_strtolower($this->order) == 'desc') {
-                    ?><a href="<?php echo $app->oHREF($_SERVER['PHP_SELF'] . '?sort=' . $col . '&order=ASC'); ?>" title="<?php echo _("Change to ascending sort order"); ?>"><?php echo $this->desc_widget; ?></a><?php echo $col_name; ?><?php
+                    ?><a href="<?php echo $app->oHREF($_SERVER['PHP_SELF'] . '?sort=' . $col . '&order=ASC'); ?>" title="<?php echo _("Change to ascending sort order"); ?>" class="sc-sort sc-desc"><?php echo $this->desc_widget; ?></a><?php echo $col_name; ?><?php
                 } else {
-                    ?><a href="<?php echo $app->oHREF($_SERVER['PHP_SELF'] . '?sort=' . $col . '&order=DESC'); ?>" title="<?php echo _("Change to descending sort order"); ?>"><?php echo $this->asc_widget; ?></a><?php echo $col_name; ?><?php
+                    ?><a href="<?php echo $app->oHREF($_SERVER['PHP_SELF'] . '?sort=' . $col . '&order=DESC'); ?>" title="<?php echo _("Change to descending sort order"); ?>" class="sc-sort sc-asc"><?php echo $this->asc_widget; ?></a><?php echo $col_name; ?><?php
                 }
             } else {
-                ?><a href="<?php echo $app->oHREF($_SERVER['PHP_SELF'] . '?sort=' . $col . '&order=' . $default_order); ?>" title="<?php echo sprintf(_("Sort by %s"), $col_name); ?>"><?php echo $col_name; ?></a><?php
+                ?><a href="<?php echo $app->oHREF($_SERVER['PHP_SELF'] . '?sort=' . $col . '&order=' . $default_order); ?>" title="<?php echo sprintf(_("Sort by %s"), $col_name); ?>" class="sc-sort"><?php echo $col_name; ?></a><?php
             }
         } else {
Index: trunk/lib/Utilities.inc.php
===================================================================
--- trunk/lib/Utilities.inc.php	(revision 494)
+++ trunk/lib/Utilities.inc.php	(revision 497)
@@ -1082,27 +1082,79 @@
 }
 
-/**
- * Returns the remote IP address, taking into consideration proxy servers.
- *
- * @param  bool $dolookup   If true we resolve to IP to a host name,
- *                          if false we don't.
- * @return string    IP address if $dolookup is false or no arg
- *                   Hostname if $dolookup is true
- */
-function getRemoteAddr($dolookup=false)
-{
-    $ip = getenv('HTTP_CLIENT_IP');
-    if (in_array($ip, array('', 'unknown', 'localhost', '127.0.0.1'))) {
-        $ip = getenv('HTTP_X_FORWARDED_FOR');
-        if (mb_strpos($ip, ',') !== false) {
-            // If HTTP_X_FORWARDED_FOR returns a comma-delimited list of IPs then return the first one (assuming the first is the original).
-            $ips = explode(',', $ip, 2);
-            $ip = $ips[0];
-        }
-        if (in_array($ip, array('', 'unknown', 'localhost', '127.0.0.1'))) {
-            $ip = getenv('REMOTE_ADDR');
-        }
-    }
-    return $dolookup && '' != $ip ? gethostbyaddr($ip) : $ip;
+/*
+* Returns the remote IP address, taking into consideration proxy servers.
+*
+* If strict checking is enabled, we will only trust REMOTE_ADDR or an HTTP header
+* value if REMOTE_ADDR is a trusted proxy (configured as an array in $cfg['trusted_proxies']).
+*
+* @access   public
+* @param    bool $dolookup            Resolve to IP to a hostname?
+* @param    bool $trust_all_proxies   Should we trust any IP address set in HTTP_* variables? Set to FALSE for secure usage.
+* @return   mixed Canonicalized IP address (or a corresponding hostname if $dolookup is true), or false if no IP was found.
+* @author   Alix Axel <http://stackoverflow.com/a/2031935/277303>
+* @author   Corey Ballou <http://blackbe.lt/advanced-method-to-obtain-the-client-ip-in-php/>
+* @author   Quinn Comendant <quinn@strangecode.com>
+* @version  1.0
+* @since    12 Sep 2014 19:07:46
+*/
+function getRemoteAddr($dolookup=false, $trust_all_proxies=true)
+{
+    global $cfg;
+
+    if (!isset($_SERVER['REMOTE_ADDR'])) {
+        // Must be a CLI.
+        return false;
+    }
+
+    // Use an HTTP header value only if $trust_all_proxies is true or when REMOTE_ADDR is in our $cfg['trusted_proxies'] array.
+    // $cfg['trusted_proxies'] is an array of proxy server addresses we expect to see in REMOTE_ADDR.
+    if ($trust_all_proxies || isset($cfg['trusted_proxies']) && is_array($cfg['trusted_proxies']) && in_array($_SERVER['REMOTE_ADDR'], $cfg['trusted_proxies'], true)) {
+        // Then it's probably safe to use an IP address value set in an HTTP header.
+        // Loop through possible IP address headers.
+        foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED') as $key) {
+            // Loop through and if
+            if (array_key_exists($key, $_SERVER)) {
+                foreach (explode(',', $_SERVER[$key]) as $addr) {
+                    $addr = canonicalIPAddr(trim($addr));
+                    if (false !== filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
+                        return $dolookup && '' != $addr ? gethostbyaddr($addr) : $addr;
+                    }
+                }
+            }
+        }
+    }
+
+    $addr = canonicalIPAddr(trim($_SERVER['REMOTE_ADDR']));
+    return $dolookup && $addr ? gethostbyaddr($addr) : $addr;
+}
+
+/*
+* Converts an ipv4 IP address in hexadecimal form into canonical form (i.e., it removes the prefix).
+*
+* @access   public
+* @param    string  $addr   IP address.
+* @return   string          Canonical IP address.
+* @author   Sander Steffann <http://stackoverflow.com/a/12436099/277303>
+* @author   Quinn Comendant <quinn@strangecode.com>
+* @version  1.0
+* @since    15 Sep 2012
+*/
+function canonicalIPAddr($addr)
+{
+    // Known prefix
+    $v4mapped_prefix_bin = pack('H*', '00000000000000000000ffff');
+
+    // Parse
+    $addr_bin = inet_pton($addr);
+
+    // Check prefix
+    if (substr($addr_bin, 0, strlen($v4mapped_prefix_bin)) == $v4mapped_prefix_bin) {
+        // Strip prefix
+        echo 'prefix matches';
+        $addr_bin = substr($addr_bin, strlen($v4mapped_prefix_bin));
+    }
+
+    // Convert back to printable address in canonical form
+    return inet_ntop($addr_bin);
 }
 
@@ -1117,5 +1169,5 @@
  * @return  mixed   Returns the network that matched on success, false on failure.
  */
-function ipInRange($ip, $networks)
+function ipInRange($addr, $networks)
 {
     if (!is_array($networks)) {
@@ -1123,5 +1175,5 @@
     }
 
-    $ip_binary = sprintf('%032b', ip2long($ip));
+    $addr_binary = sprintf('%032b', ip2long($addr));
     foreach ($networks as $network) {
         if (preg_match('![\d\.]{7,15}/\d{1,2}!', $network)) {
@@ -1129,10 +1181,10 @@
             list($cidr_ip, $cidr_bitmask) = explode('/', $network);
             $cidr_ip_binary = sprintf('%032b', ip2long($cidr_ip));
-            if (mb_substr($ip_binary, 0, $cidr_bitmask) === mb_substr($cidr_ip_binary, 0, $cidr_bitmask)) {
+            if (mb_substr($addr_binary, 0, $cidr_bitmask) === mb_substr($cidr_ip_binary, 0, $cidr_bitmask)) {
                // IP address is within the specified IP range.
                return $network;
             }
         } else {
-            if ($ip === $network) {
+            if ($addr === $network) {
                // IP address exactly matches.
                return $network;
Index: trunk/lib/Version.inc.php
===================================================================
--- trunk/lib/Version.inc.php	(revision 494)
+++ trunk/lib/Version.inc.php	(revision 497)
@@ -266,6 +266,6 @@
         ");
         if (!$record = mysql_fetch_assoc($qid)) {
-            $app->raiseMsg(sprintf(_("Version ID %s%s not found."), $version_id, (empty($record['version_title']) ? '' : ' (' . $record['version_title'] . ')')), MSG_WARNING, __FILE__, __LINE__);
-            $app->logMsg(sprintf('Version ID %s%s not found.', $version_id, (empty($record['version_title']) ? '' : ' (' . $record['version_title'] . ')')), LOG_WARNING, __FILE__, __LINE__);
+            $app->raiseMsg(sprintf(_("Version %s%s not found."), $version_id, (empty($record['version_title']) ? '' : ' (' . $record['version_title'] . ')')), MSG_WARNING, __FILE__, __LINE__);
+            $app->logMsg(sprintf('Version %s%s not found.', $version_id, (empty($record['version_title']) ? '' : ' (' . $record['version_title'] . ')')), LOG_WARNING, __FILE__, __LINE__);
             return false;
         }
@@ -274,6 +274,6 @@
         // Ensure saved db columns match current table schema.
         if (!$db->columnExists($record['record_table'], array_keys($data), $this->getParam('db_schema_strict'))) {
-            $app->raiseMsg(sprintf(_("Version ID %s%s is not compatible with the current database table."), $version_id, (empty($record['version_title']) ? '' : ' (' . $record['version_title'] . ')')), MSG_ERR, __FILE__, __LINE__);
-            $app->logMsg(sprintf('Version ID %s%s restoration failed, DB schema does not match for table %s.', $version_id, (empty($record['version_title']) ? '' : ' (' . $record['version_title'] . ')'), $record['record_table']), LOG_ALERT, __FILE__, __LINE__);
+            $app->raiseMsg(sprintf(_("Version %s%s is not compatible with the current database table."), $version_id, (empty($record['version_title']) ? '' : ' (' . $record['version_title'] . ')')), MSG_ERR, __FILE__, __LINE__);
+            $app->logMsg(sprintf('Version %s%s restoration failed, DB schema does not match for table %s.', $version_id, (empty($record['version_title']) ? '' : ' (' . $record['version_title'] . ')'), $record['record_table']), LOG_ALERT, __FILE__, __LINE__);
             return false;
         }
