<?php
/**
 * The Auth_imp:: class provides an IMP implementation of the Horde
 * authentication system.
 *
 * Required parameters:
 * ====================
 * NONE
 *
 * Optional parameters:
 * ====================
 * NONE
 *
 * 
 * $Horde: imp/lib/Auth/imp.php,v 1.5 2003/07/25 05:45:26 slusarz Exp $
 *
 * Copyright 2003 Michael Slusarz <slusarz@bigworm.colorado.edu>
 *
 * See the enclosed file COPYING for license information (LGPL). If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 *
 * @author  Michael Slusarz <slusarz@bigworm.colorado.edu>
 * @version $Revision: 1.5 $
 * @since   Horde 3.0
 * @package horde.auth
 */
class Auth_imp extends Auth {

    /**
     * IMP specific authentication parameters.
     *
     * @var array $_impParams
     */
    var $_impParams = array(
        'flags' => 0,
        'setup' => false
    );

    /**
     * Constructs a new IMP authentication object.
     *
     * @access public
     *
     * @param optional array $params  A hash containing connection parameters.
     */
    function Auth_imp($params = array())
    {
        if (!Horde::extensionExists('imap')) {
            Horde::fatal(PEAR::raiseError(_("Auth_imp: Required IMAP extension not found."), __FILE__, __LINE__));
        }
    }

    /**
     * Find out if a set of login credentials are valid, and if
     * requested, mark the user as logged in in the current session.
     *
     * @access public
     *
     * @param optional string $userID      The userID to check.
     * @param optional array $credentials  The credentials to check.
     * @param optional boolean $login      Whether to log the user in. If
     *                                     false, we'll only test the
     *                                     credentials and won't modify
     *                                     the current session.
     *
     * @return boolean  Whether or not the credentials are valid.
     */
    function authenticate($userID = null, $credentials = array(),
                          $login = false)
    {
        if (empty($userID)) {
            if (empty($_SESSION['imp']['uniquser'])) {
                return false;
            }
            $userID = $_SESSION['imp']['uniquser'];
        }

        if (empty($credentials)) {
            if (empty($_SESSION['imp']['pass'])) {
                return false;
            }
            $credentials = array('password' => Secret::read(Secret::getKey('imp'), $_SESSION['imp']['pass']));
        }

        $login = ($login && ($this->getProvider() == 'imp'));

        return parent::authenticate($userID, $credentials, $login);
    }

    /**
     * Set IMP-specific authentication options.
     *
     * @access public
     *
     * @param optional array $params  The params to set.
     * <pre>
     * Keys:
     * -----
     * 'flags'  --  (integer) Flags to pass to imap_open().
     *              DEAFULT: 0
     *   OP_READONLY  : Open the mailbox read-only.
     *   OP_ANONYMOUS : (NNTP only) Don't use or update a .newrc file.
     *   OP_HALFOPEN  : (IMAP and NNTP only) Open a connection, but not a
     *                  specific mailbox.
     *   CL_EXPUNGE   : Expunge the mailbox automatically when the stream is
     *                  closed.
     * </pre>
     */
    function authenticateOptions($params = array())
    {
        $this->_impParams = array_merge($this->_impParams, $params);
    }

    /**
     * Find out if a set of login credentials are valid.
     *
     * @access private
     *
     * @param string $userID      The userID to check.
     * @param array $credentials  An array of login credentials.
     *
     * @return boolean  Whether or not the credentials are valid.
     */
    function _authenticate($userID, $credentials)
    {
        global $conf, $prefs;

        if (!(isset($_SESSION['imp']) && is_array($_SESSION['imp']))) {
            if (isset($prefs)) {
                $prefs->cleanup(true);
            }
            // TODO: Set error message for 'session'
            return false;
        }


        /* Process the mailbox parameter (if present). */
        $mailbox = Horde::getFormData('mailbox');
        if ($mailbox != null) {
            $_SESSION['imp']['mailbox'] = $mailbox;
        } elseif (!isset($_SESSION['imp']['mailbox'])) {
            $_SESSION['imp']['mailbox'] = 'INBOX';
        }

        if (!isset($GLOBALS['imp'])) {
            $GLOBALS['imp'] = &$_SESSION['imp'];
        }

        $connstr = null;
        $flags = $this->_impParams['flags'];

        switch ($_SESSION['imp']['base_protocol']) {
        case 'pop3':
            $flags &= ~OP_ANONYMOUS;
            $flags &= ~OP_HALFOPEN;
            $_SESSION['imp']['thismailbox'] = '';

            /* Turn some options off if we are working with POP3. */
            $conf['user']['allow_folders'] = false;
            $prefs->setValue('save_sent_mail', false);
            $prefs->setLocked('save_sent_mail', true);
            $prefs->setLocked('sent_mail_folder', true);
            $prefs->setLocked('drafts_folder', true);
            $prefs->setLocked('trash_folder', true);
            break;

        default:
            $_SESSION['imp']['thismailbox'] = Horde::getFormData('thismailbox', $_SESSION['imp']['mailbox']);
            if ($_SESSION['imp']['thismailbox'] == IMP_SEARCH_MBOX) {
                if (strstr(Horde::getFormData('index'), ':')) {
                    $tmp = explode(':', Horde::getFormData('index'));
                    $connstr = $tmp[1];
                } else {
                    $aindex = Horde::getFormData('array_index');
                    if ($aindex !== null) {
                        $tmp = explode(IMP_MSG_SEP, $_SESSION['imp']['msgl']);
                        $mbox = substr($tmp[$aindex], strpos($tmp[$aindex], IMP_IDX_SEP) + 1);
                        $connstr = $mbox;
                    } else {
                        $flags |= OP_HALFOPEN;
                    }
                }
            } else {
                $connstr = $_SESSION['imp']['thismailbox'];
            }
            break;
        }

        /* Open an IMAP stream. */
        require_once IMP_BASE . '/lib/IMAP.php';
        $imp_imap = &IMP_IMAP::singleton();
        $imp_imap->changeMbox($connstr, $flags);

        if (!$_SESSION['imp']['stream']) {
            if (!empty($_SESSION['imp']['server']) && !empty($_SESSION['imp']['port']) &&
                !empty($_SESSION['imp']['protocol']) && !empty($_SESSION['imp']['user'])) {
                if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
                    $entry = sprintf('FAILED LOGIN %s (forwarded for [%s]) to %s:%s[%s] as %s', $_SERVER['REMOTE_ADDR'], $_SERVER['HTTP_X_FORWARDED_FOR'], $_SESSION['imp']['server'], $_SESSION['imp']['port'], $_SESSION['imp']['protocol'], $_SESSION['imp']['user']);
                } else {
                    $entry = sprintf('FAILED LOGIN %s to %s:%s[%s] as %s', $_SERVER['REMOTE_ADDR'], $_SESSION['imp']['server'], $_SESSION['imp']['port'], $_SESSION['imp']['protocol'], $_SESSION['imp']['user']);
                }
                Horde::logMessage($entry, __FILE__, __LINE__, PEAR_LOG_ERR);
            }

            unset($_SESSION['imp']);
            if (isset($prefs)) {
                $prefs->cleanup(true);
            }
            // TODO: Set error message for 'failed'
            return false;
        }

        return true;
    }

}
