# ==================================================================
# Gossamer List - enhanced mailing list management system
#
#   Website  : http://gossamer-threads.com/
#   Support  : http://gossamer-threads.com/scripts/support/
#   CVS Info :                          
#   Revision : $Id: Admin.pm,v 1.59 2004/10/14 22:57:54 bao Exp $
#
# Copyright (c) 2004 Gossamer Threads Inc.  All Rights Reserved.
# Redistribution in part or in whole strictly prohibited.  Please
# see LICENSE file for full details.
# ==================================================================
#

package GList::Admin;

use strict;
use GList qw/:user_type :objects $DEBUG/;
use GT::AutoLoader;

sub process {
#------------------------------------------------------------------
# Setermine what to do
#
    my $do = shift;

    my $action = _determine_action($do) or die "Error: Invalid Action! ($do)";
    if ($action eq 'admin_gtdoc') {
        return GT::Plugins->dispatch($CFG->{priv_path}.'/lib/GList/Plugins', $action, \&$action);
    }

    my ($tpl, $results) = GT::Plugins->dispatch($CFG->{priv_path}.'/lib/GList/Plugins', $action, \&$action);
    if ($tpl) {
        $MN_SELECTED = 6 if ($tpl =~ /^admin_user/);
        my $hidden = GList::hidden();
        $results->{hidden_query}   = $hidden->{hidden_query};
        $results->{hidden_objects} = $hidden->{hidden_objects};
        GList::display($tpl, $results);
    }
}

$COMPILE{admin_gtdoc} = <<'END_OF_SUB';
sub admin_gtdoc {
#-------------------------------------------------------------------
#
    my $template = $IN->param('topic') || 'index.html';

    my $help_path = "$CFG->{priv_path}/templates/help";
    $template =~ s,^/|/$,,;

# Check the topic file.
    unless ( $template =~ /^[\w\/]+\.[\w]+$/ ) {
        die "Invalid topic: $template";
    }
    if ( $template =~ /\.(gif|jpg)$/ and -e "$help_path/$template" ) {
        print $IN->header("image/$1");
        open IMG, "< $help_path/$template" or die "Unable to open image help: $help_path/$template ($!)";
        binmode IMG;
        local *BINSTDOUT;
        open BINSTDOUT, ">&STDOUT";
        binmode BINSTDOUT;
        print BINSTDOUT while <IMG>;
        close IMG;
    }
    else {
        print $IN->header;
        GT::Template->parse ($template, $USER, { print => 1, root => $help_path });
    }
}
END_OF_SUB

$COMPILE{admin_page} = <<'END_OF_SUB';
sub admin_page {
#--------------------------------------------------------------------
#
    my ($page, $vars) = @_;

    $page ||= $IN->param('pg');
    ( $page ) or return admin_user(GList::language('ADM_INVALID'));

    if ( $page =~ /^admin_template_/ ) {
        $MN_SELECTED = 7;
    }
    elsif ( $page =~ /plugin_|gt_doc/ ) {
        $MN_SELECTED = 8;
    }
    elsif ( $page =~ /admin_setup_/ ) {
        $MN_SELECTED = 9;
    }

    return ($page, $vars);
}
END_OF_SUB

$COMPILE{admin_initial_sql} = <<'END_OF_SUB';
sub admin_initial_sql {
#-------------------------------------------------------------------
#
    my $sql = _sql_load_cfg();
    unless ( $IN->param('setup_sql') ) {
        return ('admin_initial_sql.html', { %$sql, msg => GList::language("ADM_CONNECTION_ERROR") });
    }
    my $do = $IN->param('action');
    if ($do !~ /^create|overwrite|load$/) {
        return ('admin_initial_sql.html', { msg => "<font color=red><b>Invalid action: '$do'</b></font>", $sql });
    }

    my $ret = _sql_connect($IN->param('sql_host'), $IN->param('sql_driver'), $IN->param('sql_database'), $IN->param('sql_login'), $IN->param('sql_password'), $IN->param('sql_prefix'));
    if (exists $ret->{error}) {
        return ('admin_initial_sql.html', { msg => $ret->{error}, $sql });
    }

    my $output;
    if ($do eq 'create') {
        $output = GList::SQL::tables('check');
    }
    elsif ($do eq 'overwrite') {
        $output = GList::SQL::tables('force');
    }
    elsif ($do eq 'load') {
        $output = GList::SQL::load_from_sql();
    }

    if ( !$DB->table('Users')->count({ usr_Username => $USER->{username}}) ) {
        my $user = $CFG->{admin}->{$USER->{username}};
        my %hash;
        $hash{usr_type}         = ADMINISTRATOR;
        $hash{usr_username}     = $USER->{username};
        $hash{usr_password}     = $user->[0];
        $hash{usr_email}        = $user->[1];
        $hash{pro_first_name}   = $USER->{username};
        $hash{pro_last_name}    = $USER->{username};
        $hash{usr_date_format}  = '%yyyy%-%mm%-%dd%';
        $DB->table('Users')->insert(%hash) or die $GT::SQL::error;
    }

    my $results = GList::Authenticate::auth('create_session', { username => $USER->{username} });
    ( $results->{error} ) and return ('login_form.html', { msg => "<font color=red><b>$results->{error}</b></font>" });

# Delete session file if it has being used
    GList::Authenticate::auth('admin_delete_session');

# Administrator users need to be saved in Data.pm
    _save_users();

    return ('admin_initial_sql_results.html', { msg => $output });
}
END_OF_SUB

$COMPILE{admin_initial_setup} = <<'END_OF_SUB';
sub admin_initial_setup {
# ------------------------------------------------------------------
# Sets the mysql information.
#
    my ($host, $port, $overwrite);

    unless ( $IN->param('initial_step') ) {
        return admin_page('admin_initial_setup_first.html');
    }
    if ( $IN->param('initial_step') == 2 ) {
        return admin_page('admin_initial_setup_second.html');
    }

# Test the ability to create a def file.
    unless (open (TEST, "> $CFG->{priv_path}/defs/database.def")) {
        return ('admin_initial_setup_second.html', { error => sprintf(GList::language('ADM_INITIAL_ERROR'), "$CFG->{priv_path}/defs/", $!) });
    }
    close TEST;
    unlink "$CFG->{priv_path}/defs/database.def";

# Set the connection info.
    $overwrite = $IN->param('overwrite') ? 'force' : 'check';
    $host = $IN->param('host');
    ($host =~ s/\:(\d+)$//) and ($port = $1);

    my $prefix = $IN->param('prefix');
    $prefix =~ /^\w*$/ or return ('admin_initial_setup_second.html', { error => sprintf(GList::language('ADM_INITIAL_PREFIX_ERROR'), $prefix) });

    $DB->prefix($prefix);
    my $ret = $DB->set_connect ({
        driver     => scalar $IN->param('driver'),
        host       => $host,
        port       => $port,
        database   => scalar $IN->param('database'),
        login      => scalar $IN->param('login'),
        password   => scalar $IN->param('password'),
        RaiseError => 0,
        PrintError => 0,
        AutoCommit => 1
    });
    if (! defined $ret) {
        return ('admin_initial_setup_second.html', { error => $GT::SQL::error });
    }
# Now let's create the tables.
    eval { local $SIG{__DIE__}; require GList::SQL; };
    if ($@) { return ('admin_initial_setup_second.html', { error => sprintf(GList::language('ADM_INITIAL_LOAD_ERROR'), "$@\n") }); }
    my $output = GList::SQL::tables($overwrite);

# Remove admin users and Add an admin user

    my $user;
    foreach (keys % {$CFG->{admin}}) {
        $user = $_;last;
    }
    if ($user) {
        my $db = $DB->table('Users');
        $db->delete({ usr_type => ADMINISTRATOR });
        if ( !$db->insert({
            usr_username        => $user,
            usr_email           => $CFG->{admin}->{$user}->[1],
            usr_password        => $CFG->{admin}->{$user}->[0],
            usr_type            => ADMINISTRATOR,
            usr_reply_email     => $CFG->{admin}->{$user}->[1],
            usr_bounce_email    => $CFG->{admin}->{$user}->[1],
            usr_date_format     => '%yyyy%-%mm%-%dd%',
            pro_first_name      => $user,
            pro_last_name       => $user,
        }) ) {
            return ('admin_initial_setup_second.html', { error => $GT::SQL::error });
        }
    }

# Set default email templates
    GList::set_default_template('validation.eml',  $IN->param('admin_user'));
    GList::set_default_template('subscribe.eml',   $IN->param('admin_user'));
    GList::set_default_template('unsubscribe.eml', $IN->param('admin_user'));

# And lets set sensible defaults for the rest of the config vars.
    $CFG->create_defaults();

# And save the config.
    $CFG->save();

    return ('admin_initial_setup_third.html', { message => sprintf(GList::language('ADM_INITIAL_SUCCESSFUL'), $output) } );
}
END_OF_SUB

$COMPILE{admin_user} = <<'END_OF_SUB';
sub admin_user {
#--------------------------------------------------------------------
# Print home page
#
    my $msg = shift;
    $USER->{usr_type} == ADMINISTRATOR or return ('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

    my $cgi = $IN->get_hash;
    my $search_check = ($IN->param('do') eq 'admin_user_search') ? 1 : 0;
    my $results = GList::search(
        cgi         => $cgi,
        db          => $DB->table('Users'),
        prefix      => 'usr',
        sb          => 'usr_type',
        so          => 'ASC',
        skip_user   => '1',
        search_check=> $search_check
    );

    if ( ref $results ne 'HASH' ) {
        ( $IN->param('do') eq 'admin_user_search' ) ? return ('admin_user_search_form.html', { msg => $results })
                                                    : return ('admin_user_home.html',        { msg => $results });
    }
    elsif ( $results->{error} and $search_check) {
        return ('admin_user_search_form.html', { msg => $results->{error} })
    }

    my $output = $results->{results};
    $results->{msg} = ($msg) ? $msg : GList::language('USR_RESULTS', $results->{hits});

    return ('admin_user_home.html', $results);
}
END_OF_SUB

$COMPILE{admin_user_add} = __LINE__ . <<'END_OF_SUB';
sub admin_user_add {
#--------------------------------------------------------------------
# Add a user
#
    $USER->{usr_type} == ADMINISTRATOR or return ('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

#------------demo code-----------

    my $cols = $DB->table('Users')->cols;
    my $cgi  = {};

    foreach ( keys % $cols) {
        $cgi->{$_} = $IN->param("mod_$_") if ( $IN->param("mod_$_") );
    }

    ($cgi->{usr_username} and $cgi->{usr_username} =~ /^[\w\-\.]{3,}$/) or  return ('admin_user_add_form.html', { msg => GList::language('USR_INVALID') });
    ($cgi->{usr_password} and length $cgi->{usr_password} < 4 )         and return ('admin_user_add_form.html', { msg => GList::language('ADM_PWD_INVALID') });

    $cgi->{usr_password}     = GList::encrypt($cgi->{usr_password});
    $cgi->{usr_date_format}  = $IN->param('date_preview') if ($IN->param('date_preview'));
    $cgi->{usr_date_format}||= "%yyyy%-%mm%-%dd%";

# Set account limits
    $cgi = _account_limit($cgi);

# Add a new record
    GList::add('Users', 'usr', $cgi);

    return ('admin_user_add_form.html', { msg => sprintf(GList::language('USR_ADD_ERR', $GList::error)) }) if ( $GList::error );

# Add user info into Data.pm if user is a administrator
    if ( $cgi->{usr_type} == ADMINISTRATOR and not exists $CFG->{admin}->{$cgi->{usr_username}}) {
        $CFG->{admin}->{$cgi->{usr_username}} = [$cgi->{usr_password}, $cgi->{usr_email}];
        $CFG->save();
    }

# Set default email templates
    GList::set_default_template('validation.eml',  $cgi->{usr_username});
    GList::set_default_template('subscribe.eml',   $cgi->{usr_username});
    GList::set_default_template('unsubscribe.eml', $cgi->{usr_username});

    admin_user(sprintf(GList::language('USR_ADDED'), $cgi->{usr_username}));
}
END_OF_SUB

$COMPILE{admin_user_modify_form} = <<'END_OF_SUB';
sub admin_user_modify_form {
#-----------------------------------------------------------
# Print modify a user form
#
    my $msg = shift;

    $USER->{usr_type} == ADMINISTRATOR or return ('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

    my $id   = $IN->param('uid');
    my $db   = $DB->table('Users');
    my $user = $db->get($id);
    ( $user ) or return admin_user(sprintf(GList::language('USR_NOT_FOUND'), $id));

    my $cols = $db->cols;
    my $hsh = {};
    foreach ( keys % $cols ) {
        $hsh->{"mod_$_"} = $user->{$_};
    }
    return ('admin_user_modify_form.html', { msg => $msg, modify => 1,  %$hsh });
}
END_OF_SUB

$COMPILE{admin_user_modify} = <<'END_OF_SUB';
sub admin_user_modify {
#-----------------------------------------------------------
# Modify a user
#
    $USER->{usr_type} == ADMINISTRATOR or return ('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

#------------demo code-----------

    my $db   = $DB->table('Users');
    my $cols = $db->cols;
    my $hsh  = {};
    my $cgi  = $IN->get_hash();

    foreach ( keys % $cols) {
        next if ( $USER->{usr_username} eq $cgi->{mod_usr_username} and $_ eq 'usr_type' );
        $hsh->{$_} = $cgi->{"mod_$_"} if (exists $cgi->{"mod_$_"});
    }

# Setup the language for GT::SQL.
    local $GT::SQL::ERRORS->{ILLEGALVAL} = GList::language('USR_ILLEGALVAL')  if ( GList::language('USR_ILLEGALVAL') );
    local $GT::SQL::ERRORS->{UNIQUE}     = GList::language('USR_UNIQUE')      if ( GList::language('USR_UNIQUE') );
    local $GT::SQL::ERRORS->{NOTNULL}    = GList::language('USR__NOTNULL')    if ( GList::language('USR__NOTNULL') );

    $hsh->{usr_cookie} = 0 if ( !defined $hsh->{usr_cookie} );
    if ($hsh->{usr_type} == ADMINISTRATOR or $hsh->{usr_type} == UNLIMITED_USER) {
        $hsh->{usr_validate_code} = '';
    }

    if ($hsh->{usr_password}) {
        $hsh->{usr_password} = GList::encrypt($hsh->{usr_password});
    }
    else {
        delete $hsh->{usr_password};
    }

    $hsh->{usr_date_format}  = $IN->param('date_preview') if ($IN->param('date_preview'));
    $hsh->{usr_date_format}||= "%yyyy%-%mm%-%dd%";
    my $old = $db->get($hsh->{usr_username});

# Set account limits
    $hsh = _account_limit($hsh);

# Email validate this account
    if ($CFG->{signup_admin_validate} and $cgi->{email_validate}) {
        $hsh->{usr_validate_code} = '';
    }

    if ( $db->modify($hsh) ) {
        my $pass = $hsh->{usr_password} || $old->{usr_password};
        if ( $old->{usr_type} ne $hsh->{usr_type} ) { # Update Data.pm
            if ( $hsh->{usr_type} == ADMINISTRATOR ) {
                exists $CFG->{admin}->{$hsh->{usr_username}} or $CFG->{admin}->{$hsh->{usr_username}} = [$pass, $hsh->{usr_email}];
            }
            else {
                exists $CFG->{admin}->{$hsh->{usr_username}} and delete $CFG->{admin}->{$hsh->{usr_username}};
            }
            $CFG->save();
        }
        elsif ($hsh->{usr_type}) {
            $CFG->{admin}->{$hsh->{usr_username}} = [$pass, $hsh->{usr_email}];
            $CFG->save();
        }
        return admin_user(sprintf(GList::language('USR_UPDATED'), $hsh->{usr_username}));
    }
    else {
        local $^W;
        return admin_user_modify_form("<font color='red'>$GT::SQL::error</font>");
    }
}
END_OF_SUB

$COMPILE{admin_user_delete} = __LINE__ . <<'END_OF_SUB';
sub admin_user_delete {
#-------------------------------------------------------------------
# Delete the glist users
#
    $USER->{usr_type} == ADMINISTRATOR or return ('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

#------------demo code-----------

    my $cgi = $IN->get_hash();
    my $dels = (ref $cgi->{modify} eq 'ARRAY') ? $cgi->{modify} : [$cgi->{modify}];
    my (%hsh, @mods, @users);
    foreach (@$dels) {
        next if ($cgi->{"$_-usr_username"} eq $USER->{usr_username});
        $hsh{"$_-usr_username"} = $cgi->{"$_-usr_username"};
        push @mods, $_;
        push @users, $cgi->{"$_-usr_username"};
    }
    $hsh{modify} = \@mods;

    my $msg = GList::delete('Users', 'usr', \%hsh);

# Delete users from Data.pm if they are administrator users
    foreach my $u (@users) {
        next if (not exists $CFG->{admin}->{$u});
        delete $CFG->{admin}->{$u};
        $CFG->save();
    }
    return admin_user($msg);
}
END_OF_SUB

$COMPILE{admin_user_validate} = __LINE__ . <<'END_OF_SUB';
sub admin_user_validate {
#-------------------------------------------------------
# Validate users
# 
    $USER->{usr_type} == ADMINISTRATOR or return ('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

#------------demo code-----------

    my $cgi = $IN->get_hash();
    my $mod = (ref $cgi->{modify} eq 'ARRAY') ? $cgi->{modify} : [$cgi->{modify}];

    my $db_usr = $DB->table('Users');
    my $count  = 0;
    foreach (@$mod) {
        my $u = $cgi->{"$_-usr_username"};
        next if (!$u or $u eq $USER->{usr_username});
        if ($db_usr->count({ usr_username => $u })) {
            $db_usr->update({
                usr_type          => LIMITED_USER,
                usr_validate_code => '',
                usr_limit_list    => $CFG->{signup_limit_list}    || 10,
                usr_limit_sublist => $CFG->{signup_limit_sublist} || 10,
                usr_limit_email30 => $CFG->{signup_limit_email30} || 100,
            }, { usr_username => $u });
            $count++;
        }
    }
    return admin_user(GList::language('USR_VALIDATED', $count));
}
END_OF_SUB

$COMPILE{admin_plugin} = <<'END_OF_SUB';
sub admin_plugin {
# ------------------------------------------------------------------
#   Run a plugin function.
#
    $USER->{usr_type} == ADMINISTRATOR or return ('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

    my $plugin = $IN->param('plugin');
    my $func   = $IN->param('func');
    {
        local ($@, $!, $SIG{__DIE__});
        eval { require "$CFG->{priv_path}/lib/GList/Plugins/$plugin.pm"; };
        if ( $@ ) {
            return ('error_form.html', { msg => "<font color=red>Unable to load plugin: $plugin ($@)</font>" });
        }
    }
    no strict 'refs';
    my $code = ${"GList::Plugins::" . $plugin . "::"}{$func};
    use strict 'refs';

    if ( !defined $code ) {
        return ('error_form.html', { msg => "<font color=red>Invalid plugin function: $func</font>" });
    }
    $code->();
}
END_OF_SUB


$COMPILE{admin_setup_sql_form} = <<'END_OF_SUB';
sub admin_setup_sql_form {
# ------------------------------------------------------------------
# Print SQL Server Form
#
    my $msg = shift;
    $USER->{usr_type} == ADMINISTRATOR or return ('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

    my $sql = _sql_load_cfg();
    return ('admin_setup_sql_form.html', { msg => $msg, %$sql });
}
END_OF_SUB

$COMPILE{admin_setup_sql} = <<'END_OF_SUB';
sub admin_setup_sql {
# ------------------------------------------------------------------
# Change the sql server information.
#
    $USER->{usr_type} == ADMINISTRATOR or return ('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

#------------demo code-----------

    my ($host, $port, $output, $do, $ret);

    $do = $IN->param('action');
    if ($do !~ /^create|overwrite|load$/) {
        return admin_setup_sql_form("<font color=red><b>Invalid action: '$do'</b></font>");
    }

    $ret = _sql_connect($IN->param('sql_host'), $IN->param('sql_driver'), $IN->param('sql_database'), $IN->param('sql_login'), $IN->param('sql_password'), $IN->param('sql_prefix'));
    if (exists $ret->{error}) {
        return admin_setup_sql_form($ret->{error});
    }

    require GList::SQL;
    if ($do eq 'create') {
        $output = GList::SQL::tables('check');
    }
    elsif ($do eq 'overwrite') {
        $output  = GList::SQL::tables('force');
        my $db   = $DB->table('Users');
        $db->insert($USER) or die $GT::SQL::error;

        my $results = GList::Authenticate::auth('create_session', { username => $USER->{usr_username} });
        ( $results->{error} ) and return ('login_form.html', { msg => "<font color=red><b>$results->{error}</b></font>" });

# Save username and password into Data.pm
        $CFG->{admin} = { $USER->{usr_username} => [$USER->{usr_password}, $USER->{usr_email}] };
        $CFG->save();
    }
    elsif ($do eq 'load') {
        $output = GList::SQL::load_from_sql();
    }

    return admin_setup_sql_form("<font color=green>$output", 'is_set');
}
END_OF_SUB

$COMPILE{admin_setup_form} = <<'END_OF_SUB';
sub admin_setup_form {
# ------------------------------------------------------------------
# Print Setup form
#
    $USER->{usr_type} == ADMINISTRATOR or return ('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

    my $msg = shift;
    require GList::Config;
    my $cfg = GList::Config::tpl_load();
    my $pg  = $IN->param('pg') || 'admin_setup_path.html';

    return ($pg, { %$cfg, msg => $msg });
}
END_OF_SUB

$COMPILE{admin_setup} = <<'END_OF_SUB';
sub admin_setup {
# ------------------------------------------------------------------
# Set the configuration.
#
    $USER->{usr_type} == ADMINISTRATOR or return ('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

#------------demo code-----------

    my $cgi = $IN->get_hash();

    if ( $cgi->{pg} eq 'admin_setup_misc.html' and (($cgi->{mail_path} and $cgi->{smtp_server}) or (!$cgi->{smtp_server} and !$cgi->{mail_path})) ) {
        return admin_setup_form(GList::language('SET_MISC_ERR'));
    }

    if ( !$cgi->{brestore} and exists $cgi->{cgi_url} and exists $cgi->{priv_path} and exists $cgi->{image_url} and
        ( !$cgi->{cgi_url} or !$cgi->{priv_path} or !$cgi->{image_url} ) ) {
        return admin_setup_form(GList::language('SET_PATH_ERR'));
    }

    if ($cgi->{brestore}) {
        $CFG->default_path (1);
    }
    else {
        _update_cfg();
    }
    $CFG->save();
    return admin_setup_form(GList::language('SET_CFG_SUCCESS'));
}
END_OF_SUB

$COMPILE{admin_template_diff} = <<'END_OF_SUB';
sub admin_template_diff {
# ------------------------------------------------------------------
# Load fileman, but just for the purposes of displaying a diff.
#
    $USER->{usr_type} == ADMINISTRATOR or return ('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

    require GT::FileMan;
    my $fileman = GT::FileMan->new(
        cfg => {
            template_root    => "$CFG->{priv_path}/templates/common",
            root_dir         => "$CFG->{priv_path}/templates",
            html_root_url    => $CFG->{image_url}. '/fileman',
            debug_level      => 0,
            winnt            => $^O eq 'MSWin32' ? 1 : 0,
            command_time_out => 20,
            allowed_space    => 0,
        },
        url_opts => 'do=fileman_diff'
    );
    $fileman->process();exit;
}
END_OF_SUB

$COMPILE{init_setup} = __LINE__ . <<'END_OF_SUB';
sub init_setup {
# ------------------------------------------------------------------
# Sets the mysql information.
#
    my ($host, $port, $overwrite);
# Test the ability to create a def file.

    unless (open (TEST, "> $CFG->{priv_path}/defs/database.def")) {
        return GList::display('setup_second.html', {
            error => "Unable to create our def file in $CFG->{priv_path}/defs/. <br>\n
                      Please make sure this directory exists, and is writeable by the server. <br>\n
                      If this is the wrong directory, you will need to manually set the directory <br>\n
                      in GList::ConfigData. Error was: $!"
        });
    }
    close TEST;
    unlink "$CFG->{priv_path}/defs/database.def";

# Set the connection info.
    $overwrite = $IN->param('overwrite') ? 'force' : 'check';
    $host = $IN->param('host');
    ($host =~ s/\:(\d+)$//) and ($port = $1);

    my $prefix = $IN->param('prefix');
    $prefix =~ /^\w*$/ or return GList::display('setup_second.html', { error => "Invalid prefix: '$prefix'. Can only be letters, numbers and underscore." });

    $DB->prefix($prefix);
    my $ret = $DB->set_connect ({
        driver     => scalar $IN->param('driver'),
        host       => $host,
        port       => $port,
        database   => scalar $IN->param('database'),
        login      => scalar $IN->param('login'),
        password   => scalar $IN->param('password'),
        RaiseError => 0,
        PrintError => 0,
        AutoCommit => 1
    });
    if (! defined $ret) {
        return GList::display('setup_second.html', { error => $GT::SQL::error });
    }
# Now let's create the tables.
    eval { local $SIG{__DIE__}; require GList::SQL; };
    if ($@) { return GList::display('setup_second.html', { error => "Unable to load Dbsql::SQL module: $@\n" }); }

    my $output = GList::SQL::tables($overwrite);

# Add admin user
    my $db   = $DB->table('Users');
    $db->insert({
        usr_email       => $IN->param('admin_user'),
        usr_password    => $IN->param('admin_pass'),
        usr_type        => ADMINISTRATOR,
        usr_reply_email => $IN->param('admin_user'),
        usr_bounce_Email => $IN->param('admin_user')
    });
    if ( $GT::SQL::error ) {
        return GList::display('setup_second.html', { error => $GT::SQL::error });
    }

# And lets set sensible defaults for the rest of the config vars.
    $CFG->create_defaults();

# And save the config.
    $CFG->save();

    GList::display('setup_third.html', { message => "The data tables have been setup: <pre>$output</pre>" } );
}
END_OF_SUB

$COMPILE{admin_user_table} = __LINE__ . <<'END_OF_SUB';
sub admin_user_table {
#--------------------------------------------------------------------
# Load Users table properties
#
    my $msg  = shift;
    $USER->{usr_type} == ADMINISTRATOR or return GList::display('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

    my $db_usr = $DB->table('Users');
    my $cols   = $db_usr->cols;
    my $pro_cols = [ grep(/^pro_/, $db_usr->ordered_columns) ];

    my @output;
    foreach my $c ( @$pro_cols ) {
        $cols->{$c}->{name} = $c;
        push @output, $cols->{$c};
    }

    return ('admin_user_table.html', { loop_fields => \@output, msg => $msg });
}
END_OF_SUB

$COMPILE{admin_user_table_add} = __LINE__ . <<'END_OF_SUB';
sub admin_user_table_add {
#-------------------------------------------------------------
# Add a field
#
    $USER->{usr_type} == ADMINISTRATOR or return GList::display('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

#------------demo code-----------

    return ('admin_user_table_add.html') if ($IN->param('form'));

    my $db      = $DB->table('Users');
    my %cols    = $db->cols;
    my $attribs = _col_spec();
    my $column  = 'pro_'.$IN->param('column');

# Error checking
    my $errors = _field_check();
    if ( exists $cols{$column} ) {
        $errors .= sprintf(GList::language('TAB_COL_EXISTS'), $column);
    }
    if ( $IN->param('index') eq 'primary' ) {
        $errors .= GList::language('TAB_PRIMARY_ERR');
    }
    return ('admin_user_table_add.html', { msg => "<font color=red><b>$errors</b></font>" }) if ($errors);

    $attribs->{pos}       = keys(%cols) + 1;
    $attribs->{edit}      = 1;
    $attribs->{default} ||= '';
    my $editor = $DB->editor('Users');

# Add the column.
    delete $attribs->{column};
    $editor->add_col($column, $attribs) or return ('admin_user_table_add.html', { msg => GList::language('TAB_ADD_COLUMN_ERR', $column, $GT::SQL::error) });

# Add the indexes.
    if ( $IN->param('index') eq 'regular' ) {
        $editor->add_index($column . '_idx' => [$column]) or return ('admin_user_table_add.html', { msg => GList::language('TAB_ADD_INDEX_ERR', $GT::SQL::error) });
    }
    if ( $IN->param('index') eq 'unique' ) {
        $editor->add_index($column . '_idx' => [$column]) or return ('admin_user_table_add.html', { msg => GList::language('TAB_ADD_UNIQUE_ERR', $GT::SQL::error) });
    }
    $db->reload;

    return admin_user_table(GList::language('TAB_ADD_SUCCESS', $column));
}
END_OF_SUB

$COMPILE{admin_user_table_modify} = __LINE__ . <<'END_OF_SUB';
sub admin_user_table_modify {
#-------------------------------------------------------------
# Modify a field
#
    $USER->{usr_type} == ADMINISTRATOR or return GList::display('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

#------------demo code-----------

    my $col     = $IN->param('column');
    my $db      = $DB->table('Users');
    my $editor  = $DB->editor('Users');
    my $cols    = $db->cols;
    my $old_def = $cols->{$col};
    return admin_user_table(GList::language('TAB_MOD_ERR', $col)) if (!exists $cols->{$col} or !$col);

    my %attribs = %{$cols->{$col}};

# Set up defaults for the fields
    foreach my $col (qw/column type not_null file_save_in file_max_size file_save_scheme default form_display form_type form_size form_names form_values regex weight values size/) {
        $attribs{$col} = $IN->param($col) if ( defined $IN->param($col) );
    }

    $attribs{column}       ||= $col;
    $attribs{form_type}    ||= 'TEXT';
    $attribs{form_size}    ||= ($attribs{form_type} eq 'SELECT') ? 0 : '';
    ref $attribs{form_size}     and ($attribs{form_size}    = join(",",  @{$attribs{form_size}}));
    ref $attribs{form_names}    and ($attribs{form_names}   = join("\n", @{$attribs{form_names}}));
    ref $attribs{form_values}   and ($attribs{form_values}  = join("\n", @{$attribs{form_values}}));
    ref $attribs{values}        and ($attribs{values}       = join("\n", @{$attribs{values}}));
    return ('admin_user_table_modify.html', \%attribs) if ($IN->param('form'));

# Keep any values that where there before
    my $attribs = _col_spec();
    for my $val ( keys %$old_def ) {
        $attribs->{$val} = $old_def->{$val} unless exists $attribs->{$val};
    }

# Error checking
    my $errors = _field_check();
    if ( $IN->param('index') eq 'primary' and ( $col ne $db->{schema}->{pk}) ) {
        $errors .= GList::language('TAB_PRIMARY_ERR');
    }
    return ('admin_user_table_modify.html', { msg => "<font color=red><b>$errors</b></font>", %attribs }) if($errors);

# Add/Drop indexes.
    my $index_type = _index_type($col);
    if ( $index_type ne $IN->param('index') ) {
        if ($index_type eq 'none') {
            if ( $IN->param('index') eq 'regular' ) {
                $editor->add_index( $col . "_idx" => [$col] );
            }
            else {
                $editor->add_unique( $col . "_idx" => [$col] );
            }
        }
        elsif ( $IN->param('index') eq 'none' ) {
            if ( $index_type eq 'regular' ) {
                my $index = $db->index;
                INDEX: foreach my $index_name (keys %$index) {
                    foreach my $col_name ( @{$index->{$index_name}} ) {
                        next unless ($col_name eq $col);
                        $editor->drop_index($index_name) or return ('admin_user_table_modify.html', { msg => "<font color=red><b>$GT::SQL::error</b></font>", %attribs });
                        last INDEX;
                    }
                }
            }
            else {
                my $unique = $db->unique;
                INDEX: foreach my $unique_name (keys %$unique) {
                    foreach my $col_name (@{$unique->{$unique_name}}) {
                        next unless ($col_name eq $col);
                        $editor->drop_unique($unique_name) or return ('admin_user_table_modify.html', { msg => "<font color=red><b>$GT::SQL::error</b></font>", %attribs });
                        last INDEX;
                    }
                }
            }
        }
    }

# Make the changes
    delete $attribs->{column};

    $editor->alter_col($col, $attribs) or return ('admin_user_table_modify.html', { msg => '<font color=red><b>'.$editor->error.'</b></font>', %attribs });
    return admin_user_table(GList::language('TAB_MOD_SUCCESS', $col));
}
END_OF_SUB

$COMPILE{admin_user_table_delete} = __LINE__ . <<'END_OF_SUB';
sub admin_user_table_delete {
#--------------------------------------------------------------
# Delete a field of User Table
#
    $USER->{usr_type} == ADMINISTRATOR or return GList::display('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

#------------demo code-----------

    my $column = $IN->param('column');
    return admin_user_table(GList::language('TAB_MOD_INVALID')) if (!$column);
    return admin_user_table(GList::language('TAB_MOD_PERMIT_ERR', 'pro_first_name, pro_last_name')) if ($column =~ /pro_first_name|pro_last_name/);

# Keep any values that where there before
    my $db      = $DB->table('Users');
    my $editor  = $DB->editor('Users');
    my $old_def = $db->cols->{$column};

# Drop the column from the database.
    $editor->drop_col($column) or return admin_user_table("<font color=red><b>$GT::SQL::error</b></font>");

    return admin_user_table(GList::language('TAB_DEL_SUCCESS', $column));
}
END_OF_SUB

$COMPILE{admin_user_table_resync} = __LINE__ . <<'END_OF_SUB';
sub admin_user_table_resync {
#--------------------------------------------------------------------
# Resync database
#
    my $name = $IN->param('db') || 'Users';
    $USER->{usr_type} == ADMINISTRATOR or return ('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

# We need a creator for this.
    my $c  = $DB->creator($name);
    my $db = $DB->table($name);
    $c->load_table or return admin_user_table($GT::SQL::error);

# Re Load our table object.
    $db->reload;

    return admin_user_table(GList::language('TAB_RESYNC'));
}
END_OF_SUB

$COMPILE{admin_stoplist} = __LINE__ . <<'END_OF_SUB';
sub admin_stoplist {
#-------------------------------------------------------------------
# Update the stop lists
#
    my $msg = shift;
    $USER->{usr_type} == ADMINISTRATOR or return GList::display('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

    $MN_SELECTED = 9;
    return ('admin_stoplist_form.html') if ($IN->param('form'));

    my $alpha = 0;
    my $cgi   = $IN->get_hash;
    my $query= '';
    if ($IN->param('alpha') and $IN->param('alpha') ne 'all') { # from the quick search bar
        $alpha = $IN->param('alpha');
        $query = "alpha=$alpha";
    }
    my $db = $DB->table('StopLists');
    $db->select_options('ORDER BY letter');

    require GT::SQL::Condition;
    my $cd  = GT::SQL::Condition->new();
    my $url = 'glist.cgi?do=admin_stoplist';
    if ($cgi->{stl_email}) {
        $cd->add('stl_email' => 'like' => "%$cgi->{stl_email}%");
        $url .= ";stl_email=$cgi->{stl_email}";
    }

    my $sth     = $db->select($cd, ['DISTINCT SUBSTRING(stl_email, 1, 1) as letter']);
    my $results = GList::search(
        cgi         => $cgi,
        db          => $DB->table('StopLists'),
        based_on    => $DB->prefix.'StopLists',
        prefix      => 'stl',
        sb          => 'stl_email',
        so          => 'ASC',
        search_alpha=> $alpha,
        search_col  => 'stl_email',
        return_msg  => 'ADM_STOPLIST',
        skip_user   => 1,
    );

    require GList::List;
    if ( ref $results ne 'HASH' ) {
        return ('admin_stoplist.html', { search_bar => GList::List::_search_bar($sth, $url), msg => $results });
    }
    $results->{msg} = $msg if ($msg);
    return ('admin_stoplist.html', { search_bar => GList::List::_search_bar($sth, $url), toolbar_query => $query, toolbar_table => 'StopLists', %$results })
}
END_OF_SUB

$COMPILE{admin_stoplist_confirm} = __LINE__ . <<'END_OF_SUB';
sub admin_stoplist_confirm {
#--------------------------------------------------------------------
# Confirmation about remove all emails that match the addition stoplist
# from all list
# 
    $USER->{usr_type} == ADMINISTRATOR or return GList::display('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

    $MN_SELECTED = 9;
    my $emails   = $IN->param('emails') || '';
    return ('lst_stoplist_form.html', { msg => GList::language('ADM_STOPLIST_ERROR') }) if (!$emails);

    require GT::SQL::Condition;
    my $db_sub = $DB->table('Subscribers');
    my @emails = split(/\r?\n/, $emails);

    my (@results, %found);
    foreach my $e (@emails) {
        $e =~ s/^\s+//;
        $e =~ s/\s+$//;
        next unless $e and $e =~ /.@./;
        my $cond;
        if ($e =~ /[*?]/) {
            my $tmp = $e;
            $tmp =~ y/*/%/;
            $tmp =~ y/?/_/;
            $cond = GT::SQL::Condition->new(sub_email => LIKE => $tmp);
        }
        else {
            $cond = { sub_email => $e };
        }
        my $pre = keys %found;
        my @found = $db_sub->select(sub_id => $cond)->fetchall_list;
        for (@found) { $found{$_}++ }
        my $added = keys(%found) - $pre;
        push @results, { email => $e, found => $added };
    }

    my $found_emails = scalar keys %found;
    return admin_stoplist_add() if (!$found_emails);

    return ('admin_stoplist_form.html', {
        loop_results => \@results,
        loop_hits    => $#results + 1,
        found_emails => $found_emails,
        data         => $emails,
        confirmation => 1
    });
}
END_OF_SUB

$COMPILE{admin_stoplist_add} = __LINE__ . <<'END_OF_SUB';
sub admin_stoplist_add {
#--------------------------------------------------------------------
# Add email to stop list
#
    $USER->{usr_type} == ADMINISTRATOR or return GList::display('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

    $MN_SELECTED = 9;
    my $emails   = $IN->param('emails') || '';
    return ('lst_stoplist_form.html', { msg => GList::language('ADM_STOPLIST_ERROR') }) if (!$emails);

    my ($invalid, $duplicate) = (0, 0);
    my @emails = split(/\r?\n/, $emails);
    my $db_stl = $DB->table('StopLists');
    my $db_sub = $DB->table('Subscribers');

    require GT::SQL::Condition;
    my @results;
    my $cond = GT::SQL::Condition->new('OR');
    foreach my $e (@emails) {
        $e =~ s/^\s+//;
        $e =~ s/\s+$//;
        next if !$e;
        if ( $e !~ /.@./ ) { # check email address
            push @results, { email => $e, status => GList::language('SYS_INVALID_EMAIL') };
            $invalid++;
        }
        else {
            if ($e =~ /[*?]/) {
                my $tmp = $e;
                $tmp =~ y/*/%/;
                $tmp =~ y/?/_/;
                $cond->add(sub_email => LIKE => $tmp);
            }
            else {
                $cond->add(sub_email => '=' => $e);
            }

            push @results, { email => $e, status => '' };
            if ($db_stl->count({ stl_email => $e })) {
                $results[-1]->{status} = GList::language('SYS_DUPLICATE');
                $duplicate++;
            }
            else {
                $db_stl->insert({ stl_email => $e });
            }
        }
    }
    $db_sub->delete($cond) if (@{$cond->{cond}});

    return ('admin_stoplist_success.html', {
        results    => \@results,
        duplicate  => $duplicate,
        invalid    => $invalid,
        hits       => scalar @results,
        successful => scalar @results - $invalid - $duplicate,
    });
}
END_OF_SUB

$COMPILE{admin_stoplist_delete} = __LINE__ . <<'END_OF_SUB';
sub admin_stoplist_delete {
#---------------------------------------------------------------------
# Delete email from stop list
#
    $USER->{usr_type} == ADMINISTRATOR or return GList::display('error_form.html', { msg => GList::language('ADM_PERMISSION_ERR') });

    my $mod = ( ref $IN->param('modify') eq 'ARRAY' ) ? $IN->param('modify') : [$IN->param('modify')];
    my $db  = $DB->table('StopLists');
    my $cgi = $IN->get_hash();

    foreach my $rec_num ( @{$mod} ) {
        $db->delete({ stl_id => $cgi->{"$rec_num-stl_id"} });
    }
    return admin_stoplist(GList::language('ADM_STOPLIST_DELETED', $#$mod + 1));
}
END_OF_SUB

$COMPILE{_update_cfg} = __LINE__ . <<'END_OF_SUB';
sub _update_cfg {
# ------------------------------------------------------------------
# Updates the config based on the form input.
#
    foreach my $param ($IN->param) {
        if (exists $CFG->{$param}) {
            if (ref $CFG->{$param} eq ref []) {
                my @val = split /\s*,\s*/, $IN->param($param);
                $CFG->{$param} = \@val;
            }
            elsif (ref $CFG->{$param} eq ref {}) {
                my $h = {};
                my @pairs = split /\s*,\s*/, $IN->param($param);
                foreach my $pair (@pairs) {
                    my ($k, $v) = split /\s*=\s*/, $pair;
                    $h->{$k} = $v;
                }
                $CFG->{$param} = $h;
            }
            else {
                $CFG->{$param} = $IN->param($param);
            }
        }
    }
}
END_OF_SUB

$COMPILE{_field_check} = __LINE__ . <<'END_OF_SUB';
sub _field_check {
# ----------------------------------------------------------
# Checks to see if the input field name is a valid one,
# the function checks the following:
# 1. Column name
# 2. Check column exist
# 3. Check field size
    my $cgi       = $IN->get_hash;
    my $col_name  = $cgi->{column} || $cgi->{mod};
    my $form_type = uc($cgi->{form_type});
    my $type      = uc($cgi->{type});

    return GList::language('TAB_COL_NAME') if ( $col_name !~ /^(\w+)$/ );

# Max lengths
    if (( $type eq 'CHAR' ) and ( $cgi->{size} > 255 ) ) {
        return  GList::language('TAB_COL_SIZE');
    }

    if ( ( $type eq 'INT' ) and ( $cgi->{size} > 0 ) ) {
        return GList::language('TAB_COL_SIZE_INT');
    }

    if ( ( $type eq 'ENUM' ) and ( !$cgi->{values} ) ) {
        return GList::language('TAB_COL_VALUES');
    }

    if ( ( $cgi->{index} eq 'primary' or $cgi->{index} eq 'index' or $cgi->{index} eq 'unique' ) and ( ! $cgi->{not_null} ) ) {
        return sprintf(GList::language('TAB_COL_NOTNULL'), $col_name);
    }

    if ( ( $form_type eq 'FILE' ) and ( $type ne 'CHAR' ) and ( $type ne 'VARCHAR' ) ) {
        return GList::language('TAB_COL_FILE_TYPE');
    }

    my $location = $cgi->{file_save_in};
    if ( ( $form_type eq 'FILE' ) and ( !$location ) ) {
        return GList::language('TAB_COL_FILE_IN');
    }

    if ( ( $form_type eq 'FILE' ) and ( !-w $location ) ) {
        return sprintf(GList::language('TAB_COL_FILE_ERR'), $location);
    }
}
END_OF_SUB

$COMPILE{_col_spec} = __LINE__ . <<'END_OF_SUB';
sub _col_spec {
# ----------------------------------------------------------
# Reconstruct the input variables into a string in the form
# "field_name(type(length_set) attribute DEFAULT default_value extra)"

    my $cgi = $IN->get_hash;
    my $col_spec;

    # add field properties into a hash
    $col_spec->{'type'} = $cgi->{type};
    if ( $cgi->{type} eq 'ENUM' ) {
        $col_spec->{'values'} = [split /(?:\n|\r)+/, $cgi->{values}];
    }
    else {
        $col_spec->{'size'} = $cgi->{size};
    }
    $col_spec->{'default'}      = $cgi->{default};
    $col_spec->{'not_null'}     = ($cgi->{not_null})    ? '1' : '';
    $col_spec->{'form_display'} = ($cgi->{form_display})? $cgi->{form_display} : $cgi->{column};
    $col_spec->{'form_type'}    = ($cgi->{form_type})   ? $cgi->{form_type} : 'TEXT';
    $col_spec->{'form_size'}    = ($cgi->{form_size})   ? $cgi->{form_size} : '';
    $col_spec->{'form_names'}   = ($cgi->{form_names})  ? [split /(?:\n|\r)+/, $cgi->{form_names}] : [];
    $col_spec->{'form_values'}  = ($cgi->{form_values}) ? [split /(?:\n|\r)+/, $cgi->{form_values}]: [];
    $col_spec->{'regex'}        = ($cgi->{regex})       ? $cgi->{regex} : '';

    if ( $cgi->{file_save_in} ) {
        $col_spec->{'file_save_in'}     = $cgi->{file_save_in};
        $col_spec->{'file_save_scheme'} = $cgi->{file_save_scheme};
        $col_spec->{'file_max_size'}    = $cgi->{file_max_size};
    }

    return $col_spec;
}
END_OF_SUB

$COMPILE{_index_type} = __LINE__ . <<'END_OF_SUB';
sub _index_type {
#-----------------------------------------------------------------
    my $column = shift;
    my $db = $DB->table('Users');
    my $indexed = 'none';
    if ($column) {
        $db->_is_indexed($column) and ($indexed = 'regular');
        $db->_is_unique($column)  and ($indexed = 'unique');
        $db->_is_pk($column)      and ($indexed = 'primary');
    }
    return $indexed;
}
END_OF_SUB

$COMPILE{_save_users} = __LINE__ . <<'END_OF_SUB';
sub _save_users {
#-------------------------------------------------------------------
#
    my $users = $DB->table('Users')->select({ usr_type => ADMINISTRATOR }, ['usr_username', 'usr_password', 'usr_email'])->fetchall_hashref;
    my %hash;
    foreach (@$users) {
        $hash{$_->{usr_username}} = [$_->{usr_password}, $_->{usr_email}];
    }
    $CFG->{admin} = \%hash;
    $CFG->save;
}
END_OF_SUB

$COMPILE{_sql_load_cfg} = __LINE__ . <<'END_OF_SUB';
sub _sql_load_cfg {
#-------------------------------------------------------------------
# Load current sql information
#
    require GList::SQL;
    my $cfg = GList::SQL::load();
    foreach (keys % $cfg) {
        $cfg->{"sql_$_"} = $cfg->{$_};
        delete $cfg->{$_};
    }
    return $cfg;
}
END_OF_SUB

$COMPILE{_sql_connect} = __LINE__ . <<'END_OF_SUB';
sub _sql_connect {
#----------------------------------------------------------
#
    my ($host, $driver, $database, $login, $password, $prefix) = @_;

    my ($port, $ret);
    ($host =~ s/\:(\d+)$//) and ($port = $1);

    $prefix =~ /^\w*$/ or return { error => "<font color=red><b>Invalid prefix: '$prefix'. Can only be letters, numbers and underscore.</b></font>" };

    GT::SQL->reset_env();
    $DB->prefix($prefix);
    $ret = $DB->set_connect({
        driver     => $driver,
        host       => $host,
        port       => $port,
        database   => $database,
        login      => $login,
        password   => $password,
        RaiseError => 0,
        PrintError => 0,
        AutoCommit => 1
    });

    if (! defined $ret) {
        return { error => "<font color=red><b>$GT::SQL::error</b></font>" };
    }

    return $ret;
}
END_OF_SUB

$COMPILE{_account_limit} = __LINE__ . <<'END_OF_SUB';
sub _account_limit {
#-----------------------------------------------------------
#
    my $data = shift;
    if ($data->{usr_type} == ADMINISTRATOR or $data->{usr_type} == UNLIMITED_USER ) {
        $data->{usr_limit_list}    = 0;
        $data->{usr_limit_sublist} = 0;
        $data->{usr_limit_email30} = 0;
    }
    else {
        $data->{usr_limit_list}    ||= $CFG->{signup_limit_list}    || 10;
        $data->{usr_limit_sublist} ||= $CFG->{signup_limit_sublist} || 10;
        $data->{usr_limit_email30} ||= $CFG->{signup_limit_email30} || 100;
    }
    return $data;
}
END_OF_SUB

$COMPILE{_determine_action} = __LINE__ . <<'END_OF_SUB';
sub _determine_action {
#----------------------------------------------------------------------------
# Check valid action
#
    my $action = shift || undef;

    if ( $action =~ /admin_setup_sql_form|admin_setup_sql|admin_setup_form|admin_setup/ ) {
        $MN_SELECTED = 9;
    }
    ($action eq 'admin_user_search') and return 'admin_user';
    return if ( !$action );

    my %valid = (
        map { $_ => 1 } qw(
            admin_gtdoc
            admin_page
            admin_initial_sql
            admin_initial_setup
            admin_user
            admin_user_add
            admin_user_modify_form
            admin_user_modify
            admin_user_delete
            admin_user_validate
            admin_user_table
            admin_user_table_add
            admin_user_table_modify
            admin_user_table_delete
            admin_user_table_resync
            admin_plugin
            admin_setup_sql_form
            admin_setup_sql
            admin_setup_form
            admin_setup
            admin_template_diff
            admin_stoplist
            admin_stoplist_add
            admin_stoplist_confirm
            admin_stoplist_delete
        )
    );
    exists $valid{$action} and return $action;
    return;
}
END_OF_SUB

1;
