<?php
/**
 * Functions required to start an IMP session.
 *
 * $Horde: imp/lib/Session.php,v 1.48 2003/07/25 05:55:03 slusarz Exp $
 *
 * Copyright 1999-2003 Chuck Hagenbuch <chuck@horde.org>
 * Copyright 1999-2003 Jon Parise <jon@horde.org>
 *
 * See the enclosed file COPYING for license information (GPL). If you
 * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
 *
 * @author  Chuck Hagenbuch <chuck@horde.org>
 * @author  Jon Parise <jon@horde.org>
 * @version $Revision: 1.48 $
 * @since   IMP 4.0
 * @package imp
 */
class IMP_Session {

    /**
     * Take information posted from a login attempt and try setting up
     * an initial IMP session. Handle Horde authentication, if
     * required, and only do enough work to see if the user can log
     * in. This function should only be called once, when the user
     * first logs in.
     *
     * Creates the $imp session variable with the following entries:
     * '_login'        -- Have the login tasks been completed?
     * 'acl'           -- See config/servers.php.
     * 'base_protocol' -- Either 'imap' or 'pop3'.
     * 'cache'         -- Various IMP libraries can use this variable to cache
     *                    data.
     * 'dotfiles'      -- See config/servers.php.
     * 'file_upload'   -- If file uploads are allowed, the max size.
     * 'filteravail'   -- Can we apply filters manually?
     * 'folders'       -- See config/servers.php.
     * 'hierarchies'   -- See config/servers.php.
     * 'mailbox'       -- The current mailbox.
     * 'maildomain'    -- See config/servers.php.
     * 'namespace'     -- See config/servers.php.
     * 'pass'          -- The encrypted password.
     * 'port'          -- See config/servers.php.
     * 'protocol'      -- See config/servers.php.
     * 'quota'         -- See config/servers.php.
     * 'server'        -- The name of the server entry in config/servers.php.
     * 'uniquser'      -- The unique user name.
     * 'user'          -- The IMAP username.
     *
     * @access public
     *
     * @param string $imapuser      The username of the user.
     * @param string $password      The password of the user.
     * @param string $server        The server to use (see
     *                              config/servers.php).
     * @param optional array $args  The necessary server information.
     *
     * @return boolean  True on success, false on failure.
     */
    function createSession($imapuser, $password, $server, $args = array())
    {
        global $browser, $conf, $registry;

        /* We need both a username and password. */
        if (empty($imapuser) || empty($password)) {
            return false;
        }

        /* Make sure all necessary parameters are set. */
        $default_args = array(
            'realm'      => '',
            'port'       => '',
            'protocol'   => '',
            'maildomain' => '',
            'namespace'  => '',
            'folders'    => ''
        );

        /* Merge with the passed-in parameters. */
        $args = array_merge($default_args, $args);

        /* Create the $imp session variable. */
        $_SESSION['imp'] = array();
        $_SESSION['imp']['cache'] = array();
        $_SESSION['imp']['pass'] = Secret::write(Secret::getKey('imp'), $password);

        /* Set the login flag. */
        IMP_Session::loginFlag(true);

        /* Run the username through virtualhost expansion functions if
           necessary. */
        $_SESSION['imp']['user'] = $imapuser;
        if (!empty($conf['hooks']['vinfo'])) {
            require_once HORDE_BASE . '/config/hooks.php';
            if (function_exists('_imp_hook_vinfo')) {
                $_SESSION['imp']['user'] = call_user_func('_imp_hook_vinfo');
            }
        }

        /* We might need to override some of the defaults with
           environment-wide settings. Do NOT use the global $servers
           variable as it may not exist. */
        require IMP_BASE . '/config/servers.php';

        /* Determine the unique user name. */
        if (Auth::isAuthenticated()) {
            $_SESSION['imp']['uniquser'] = Auth::getAuth();
        } else {
            $_SESSION['imp']['uniquser'] = $_SESSION['imp']['user'];

            if (($conf['server']['server_list'] != 'none') &&
                !empty($servers[$server]['realm'])) {
                $_SESSION['imp']['uniquser'] .= '@' . $servers[$server]['realm'];
            } elseif (!empty($args['realm'])) {
                $_SESSION['imp']['uniquser'] .= '@' . $args['realm'];
            }
        }

        if (($conf['server']['server_list'] != 'none') &&
            array_key_exists($server, $servers) &&
            is_array($servers[$server])) {
            $fields = array('server', 'protocol', 'port', 'folders',
                            'namespace','maildomain', 'quota', 'acl', 'dotfiles',
                            'hierarchies', 'admin');
            $ptr = &$servers[$server];

            foreach ($fields as $val) {
                $_SESSION['imp'][$val] = isset($ptr[$val]) ? $ptr[$val] : null;
            }

            if (($conf['mailer']['type'] == 'smtp') &&
                !empty($settings['smtphost'])) {
                $_SESSION['imp']['smtphost'] = $settings['smtphost'];
            }
        } else {
            $server_key = null;
            foreach ($servers as $key => $val) {
                if (is_null($server_key) && (substr($key, 0, 1) != '_')) {
                    $server_key = $key;
                }
                if (IMP::isPreferredServer($val, $key)) {
                    $server_key = $key;
                    break;
                }
            }
            $ptr = &$servers[$server_key];

            if ($conf['server']['change_server']) {
                $_SESSION['imp']['server'] = $server;
            } else {
                $_SESSION['imp']['server'] = $ptr['server'];
                $_SESSION['imp']['admin'] = isset($ptr['admin']) ? $ptr['admin'] : false;
                $_SESSION['imp']['quota'] = isset($ptr['quota']) ? $ptr['quota'] : false;
                $_SESSION['imp']['acl'] = isset($ptr['acl']) ? $ptr['acl'] : false;
            }

            if ($conf['server']['change_port']) {
                $_SESSION['imp']['port'] = $args['port'];
            } else {
                $_SESSION['imp']['port'] = $ptr['port'];
            }

            if ($conf['server']['change_protocol']) {
                $_SESSION['imp']['protocol'] = $args['protocol'];
            } else {
                $_SESSION['imp']['protocol'] = $ptr['protocol'];
            }

            if ($conf['server']['change_folders']) {
                $_SESSION['imp']['folders'] = $args['folders'];
            } else {
                $_SESSION['imp']['folders'] = $ptr['folders'];
            }

            $_SESSION['imp']['maildomain'] = $args['maildomain'];
            $_SESSION['imp']['namespace'] = $args['namespace'];
            $_SESSION['imp']['dotfiles'] = $ptr['dotfiles'];
            $_SESSION['imp']['hierarchies'] = $ptr['hierarchies'];
        }

        /* Determine the base protocol. */
        if (($pos = strpos($_SESSION['imp']['protocol'], '/'))) {
            $_SESSION['imp']['base_protocol'] = substr($_SESSION['imp']['protocol'], 0, $pos);
        } else {
            $_SESSION['imp']['base_protocol'] = $_SESSION['imp']['protocol'];
        }

        /* Set the initial mailbox to blank. */
        $_SESSION['imp']['mailbox'] = '';

        /* Try to authenticate with the given information. */
        $auth_imp = &Auth::singleton(array('imp', 'imp'));
        $auth_imp->authenticateOptions(array('flags' => OP_HALFOPEN));
        if ($auth_imp->authenticate(null, null, true) === true) {
            global $prefs;

            /* Set the session variables. These are cached. */
            $_SESSION['imp']['mailbox'] = $prefs->getValue('mailbox');

            /* Does the server allow file uploads? If yes, store the value,
               in bytes, of the maximum file size. */
            require_once HORDE_BASE . '/lib/Server.php';
            $_SESSION['imp']['file_upload'] = Server::allowFileUploads();

            /* Is the 'mail/canApplyFilters' API call available? */
            if ($registry->hasMethod('mail/canApplyFilters')) {
                $_SESSION['imp']['filteravail'] = $registry->call('mail/canApplyFilters');
            } else {
                $_SESSION['imp']['filteravail'] = false;
            }

            /* Store the $imp variable globally. */
            $GLOBALS['imp'] = &$_SESSION['imp'];

            return true;
        } else {
            return false;
        }
    }

    /**
     * Perform IMP login tasks.
     *
     * @access public
     */
    function loginTasks()
    {
        global $conf, $notification, $prefs;

        if (IMP_Session::loginFlag()) {
            if (empty($_SESSION['imp']['stream'])) {
                IMP::checkAuthentication(OP_HALFOPEN, true);
            }

            /* Get UNIX timestamp of the last time the user logged in. */
            $last_login = isset($_SESSION['__auth']['last_login']) ? $_SESSION['__auth']['last_login'] : 0;

            /* Do maintenance operations. */
            if ($prefs->getValue('do_maintenance')) {
                require_once HORDE_BASE . '/lib/Maintenance.php';
                $maint = &Maintenance::factory('imp', array('last_login' => $last_login));
                if (empty($maint)) {
                    $notification->push(_("Could not execute maintenance operations."), 'horde.warning');
                } else {
                    unset($_POST['imapuser'], $_POST['pass']);
                    $maint->runMaintenance();
                }
            }

            /* If the user wants to run filters on login, make sure they get
               run. */
            if ($prefs->getValue('filter_on_login')) {
                require_once IMP_BASE . '/lib/IMAP.php';
                $imp_imap = &IMP_IMAP::singleton();

                /* Open the INBOX read-write. */
                $imp_imap->changeMbox('INBOX');

                /* Run filters. */
                require_once IMP_BASE . '/lib/Filter.php';
                IMP_Filter::filter();

                /* Return to read-only. */
                $imp_imap->changeMbox('', OP_HALFOPEN);
            }

            IMP_Session::loginFlag(false);
        }
    }

    /**
     * Either sets or checks the value of the login flag.
     *
     * @access public
     *
     * @param optional boolean $set  The value of the flag.
     *
     * @return boolean  The value of the flag.
     */
    function loginFlag($set = null)
    {
        if (!is_null($set)) {
            if ($set) {
                $_SESSION['imp']['_login'] = true;
            } else {
                unset($_SESSION['imp']['_login']);
            }
        }

        return isset($_SESSION['imp']['_login']);
    }

}
