/*
===============================================================================
User registration plugin - Version 1.25
===============================================================================
http://www.amxmodx.org/forums/viewtopic.php?p=125169

--------
Features
--------
-Changes users names if
    # not logged in
    # uses a blocked name (support for exceptions)
-Option to gag users that are not logged in (gag say, say_team and voice comm)
** voice comm gag untested **
-Authentication via 3 systems
    # Name and password
    # Steam ID
    # IP
-1 account per Steam ID / IP (only if Steam ID / IP authentication is used)
-uses a variable in 'setinfo' to store password / Steam ID / IP
-For email registration in game register and unregister is disabled
-PHP registration form available

------------
Requirements
------------
-MySQL
-engine module (used for voice mute)

---------
Tested on
---------
-Windows XP Professional Edition
-AMX mod v 1.71
-MySQL 5.0.18-nt
-Counter-Strike
    Exe version 1.1.2.5/2.0.0.0 (cstrike)
    Exe build: 21:56:52 Feb  8 2006 (338

--------------
Main Functions
--------------
Register, Unregister, Login functions have different syntax depending on authentication type

    reg <name> <pass>       Register a name (Name/Password authentication)
    reg <name>              Register a name (Steam ID / IP authentication)
    ureg <name> <pass>      Unregister (Name/Password authentication)
    ureg                    Unregister (Steam ID / IP authentication)
    login <name> <pass>     Login (Name/Password authentication)
    login                   Login (Steam ID / IP authentication)
    logout                  Logout of account
    userReghelp             Help screen

'''''''''''''''
Admin Functions
'''''''''''''''
    adreg <user> <pass>      Register a user. <pass> may be password / Steam ID / IP
    adureg <name>            Unregister user via name
    aduregID <id>            Unregister user via Steam ID / IP
    addblock <word>          Add word to block list
    delblock <word>          Remove word to block list

-----
cvars
-----
    amx_registerLogin        if set auto logs user in after registration of name

    punishments for not loggin in
    '''''''''''''''''''''''''''''
    amx_punishGag            gag chat
        -1 - no gag
         0 - gag say and team say
         1 - gag say
         2 - gag team say
    amx_punishGagVoice        gag voice communication
        0 - no gag
        1 - gag set

    amx_msgOverload
        1 - displays a lot of messages continually


---------
Changelog
---------
v 1.25  Added using a file to store data instead of a database
        Works with AMX Mod v 1.71: changed set_user_info() function - removed last parameter
        Fixed consoleAdminUnregister() that did not unregister user
v 1.24  Changed behavour of msgOverload slightly and fixed bug where logged in users logouts and does not get any msgOverload
        Added md5 hashing of passwords, and thus changed table layout for email activation        
v 1.23  Added a few fixes and changed the working of the plugin so that as long as user isnt registered, name will be [Unregistered]
v 1.22  Added plugin_modules() as suggested by devicenull :)




CREATE TABLE IF NOT EXISTS `ur_users` ( `name` VARCHAR( 32 ) NOT NULL, `pass` VARCHAR( 100 ) NOT NULL, `email` VARCHAR(100) NOT NULL);
CREATE TABLE IF NOT EXISTS `ur_users_waiting` ( `name` VARCHAR( 32 ) NOT NULL, `pass` VARCHAR( 100 ) NOT NULL, `email` VARCHAR(100) NOT NULL, `activateCode` varchar(200) NOT NULL);
CREATE TABLE IF NOT EXISTS `ur_reserved` ( `type` VARCHAR( 32 ) UNIQUE NOT NULL, `name` VARCHAR( 32 ) NOT NULL );
INSERT INTO `ur_reserved` (type, name) VALUES(0, '[Unregistered]');
INSERT INTO `ur_reserved` (type, name) VALUES(1, '[BlockedName]');
CREATE TABLE IF NOT EXISTS `ur_blocked` (`name` VARCHAR( 32 ) UNIQUE NOT NULL );
INSERT INTO `ur_blocked` (name) VALUES('fuck');
INSERT INTO `ur_blocked` (name) VALUES('shit');
CREATE TABLE IF NOT EXISTS `ur_exceptions` (`name` VARCHAR( 32 ) NOT NULL );


*/

#include <amxmodx>
#include <amxmisc>
#include <engine>

#define MYSQL 0

#if MYSQL
    #include <dbi>
#endif

#define MAX_PLAYERS 32
#define MAX_LINE_LENGTH 80
#define MSG_SIZE 200
#define MSG_OVERLOAD_SIZE 1000
// authentication type
// 0 password
// 1 steamid
// 2 ip
#define AUTH_TYPE 0
#define EMAIL_VERIFY 0

// console command user access levels
#define REG_ACCESS ADMIN_ALL
#define UREG_ACCESS ADMIN_ALL
#define LOGIN_ACCESS ADMIN_ALL
#define HELP_ACCESS ADMIN_ALL
#define ADMIN ADMIN_KICK

// reserved name list used for name changing
// key => value association
// key:   id number
// value: name associated with the key
#define RESERVED_UNREGISTERED 0
#define RESERVED_BLOCKED 1
new const RESERVED_UNREGISTERED_TEXT[] = "[Unregistered]"
new const RESERVED_BLOCKED_TEXT[] = "[BlockedName]"

// for displaying different types of help menu displaying console commands
#define HELP_ONLY_COMMANDS 0
#define HELP_MISC 1
#define HELP_GAG 2

// program details
new const PLUGIN_NAME[] = "User Registration"
new const AUTHOR[] = "TheWeed"
new const VERSION[] = "1.24"

// user setinfo variable to set password to
// used for auto login and storing users current password
new const PASSWORD_FIELD[] = "_uPwd"

///////////////
// gag vars - 1
new gag[MAX_PLAYERS+1]
// gag vars - 0
///////////////


//////////////////
// mysql vars - 1
new bool:SQL_CONNECTED = false

// mysql table names
new const USER_TABLE[] = "ur_users"
new const WAITING_TABLE[] = "ur_users_waiting"
new const RESERVED_TABLE[] = "ur_reserved"
new const BLOCKED_TABLE[] = "ur_blocked"
new const EXCEPTIONS_TABLE[] = "ur_exceptions"

#if MYSQL
    new Sql:sql
    new Result:result
#endif
// mysql vars - 0
//////////////////

/*#############################################################################
    INITIALISE FUNCTIONS - 1
#############################################################################*/

public plugin_init()
{
    register_plugin(PLUGIN_NAME, VERSION, AUTHOR)
    register_clcmd("say","check_gag")
    register_clcmd("say_team","check_gag")

    #if AUTH_TYPE == 0
        #if EMAIL_VERIFY == 0
            register_concmd("reg","consoleRegister",REG_ACCESS," <name> <pass> - Register a name")
            register_concmd("ureg","consoleUnregister",UREG_ACCESS," <name> <pass> - Unregister a name")
        #endif
        register_concmd("login","consoleLogin",LOGIN_ACCESS," <name> <pass> - Login")
    #else
    #if AUTH_TYPE == 1
        register_concmd("reg","consoleRegister",REG_ACCESS," <name> - Register a name")
        register_concmd("ureg","consoleUnregister",UREG_ACCESS," - Unregister your name")
        register_concmd("login","consoleLogin",LOGIN_ACCESS," - Login")
    #else
    #if AUTH_TYPE == 2
        register_concmd("reg","consoleRegister",REG_ACCESS," <name> - Register a name")
        register_concmd("ureg","consoleUnregister",UREG_ACCESS," - Unregister a name")
        register_concmd("login","consoleLogin",LOGIN_ACCESS," - Login")
        register_concmd("logout","consoleLogout",LOGIN_ACCESS," - Logout")
    #endif
    #endif
    #endif

    // common fucntions
    register_concmd("logout","consoleLogout",LOGIN_ACCESS," - Logout")
    register_concmd("userReghelp","consoleHelp",LOGIN_ACCESS," - Displays help")

    // admin fucntions
    register_concmd("adreg","consoleAdminRegister",ADMIN," <name> <pass> - Register a name")
    register_concmd("adureg","consoleAdminUnregister",ADMIN," <name> - Unregister a name")
    register_concmd("aduregID","consoleAdminUnregisterID",ADMIN," <id> - Unregister a name")
    register_concmd("addBlock","consoleBlock",ADMIN," <word> - Adds <word> from block table")
    register_concmd("delBlock","consoleUnblock",ADMIN," <word> - Removes <word> from block table")

    // cvars
    register_cvar("amx_registerLogin","0")
    register_cvar("amx_punishGag","0")
    register_cvar("amx_punishGagVoice","1")
    register_cvar("amx_msgOverload","1")
    
    #if MYSQL
        sqlInit()
    #else
        fileInit()
    #endif
}

// checks for required modules
public plugin_modules()
{
    require_module("engine")
    #if MYSQL
        require_module("DBI")
    #endif
}


#if MYSQL
    public sqlInit()
    {
    
        new host[64],user[32],pass[32],db[32],error[128]
        get_cvar_string("amx_sql_host",host,63)
        get_cvar_string("amx_sql_user",user,31)
        get_cvar_string("amx_sql_pass",pass,31)
        get_cvar_string("amx_sql_db",db,31)

        sql = dbi_connect(host,user,pass,db,error,127)
        if (sql <= SQL_FAILED)
        {
            server_print("ERROR. Failed to connect to mySQL. Plugin ending")
        }
        else
        {
            // create tables if doesnt exist
    		result = dbi_query(sql,"CREATE TABLE IF NOT EXISTS `%s` ( `name` VARCHAR( 32 ) NOT NULL, `pass` VARCHAR( 100 ) NOT NULL, `email` VARCHAR(100) NOT NULL)", USER_TABLE)
    		dbi_free_result (result) 
    		result = dbi_query(sql,"CREATE TABLE IF NOT EXISTS `%s` ( `name` VARCHAR( 32 ) NOT NULL, `pass` VARCHAR( 100 ) NOT NULL, `email` VARCHAR(100) NOT NULL, `activateCode` varchar(200) NOT NULL)", WAITING_TABLE)
    		dbi_free_result (result) 
    		result = dbi_query(sql,"CREATE TABLE IF NOT EXISTS `%s` ( `type` VARCHAR( 32 ) UNIQUE NOT NULL, `name` VARCHAR( 32 ) NOT NULL )", RESERVED_TABLE)
    		dbi_free_result (result) 
    		dbi_query(sql,"INSERT INTO `%s` (type, name) VALUES(%d, '%s')", RESERVED_TABLE, RESERVED_UNREGISTERED, RESERVED_UNREGISTERED_TEXT)
    		dbi_query(sql,"INSERT INTO `%s` (type, name) VALUES(%d, '%s')", RESERVED_TABLE, RESERVED_BLOCKED, RESERVED_BLOCKED_TEXT)
    		result = dbi_query(sql,"CREATE TABLE IF NOT EXISTS `%s` (`name` VARCHAR( 32 ) UNIQUE NOT NULL )", BLOCKED_TABLE)
    		dbi_free_result (result) 
    		dbi_query(sql,"INSERT INTO `%s` (name) VALUES('fuck')", BLOCKED_TABLE)
    		dbi_query(sql,"INSERT INTO `%s` (name) VALUES('shit')", BLOCKED_TABLE)
    		result = dbi_query(sql,"CREATE TABLE IF NOT EXISTS `%s` (`name` VARCHAR( 32 ) NOT NULL )", EXCEPTIONS_TABLE)
    		dbi_free_result (result) 
    		SQL_CONNECTED = true
        }
        return PLUGIN_HANDLED
    }
#else
    public fileInit()
    {
        new fp
        new buff[MAX_LINE_LENGTH]
        
        if(!file_exists(USER_TABLE))
        {
            fp = fopen(USER_TABLE, "wt")
            fclose(fp)
        }
        if(!file_exists(WAITING_TABLE))
        {
            fp = fopen(WAITING_TABLE, "wt")
            fclose(fp)
        }
        if(!file_exists(RESERVED_TABLE))
        {
            fp = fopen(RESERVED_TABLE, "wt")
            fclose(fp)
            format(buff, MAX_LINE_LENGTH, "%d %s", RESERVED_UNREGISTERED, RESERVED_UNREGISTERED_TEXT)
            write_file(RESERVED_TABLE, buff)
            format(buff, MAX_LINE_LENGTH, "%d %s", RESERVED_BLOCKED, RESERVED_BLOCKED_TEXT)
            write_file(RESERVED_TABLE, buff)
        }
        if(!file_exists(BLOCKED_TABLE))
        {
            fp = fopen(BLOCKED_TABLE, "wt")
            fclose(fp)
            write_file(BLOCKED_TABLE, "fuck")
            write_file(BLOCKED_TABLE, "shit")
        }

        if(!file_exists(EXCEPTIONS_TABLE))
        {
            fp = fopen(EXCEPTIONS_TABLE, "wt")
            fclose(fp)
        }
        return PLUGIN_HANDLED
    }
#endif
/*#############################################################################
    INITIALISE FUNCTIONS - 0
    CONSOLE FUNCTIONS - 1
#############################################################################*/
public consoleBlock(id,level,cid)
{
    if (!cmd_access(id, level, cid, 2))
        return PLUGIN_HANDLED
    new word[32]
    read_argv(1, word, 31)
    #if MYSQL
    {
        result = dbi_query(sql,"INSERT INTO `%s` (name) VALUES('%s')", BLOCKED_TABLE, word)
        dbi_free_result (result) 
        console_print(id, "Word(%s) added.", word)
    }
    #else
    {
        if(!find(word, BLOCKED_TABLE))
        {
            write_file(BLOCKED_TABLE, word)
            console_print(id, "Word(%s) added.", word)
        }
        else
            console_print(id, "Word(%s) already exists.", word)
    }
    #endif
    return PLUGIN_HANDLED
}
public consoleUnblock(id,level,cid)
{
    if (!cmd_access(id, level, cid, 2))
        return PLUGIN_HANDLED
    new word[32]
    read_argv(1, word, 31)
    #if MYSQL
    {
        result = dbi_query(sql,"select * from `%s` where name = '%s'", BLOCKED_TABLE, word)
        if(result == RESULT_FAILED)
        {
            console_print(id, "ERROR. Cannot delete name from database. Please contact admin")
        }
        else if(result == RESULT_NONE)
        {
            console_print(id, "ERROR. Word(%s) does not exist in database.", word)
        }
        else
        {
            result = dbi_query(sql,"delete from `%s` where name = '%s'", BLOCKED_TABLE, word)
            console_print(id, "Word(%s) deleted.", word)
        }
        dbi_free_result (result)
    }
    #else
    {
        new lineNo
        lineNo = find(word, BLOCKED_TABLE)
        if(lineNo)
        {
            if(delLine(lineNo, BLOCKED_TABLE))
                console_print(id, "Word(%s) deleted.", word)
            else
                console_print(id, "Error deleting word(%s).", word)
        }
        else
            console_print(id, "Word(%s) not found.", word)
    }
    #endif

    return PLUGIN_HANDLED
}

/*-----------------------------------------------------------------------------
admin registering
-----------------------------------------------------------------------------*/
public consoleAdminRegister(id,level,cid)
{
    new name[32], pass[35]
    if (!cmd_access(id, level, cid, 3))
        return PLUGIN_HANDLED
    read_argv(1, name, 31)
    read_argv(2, pass, 34)
    if(!validNameMsg(id, name))
        return PLUGIN_HANDLED
    if(!validPassMsg(id, pass))
        return PLUGIN_HANDLED
    registerUser(id,name,pass)
    return PLUGIN_HANDLED
}

/*-----------------------------------------------------------------------------
admin unregistering a name
-----------------------------------------------------------------------------*/
public consoleAdminUnregister(id,level,cid)
{
    if (!cmd_access(id, level, cid, 2))
        return PLUGIN_HANDLED
    new name[32]
    read_argv(1, name, 31)
    if(validName(name) != -1)
    {
        console_print(id, "ERROR. Unregitered name. Cannot unregister")
        return PLUGIN_HANDLED
    }
    unregisterUser(id, name)
    return PLUGIN_HANDLED
}

/*-----------------------------------------------------------------------------
admin unregistering an ID [IP / steam id]
-----------------------------------------------------------------------------*/
public consoleAdminUnregisterID(id,level,cid)
{
    #if AUTH_TYPE == 0
        return PLUGIN_HANDLED
    #endif
    if (!cmd_access(id, level, cid, 2))
        return PLUGIN_HANDLED

    new pass[35]
    read_argv(1, pass, 34)
    if(!validPassMsg(id, pass))
    {
        console_print(id, "ERROR. Invalid password")
        return PLUGIN_HANDLED
    }
    unregisterID(id, pass)
    return PLUGIN_HANDLED
}

/*-----------------------------------------------------------------------------
register a name
    syntax:        reg <name> <password>
-------------------------------------------------------------------------------
checks database for clash with name
    if clash fail registration and tell user
-------------------------------------------------------------------------------

input
    syntax:        reg <name> <password>
output
    sets user name and password to that registered
    if registerLogin is set
        logs user in after registration
    else
        requires manual login
-----------------------------------------------------------------------------*/
public consoleRegister(id,level,cid)
{
    new name[32], pass[35], bool:checkPass = false
    #if MYSQL
        if (!SQLconnected())
            return PLUGIN_HANDLED
    #endif
    read_argv(1, name, 34)

    #if AUTH_TYPE == 0
    {
        #if EMAIL_VERIFY
            return PLUGIN_HANDLED
        #endif

        if (!cmd_access(id, level, cid, 3))
            return PLUGIN_HANDLED
        read_argv(2, pass, 34)

        if(!validPassMsg(id,pass))
            return PLUGIN_HANDLED
    }
    #else
    #if AUTH_TYPE == 1
    {
        if (!cmd_access(id, level, cid, 2))
            return PLUGIN_HANDLED
        get_user_authid(id, pass, 34)
        checkPass = true
    }
    #else
    #if AUTH_TYPE == 2
    {
        if (!cmd_access(id, level, cid, 2))
            return PLUGIN_HANDLED
        get_user_ip(id,pass,34,1)
        checkPass = true
    }
    #else
    #endif
    #endif
    #endif
    if(!validNameMsg(id, name))
       return PLUGIN_HANDLED
    if(checkPass && (getRegisteredName(name,pass) > 0))
    {
        console_print(id, "Registration failed: Steam ID / IP already registered. Type 'login' to log into your account")
        return PLUGIN_HANDLED
    }
    else
    {
        read_argv(1, name, 31)
        if(registerUser(id, name, pass) > 0)
        {
            if(get_cvar_num("amx_registerlogin") > 0)
            {
                completeLogin(id, name, pass)
            }
        }
    }
    return PLUGIN_HANDLED
}

/*-----------------------------------------------------------------------------
unregister a name
    syntax:        ureg <name> <password>
-------------------------------------------------------------------------------
if unregister name currently logged into
    reset users current password
-----------------------------------------------------------------------------*/

public consoleUnregister(id,level,cid)
{
    new bool: passAuth = false
    #if MYSQL
        if (!SQLconnected())
            return PLUGIN_HANDLED
    #endif

    new name[32], pass[35]
    #if AUTH_TYPE == 0
    {
        #if EMAIL_VERIFY
            return PLUGIN_HANDLED
        #endif
        if (!cmd_access(id, level, cid, 3))
            return PLUGIN_HANDLED
        read_argv(1, name, 31)
        read_argv(2, pass, 34)
        passAuth = true
        if(!validNameMsg(id, name))
            return PLUGIN_HANDLED
        if(!validPassMsg(id, pass))
            return PLUGIN_HANDLED
    }
    #else
    #if AUTH_TYPE == 1
    {
        if (!cmd_access(id, level, cid, 1))
            return PLUGIN_HANDLED
        get_user_authid(id, pass, 34)
    }
    #else
    #if AUTH_TYPE == 2
    {
        if (!cmd_access(id, level, cid, 1))
            return PLUGIN_HANDLED
        get_user_ip(id,pass,34,1)
    }
    #else
    #endif
    #endif
    #endif

    if(!passAuth)
    {
        if(unregisterID(id, pass) > 0)
        {
            client_cmd(id, "setinfo %s ^"^"", PASSWORD_FIELD)
            console_print(id, "Succesfully unregistered", name)
        }
        return PLUGIN_HANDLED
    }
    else if((login(name, pass) > 0))
    {
        new success
        success = false
        #if MYSQL
        {
            result = dbi_query(sql,"delete from %s where name = '%s' and pass LIKE BINARY '%s'",USER_TABLE, name, pass)

            if(result == RESULT_FAILED)
            {
                console_print(id, "ERROR. Cannot delete name from database. Please contact admin")
            }
            else
            {
                success = true
            }
            dbi_free_result(result)
        }
        #else
        {
            new lineNo, numChars
            new buff[MAX_LINE_LENGTH]
            new nameF[MAX_LINE_LENGTH], passF[MAX_LINE_LENGTH]
            for(lineNo = 0; lineNo< file_size(USER_TABLE, 1); lineNo++)
            {
                if(!read_file(USER_TABLE,lineNo,buff,MAX_LINE_LENGTH,numChars))
                    break
                parse(buff, nameF, MAX_LINE_LENGTH, passF, MAX_LINE_LENGTH)
                if(equali(nameF, name) && equal(passF, pass))
                {
                    if(delLine(id, USER_TABLE))
                        success = true
                    else
                        console_print(id, "ERROR. Cannot delete name from database. Please contact admin")
                    break
                }
            }
        }
        #endif
        if(success)
        {
            // check if user is currently logged in as name unregister
            // if so clear password field
            new currName[32], currPass[35]
            get_user_info(id,"name",currName,31)
            get_user_info(id,PASSWORD_FIELD,currPass,34)
            if(equali(currName, name) && equal(currPass, pass))
                client_cmd(id, "setinfo %s ^"^"", PASSWORD_FIELD)
            console_print(id, "Name (%s) succesfully unregistered", name)
        }
    }
    else
    {
        console_print(id, "Invalid user/password combination", name)
    }
    return PLUGIN_HANDLED
}


/*-----------------------------------------------------------------------------
user login
    syntax:        login <name> <password>
-------------------------------------------------------------------------------
if success
    sets name password
    print welcome msg
-------------------------------------------------------------------------------
output
    sets user name and password to that registered
-----------------------------------------------------------------------------*/

public consoleLogin(id,level,cid)
{
    #if MYSQL
        if (!SQLconnected())
            return PLUGIN_HANDLED
    #endif

    new name[32], pass[35]
    #if AUTH_TYPE == 0
    {
        if (!cmd_access(id, level, cid, 3))
            return PLUGIN_HANDLED
        read_argv(1, name, 31)
        read_argv(2, pass, 34)
        if(!validPassMsg(id, pass))
            return PLUGIN_HANDLED
    }
    #else
    #if AUTH_TYPE == 1
    {
        if (!cmd_access(id, level, cid, 1))
            return PLUGIN_HANDLED
        get_user_authid(id, pass, 34)
        getRegisteredName(name, pass)
    }
    #else
    #if AUTH_TYPE == 2
    {
        if (!cmd_access(id, level, cid, 1))
            return PLUGIN_HANDLED
        get_user_ip(id,pass,34,1)
        getRegisteredName(name, pass)
    }
    #else
    #endif
    #endif
    #endif
//    if(!validNameMsg(id, name))
//        return PLUGIN_HANDLED
    switch(login(name,pass))
    {
        case 1:
            completeLogin(id, name, pass)
        case -1:
            console_print(id, "Login failed")
        case -2:
            console_print(id, "Login failed: Email not verified. Please check email for verifcation email")
        default:
            console_print(id, "ERROR. Please report to admin")
    }
    return PLUGIN_HANDLED
}

/*-----------------------------------------------------------------------------
user logout
    syntax:        logout
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
output
    if success
        resets password
-----------------------------------------------------------------------------*/

public consoleLogout(id,level,cid)
{
    #if MYSQL
        if (!SQLconnected())
            return PLUGIN_HANDLED
    #endif
    if (!cmd_access(id, level, cid, 1))
        return PLUGIN_HANDLED
    new name[32], pass[35]

    get_user_info(id, "name", name, 31)
    #if AUTH_TYPE == 0
        get_user_info(id, PASSWORD_FIELD, pass, 34)
    #else
    #if AUTH_TYPE == 1
        get_user_authid(id, pass, 34)
    #else
    #if AUTH_TYPE == 2
        get_user_ip(id,pass,34,1)
    #else
    #endif
    #endif
    #endif

    if(login(name,pass) > 0)
    {
        completeLogout(id)
    }
    else
    {
        console_print(id, "You are not logged in")
    }
    return PLUGIN_HANDLED
}
/*-----------------------------------------------------------------------------
displays console command on screen via HUD and the console
-------------------------------------------------------------------------------
input
    id:    user to print to
    type: used to display different info depending
        HELP_ONLY_COMMANDS :   display ONLY the console commands
        HELP_MISC          :   displays console command and additional messages
-------------------------------------------------------------------------------
output
    if success
        resets password
-----------------------------------------------------------------------------*/

public consoleHelpMsg(id, type)
{
    #if AUTH_TYPE == 0
        new pass[] = "<password>"
        new name[] = "<name>"
    #else
        new pass[] = ""
        new name[] = ""
    #endif
    new msg[MSG_SIZE+1]
    switch(type)
    {
        case HELP_GAG:
        {
            console_print(id,"===============================================^n")
            console_print(id,"You have been gagged as you have not registered / logged in")
            console_print(id,"Console commands:")
            console_print(id,"Register: reg %s %s^n - to register a name", name, pass)
            console_print(id,"Login: login %s %s^n - to log in if you are not automatically logged in after registering", name, pass)
            console_print(id,"Help: userReghelp^n   - to bring up the help screen")
            console_print(id,"===============================================^n")
            format(msg, MSG_SIZE, "You have been gagged as you have not registered / logged in. Register: reg <name> %s^n Login: login %s %s ^n Help: userReghelp", pass, name, pass)
            errMsg(id, msg)
        }
        case HELP_MISC:
        {
            console_print(id,"This server requires user registration")
            console_print(id,"===============================================")
            console_print(id,"%s %s : %s", PLUGIN_NAME, VERSION, AUTHOR)
            console_print(id,"===============================================")
            console_print(id,"Console commands:-")
            console_print(id,"Register: reg <name> %s", pass)
            console_print(id,"Login: login %s %s", name, pass)
            console_print(id,"Help: userReghelp")
            console_print(id,"===============================================^n")
            format(msg, MSG_SIZE, "You have been gagged as you have not registered / logged in. Register: reg <name> %s^n Login: login %s %s ^n Help: userReghelp", pass, name, pass)
            errMsg(id, msg)
            errMsg(id, "This server requires user registration:^n \
                        Console commands:- ^nRegister: reg <name> <password>^n Login: login <name> <password> ^n Help: userReghelp")
        }
        case HELP_ONLY_COMMANDS:
        {
            console_print(id,"===============================================")
            console_print(id,"Console commands:-")
            console_print(id,"Register: reg <name> %s", pass)
            console_print(id,"Unregister: ureg %s %s", name, pass)
            console_print(id,"Login: login %s %s", name, pass)
            console_print(id,"Logout: logout")
            console_print(id,"Help: userReghelp")
            console_print(id,"===============================================^n")
            format(msg, MSG_SIZE,"Console commands:- ^nRegister: reg <name> %s^nUnregister: ureg %s %s^nLogin: login %s %s^nLogout: logout^nHelp: userReghelp", pass, name, pass, name, pass)
            set_hudmessage(255,100,0,-1.0,0.25,0,3.0,10.0,0.1,0.1)
            show_hudmessage(id,msg)
        }

    }
    return PLUGIN_HANDLED
}

public consoleHelp(id,level,cid)
{
    #if MYSQL
        if (!SQLconnected())
            return PLUGIN_HANDLED
    #endif
    if (!cmd_access(id, level, cid, 1))
        return PLUGIN_HANDLED
    consoleHelpMsg(id, HELP_ONLY_COMMANDS)
    return PLUGIN_HANDLED
}

/*#############################################################################
    CONSOLE FUNCTIONS - 0
    AUTO CALLED FUNCTIONS - 1
#############################################################################*/

/*
when user joins server
    check if user name and password stored authenticates user
    if doesnt dont prompt
    if user authenticated show welcome msg
*/
public client_putinserver(id)
{
    new name[32], pass[35]

    get_user_name(id, name, 31)
    #if AUTH_TYPE == 0
        get_user_info(id, PASSWORD_FIELD, pass, 34)
    #else
    #if AUTH_TYPE == 1
        get_user_authid(id, pass, 34)
    #else
    #if AUTH_TYPE == 2
        get_user_ip(id,pass,34,1)
    #else
    #endif
    #endif
    #endif
    gag[id] = 1
    if(get_cvar_num("amx_punishGagVoice"))
        set_speak(id, SPEAK_MUTED)

    if(login(name, pass) > 0)
    {
        new details[1]
        details[0] = id
        set_task(5.0,"completeLoginWrapper",450+id,details,1)
    }
    else
    {
        if(get_cvar_num("amx_msgOverload"))
        {
            new details[2]
            details[0] = id
            details[1] = 1
            set_task(5.0, "msgOverload", 480+id, details, 2)
        }
        client_infochanged(id)
    }
    return PLUGIN_CONTINUE
}

/*
 called when change name / password
 can detect name change
 cannot detect password change
*/
public client_infochanged(id)
{
    new newName[32], oldName[32], pass[35], details[2], bool:changeName = false
    get_user_name(id,oldName,31)
    get_user_info(id, "name", newName,31)
    #if AUTH_TYPE == 0
        get_user_info(id, PASSWORD_FIELD, pass, 34)
    #else
    #if AUTH_TYPE == 1
        get_user_authid(id, pass, 34)
    #else
    #if AUTH_TYPE == 2
        get_user_ip(id,pass,34,1)
    #else
    #endif
    #endif
    #endif
    details[0] = id

    if(!equali(oldName,newName))
        changeName = true
    if (login(newName, pass) > 0)
    {
        if(changeName)
            set_task(5.0,"completeLoginWrapper",470+id,details,1)
        return PLUGIN_CONTINUE
    }

    if(contain(newName, RESERVED_UNREGISTERED_TEXT) == -1)
    {
        client_cmd(id, "name ^"%s^"",RESERVED_UNREGISTERED_TEXT)
        set_user_info(id, "name", RESERVED_UNREGISTERED_TEXT)
    }

/*    
    switch(validName(newName))
    {
        // blocked name
        case -3:
        {
            details[1] = RESERVED_BLOCKED
            client_cmd(id, "name ^"%s^"",RESERVED_UNREGISTERED_TEXT)
            set_user_info(id, "name", RESERVED_UNREGISTERED_TEXT,31)
        }
        // reserved name
        // for those logged in already then manually change password
        // for those logged in already then unregister
        default:
        {
            details[1] = RESERVED_UNREGISTERED
            client_cmd(id, "name ^"%s^"",RESERVED_BLOCKED_TEXT)
            set_user_info(id, "name", RESERVED_BLOCKED_TEXT,31)
        }
        }
    //*/
    //set_user_info(id, "name", oldName,31)
    //*
    //set_task(5.0,"promptUser",450+id,details,2)
    return PLUGIN_CONTINUE
}


/*#############################################################################
    AUTO CALLED FUNCTIONS - 0
    MISC FUNCTIONS - 1
#############################################################################*/

/*-----------------------------------------------------------------------------
annoying message to encourage registration and login
-------------------------------------------------------------------------------
input
    details[0] = id
-----------------------------------------------------------------------------*/
public msgOverload(details[])
{
    #if AUTH_TYPE == 0
        new pass[] = "<password>"
        new name[] = "<name>"
    #else
        new pass[] = ""
        new name[] = ""
    #endif
    new id = details[0]
    new msg[MSG_OVERLOAD_SIZE+1]
    if(gag[id] == 0)
        return PLUGIN_HANDLED
    format(msg, MSG_OVERLOAD_SIZE, "You have been gagged as you have not registered / logged in. Register: reg <name> %s^n Login: login %s %s ^n Help: userReghelp", pass, name, pass)
    format(msg, MSG_OVERLOAD_SIZE, "%s^n^n%s^n^n%s", msg,msg,msg)
    switch(details[1])
    {
        case 1:
            set_hudmessage(255,0,0,-1.0,0.25,1,2.0,4.0,0.1,0.1)
        case 2:
            set_hudmessage(0, 255,0,-1.0,0.25,1,2.0,4.0,0.1,0.1)
        case 3:
            set_hudmessage(0,0,255,-1.0,0.25,1,2.0,4.0,0.1,0.1)
        case 4:
            set_hudmessage(255,255,255,-1.0,0.25,1,2.0,4.0,0.1,0.1)
        case 5:
            set_hudmessage(255,255,0,-1.0,0.25,1,2.0,4.0,0.1,0.1)
        case 6:
            set_hudmessage(255,0,255,-1.0,0.25,1,2.0,4.0,0.1,0.1)
        case 7:
            set_hudmessage(0,255,255,-1.0,0.25,1,2.0,4.0,0.1,0.1)
        default:
        {
            set_hudmessage(0,0,0,-1.0,0.25,1,2.0,4.0,0.1,0.1)
            details[1] = 0
        }
    }
    details[1]++
    show_hudmessage(id,"%s", msg)
    set_task(2.0, "msgOverload", 100+id, details, 2)
    return PLUGIN_HANDLED
}

/*-----------------------------------------------------------------------------
prompts user about registering
-------------------------------------------------------------------------------
input
    details[0] = id
    details[1] = 1    // change name type
-----------------------------------------------------------------------------*/

public promptUser(details[])
{
    new id = details[0]
    new name[32], pass[35]
    new type = details[1]
    
    get_user_info(id,"name",name,31)
    get_user_info(id,PASSWORD_FIELD,pass,34)

    // if authenticated return
    if(login(name,pass) > 0)
    {
        return PLUGIN_HANDLED
    }
    // change user name
    new success = false
    #if MYSQL
    {
        result = dbi_query(sql,"SELECT * FROM %s WHERE type=%d", RESERVED_TABLE, type)
        if(result >= RESULT_OK)
        {
            dbi_nextrow(result)
            dbi_result(result, "name", name, 31)
            success = true
        }
        dbi_free_result(result)
    }
    #else
    {
        new lineNo, numChars
        new buff[MAX_LINE_LENGTH]
        new buff2[MAX_LINE_LENGTH]
        for(lineNo = 0; lineNo< file_size(RESERVED_TABLE, 1); lineNo++)
        {
            if(!read_file(RESERVED_TABLE,lineNo,buff,MAX_LINE_LENGTH,numChars))
                break
            parse(buff, buff2, MAX_LINE_LENGTH)
            if(type == str_to_num(buff2))
            {
                parse(buff, name, 31)
                success = true
                break;
            }
        }
    }
    #endif
    if(success)
    {
        client_cmd(id, "name ^"%s^"", name)
        if(get_cvar_num("amx_punishGagVoice"))
            gag[id] = 1
        set_speak(id, SPEAK_MUTED)
        consoleHelpMsg(id, HELP_MISC)
    }
    return PLUGIN_HANDLED
}


/*-----------------------------------------------------------------------------
unregister a name
    assume perfect input
-------------------------------------------------------------------------------
does actual deletion from database
-----------------------------------------------------------------------------*/
public unregisterUser(id, name[])
{
    #if MYSQL
    {
        result = dbi_query(sql,"select * from %s where name = '%s'",USER_TABLE, name)
        if(result == RESULT_FAILED)
        {
            console_print(id, "ERROR. Cannot delete name from database. Please contact admin")
        }
        else if(result == RESULT_NONE)
        {
            console_print(id, "ERROR. Name(%s) does not exist in database.", name)
        }
        else
        {
            result = dbi_query(sql,"delete from %s where name = '%s'",USER_TABLE, name)
            console_print(id, "Name (%s) succesfully unregistered", name)
            dbi_free_result(result)
            return true
        }
        dbi_free_result(result)
    }
    #else
    {
        new lineNo, numChars
        new buff[MAX_LINE_LENGTH]
        new nameF[MAX_LINE_LENGTH]
        for(lineNo = 0; lineNo< file_size(USER_TABLE, 1); lineNo++)
        {
            if(!read_file(USER_TABLE,lineNo,buff,MAX_LINE_LENGTH,numChars))
                break
            parse(buff, nameF, MAX_LINE_LENGTH)
            if(equali(nameF, name))
            {
                if(delLine(lineNo+1, USER_TABLE))
                {
                    console_print(id, "Name (%s) succesfully unregistered", name)
                    return true
                }
                else
                {
                    console_print(id, "ERROR. Cannot delete name from database. Please contact admin")
                    break
                }
            }
        }
        console_print(id, "ERROR. Name(%s) does not exist in database.", name)
    }
    #endif
    return false
}
/*-----------------------------------------------------------------------------
unregister a name
    assume perfect input
-------------------------------------------------------------------------------
does actual deletion from database
-----------------------------------------------------------------------------*/
public unregisterID(id, pass[])
{
    #if MYSQL
    {
        result = dbi_query(sql,"select * from %s where pass = '%s'",USER_TABLE, pass)
        if(result == RESULT_FAILED)
        {
            console_print(id, "ERROR. Cannot delete ID from database. Please contact admin")
        }
        else if(result == RESULT_NONE)
        {
            console_print(id, "ERROR. ID(%s) does not exist in database.", pass)
        }
        else
        {
            result = dbi_query(sql,"delete from %s where pass = '%s'",USER_TABLE, pass)
            console_print(id, "ID (%s) succesfully unregistered", pass)
            dbi_free_result(result)
            return true
        }
        dbi_free_result(result)
    }
    #else
    {
        new lineNo, numChars
        new buff[MAX_LINE_LENGTH]
        new nameF[MAX_LINE_LENGTH], passF[MAX_LINE_LENGTH]
        for(lineNo = 0; lineNo< file_size(USER_TABLE, 1); lineNo++)
        {
            if(!read_file(USER_TABLE,lineNo,buff,MAX_LINE_LENGTH,numChars))
                break
            parse(buff, nameF, MAX_LINE_LENGTH, passF, MAX_LINE_LENGTH)
            if(equal(passF, pass))
            {
                if(delLine(lineNo+1, USER_TABLE))
                {
                    console_print(id, "ID (%s) succesfully unregistered", pass)
                    return true
                }
                else
                {
                    console_print(id, "ERROR. Cannot delete ID from database. Please contact admin")
                    break
                }
            }
        }
        console_print(id, "ERROR. ID(%s) does not exist in database.", pass)
    }
    #endif
    return false
}

/*-----------------------------------------------------------------------------
register a name
    assume perfect input
-------------------------------------------------------------------------------
does actual registration into database
-----------------------------------------------------------------------------*/
public registerUser(id, name[], pass[])
{
    new hash[34]
    md5(pass, hash)
    #if MYSQL
    {
        result = dbi_query(sql,"INSERT INTO %s(name, pass) values('%s','%s')",USER_TABLE, name, hash)
        if(result == RESULT_FAILED)
        {
            console_print(id, "ERROR. Cannot register name into database. Please contact admin")
            dbi_free_result(result)
        }
        else
        {
            console_print(id, "Name (%s) succesfully registered", name)
            dbi_free_result(result)
            return true
        }
    }
    #else
    {
        new buff[MAX_LINE_LENGTH]
        format(buff, MAX_LINE_LENGTH, "^"%s^" ^"%s^"", name, hash)
        if(write_file(USER_TABLE, buff))
            console_print(id, "Name (%s) succesfully registered", name)
        else
            console_print(id, "ERROR. Cannot register name into database. Please contact admin")
    }
    #endif
    return false
}


/*-----------------------------------------------------------------------------
completes user logout
-------------------------------------------------------------------------------
    resets
        password
------------------------------------------------------------------------------*/
public completeLogout(id)
{
    client_cmd(id, "setinfo %s ^"^"", PASSWORD_FIELD)
    console_print(id,"Logout successful")
    gag[id] = 1
    client_cmd(id, "name ^"%s^"",RESERVED_UNREGISTERED_TEXT)
    set_user_info(id, "name", RESERVED_UNREGISTERED_TEXT)
    if(get_cvar_num("amx_msgOverload"))
    {
        new details[2]
        details[0] = id
        details[1] = 1
        set_task(5.0, "msgOverload", 480+id, details, 2)
    }
    
    return PLUGIN_HANDLED
}

/*-----------------------------------------------------------------------------
completes user login
-------------------------------------------------------------------------------
    sets
        name        : name
        password    : setinfo
-----------------------------------------------------------------------------*/
public completeLogin(id, name[], pass[])
{
    client_cmd(id, "name ^"%s^"", name)
    client_cmd(id, "setinfo %s ^"%s^"", PASSWORD_FIELD, pass)
    gag[id] = 0
    if(get_cvar_num("amx_punishGagVoice"))
    {
        if(get_cvar_num("sv_alltalk") == 1)
            set_speak(id, SPEAK_ALL)
        else
            set_speak(id, SPEAK_NORMAL)
    }
    set_speak(id, SPEAK_MUTED)
    // blue
    set_hudmessage(0, 255, 100, -1.0, 0.35, 0, 0.0, 5.0, 0.7, 0.7)
    show_hudmessage(id,"Welcome %s", name)
    console_print(id,"Welcome %s", name)
    return PLUGIN_HANDLED
}

/*-----------------------------------------------------------------------------
completes user login wrapper
-------------------------------------------------------------------------------
only called from user authentication from client_putinserver
wrapper used to delay welcome message as if not it will not be seen otherwise
-------------------------------------------------------------------------------
    sets 
        name        : name
        password    : setinfo
-----------------------------------------------------------------------------*/
public completeLoginWrapper(details[])
{
    new id = details[0]
    new name[32], pass[35]
    get_user_info(id,"name",name,31)
    get_user_info(id,PASSWORD_FIELD,pass,34)
    completeLogin(id, name, pass)
    return PLUGIN_HANDLED
}


/*-----------------------------------------------------------------------------
login
-------------------------------------------------------------------------------
    if password authentication
        checks name and pass input
    else
        retrieve name if registered
-------------------------------------------------------------------------------
output
    returns
        -1    failed
        1    passed
-----------------------------------------------------------------------------*/
public login(name[],pass[])
{
    new hash[34]
    md5(pass,hash)
    #if MYSQL
    {
        result = dbi_query(sql,"SELECT * FROM %s WHERE name like '%s' and pass like BINARY '%s'", USER_TABLE, name, hash)
        if(result >= RESULT_OK)
        {
            dbi_free_result(result)
            server_print("Success");
            return 1
        }
        result = dbi_query(sql,"SELECT * FROM %s WHERE name like '%s' and pass like BINARY '%s'", WAITING_TABLE, name, hash)
        if(result >= RESULT_OK)
        {
            dbi_free_result(result)
            return -2
        }
    }
    #else
    {
        new lineNo, numChars
        new buff[MAX_LINE_LENGTH]
        new nameF[MAX_LINE_LENGTH], passF[MAX_LINE_LENGTH]
        for(lineNo = 0; lineNo< file_size(USER_TABLE, 1); lineNo++)
        {
            if(!read_file(USER_TABLE,lineNo,buff,MAX_LINE_LENGTH,numChars))
                break
            parse(buff, nameF, MAX_LINE_LENGTH, passF, MAX_LINE_LENGTH)
            if(equali(nameF, name) && equal(passF, hash))
            {
                server_print("Success");
                return 1
            }
        }
        for(lineNo = 0; lineNo< file_size(WAITING_TABLE, 1); lineNo++)
        {
            if(!read_file(WAITING_TABLE,lineNo,buff,MAX_LINE_LENGTH,numChars))
                break
            parse(buff, nameF, MAX_LINE_LENGTH, passF, MAX_LINE_LENGTH)
            if(equali(nameF, name) && equal(passF, hash))
            {
                return -2
            }
        }
    }
    #endif
    return -1
}


/*-----------------------------------------------------------------------------
retrieves users registered name
    for authentication using STEAM_ID or IP
    assume perfect input
-------------------------------------------------------------------------------
checks db
    stores name in _name_ input var
-------------------------------------------------------------------------------
output
    returns
        -1    if no registered name
        1    valid (name stored in _name_)
-----------------------------------------------------------------------------*/
public getRegisteredName(name[], pass[])
{
    #if MYSQL    
    {
        result = dbi_query(sql,"SELECT * FROM %s WHERE pass like '%s'", USER_TABLE, pass)
        if(result >= RESULT_OK)
        {
            dbi_nextrow(result)
            dbi_result(result, "name", name, 31)
            dbi_free_result(result)
            return 1
        }
        dbi_free_result(result)
    }
    #else
    {
        new lineNo, numChars
        new buff[MAX_LINE_LENGTH]
        new nameF[MAX_LINE_LENGTH], passF[MAX_LINE_LENGTH]
        for(lineNo = 0; lineNo< file_size(USER_TABLE, 1); lineNo++)
        {
            if(!read_file(USER_TABLE,lineNo,buff,MAX_LINE_LENGTH,numChars))
                break
            parse(buff, nameF, MAX_LINE_LENGTH, passF, MAX_LINE_LENGTH)
            if(equal(passF, pass))
                return 1
        }
    }
    #endif
    return -1
}

/*-----------------------------------------------------------------------------
validates password
-------------------------------------------------------------------------------
    returns
        false  invalid
        true   valid
-----------------------------------------------------------------------------*/
public validPass(pass[])
{
    trim(pass)
    if((containi (pass, "^"") >= 0) || (containi (pass, "^'") >= 0) )
        return false
    return true
}

public validPassMsg(id, pass[])
{
    if(validPass(pass))
        return true
    console_print(id, "ERROR. Password invalid. Invalid characters: ^", ^'")
    return false
}

/*-----------------------------------------------------------------------------
validates name
-------------------------------------------------------------------------------
checks name for
    clash with
        registered names
        reserved names
-------------------------------------------------------------------------------
output
    returns
        -10 parse error ie " / ' inside
        -3  already registered
        -2  clash with reserved name
        -1  clash with registered name
         1  valid
-----------------------------------------------------------------------------*/
public validName(name[])
{
    // check blocked names table
    trim(name)
    if((containi (name, "^"") >= 0) || (containi (name, "^'") >= 0) )
    {
        return -10
    }

    #if MYSQL
    {
        // check blocked words
        result = dbi_query(sql,"SELECT name FROM %s", BLOCKED_TABLE)
        if(result >= RESULT_OK)
        {
            while( result && dbi_nextrow(result) > 0 )
            {
                new blockedName[32]
                dbi_result(result, "name", blockedName, 31)
                if(containi(name,blockedName) != -1)
                {
                    dbi_free_result(result)
                    if(!exception(name))
                        return -3
                }
            }
        }
        dbi_free_result(result)

        // check reserved names table
        result = dbi_query(sql,"SELECT name FROM %s", RESERVED_TABLE)
        if(result >= RESULT_OK)
        {
            while( result && dbi_nextrow(result) > 0 )
            {
                new reservedName[32]
                dbi_result(result, "name", reservedName, 31)
                if(containi(name,reservedName) != -1)
                {
                    dbi_free_result(result)
                    if(!exception(name))
                        return -2
                }
            }
        }
        dbi_free_result(result)
        
        
        // check user table
        result = dbi_query(sql,"SELECT * FROM %s WHERE name like '%s'", USER_TABLE, name)
        if(result >= RESULT_OK)
        {
            dbi_free_result(result)
            return -1
        }
        dbi_free_result(result)

        // check waiting table
        result = dbi_query(sql,"SELECT * FROM %s WHERE name like '%s'", WAITING_TABLE, name)
        if(result >= RESULT_OK)
        {
            dbi_free_result(result)
            return -1
        }
        dbi_free_result(result)
    }
    #else
    {
        // check blocked words
        new lineNo, numChars
        new buff[MAX_LINE_LENGTH]
        new buff2[MAX_LINE_LENGTH]
        for(lineNo = 0; lineNo< file_size(BLOCKED_TABLE, 1); lineNo++)
        {
            if(!read_file(BLOCKED_TABLE,lineNo,buff,MAX_LINE_LENGTH,numChars))
                break
            if(containi(name, buff) != -1)
                if(!exception(name))
                    return -3
        }
        // check reserved names table
        for(lineNo = 0; lineNo< file_size(RESERVED_TABLE, 1); lineNo++)
        {
            if(!read_file(RESERVED_TABLE,lineNo,buff,MAX_LINE_LENGTH,numChars))
                break
            parse(buff, buff2, MAX_LINE_LENGTH, buff2, MAX_LINE_LENGTH)
            if(containi(name, buff2) != -1)
                if(!exception(name))
                    return -2
        }

        // check user table
        if(findUser(name, USER_TABLE))
            return -1

        // check waiting table
        if(findUser(name, WAITING_TABLE))
            return -1
    }
    
    #endif

    return 1
}

public validNameMsg(id, name[])
{
    switch(validName(name))
    {
        case 1:
            return true
        case -1:
            console_print(id, "ERROR. Name already registered")
        case -2:
            console_print(id, "ERROR. Name is reserved for the system")
        case -3:
            console_print(id, "ERROR. Name is blocked (possibly contains profanity, if it does not contact admin for manual registration)")
        case -10:
            console_print(id, "ERROR. Name invalid. Invalid characters: ^", ^'")
        default:
            console_print(id, "ERROR. Invalid name")
    }
    return false
}
/*-----------------------------------------------------------------------------
checks for exceptions of registered names
    assume perfect input
-------------------------------------------------------------------------------
output
    true / false
-----------------------------------------------------------------------------*/
public exception(name[])
{
    #if MYSQL
    {
        result = dbi_query(sql,"SELECT * FROM %s WHERE name like '%s'", EXCEPTIONS_TABLE, name)
        if(result >= RESULT_OK)
        {
            dbi_free_result(result)
            return true
        }
        dbi_free_result(result)
    }
    #else
        if(find(name, EXCEPTIONS_TABLE))
            return true
    #endif
    return false
}


/*-----------------------------------------------------------------------------
prints welcome msg
-------------------------------------------------------------------------------
input
    id of player to display welcome message to
-----------------------------------------------------------------------------*/
public welcomeMsg(id)
{
    new name[32]
    get_user_info(id, "name", name,31)
    set_hudmessage(0, 255, 100, -1.0, 0.35, 0, 0.0, 5.0, 0.7, 0.7)
    show_hudmessage(id,"Welcome %s", name)
    console_print(id,"Welcome %s", name)
    return PLUGIN_HANDLED
}

/*-----------------------------------------------------------------------------
prints error msg
-------------------------------------------------------------------------------
input
    id of player to display welcome message to
-----------------------------------------------------------------------------*/
public errMsg(id, msg[])
{
    set_hudmessage(255,0,0,-1.0,0.25,0,3.0,10.0,0.1,0.1)
    show_hudmessage(id,"%s", msg)
}
/*-----------------------------------------------------------------------------
checks if currently connected to the database
-------------------------------------------------------------------------------
output
    returns
        true    connected
        false    not connected
-----------------------------------------------------------------------------*/
public SQLconnected()
{
    if (SQL_CONNECTED)
        return true
    console_print(0, "ERROR. Cannot connect to database. Please contact admin")
    server_print("ERROR. Cannot connect to database")
    return false
}
/*#############################################################################
    MISC FUNCTIONS - 0
    GAG FUNCTIONS - 1
#############################################################################*/

/*
-1 - no punishment
 0 - say and team say
 1 - say
 2 - team say

if gag[n] == 1 => player with id 'n' is gagged
*/
public check_gag(id)
{
    new gagLevel = get_cvar_num("amx_punishGag")
    if((gagLevel == -1) || (gag[id] == 0))
        return PLUGIN_CONTINUE
    new say[5], bool:tsay=false
    read_argv(0,say,4)
    if(say[3] == '_')
        tsay = true
    switch(gagLevel)
    {
        case 0:
        {
        }
        case 1:
        {
            if(tsay)
                return PLUGIN_CONTINUE
        }
        case 2:
        {
            if(!tsay)
                return PLUGIN_CONTINUE
        }
        default:
        {
        }
    }
    consoleHelpMsg(id, HELP_GAG)
    return PLUGIN_HANDLED

}

/*#############################################################################
    GAG FUNCTIONS - 0
#############################################################################*/

/******************************************************************************
tries to find _line_ in the _file_
*******************************************************************************
tries to find a matchin line in the file by reading it line by line and tries
to match with the line value inputted
*******************************************************************************
return values
    0   not found
    x   lineNumber found line at [start from 1]
******************************************************************************/
public find(line[], const file[])
{
    new lineNo, numChars
    new buff[MAX_LINE_LENGTH]
    for(lineNo = 0; lineNo< file_size(file, 1); lineNo++)
    {
        if(!read_file(file,lineNo,buff,MAX_LINE_LENGTH,numChars))
            break
        if(equali(line, buff))
            return (lineNo+1)
    }
    return 0
}

/******************************************************************************
tries to find user in the _file_
*******************************************************************************
tries to find a matchin line in the file by reading it line by line and tries
to match with the line value inputted
*******************************************************************************
format of file
"userName" "hashedPassword"
*******************************************************************************
return values
    0   not found
    x   lineNumber found line at [start from 1]
******************************************************************************/
public findUser(line[], const file[])
{
    new lineNo, numChars
    new buff[MAX_LINE_LENGTH]
    new name[MAX_LINE_LENGTH]
    for(lineNo = 0; lineNo< file_size(file, 1); lineNo++)
    {
        if(!read_file(file,lineNo,buff,MAX_LINE_LENGTH,numChars))
            break
        parse(buff, name, MAX_LINE_LENGTH)
        if(equali(line, name))
            return (lineNo+1)
    }
    return 0
}


/******************************************************************************
deletes a line from a file
*******************************************************************************
shifts the values up, to replace the line deleted
*******************************************************************************
note
    line: starts from 1
*******************************************************************************
return values
    0   not found
    x   lineNumber found line at [start from 1]
******************************************************************************/
public delLine(line, const file[])
{
    //*
    line--
    if (write_file(file, "", line))
        return 1
    return 0
    //*/
    /*
    new numChars, maxLines;
    new buff[MAX_LINE_LENGTH]
    new fp
    line--
    maxLines = file_size(file, 1) - 2
    read_file(file,maxLines,buff,MAX_LINE_LENGTH,numChars)
    server_print("file: %s, last line: %d %s (%d), delLine: %d", file, maxLines, buff, numChars, line)
    if(read_file(file,maxLines,buff,MAX_LINE_LENGTH,numChars))
    {
        server_print("Copy (%s) from line %d to line %d.", buff, maxLines, line)

        // only line in file, clear the file by creating a new file
        if(line == maxLines)        
        {
            if (write_file(file, "", line))
                return 1
        }
        else if (write_file(file, buff, line))
        {
            if (write_file(file, "", maxLines))
                return 1
            return 1
        }
    }
    return 0;
    //*/
}