<?php
/*******************************************************************************
 *
 * LEIDEN OPEN VARIATION DATABASE (LOVD)
 *
 * Created     : 2006-07-11
 * Modified    : 2010-03-12
 * For LOVD    : 2.0-25
 *
 * Access      : Administrator and managers.
 * Purpose     : Create and manage LOVD authorized users (curators, managers,
 *               database administrator).
 *
 * Copyright   : 2004-2010 Leiden University Medical Center; http://www.LUMC.nl/
 * Programmer  : Ing. Ivo F.A.C. Fokkema <I.F.A.C.Fokkema@LUMC.nl>
 * Last edited : Ing. Ivo F.A.C. Fokkema <I.F.A.C.Fokkema@LUMC.nl>
 *
 *
 * This file is part of LOVD.
 *
 * LOVD 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 2 of the License, or
 * (at your option) any later version.
 *
 * LOVD 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 LOVD; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *************/

define('ROOT_PATH', './');
require ROOT_PATH . 'inc-init.php';

if (HAS_AUTH) {
    // If authorized, check for updates.
    require ROOT_PATH . 'inc-upgrade.php';
}

// Require manager clearance.
lovd_requireAUTH(LEVEL_MANAGER);





if ($_GET['action'] == 'view_all') {
    // View all users.

    require ROOT_PATH . 'inc-lib-list.php';
    require ROOT_PATH . 'inc-top.php';
// FIXME; get menu fixed up?
//    lovd_includeJS(ROOT_PATH . 'inc-js-user_menu.js');
    lovd_printHeader('setup_users_manage', 'LOVD Setup - Manage authorized users');

    list($nTotal) = mysql_fetch_row(mysql_query('SELECT COUNT(*) FROM ' . TABLE_USERS));
    if (!$nTotal) {
        // IMPOSSIBLE!!!
        print('      There are no users with this system.<BR>' . "\n");
        require ROOT_PATH . 'inc-bot.php';
        exit;
    }

    // Standard query, will be extended later on.
    $sQ = 'SELECT u.*, (u.login_attempts >= 3) AS locked, COUNT(c.symbol) AS curates FROM ' . TABLE_USERS . ' AS u LEFT OUTER JOIN ' . TABLE_CURATES . ' AS c USING (userid)';

    // SORT: Current settings.
    // 2008-08-07; 2.0-10; Implement XSS check on order variable.
    if (isset($_GET['order']) && $_GET['order'] && $_GET['order'] == strip_tags($_GET['order'])) {
        $aOrder = explode(',', $_GET['order']);
    } else {
        $aOrder = array('', '');
    }

    // SORT: Column data.
    $aOrderList = array('userid' => array('userid', 'ASC'), 'name' => array('name', 'ASC'), 'username' => array('username', 'ASC'), 'level' => array('level', 'DESC'), 'last_login' => array('last_login', 'DESC'), 'created_date' => array('created_date', 'ASC'));
    if (!array_key_exists($aOrder[0], $aOrderList)) {
        $aOrder[0] = 'level';
    }
    if ($aOrder[1] != 'ASC' && $aOrder[1] != 'DESC') {
        $aOrder[1] = $aOrderList[$aOrder[0]][1];
    }

    $sQ .= ' GROUP BY u.userid';
    $sQueryLimit = lovd_pagesplitInit($nTotal, 25);
    $sQ .= ' ORDER BY deleted ASC, ' . $aOrderList[$aOrder[0]][0] . ' ' . $aOrder[1] . ', level DESC, name ' . $sQueryLimit;



    // Show form; required for sorting and searching.
    print('      <FORM action="' . $_SERVER['PHP_SELF'] . '" method="get" style="margin : 0px;">' . "\n" .
          '        <INPUT type="hidden" name="action" value="' . $_GET['action'] . '">' . "\n" .
          '        <INPUT type="hidden" name="order" value="' . implode(',', $aOrder) . '">');
    print('</FORM>' . "\n\n");

    $q = mysql_query($sQ);
    if (!$q) {
        lovd_dbFout('Users' . ucfirst($_GET['action']), $sQ, mysql_error());
    }

    $n = (isset($nResults)? $nResults : $nTotal);
    print('      <SPAN class="S11">' . $n . ' entr' . ($n == 1? 'y' : 'ies') . '</SPAN><BR>' . "\n");

    // Array which will make up the table (header and data).
    $aTable =
             array(
                    'userid' => array('ID', '40'),
                    'name' => array('Name', '*'),
                    'username' => array('Username', '*'),
                    'current_db' => array('Current DB', '80'),
                    'curates' => array('Curated DBs', '90'),
                    'status_' => array('Status', '50', 'align="center"'),
                    'last_login' => array('Last login', '140'),
                    'level' => array('Level', '150'),
                  );

    // Table.
    print('      <TABLE border="0" cellpadding="0" cellspacing="1" width="950" class="data">' . "\n" .
          '        <TR>');

    foreach ($aTable as $sField => $aCol) {
        print("\n" . '          <TH' . (!empty($aCol[2])? ' ' . $aCol[2] : '') . (is_numeric($aCol[1])? ' width="' . $aCol[1] . '"' : '') . (array_key_exists($sField, $aOrderList)? ' class="order' . ($aOrder[0] == $sField? 'ed' : '') . '" onclick="document.forms[0].order.value=\'' . $sField . ',' . ($aOrder[0] == $sField? ($aOrder[1] == 'ASC'? 'DESC' : 'ASC') : $aOrderList[$sField][1]) . '\';document.forms[0].submit();"' : '') . '>' .
              (array_key_exists($sField, $aOrderList)? "\n" .
                                                           '            <TABLE border="0" cellpadding="0" cellspacing="0" width="100%" class="S11">' . "\n" .
                                                           '              <TR>' . "\n" .
                                                           '                <TH>' . str_replace(' ', '&nbsp;', $aCol[0]) . '</TH>' . "\n" .
                                                           '                <TD align="right"><IMG src="gfx/order_arrow_desc' . ($aOrder[0] == $sField && $aOrder[1] == 'DESC'? '_sel' : '') . '.png" alt="Descending" title="Descending" width="13" height="6"><BR><IMG src="gfx/order_arrow_asc' . ($aOrder[0] == $sField && $aOrder[1] == 'ASC'? '_sel' : '') . '.png" alt="Ascending" title="Ascending" width="13" height="6"></TD></TR></TABLE>' : $aCol[0]) . '</TH>');
    }
    print('</TR>');

    while ($zData = mysql_fetch_assoc($q)) {
        print("\n" .
              '        <TR' . ($zData['deleted']? ' class="del"' : '') . ' style="cursor : pointer; cursor : hand;" onmouseover="this.className = \'' . ($zData['deleted']? 'del_' : '') . 'hover\';" onmouseout="this.className = \'' . ($zData['deleted']? 'del' : '') . '\';" onclick="window.location.href = \'' . $_SERVER['PHP_SELF'] . '?action=view&amp;view=' . $zData['userid'] . lovd_showSID(true, true) . '\';">');
// FIXME; get menu fixed up?
//              '        <TR' . ($zData['deleted']? ' class="del"' : '') . ' style="cursor : pointer; cursor : hand;" onmouseover="this.className = \'' . ($zData['deleted']? 'del_' : '') . 'hover\';" onmouseout="this.className = \'' . ($zData['deleted']? 'del' : '') . '\';" onclick="lovd_userMenu(this, \'' . $zData['userid'] . '\'); return false;">');

        $zData['name']          = '<A href="' . $_SERVER['PHP_SELF'] . '?action=view&amp;view=' . $zData['userid'] . '" class="data">' . $zData['name'] . '</A>';
        $bActive                = file_exists(ini_get('session.save_path') . '/sess_' . $zData['phpsessid']);
        $sAlt                   = ($bActive? 'Online' : ($zData['locked']? 'Locked' : 'Offline'));
        $zData['status_']       = ($zData['locked'] || $bActive? '<IMG src="' . ROOT_PATH . 'gfx/' . ($zData['locked']? 'status_locked' : 'status_online') . '.png" alt="' . $sAlt . '" title="' . $sAlt . '" width="14" height="14">' : '');
        $zData['level']         = $_SETT['user_levels'][$zData['level']];

        foreach ($aTable as $sField => $aCol) {
            print("\n" . '          <TD' . (!empty($aCol[2])? ' ' . $aCol[2] : '') . (is_numeric($aCol[1])? ' width="' . $aCol[1] . '"' : '') . ($aOrder[0] == $sField? ' class="ordered"' : '') . '>' . (!$zData[$sField]? '-' : $zData[$sField]) . '</TD>');
        }
        print('</TR>');
    }
    print('</TABLE>' . "\n\n");

    // URL pagelink.
    $sPageLink = 'order=' . rawurlencode(implode(',', $aOrder));

    lovd_pagesplitShowNav($sPageLink);

    require ROOT_PATH . 'inc-bot.php';
    exit;





} elseif ($_GET['action'] == 'view' && is_numeric($_GET['view'])) {
    // View specific user.

    require ROOT_PATH . 'inc-top.php';
    lovd_printHeader('setup_users_manage', 'LOVD Setup - Manage authorized users');

    $zData = @mysql_fetch_assoc(mysql_query('SELECT t1.*, (t1.login_attempts >= 3) AS locked, t2.name AS created_by, t3.name AS edited_by FROM ' . TABLE_USERS . ' AS t1 LEFT OUTER JOIN ' . TABLE_USERS . ' AS t2 ON (t1.created_by = t2.userid) LEFT OUTER JOIN ' . TABLE_USERS . ' AS t3 ON (t1.edited_by = t3.userid) WHERE t1.userid = "' . $_GET['view'] . '"'));
    if (!$zData) {
        // Wrong ID, apparently.
        print('      No such ID!<BR>' . "\n");
        require ROOT_PATH . 'inc-bot.php';
        exit;
    }

    // Array which will make up the data table.
    $aTable =
             array(
                    'userid' => 'User ID',
                    'name' => 'Name',
                    'institute' => 'Institute',
                    'email' => 'Email address',
                    'username' => 'Username',
                    'phpsessid' => 'PHP Session ID',
                    'current_db' => 'Current gene',
                    'curates' => 'Curator for',
                    'list_size' => 'Number of entries per page',
                    'level_' => 'User level',
                    'allowed_ip' => 'Allowed IP address list',
                    'status_' => 'Status',
                    'password_force_change_' => 'Force change password',
                    'locked_' => 'Locked',
                    'last_login' => 'Last login',
                    'deleted_' => 'Deleted',
                    'created_by' => 'Created by',
                    'created_date' => 'Date created',
                    'edited_by' => 'Last edited by',
                    'edited_date' => 'Date last edited',
                  );

    // Prepare information for created by column.
    if (!$zData['created_by']) {
        // Self-registration.
        $zData['created_by'] = $zData['name'];
    }

    // Remove unnecessary columns.
    if ($zData['edited_by'] == NULL) {
        // Never been edited.
        unset($aTable['edited_by'], $aTable['edited_date']);
    }

    // Table.
    print('      <TABLE border="0" cellpadding="0" cellspacing="1" width="600" class="data">');

    // MySQL 4.1 allows group_concat, which would come in handy now. Query is backwards compatible with 4.0.
    $zData['curates'] = '';
    $q = mysql_query('SELECT symbol FROM ' . TABLE_CURATES . ' WHERE userid = "' . $zData['userid'] . '" ORDER BY symbol');
    while (list($sGene) = mysql_fetch_row($q)) {
        $zData['curates'] .= ($zData['curates']? ', ' : '') . $sGene;
    }
    $zData['level_']       = $_SETT['user_levels'][$zData['level']];
    $zData['allowed_ip']   = preg_replace('/[;,]+/', '<BR>', $zData['allowed_ip']);
    $bActive               = file_exists(ini_get('session.save_path') . '/sess_' . $zData['phpsessid']);
    $zData['status_']      = ($bActive? '<IMG src="' . ROOT_PATH . 'gfx/status_online.png" alt="Online" title="Online" width="14" height="14" align="top"> Online' : 'Offline');
    $zData['password_force_change_'] = ($zData['password_force_change']? '<IMG src="gfx/mark_1.png" alt="" width="11" height="11"> Yes' : 'No');
    $zData['locked_']      = ($zData['locked']? '<IMG src="gfx/status_locked.png" alt="Locked" title="Locked" width="14" height="14" align="top"> Locked' : 'No');
    $zData['deleted_']     = ($zData['deleted']? '<IMG src="gfx/light_1_r.png" alt="" width="11" height="11"> Yes' : 'No');

    foreach ($aTable as $sField => $sHeader) {
        print("\n" .
              '        <TR>' . "\n" .
              '          <TH valign="top">' . str_replace(' ', '&nbsp;', $sHeader) . '</TH>' . "\n" .
              '          <TD>' . (!$zData[$sField]? '-' : $zData[$sField]) . '</TD></TR>');
    }
    print('</TABLE>' . "\n\n");

    $sNavigation = '';
    if ($_AUTH['level'] > $zData['level']) {
        // Authorized user (admin or manager) is logged in. Provide tools.
        $sNavigation = '<A href="' . $_SERVER['PHP_SELF'] . '?action=edit&amp;edit=' . $zData['userid'] . '">Edit user</A>';
        if ($bActive) {
            $sNavigation .= ' | <A href="' . $_SERVER['PHP_SELF'] . '?action=boot&amp;boot=' . $zData['userid'] . '&amp;return=' . urlencode($_GET['action'] . '&view=' . $_GET['view']) . '">Force user log out</A>';
        }
        $sNavigation .= ' | <A href="' . $_SERVER['PHP_SELF'] . '?action=' . ($zData['locked']? 'un' : '') . 'lock&amp;lock=' . $zData['userid'] . '&amp;return=' . urlencode($_GET['action'] . '&view=' . $_GET['view']) . '">' . ($zData['locked']? 'Unl' : 'L') . 'ock user</A>';
        if (!$zData['deleted']) {
            $sNavigation .= ' | <A href="' . $_SERVER['PHP_SELF'] . '?action=drop&amp;drop=' . $zData['userid'] . '">Delete user</A>';
        }
    } elseif ($_AUTH['userid'] == $zData['userid']) {
        // Viewing himself!
        $sNavigation = '<A href="account_update.php?action=edit">Update your registration</A>';
    }

    if ($sNavigation) {
        print('      <IMG src="gfx/trans.png" alt="" width="1" height="5"><BR>' . "\n");
        lovd_viewNavigation($sNavigation);
    }

    require ROOT_PATH . 'inc-bot.php';
    exit;





} elseif ($_GET['action'] == 'boot' && is_numeric($_GET['boot'])) {
    // Throw a user out of the system.

    $zData = @mysql_fetch_assoc(mysql_query('SELECT t1.phpsessid, t1.level FROM ' . TABLE_USERS . ' AS t1 WHERE t1.userid = "' . $_GET['boot'] . '"'));
    if (!$zData || $zData['level'] >= $_AUTH['level']) {
        // Wrong ID, apparently.
        require ROOT_PATH . 'inc-top.php';
        lovd_printHeader('setup_users_manage', 'LOVD Setup - Manage authorized users');

        print('      No such ID!<BR>' . "\n");
        require ROOT_PATH . 'inc-bot.php';
        exit;
    }

    $sFile = ini_get('session.save_path') . '/sess_' . $zData['phpsessid'];
    if (file_exists($sFile)) {
        @unlink($sFile);
    }

    // Write to log...
    lovd_writeLog('MySQL:Event', 'UserBoot', $_AUTH['username'] . ' (' . mysql_real_escape_string($_AUTH['name']) . ') successfully booted user ' . $_POST['username'] . ' (' . $_POST['name'] . ')');
    
    // Return the user where they came from.
    // FIXME; wasn't this for the menu that was never implemented?
    $sAction = (!empty($_GET['return'])? $_GET['return'] . (isset($_GET[$_GET['return']])? '&' . $_GET['return'] . '=' . $_GET[$_GET['return']] : ''): 'view_all');
    header('Location: ' . PROTOCOL . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . '?action=' . $sAction . lovd_showSID(true));
    exit;





} elseif (in_array($_GET['action'], array('lock', 'unlock')) && is_numeric($_GET['lock'])) {
    // Lock / unlock a user.

    $zData = @mysql_fetch_assoc(mysql_query('SELECT username, name, (login_attempts >= 3) AS locked, level FROM ' . TABLE_USERS . ' WHERE userid = "' . $_GET['lock'] . '"'));
    if (!$zData || $zData['level'] >= $_AUTH['level']) {
        // Wrong ID, apparently.
        require ROOT_PATH . 'inc-top.php';
        lovd_printHeader('setup_users_manage', 'LOVD Setup - Manage authorized users');
        lovd_showInfoTable('No such ID!', 'stop');
        require ROOT_PATH . 'inc-bot.php';
        exit;
    }

    // What are we doing?
    $sAction = ($zData['locked']? 'Unl' : 'L') . 'ock';

    // The actual query.
    $sQ = 'UPDATE ' . TABLE_USERS . ' SET login_attempts = ' . ($zData['locked']? 0 : 3) . ' WHERE userid = "' . $_GET['lock'] . '"';
    $q = @mysql_query($sQ);
    if (!$q) {
        $sError = mysql_error(); // Save the mysql_error before it disappears.
        require ROOT_PATH . 'inc-top.php';
        lovd_printHeader('setup_users_manage', 'LOVD Setup - Manage authorized users');
        lovd_dbFout('User' . $sAction, $sQ, $sError);
    }

    // Write to log...
    lovd_writeLog('MySQL:Event', 'User' . $sAction, $_AUTH['username'] . ' (' . mysql_real_escape_string($_AUTH['name']) . ') successfully ' . strtolower($sAction) . 'ed user ' . $zData['username'] . ' (' . $zData['name'] . ')');

    // Return the user where they came from.
    // FIXME; wasn't this for the menu that was never implemented?
    $sAction = (!empty($_GET['return'])? $_GET['return'] . (isset($_GET[$_GET['return']])? '&' . $_GET['return'] . '=' . $_GET[$_GET['return']] : ''): 'view_all');
    header('Location: ' . PROTOCOL . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . '?action=' . $sAction . lovd_showSID(true));
    exit;





} elseif ($_GET['action'] == 'create') {
    // Create new user.

    // Require form functions.
    require ROOT_PATH . 'inc-lib-form.php';

    if (isset($_GET['sent'])) {
        lovd_errorClean();

        // Mandatory fields.
        $aCheck =
                 array(
                        'name' => 'Name',
                        'institute' => 'Institute',
                        'email' => 'Email address',
                        'username' => 'Username',
                        'password_1' => 'Password',
                        'password_2' => 'Password (confirm)',
                        'allowed_ip' => 'Allowed IP address list',
                        'password' => 'Enter your password for authorization',
                      );

        foreach ($aCheck as $key => $val) {
            if (empty($_POST[$key])) {
                lovd_errorAdd('Please fill in the \'' . $val . '\' field.');
            }
        }

        // 2008-08-07; 2.0-10; Block newlines to prevent registration form from being used as a spam sender.
        // Fields not allowed to contain newlines (hack attempt - sending spam using the form).
        $aCheck =
                 array(
                        'name' => 'Name',
                      );

        foreach ($aCheck as $key => $val) {
            if (substr_count($_POST[$key], "\n")) {
                lovd_errorAdd('Disallowed newline found in form field "' . $val . '". SPAM attack?');
            }
        }

        // Check username format.
        if ($_POST['username'] && !lovd_matchUsername($_POST['username'])) {
            lovd_errorAdd('Please fill in a correct username; 4 to 20 characters and starting with a letter followed by letters, numbers, dots, underscores and dashes only.');
        }

        // Does the username exist already?
        // We check in both tables to be able to provide one login form.
        if ($_POST['username']) {
            list($nSubs) = mysql_fetch_row(mysql_query('SELECT COUNT(*) FROM ' . TABLE_SUBS . ' WHERE username = "' . $_POST['username'] . '"'));
            list($nUsers) = mysql_fetch_row(mysql_query('SELECT COUNT(*) FROM ' . TABLE_USERS . ' WHERE username = "' . $_POST['username'] . '"'));
            
            if ($nSubs || $nUsers) {
                lovd_errorAdd('There is already a user with this username. Please choose another one.');
            }
        }

        // Email address.
        if ($_POST['email'] && !lovd_matchEmail($_POST['email'])) {
            lovd_errorAdd('Please fill in a correct email address.');
        }

        // One of two password fields entered... check 'em.
        if ($_POST['password_1'] || $_POST['password_2']) {
            if ($_POST['password_1'] && $_POST['password_2']) {
                // Both entered.
                if ($_POST['password_1'] != $_POST['password_2']) {
                    lovd_errorAdd('The \'Password\' fields are not equal. Please try again.');
                } else {
                    // Password quality.
                    if (!lovd_matchPassword($_POST['password_1'])) {
                        lovd_errorAdd('Your password is found too weak. Please fill in a proper password; at least 4 characters long and containing at least one number or special character.');
                    }
                }
            } else {
                lovd_errorAdd('Please fill in both \'Password\' fields.');
            }
        }

        // Check given security IP range.
        if (trim($_POST['allowed_ip'])) {
            // This function will throw an error itself (second argument).
            $bIP = lovd_matchIPRange($_POST['allowed_ip'], true);
        } else {
            $_POST['allowed_ip'] = '*';
        }

        // Level can't be higher or equal than the current user.
        if ($_POST['level'] >= $_AUTH['level']) {
            lovd_errorAdd('User level is not permitted. Hack attempt.');
        }

        // User had to enter his/her password for authorization.
        if ($_POST['password'] && md5($_POST['password']) != $_AUTH['password']) {
            lovd_errorAdd('Please enter your correct password for authorization.');
        }

        // 2006-12-07; 2.0-alpha-02
        // XSS attack prevention. Simply deny input of HTML, PHP other stuff blocked by strip_tags().
        lovd_checkXSS();

        if (!lovd_error()) {
            // Query text.
            $sQ = 'INSERT INTO ' . TABLE_USERS . ' VALUES (NULL, ';

            $_POST['password'] = md5($_POST['password_1']);
            $_POST['password_autogen'] = '';
            $_POST['phpsessid'] = '';
            $_POST['current_db'] = '';

            // Standard fields to be used.
            $aQ = array('name', 'institute', 'email', 'username', 'password', 'password_autogen', 'password_force_change', 'phpsessid', 'current_db', 'list_size', 'level', 'allowed_ip', 'login_attempts');

            // Lock / Unlock user.
            $_POST['login_attempts'] = ($_POST['locked']? 3 : 0);

            foreach ($aQ as $key => $val) {
                $sQ .= ($key? ', ' : '') . '"' . $_POST[$val] . '"';
            }

            $sQ .= ', NULL, ' . (int) $_POST['deleted'] . ', ' . $_AUTH['userid'] . ', NOW(), NULL, NULL)';

            $q = mysql_query($sQ);
            if (!$q) {
                $sError = mysql_error(); // Save the mysql_error before it disappears.
                require ROOT_PATH . 'inc-top.php';
                lovd_printHeader('setup_users_create', 'LOVD Setup - Create new authorized user');
                lovd_dbFout('UserCreate', $sQ, $sError);
            }

            $nID = str_pad(mysql_insert_id(), 3, '0', STR_PAD_LEFT);

            // Write to log...
            lovd_writeLog('MySQL:Event', 'UserCreate', $_AUTH['username'] . ' (' . mysql_real_escape_string($_AUTH['name']) . ') successfully created user ' . $_POST['username'] . ' (' . $_POST['name'] . ') with level ' . $_SETT['user_levels'][$_POST['level']]);

            // Add as curator.
            if (isset($_POST['curates'])) {
                foreach ($_POST['curates'] AS $sSymbol) {
                    // User has requested addition...
                    $q = mysql_query('INSERT INTO ' . TABLE_CURATES . ' VALUES ("' . $nID . '", "' . $sSymbol . '")');
                    if (!$q) {
                        // Silent error.
                        lovd_writeLog('MySQL:Error', 'UserCreate', $_POST['username'] . ' (' . $_POST['name'] . ') could not be added as curator for ' . $sSymbol);
                    } else {
                        lovd_writeLog('MySQL:Event', 'UserCreate', $_POST['username'] . ' (' . $_POST['name'] . ') successfully added as curator for ' . $sSymbol);
                    }
                }
            }

            // Thank the user...
            header('Refresh: 3; url=' . PROTOCOL . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . '?action=view&view=' . $nID . lovd_showSID(true));

            require ROOT_PATH . 'inc-top.php';
            lovd_printHeader('setup_users_create', 'LOVD Setup - Create new authorized user');
            print('      Account \'' . stripslashes($_POST['name']) . '\' has successfully been created!<BR><BR>' . "\n\n");

            require ROOT_PATH . 'inc-bot.php';
            exit;

        } else {
            // Errors, so the whole lot returns to the form.
            lovd_magicUnquoteAll();

            // Because we're sending the data back to the form, I need to unset the password fields!
            unset($_POST['password'], $_POST['password_1'], $_POST['password_2']);
        }

    } else {
        // Default values.
        $_POST['list_size'] = 100;
        $_POST['allowed_ip'] = '*';
    }



    require ROOT_PATH . 'inc-top.php';
    lovd_printHeader('setup_users_create', 'LOVD Setup - Create new authorized user');

    if (!isset($_GET['sent'])) {
        print('      To create a new user, please fill out the form below.<BR>' . "\n" .
              '      <BR>' . "\n\n");
    }

    lovd_errorPrint();

    // Table.
    print('      <FORM action="' . $_SERVER['PHP_SELF'] . '?action=' . $_GET['action'] . '&amp;sent=true" method="post">' . "\n" .
          '        <TABLE border="0" cellpadding="0" cellspacing="1" width="760">');

    // Remove user levels that are higher than or equal to the current user's level.
    $aUserLevels = $_SETT['user_levels'];
    for ($i = 9; $i >= $_AUTH['level']; $i --) {
        if (isset($aUserLevels[$i])) {
            unset($aUserLevels[$i]);
        }
    }

    // Get gene list, to select user as curator.
    // 2010-03-12; 2.0-25; This will make this query very complicated, but it will also shorten the gene names quite properly.
    $qGenes = mysql_query('SELECT symbol, CONCAT(SUBSTRING(CONCAT(symbol, " (", gene), 1, 50), SUBSTRING("...)", (((LENGTH(CONCAT(symbol, gene))<49)+1)*3)-2)) AS gene FROM ' . TABLE_DBS . ' ORDER BY symbol');
    $nGenes = mysql_num_rows($qGenes);
    $nGeneSize = ($nGenes < 5? $nGenes : 5);

    // Array which will make up the form table.
    $aForm = array(
                    array('POST', '', '', '50%', '50%'),
                    array('', 'print', '<B>User details</B>'),
                    array('Name', 'text', 'name', 30),
                    array('Institute', 'text', 'institute', 40),
                    array('Email address', 'text', 'email', 30),
                    array('Username', 'text', 'username', 20),
                    array('Password', 'password', 'password_1', 20),
                    array('Password (confirm)', 'password', 'password_2', 20),
                    array('Must change password at next logon', 'checkbox', 'password_force_change', 1),
                    'skip',
                    array('', 'print', '<B>General user settings</B>'),
                    array('Number of entries per page', 'select', 'list_size', 1, array_combine($_SETT['variant_listsizes'], $_SETT['variant_listsizes']), false, false, false),
                    array('', 'print', '<SPAN class="form_note">Variant listings will be split in pages. How many variants do you want to show per page by default?</SPAN>'),
                    'skip',
                    array('', 'print', '<B>Security</B>'),
                    array('Level', 'select', 'level', 1, $aUserLevels, false, false, false),
                    array('Allowed IP address list', 'text', 'allowed_ip', 20),
                    array('', 'print', '<SPAN class="form_note"><I>Your current IP address: ' . $_SERVER['REMOTE_ADDR'] . '</I><BR>To help prevent others to try and guess the username/password combination, you can restrict access to the account to a number of IP addresses or ranges.<BR><B>Please be extremely careful using this setting.</B> Using this setting too strictly, can deny the user access to LOVD, even if the correct credentials have been provided.<BR>Set to \'*\' to allow all IP addresses, use \'-\' to specify a range and use \';\' to separate addresses or ranges.</SPAN>'),
                    array('Locked', 'checkbox', 'locked', 0),
                    array('Deleted', 'checkbox', 'deleted', 0),
                    'skip',
                    array('', 'print', '<B>Curated genes</B>'),
                    array('Curator for', 'select', 'curates', $nGeneSize, $qGenes, false, true, true),
                    'skip',
                    array('Enter your password for authorization', 'password', 'password', 20),
                    array('', 'submit', 'Create user'),
                  );
    $_MODULES->processForm('SetupUsersCreate', $aForm);
    lovd_viewForm($aForm);

    print('</TABLE></FORM>' . "\n\n");

    require ROOT_PATH . 'inc-bot.php';
    exit;





} elseif ($_GET['action'] == 'edit' && is_numeric($_GET['edit'])) {
    // Edit specific user.

    $zData = @mysql_fetch_assoc(mysql_query('SELECT *, (login_attempts >= 3) AS locked FROM ' . TABLE_USERS . ' WHERE userid = "' . $_GET['edit'] . '"'));
    if (!$zData) {
        // Wrong ID, apparently.
        require ROOT_PATH . 'inc-top.php';
        lovd_printHeader('setup_users_manage', 'LOVD Setup - Manage authorized users');
        print('      No such ID!<BR>' . "\n");
        require ROOT_PATH . 'inc-bot.php';
        exit;
    }

    if ($zData['level'] >= $_AUTH['level']) {
        // This is a hack-attempt.
        require ROOT_PATH . 'inc-top.php';
        lovd_printHeader('setup_users_manage', 'LOVD Setup - Manage authorized users');
        lovd_writeLog('MySQL:Error', 'HackAttempt', $_AUTH['username'] . ' (' . mysql_real_escape_string($_AUTH['name']) . ') tried to edit ' . $zData['username'] . ' (' . mysql_real_escape_string($zData['name']) . ')');
        print('      Hack Attempt.<BR>' . "\n");
        require ROOT_PATH . 'inc-bot.php';
        exit;
    }

    // Require form functions.
    require ROOT_PATH . 'inc-lib-form.php';

    if (isset($_GET['sent'])) {
        lovd_errorClean();

        // Mandatory fields.
        $aCheck =
                 array(
                        'name' => 'Name',
                        'institute' => 'Institute',
                        'email' => 'Email address',
                        'allowed_ip' => 'Allowed IP address list',
                        'password' => 'Enter your password for authorization',
                      );

        foreach ($aCheck as $key => $val) {
            if (empty($_POST[$key])) {
                lovd_errorAdd('Please fill in the \'' . $val . '\' field.');
            }
        }

        // 2008-08-07; 2.0-10; Block newlines to prevent registration form from being used as a spam sender.
        // Fields not allowed to contain newlines (hack attempt - sending spam using the form).
        $aCheck =
                 array(
                        'name' => 'Name',
                      );

        foreach ($aCheck as $key => $val) {
            if (substr_count($_POST[$key], "\n")) {
                lovd_errorAdd('Disallowed newline found in form field "' . $val . '". SPAM attack?');
            }
        }

        // Email address.
        if ($_POST['email'] && !lovd_matchEmail($_POST['email'])) {
            lovd_errorAdd('Please fill in a correct email address.');
        }

        // One of two password fields entered... check 'em.
        if ($_POST['password_1'] || $_POST['password_2']) {
            if ($_POST['password_1'] && $_POST['password_2']) {
                // Both entered.
                if ($_POST['password_1'] != $_POST['password_2']) {
                    lovd_errorAdd('The \'New password\' fields are not equal. Please try again.');
                } else {
                    // Password quality.
                    if (!lovd_matchPassword($_POST['password_1'])) {
                        lovd_errorAdd('Your password is found too weak. Please fill in a proper password; at least 4 characters long and containing at least one number or special character.');
                    }
                }
            } else {
                lovd_errorAdd('If you want to change the current password, please fill in both \'New password\' fields.');
            }
        }

        // Check given security IP range.
        if (trim($_POST['allowed_ip'])) {
            // This function will throw an error itself (second argument).
            $bIP = lovd_matchIPRange($_POST['allowed_ip'], true);
        } else {
            $_POST['allowed_ip'] = '*';
        }

        // Level can't be higher or equal than the current user.
        if ($_POST['level'] >= $_AUTH['level']) {
            lovd_errorAdd('User level is not permitted. Hack attempt.');
        }

        // User had to enter his/her password for authorization.
        if ($_POST['password'] && md5($_POST['password']) != $_AUTH['password']) {
            lovd_errorAdd('Please enter your correct password for authorization.');
        }

        // Select genes to curate.
        if (!isset($_POST['curates'])) {
            // Why is this variable unset if nothing has been selected?!!??
            $_POST['curates'] = array();
        }

        $q = mysql_query('SELECT t1.symbol, t1.gene, COUNT(t2.userid) AS count FROM ' . TABLE_DBS . ' AS t1 LEFT OUTER JOIN ' . TABLE_CURATES . ' AS t2 ON (t1.symbol = t2.symbol AND t2.userid != "' . $zData['userid'] . '") GROUP BY t1.symbol ORDER BY t1.symbol');
        while ($z = mysql_fetch_assoc($q)) {
            // Gene has no curator, and user hasn't been selected as one.
            if (!$z['count'] && !in_array($z['symbol'], $_POST['curates'])) {
                lovd_errorAdd('This gene has no curator: ' . $z['symbol'] . ' (' . $z['gene'] . '). Please (re)select the user as a curator for this gene.');
            }
        }

        // 2006-12-07; 2.0-alpha-02
        // XSS attack prevention. Simply deny input of HTML, PHP other stuff blocked by strip_tags().
        lovd_checkXSS();

        if (!lovd_error()) {
            // Query text.
            $sQ = 'UPDATE ' . TABLE_USERS . ' SET ';

            // Standard fields to be used.
            $aQ = array('name', 'institute', 'email', 'password_force_change', 'list_size', 'level', 'allowed_ip', 'login_attempts', 'deleted');

            // 2008-07-16; 2.0-09; A user can no longer be deleted through the edit form.
            if (!$zData['deleted']) {
                unset($aQ[array_search('deleted', $aQ)]);
            }

            // In case the password is getting changed...
            if ($_POST['password_1']) {
                $_POST['password'] = md5($_POST['password_1']);
                $aQ[] = 'password';
            }

            // Lock / Unlock user.
            $_POST['login_attempts'] = ($_POST['locked']? 3 : 0);

            foreach ($aQ as $key => $val) {
                $sQ .= ($key? ', ' : '') . $val . ' = "' . $_POST[$val] . '"';
            }

            $sQ .= ', edited_by = "' . $_AUTH['userid'] . '", edited_date = NOW() WHERE userid = ' . $zData['userid'];

            $q = mysql_query($sQ);
            if (!$q) {
                $sError = mysql_error(); // Save the mysql_error before it disappears.
                require ROOT_PATH . 'inc-top.php';
                lovd_printHeader('setup_users_manage', 'LOVD Setup - Manage authorized users');
                lovd_dbFout('UserEdit', $sQ, $sError);
            }

            // Write to log...
            lovd_writeLog('MySQL:Event', 'UserEdit', $_AUTH['username'] . ' (' . mysql_real_escape_string($_AUTH['name']) . ') successfully edited user ' . $zData['username'] . ' (' . $_POST['name'] . ')');

            // Change curator?
            // Fetch genes user is currently curator for.
            $aCurates = array();
            $q = mysql_query('SELECT symbol FROM ' . TABLE_CURATES . ' WHERE userid = "' . $zData['userid'] . '"');
            while ($r = mysql_fetch_row($q)) {
                $aCurates[] = $r[0];
            }

            // Remove as curator.
            foreach ($aCurates AS $sSymbol) {
                if (!in_array($sSymbol, $_POST['curates'])) {
                    // User has requested removal...
                    $q = mysql_query('DELETE FROM ' . TABLE_CURATES . ' WHERE symbol = "' . $sSymbol . '" AND userid = "' . $zData['userid'] . '"');
                    if (!$q) {
                        // Silent error.
                        lovd_writeLog('MySQL:Error', 'UserEdit', $zData['username'] . ' (' . mysql_real_escape_string($zData['name']) . ') could not be removed as curator for ' . $sSymbol);
                    } else {
                        lovd_writeLog('MySQL:Event', 'UserEdit', $zData['username'] . ' (' . mysql_real_escape_string($zData['name']) . ') successfully removed as curator for ' . $sSymbol);
                    }
                }
            }

            // Add as curator.
            if (isset($_POST['curates'])) {
                foreach ($_POST['curates'] AS $sSymbol) {
                    if (!in_array($sSymbol, $aCurates)) {
                        // User has requested addition...
                        $q = mysql_query('INSERT INTO ' . TABLE_CURATES . ' VALUES ("' . $zData['userid'] . '", "' . $sSymbol . '")');
                        if (!$q) {
                            // Silent error.
                            lovd_writeLog('MySQL:Error', 'UserEdit', $zData['username'] . ' (' . mysql_real_escape_string($zData['name']) . ') could not be added as curator for ' . $sSymbol);
                        } else {
                            lovd_writeLog('MySQL:Event', 'UserEdit', $zData['username'] . ' (' . mysql_real_escape_string($zData['name']) . ') successfully added as curator for ' . $sSymbol);
                        }
                    }
                }
            }

            // Thank the user...
            header('Refresh: 3; url=' . PROTOCOL . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . '?action=view&view=' . $_GET['edit'] . lovd_showSID(true));

            require ROOT_PATH . 'inc-top.php';
            lovd_printHeader('setup_users_manage', 'LOVD Setup - Manage authorized users');
            print('      Successfully updated user ' . stripslashes($_POST['name']) . '!<BR><BR>' . "\n\n");

            require ROOT_PATH . 'inc-bot.php';
            exit;

        } else {
            // Errors, so the whole lot returns to the form.
            lovd_magicUnquoteAll();

            // Because we're sending the data back to the form, I need to unset the password fields!
            unset($_POST['password'], $_POST['password_1'], $_POST['password_2']);
        }

    } else {
        foreach ($zData as $key => $val) {
            if (!isset($_POST[$key]) || !$_POST[$key]) {
                $_POST[$key] = $val;
            }
        }
        $_POST['password'] = '';

        // Load curated DBs.
        $_POST['curates'] = array();
        $q = mysql_query('SELECT symbol FROM ' . TABLE_CURATES . ' WHERE userid = "' . $zData['userid'] . '"');
        while ($r = mysql_fetch_row($q)) {
            $_POST['curates'][] = $r[0];
        }
    }



    require ROOT_PATH . 'inc-top.php';
    lovd_printHeader('setup_users_manage', 'LOVD Setup - Manage authorized users');

    lovd_errorPrint();

    // Table.
    print('      <FORM action="' . $_SERVER['PHP_SELF'] . '?action=' . $_GET['action'] . '&amp;edit=' . $zData['userid'] . '&amp;sent=true" method="post">' . "\n" .
          '        <TABLE border="0" cellpadding="0" cellspacing="1" width="760">');

    // Remove user levels that are higher than or equal to the current user's level.
    $aUserLevels = $_SETT['user_levels'];
    for ($i = 9; $i >= $_AUTH['level']; $i --) {
        if (isset($aUserLevels[$i])) {
            unset($aUserLevels[$i]);
        }
    }

    // Get gene list, to select user as curator.
    // 2010-03-12; 2.0-25; This will make this query very complicated, but it will also shorten the gene names quite properly.
    $qGenes = mysql_query('SELECT symbol, CONCAT(SUBSTRING(CONCAT(symbol, " (", gene), 1, 50), SUBSTRING("...)", (((LENGTH(CONCAT(symbol, gene))<49)+1)*3)-2)) AS gene FROM ' . TABLE_DBS . ' ORDER BY symbol');
    $nGenes = mysql_num_rows($qGenes);
    $nGeneSize = ($nGenes < 5? $nGenes : 5);

    // Array which will make up the form table.
    $aForm = array(
                    array('POST', '', '', '50%', '50%'),
                    array('', 'print', '<B>User details</B>'),
                    array('Name', 'text', 'name', 30),
                    array('Institute', 'text', 'institute', 40),
                    array('Email address', 'text', 'email', 30),
                    array('New password (optional)', 'password', 'password_1', 20),
                    array('New password (confirm, optional)', 'password', 'password_2', 20),
                    array('Must change password at next logon', 'checkbox', 'password_force_change', 1),
                    'skip',
                    array('', 'print', '<B>General user settings</B>'),
                    array('Number of entries per page', 'select', 'list_size', 1, array_combine($_SETT['variant_listsizes'], $_SETT['variant_listsizes']), false, false, false),
                    array('', 'print', '<SPAN class="form_note">Variant listings will be split in pages. How many variants do you want to show per page by default?</SPAN>'),
                    'skip',
                    array('', 'print', '<B>Security</B>'),
                    array('Level', 'select', 'level', 1, $aUserLevels, false, false, false),
                    array('Allowed IP address list', 'text', 'allowed_ip', 20),
                    array('', 'print', '<SPAN class="form_note"><I>Your current IP address: ' . $_SERVER['REMOTE_ADDR'] . '</I><BR>To help prevent others to try and guess the username/password combination, you can restrict access to the account to a number of IP addresses or ranges.<BR><B>Please be extremely careful using this setting.</B> Using this setting too strictly, can deny the user access to LOVD, even if the correct credentials have been provided.<BR>Set to \'*\' to allow all IP addresses, use \'-\' to specify a range and use \';\' to separate addresses or ranges.</SPAN>'),
                    array('Locked', 'checkbox', 'locked', 0),
                    array('Deleted', 'checkbox', 'deleted', 0),
                    'skip',
                    array('', 'print', '<B>Curated genes</B>'),
                    array('Curator for', 'select', 'curates', $nGeneSize, $qGenes, false, true, true),
                    'skip',
                    array('Enter your password for authorization', 'password', 'password', 20),
                    array('', 'submit', 'Edit user'),
                  );
    // 2008-07-16; 2.0-09; A user can no longer be deleted through the edit form.
    if (!$zData['deleted']) {
        unset($aForm[18]);
    }
    $_MODULES->processForm('SetupUsersEdit', $aForm);
    lovd_viewForm($aForm);

    print('</TABLE></FORM>' . "\n\n");

    require ROOT_PATH . 'inc-bot.php';
    exit;





} elseif ($_GET['action'] == 'drop' && is_numeric($_GET['drop'])) {
    // Drop specific user.

    $zData = @mysql_fetch_assoc(mysql_query('SELECT * FROM ' . TABLE_USERS . ' WHERE userid = "' . $_GET['drop'] . '"'));
    if (!$zData) {
        // Wrong ID, apparently.
        require ROOT_PATH . 'inc-top.php';
        lovd_printHeader('setup_users_manage', 'LOVD Setup - Manage authorized users');
        print('      No such ID!<BR>' . "\n");
        require ROOT_PATH . 'inc-bot.php';
        exit;
    }

    if ($zData['level'] >= $_AUTH['level']) {
        // This is a hack-attempt.
        require ROOT_PATH . 'inc-top.php';
        lovd_printHeader('setup_users_manage', 'LOVD Setup - Manage authorized users');
        lovd_writeLog('MySQL:Error', 'HackAttempt', $_AUTH['username'] . ' (' . mysql_real_escape_string($_AUTH['name']) . ') tried to drop ' . $zData['username'] . ' (' . mysql_real_escape_string($zData['name']) . ')');
        print('      Hack Attempt.<BR>' . "\n");
        require ROOT_PATH . 'inc-bot.php';
        exit;
    }

    // 2008-07-16; 2.0-09; Deleting a user makes the current user curator of the deleted user's genes if there is no curator left for them.
    // Find curated genes and see if they're alone.
    $q = mysql_query('SELECT t1.symbol FROM ' . TABLE_CURATES . ' AS t1 LEFT OUTER JOIN ' . TABLE_CURATES . ' AS t2 ON (t1.symbol = t2.symbol AND t1.userid != t2.userid) WHERE t1.userid = "' . $zData['userid'] . '" AND t2.userid IS NULL');
    $aGenesCurate = array();
    while ($r = mysql_fetch_row($q)) {
        // Gene has no curator, and user is going to be deleted!
        $aGenesCurate[] = $r[0];
    }

    // Require form functions.
    require ROOT_PATH . 'inc-lib-form.php';

    if (isset($_GET['sent'])) {
        lovd_errorClean();

        // Mandatory fields.
        $aCheck =
                 array(
                        'password' => 'Enter your password for authorization',
                      );

        foreach ($aCheck as $key => $val) {
            if (empty($_POST[$key])) {
                lovd_errorAdd('Please fill in the \'' . $val . '\' field.');
            }
        }

        // User had to enter his/her password for authorization.
        if ($_POST['password'] && md5($_POST['password']) != $_AUTH['password']) {
            lovd_errorAdd('Please enter your correct password for authorization.');
        }

        if (!lovd_error()) {
            // Query text; clean curator associations first.
            $sQ = 'DELETE FROM ' . TABLE_CURATES . ' WHERE userid = "' . $zData['userid'] . '"';
            $q = mysql_query($sQ);
            if (!$q) {
                lovd_dbFout('UserDrop', $sQ, mysql_error(), false);
            }

            // 2008-07-16; 2.0-09; Deleting a user makes the current user curator of the deleted user's genes if there is no curator left for them.
            // Now check if we need to make the current user curator of some gene(s).
            if (count($aGenesCurate)) {
                foreach ($aGenesCurate as $sGene) {
                    $sQ = 'INSERT INTO ' . TABLE_CURATES . ' VALUES ("' . $_AUTH['userid'] . '", "' . mysql_real_escape_string($sGene) . '")';
                    $q = mysql_query($sQ);
                    if (!$q) {
                        lovd_dbFout('UserDrop', $sQ, mysql_error(), false);
                    }
                }
            }

            // Query text.
            $sQ = 'UPDATE ' . TABLE_USERS . ' SET deleted = 1 WHERE userid = "' . $zData['userid'] . '"';

            $q = mysql_query($sQ);
            if (!$q) {
                $sError = mysql_error(); // Save the mysql_error before it disappears.
                require ROOT_PATH . 'inc-top.php';
                lovd_printHeader('setup_users_manage', 'LOVD Setup - Manage authorized users');
                lovd_dbFout('UserDrop', $sQ, $sError);
            }

            // Write to log...
            lovd_writeLog('MySQL:Event', 'UserDrop', $_AUTH['username'] . ' (' . mysql_real_escape_string($_AUTH['name']) . ') successfully deleted user ' . $zData['username'] . ' (' . mysql_real_escape_string($zData['name']) . ')');

            // Thank the user...
            header('Refresh: 3; url=' . PROTOCOL . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . '?action=view_all' . lovd_showSID(true));

            require ROOT_PATH . 'inc-top.php';
            lovd_printHeader('setup_users_manage', 'LOVD Setup - Manage authorized users');
            print('      Successfully deleted user ' . $zData['name'] . '!<BR><BR>' . "\n\n");

            require ROOT_PATH . 'inc-bot.php';
            exit;

        } else {
            // Errors, so the whole lot returns to the form.
            lovd_magicUnquoteAll();

            // Because we're sending the data back to the form, I need to unset the password fields!
            unset($_POST['password']);
        }
    }



    require ROOT_PATH . 'inc-top.php';
    lovd_printHeader('setup_users_manage', 'LOVD Setup - Manage authorized users');

    lovd_errorPrint();

    // Table.
    print('      <FORM action="' . $_SERVER['PHP_SELF'] . '?action=' . $_GET['action'] . '&amp;drop=' . $zData['userid'] . '&amp;sent=true" method="post">' . "\n" .
          '        <TABLE border="0" cellpadding="0" cellspacing="1" width="760">');

    // Array which will make up the form table.
    $aForm = array(
                    array('POST', '', '', '50%', '50%'),
                    array('Deleting user', 'print', $zData['username'] . ' (' . $zData['name'] . ')'),
                  );
    // 2008-07-16; 2.0-09; Deleting a user makes the current user curator of the deleted user's genes if there is no curator left for them.
    if (count($aGenesCurate)) {
        $aForm[] = array('&nbsp;', 'print', '<B>This user is the only curator of ' . count($aGenesCurate) . ' gene' . (count($aGenesCurate) == 1? '' : 's') . ': ' . implode(', ', $aGenesCurate) . '. You will become the curator of ' . (count($aGenesCurate) == 1? 'this gene' : 'these genes') . ' once this user is deleted.</B>');
    }
    $aForm = array_merge(
            $aForm,
             array(
                    'skip',
                    array('Enter your password for authorization', 'password', 'password', 20),
                    array('', 'submit', 'Delete user'),
                  ));
    $_MODULES->processForm('SetupUsersDelete', $aForm);
    lovd_viewForm($aForm);

    print('</TABLE></FORM>' . "\n\n");

    require ROOT_PATH . 'inc-bot.php';
    exit;





} else {
    // Default action:
    header('Location: ' . PROTOCOL . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . '?action=view_all' . lovd_showSID(true));
    exit;
}
?>