<?php

// TMS Rewritten - Early 2010
// By Joseph Robert Gillotti

defined('in_tms'or exit;  // Anti inclusion hack

// User management
class Ui {

    /*
     * These pertain to a logged in user
     */
    private
        $user array(), // Array of their info
        $_logged_in false,
        $verif_key,
        $verif_val;

    /*
     * Overall and Daily hits
     */
    public
        $hits array();


    /*
     * Start us off
     */
    function __construct() {

        global $layout;

        // Log us in
        $this->manageSession();

        // Are we banned?
        if ($this->isBanned()) {
            $layout->errorMsgMinimal('You are banned.');
            exit// Redundantly prevent anything more
        }

    }

    /*
     * Get contents of login cookie
     */
    private function loginCookieGet() {
        global $login_remember_cookie;

        // Does it not exist?
        if (!isset($_COOKIE[$login_remember_cookie]) || trim($_COOKIE[$login_remember_cookie]) == '')
            return false;

        // Get it's parts
        list($uid$pw) = explode('_'trim($_COOKIE[$login_remember_cookie]), 2);

        // Are they okay?
        if (!ctype_digit($uid) || strlen($pw) != 32) {
            return false;
        }

        // They might be good, return vals
        return array('uid' => $uid'pw' => $pw);

    }

    /*
     * Scrap login cookie
     */
    public function loginCookieScrap() {
        global $login_remember_cookie;
        if (isset($_COOKIE[$login_remember_cookie]))
            setcookie($login_remember_cookie''time() - 5000);
    }

    /*
     * Attempt to auth
     */
    private function manageSession() {
        global $sql$sp;

        // First of all, see if we have a login cookie
        // It's contents will overwrite the session value if different
        $loginCookie $this->loginCookieGet();

        // It okay? Replace session vals with it
        if (is_array($loginCookie)) {
            $_SESSION['uid'] = $loginCookie['uid'];
            $_SESSION['pass'] = $loginCookie['pw'];
        }

        // See if session variables are okay. If not, stop here
        if (!ctype_digit($_SESSION['uid']) || strlen($_SESSION['pass']) != 32)
            return;

        // Localize
        $sess_uid $sql->prot($_SESSION['uid']);
        $sess_pass $sql->prot($_SESSION['pass']);

        // Might be satisfactory, test
        $check_user $sql->query("
        select
            `id`,
            `username`,
            `banned`,
            `pending`,
            `theme`,
            `timezone_offset`,
            `nobwfilter`,
            `nummaps`
        from
            `members`
        where
            `id` = '$sess_uid' and
            `password` = '$sess_pass'
        limit 1
        ");

        // No?
        if ($sql->num($check_user) == 0) {

            $this->killSession();

        }

        // Yes we have a match; get values
        list(
            $this->user['uid'], $this->user['username'], $this->user['banned'], $this->user['pending'],
            $this->user['theme'], $this->user['timezone_offset'], $this->user['filter_badwords'], $this->user['num_maps']
        )
        $sql->fetch_row($check_user);

        // And we're logged in, btw
        $this->_logged_in true;

        // Deal with user verification shiz
        $this->setUserVerification();

        // Useful when called in a long fucking loop to avoid the overhead of a function call ($ui->userID);
        define('USER_ID'$this->user['uid']);

        // Reference later on
        $sql->query("update `members` set `lastaction` = unix_timestamp(), `lastip` = '{$_SERVER['REMOTE_ADDR']}' where `id` = '{$this->user['uid']}' limit 1");
    }

    /*
     * Values that are limited to this session and this user
     */
    private function setUserVerification() {
        // Need to be logged in to be of any use
        if (!$this->_logged_in)
            return;

        // Make them random but constant. Key must start with a non-number.
        $this->verif_key 'k'.substr(sha1(md5($this->user['uid'].session_id())), 115);
        $this->verif_val sha1(md5(serialize($this->user).md5($this->user['uid'].session_id())));

        // Any scope access
        define('VERIF_KEY'$this->verif_key);
        define('VERIF_VAL'$this->verif_val);
    }

    /*
     * Get vals for above
     */
    public function verifKey() {
        return $this->_logged_in $this->verif_key false;
    }

    /*
     * Get key for above
     */
    public function verifVal() {
        return $this->_logged_in $this->verif_val false;
    }

    /*
     * Are we verified?
     */
    public function isVerified() {
        // If we're not logged in, definitely not
        if (!$this->_logged_in) {
            return false;
        }

        // If a POST or GET value is our key. Not a val in session and definitely not in a cookie
        return $_POST[$this->verifKey] == $this->verifVal() || $_GET[$this->verifKey()] == $this->verifVal();
    }

    /*
     * Log us out
     */
    public function killSession() {

        // Kill possible login values
        $this->loginCookieScrap();
        unset($_SESSION['uid'], $_SESSION['pass']);

        // Set us logged out.
        $this->_logged_in false;

        // Make sure use array is empty
        $this->user false;
    }

    /*
     * Am I banned?
     */
    public function isBanned() {
        global $sql;

        // Check if user is banned
        if ($ui->_logged_in) {
            return $this->user['banned'] == '1';
        }

        // Check if IP is banned
        //$ip_check = $sql->query("select null from `` where `ip` = '' limit 1");
    }


    /*
     * Is current user a bot?
     */
    function isBot() {
        // Some bots do not have a user agent
        if (trim($_SERVER['HTTP_USER_AGENT']) == '')
            return true;

        // Others are typical:
        $bots array(
            'googlebot',
            'yahoo',
            'msn',
            'search',
            'bot',
            'index',
            'load',
            'Charlotte',
            'crawl',
            'Mediapartners',
            'feed',
            'fetch',
            'spider',
            'bot',
            'yandex',
            'lwp\-request',
            'W3C',
            'krawl',
            'PHP\/SMF',
        'alexa');

        // Go for it:
        return (boolpreg_match('/'.implode('|'$bots).'/i'$_SERVER['HTTP_USER_AGENT']);
    }

    /*
     *  Handle stats
     */
    public function track() {
        global $sql;

        // Make sure we aren't a bot
        if ($this->isBot())
            return;

        // Make sure current IP is in the list
        $sql->query("insert ignore into `hits_ip` set `ip` = '{$_SERVER['REMOTE_ADDR']}'");

        // Deal with daily IP's
        $sql->query("insert ignore into `hits_daily` set `day` = curdate(), `ip` = '{$_SERVER['REMOTE_ADDR']}', `useragent` = '".$sql->prot($_SERVER['HTTP_USER_AGENT'])."'");

        // Delete older daily ip's
        $sql->query("delete from `hits_daily` where `day` < curdate()");

        // Get current hits
        $get_hits $sql->query("
        select
            (select count(`ip`) from `hits_ip`),
            (select count(`ip`) from `hits_daily` where `day` = curdate())");

        // Set them
        list($this->hits['overall'], $this->hits['today']) = $sql->fetch_row($get_hits);

        // Free that ram
        $sql->free($get_hits);
    }

    /*
     * Functions used all over the place to test stuff
     */
    public function loggedIn() {
        return (bool$this->_logged_in;
    }

    public function userID() {
        return $this->_logged_in ? (int$this->user['uid'] : false;
    }

    public function userName() {
        return $this->_logged_in stripslashes($this->user['username']) : false;
    }

    public function userActivated() {
        return $this->_logged_in $this->user['pending'] == '0' false;
    }

    public function userAdmin() {
        global $site_admins;
        return $this->_logged_in in_array($this->user['uid'], $site_admins) : false;
    }

    public function userTheme() {
        return $this->_logged_in $this->user['theme'] : (ctype_digit(@$_SESSION['theme']) ? $_SESSION['theme'] : 0);
    }

    public function userAvatar() {
        return $this->_logged_in ? (file_exists($this->user['avatar']) ? $this->user['avatar'] : 'theme/default_ave.png') : 'theme/default_ave.png';
    }

    /*
     * Change my theme
     */
    public function changeTheme($desired_theme) {
        global $sql;

        // Sanity check
        if (!ctype_digit($desired_theme))
            return false;

        // If we're logged in, change user pref
        if ($this->loggedIn()) {
            $sql->query("update `members` set `theme` = '$desired_theme' where `id` = '".$this->userID()."' limit 1");
        }

        // Otherwise, save it to session
        else {
            $_SESSION['theme'] = $desired_theme;
        }
    }

}

/*
 * Get a user id from a username
 */
function username2uid($username) {

    // Avoid doing the same one more than once
    static $cache array();

    // Gain access to SQL and current user id
    global $sql$ui;

    // Safety first
    $username $sql->prot(trim($username));

    // Ugh
    if ($username == '')
        return false;

    // First off, is this cached?
    if (array_key_exists($username$cache))
        return $cache[$username];

    // Is it me?
    if ($ui->loggedIn() && $ui->userName() == $username)
        return $ui->userID();

    // No. Search for it. :P
    $get $sql->query("select `id` from `members` where `username` = '$username' limit 1");

    // Nothing?
    if ($sql->num($get) == 0) {
        $sql->free($get);
        return false;
    }

    // Got it.
    list($uid) = $sql->fetch_row($get);

    // Free ram
    $sql->free($get);

    // Cache it so we don't repeat ourselves next time
    $cache[$username] = $uid;

    // Return it, finally
    return $uid;
}

/*
 * Get a user name from a user id, while validating the id
 */
function uid2username($userid) {

    // Avoid doing the same one more than once
    static $cache array();

    // Gain access to SQL and current user id
    global $sql$ui;

    // Ugh
    if (!ctype_digit($userid) && $userid 0)
        return false;

    // First off, is this cached?
    if (array_key_exists($userid$cache))
        return $cache[$userid];

    // Is it me?
    if ($ui->loggedIn() && $ui->userID() == $userid)
        return $ui->userName();

    // No. Search for it. :P
    $get $sql->query("select `username` from `members` where `id` = '$userid' limit 1");

    // Nothing?
    if ($sql->num($get) == 0) {
        $sql->free($get);
        return false;
    }

    // Got it.
    list($username) = $sql->fetch_row($get);

    // Free ram
    $sql->free($get);

    // Cache it so we don't repeat ourselves next time
    $cache[$userid] = stripslashes($username);

    // Return it, finally
    return $username;
}