/* $Cambridge: hermes/src/prayer/session/account.c,v 1.6 2012/05/01 11:49:07 dpc22 Exp $ */
/************************************************
 *    Prayer - a Webmail Interface              *
 ************************************************/

/* Copyright (c) University of Cambridge 2000 - 2008 */
/* See the file NOTICE for conditions of use and distribution. */

/* Auxillary routines for accountd service */

#include "prayer_session.h"

/* account_create() *****************************************************
 *
 * Create a fresh account structure based on session defaults.
 * Returns: account structure
 ***********************************************************************/

struct account *account_create(struct pool *pool, struct session *session)
{
    struct account *result = pool_alloc(pool, sizeof(struct account));

    result->pool = pool;
    result->session = session;
    result->stream = NIL;
    result->last_ping = (time_t) 0L;
    result->nis_stream = NIL;
    result->nis_last_ping = (time_t) 0L;
    result->bused = 0;
    result->blimit = 0;
    result->iused = 0;
    result->ilimit = 0;
    result->fullname = NIL;
    result->mail_checked = NIL;
    result->vacation_enabled = NIL;
    result->vacation_msg = NIL;
    result->vacation_aliases = NIL;
    result->vacation_subject = NIL;
    result->vacation_days    = 31;

    /* NB: Following are not part of pool. account_reset() rebuilds */
    result->filter_list = list_create(NIL, T);
    result->block_list = list_create(NIL, T);

    result->redirect_enabled = NIL;
    result->redirect_copy = NIL;
    result->redirect_address = NIL;
    result->spam_enabled   = NIL;
    result->spam_threshold = 0;
    result->spam_threshold_valid = NIL;
    result->spam_purge_enabled = T;
    result->spam_purge_timeout = 60;
    result->spam_whitelist = NIL;
    result->have_message = NIL;
    result->message = memblock_create(pool, 64);
    result->sieve_have_auto  = NIL;

    return (result);
}

/* account_reset() ******************************************************
 *
 * Reset filter and block lists to be empty lists.
 ***********************************************************************/

static void
account_reset(struct account *account)
{
    if (account->filter_list)
        list_free(account->filter_list);

    if (account->block_list)
        list_free(account->block_list);

    account->filter_list = list_create(NIL, T);
    account->block_list = list_create(NIL, T);
}


/* account_free() *******************************************************
 *
 * Free account strucure
 *   Closes down main and NIS streams if active.
 * 
 ***********************************************************************/

void account_free(struct account *account)
{
    if (account->stream)
        iostream_close(account->stream);

    if (account->nis_stream)
        iostream_close(account->nis_stream);

    string_free((void **) &account->vacation_msg);
    string_free((void **) &account->vacation_aliases);
    string_free((void **) &account->vacation_subject);
    string_free((void **) &account->spam_whitelist);

    if (!account->pool)
        memblock_free(account->message);
}

/* ====================================================================== */

/* account_close() *******************************************************
 *
 * Close down connections to accountd servers
 ************************************************************************/

void
account_timeout_close(struct account *account)
{
    struct session *session = account->session;
    struct config *config = session->config;
    time_t now = time(NIL);

    if (account->stream && (config->accountd_timeout > 0) &&
        ((account->last_ping + config->accountd_timeout) < now)) {
        iostream_close(account->stream);
        account->stream = NIL;
    }

    if (account->nis_stream && (config->accountd_timeout > 0) &&
        ((account->nis_last_ping + config->accountd_timeout) < now)) {
        iostream_close(account->nis_stream);
        account->nis_stream = NIL;
    }
}

/* ====================================================================== */

/* account_close() *******************************************************
 *
 * Close down connections to accountd servers
 ************************************************************************/

void account_close(struct account *account)
{
    if (account->stream) {
        iostream_close(account->stream);
        account->stream = NIL;
    }

    if (account->nis_stream) {
        iostream_close(account->nis_stream);
        account->nis_stream = NIL;
    }
}

/* ====================================================================== */

/* account_message() ****************************************************
 *
 * Record status message for later feedback to user.
 * account:
 *     fmt: printf format string, followed by arguments.
 * 
 ***********************************************************************/

void account_message(struct account *account, char *fmt, ...)
{
    struct memblock *m = account->message;
    va_list ap;
    unsigned long size;

    va_start(ap, fmt);
    size = memblock_vprintf_size(m, fmt, ap);
    va_end(ap);

    memblock_resize(m, size + 1);

    va_start(ap, fmt);
    memblock_vprintf(m, fmt, ap);
    va_end(ap);

    account->have_message = T;
}

/* account_fetch_message() **********************************************
 *
 * Record status message for later feedback to user.
 * account:
 *     fmt: printf format string, followed by arguments.
 * 
 ***********************************************************************/

char *account_fetch_message(struct account *account)
{
    if (account->have_message) {
        account->have_message = NIL;
        return (memblock_data(account->message));
    }

    return (NIL);
}


/* ====================================================================== */

/* account_filter_add() *************************************************
 *
 * Add filter to account structure
 * account:
 *  filter: Filter to add
 * 
 ***********************************************************************/

BOOL
account_filter_add(struct account * account, struct filter * filter)
{
    list_unshift(account->filter_list, (struct list_item *) filter, NIL);
    return (T);
}

/* account_filter_remove() **********************************************
 *
 * Remove filter (by offset) from account structure
 * account:
 *  offset: Offset to filter
 *
 * Returns: T on sucess. NIL => offset invalid
 ***********************************************************************/

BOOL
account_filter_remove(struct account * account, unsigned long offset)
{
    return (list_remove_byoffset(account->filter_list, offset));
}

/* account_block_add() *************************************************
 *
 * Add block to account structure
 * account:
 *  filter: Block to add
 * 
 ***********************************************************************/

BOOL
account_block_add(struct account * account, struct filter * filter)
{
    list_unshift(account->block_list, (struct list_item *) filter, NIL);
    return (T);
}

/* account_block_remove() ***********************************************
 *
 * Remove block (by offset) from account structure
 * account:
 *  offset: Offset to block
 *
 * Returns: T on sucess. NIL => offset invalid
 ***********************************************************************/

BOOL
account_block_remove(struct account * account, unsigned long offset)
{
    return (list_remove_byoffset(account->block_list, offset));
}

/* ====================================================================== */

/* account_change_password() ********************************************
 *
 * Change password on server.
 * account:
 *    pool: Scratch stream
 *     old: Old password
 *     new: New password
 *
 * Returns: T   => sucess
 *          NIL => error (reason sent to account_message).
 *         
 ***********************************************************************/

BOOL
account_change_password(struct account * account,
                        struct pool * pool, char *old, char *new)
{
    return(account_msshell_change_password(account, pool, old, new));
}

/* ====================================================================== */

/* account_fullname() ****************************************************
 *
 * Change fullname on server.
 * account:
 *    pool: Scratch stream
 *
 * Returns: Fullname string
 *          NIL => error (reason sent to account_message).
 *         
 ***********************************************************************/

char *account_fullname(struct account *account, struct pool *pool)
{
    return(account_msshell_fullname(account, pool));
}

/* account_change_fullname() ********************************************
 *
 * Change fullname on server.
 * account:
 *    pool: Scratch stream
 *     new: New password
 *
 * Returns: T   => success
 *          NIL => error (reason sent to account_message).
 *         
 ***********************************************************************/

BOOL
account_change_fullname(struct account *account, struct pool *pool, char *new)
{
    return(account_msshell_change_fullname(account, pool, new));
}

/* ====================================================================== */

/* account_check_quota() ************************************************
 *
 * Check disk quota
 * account:
 *    pool: Scratch stream
 *
 * Returns: T   => success  (quota details records in account structure).
 *          NIL => error (reason sent to account_message).
 *         
 ***********************************************************************/

BOOL
account_check_quota(struct account *account, struct pool *pool)
{
    return(account_msshell_check_quota(account, pool));
}

/* account_mail_check() ************************************************
 *
 * Check mail filtering and vacation message using above routines.
 * account:
 *    pool: Scratch stream
 *
 * Returns: T   => success (details recorded in account structure)
 *          NIL => error   (reason sent to account_message).
 *         
 ***********************************************************************/

BOOL
account_mail_check(struct account * account, struct pool * pool)
{
    struct session *session = account->session;
    struct options *options = session->options;
    struct prefs *prefs = options->prefs;

    if (account->mail_checked)
        return (T);

    /* Can get here twice if someone hits update on Advanced page with
       valid automatic sieve rules. account_reset() clears out the filters
       and block lists: otherwise everything doubles up */

    account_reset(account);

    if (session->use_sieve) {
        if (!account_sieve_mail_check(account, pool))
            return(NIL);
    } else {
        if (!account_msshell_mail_check(account, pool))
            return(NIL);
    }

    /* XXX Better place for this? */
    if (!(account->vacation_aliases && account->vacation_aliases[0]) &&
        prefs->alt_addr && prefs->alt_addr[0])
        string_strdup(&account->vacation_aliases, prefs->alt_addr);

    account->mail_checked = T;

    return(T);
}

/* ====================================================================== */

/* account_mail_update() ************************************************
 *
 * Update mail filtering and vacation message to reflect account structure
 * account:
 *    pool: Scratch stream
 *
 * Returns: T   => success
 *          NIL => error   (reason sent to account_message).
 *         
 ***********************************************************************/

BOOL
account_mail_update(struct account * account, struct pool * pool)
{
    struct session *session = account->session;

    if (session->use_sieve)
        return(account_sieve_mail_update(account, pool));
    else
        return(account_msshell_mail_update(account, pool));
}

/* ====================================================================== */

BOOL
account_vacation_update(struct account * account, struct pool * pool)
{
    struct session *session = account->session;

    if (session->use_sieve)
        return(account_sieve_vacation_update(account, pool));
    else
        return(account_msshell_vacation_update(account, pool));
}

/* ====================================================================== */

/* account_vaclog_fetch() ***********************************************
 *
 * Fetch current vacation log.
 * account:
 *    pool: Scratch stream
 *
 * Returns: Vacation log as NULL terminated string
 *          NIL => error   (reason sent to account_message).
 *         
 ***********************************************************************/

char *account_vaclog_fetch(struct account *account, struct pool *pool)
{
    return(account_msshell_vaclog_fetch(account, pool));
}

/* account_vaclog_clear() ***********************************************
 *
 * Clear vacation log.
 * account:
 *    pool: Scratch stream
 *
 * Returns:   T => success
 *          NIL => error   (reason sent to account_message).
 *         
 ***********************************************************************/


BOOL
account_vaclog_clear(struct account * account, struct pool * pool)
{
    return(account_msshell_vaclog_clear(account, pool));
}

/* ====================================================================== */

/* account_abook_fetch() ************************************************
 *
 * Fetch .addressbook file from server
 * account:
 *    pool: Scratch stream
 *
 * Returns: Vacation log as NULL terminated string
 *          NIL => error   (reason sent to account_message).
 *         
 ***********************************************************************/

char *account_abook_get(struct account *account, struct pool *pool)
{
    return(account_msshell_abook_get(account, pool));
}

/* account_abook_put() **************************************************a
 *
 * Clear vacation log.
 * account:
 *    pool: Scratch stream
 *
 * Returns:   T => success
 *          NIL => error   (reason sent to account_message).
 *         
 ***********************************************************************/


BOOL
account_abook_put(struct account * account, struct pool * pool, char *text)
{
    return(account_msshell_abook_put(account, pool, text));
}
