/* $Cambridge: hermes/src/prayer/session/account_msshell.c,v 1.3 2008/09/16 09:59:58 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_msshell_get_line() ********************************************
 *
 * Get a line (of arbitary length) from input stream.
 * stream: iostream linked to one of the accountd servers
 *   pool: Target pool (typically scratch)
 *
 * Returns: NULL terminated string
 ***********************************************************************/

static char *
account_msshell_get_line(struct iostream *stream, struct pool *pool)
{
    char *result;

    do {
        struct buffer *b = buffer_create(pool, 80);
        int c;

        while ((c = iogetc(stream)) != EOF) {
            if (c == '\015')
                continue;
            if (c == '\012')
                break;

            bputc(b, c);
        }
        if (c == EOF)
            return (NIL);

        result = buffer_fetch(b, 0, buffer_size(b), NIL);
    }
    while (!(result && result[0] && (result[0] != ' ')));

    return (result);
}

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

/* account_msshell_connect() ********************************************
 *
 * Connect to nominated server
 * account:
 *  server: Name of server with port and SSL modifiers.
 *          e.g: prism-intramail:145 or server:8082/ssl
 *
 * Returns: iostream to server
 *          NIL if connection attempt failed. (reason to account_message)
 ***********************************************************************/

static struct iostream *
account_msshell_connect(struct account *account, char *server)
{
    struct session *session = account->session;
    struct config *config = session->config;
    struct request *request = session->request;
    struct pool *pool = request->pool;  /* Scratch space */
    unsigned long port = ACCOUNTD_DEFAULT_PORT;
    int sockfd;
    char *line, *rcode, *text, *s, *t, c;
    BOOL use_ssl = NIL;
    struct iostream *stream;

    if (server == NIL)
        return (NIL);

    server = pool_strdup(pool, server);

    /* Split up string of form server:port/ssl or server/ssl:port */
    s = server;
    while (*s) {
        switch (*s) {
        case ':':
            *s++ = '\0';
            port = atoi(s);
            while (Uisdigit(*s))
                s++;
            break;
        case '/':
            *s++ = '\0';

            /* Isolate the next token */
            t = s;
            while (*t && (*t != '/') && (*t != ':'))
                t++;

            c = *t;
            *t = '\0';
            if (!strcmp(s, "ssl"))
                use_ssl = T;
            *t = c;
            s = t;
            break;
        default:
            s++;
        }
    }

    if (port == 0L)
        return (NIL);

    /* Bind connection to account server */
    if ((sockfd = os_connect_inet_socket(server, port)) < 0) {
        account_message(account,
                        "Can't communicate with account management system");
        session_log(session,
                    "[account_msshell_connect]: os_connect_inet() failed");
        return (NIL);
    }

    /* Bind the iostream */
    if (!(stream = iostream_create(NIL, sockfd, ACCOUNT_BLOCKSIZE))) {
        account_message(account,
                        "Can't communicate with account management system");
        session_log(session,
                    "[account_msshell_connect]: iostream_create() failed");
        return (NIL);
    }

    iostream_set_timeout(stream, config->accountd_timeout);

    /* Start SSL if requested */
    if (use_ssl)
        iostream_ssl_start_client(stream);

    /* Get banner line */
    if ((line = account_msshell_get_line(stream, pool)) == NIL)
        return (NIL);

    /* Initial login attempt */
    ioprintf(stream, "LOGIN %s %s" CRLF,
             string_canon_encode(request->pool, session->username),
             string_canon_encode(request->pool, session->password));
    if (!ioflush(stream))
        return (NIL);

    /* Get result line */
    if ((line = account_msshell_get_line(stream, pool)) == NIL)
        return (NIL);

    rcode = string_get_token(&line);
    text = line;
    string_ucase(rcode);

    if (!strcmp(rcode, "OK"))
        return (stream);

    if (!strcmp(rcode, "NO") && session->newpassword) {
        /* Try replacement password */
        ioprintf(stream, "LOGIN %s %s" CRLF,
                 string_canon_encode(request->pool, session->username),
                 string_canon_encode(request->pool, session->newpassword));

        if (!ioflush(stream))
            return (NIL);

        /* Get result line */
        if ((line = account_msshell_get_line(stream, pool)) == NIL)
            return (NIL);

        rcode = string_get_token(&line);
        text = line;
        string_ucase(rcode);

        if (!strcmp(rcode, "OK")) {
            session->password = session->newpassword;
            session->newpassword = NIL;
            return (stream);
        }
    }

    if (!strcmp(rcode, "NO")) {
        account_message(account, "Login error: %s", text);
        return (NIL);
    }

    account_message(account,
                    "Can't communicate with account management system");

    session_log(session,
                "[account_msshell_connect]: Protocol failure: %s %s", rcode, text);

    return (NIL);
}

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

/* account_msshell_stream_existing() ************************************
 *
 * Return iostream connection to relevant server
 * account:
 * use_nis: T => use nis server if defined. Otherwise normal server
 *
 * Returns: Existing iostream to server
 *          NIL if none exists
 ***********************************************************************/

static struct iostream *
account_msshell_stream_existing(struct account *account, BOOL use_nis)
{
    struct session *session = account->session;

    if (use_nis && session->accountd_nis_server) {
        if (account->nis_stream) {
            account->nis_last_ping = time(NIL);
            return (account->nis_stream);
        }
        return (NIL);
    }

    if (account->stream) {
        account->last_ping = time(NIL);
        return (account->stream);
    }
    return (NIL);
}

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

/* account_msshell_stream_new() *****************************************
 *
 * Return iostream connection to relevant server
 * account:
 * use_nis: T => use nis server if defined. Otherwise normal server
 *
 * Returns: iostream to server
 *          NIL on error (reason to session message)
 ***********************************************************************/

static struct iostream *
account_msshell_stream_new(struct account *account, BOOL use_nis)
{
    struct session *session = account->session;

    if (use_nis && session->accountd_nis_server) {
        if (account->nis_stream)
            iostream_close(account->nis_stream);

        account->nis_stream
            = account_msshell_connect(account, session->accountd_nis_server);

        /* Need to use new connection */
        if (!account->nis_stream)
            return (NIL);
        account->nis_last_ping = time(NIL);
        return (account->nis_stream);
    }

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

    /* Need to use new connection */
    account->stream
        = account_msshell_connect(account, session->accountd_server);

    if (!account->stream)
        return (NIL);

    account->last_ping = time(NIL);
    return (account->stream);
}

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

/* account_msshell_send_cmd?() ******************************************
 *
 * Send and flush simple command to server
 * account:
 * use_nis: Want connection to NIS accountd server, if different.
 *     cmd: Command to send
 *    arg1: First argument
 *     .  .  .
 *    argN: Nth argument
 *
 * Returns: Active iostream link to server on sucess.
 *          NIL => couldn't write to server
 ***********************************************************************/

static struct iostream *
account_msshell_send_cmd(struct account *account, BOOL use_nis, char *cmd)
{
    struct iostream *stream;

    if ((stream = account_msshell_stream_existing(account, use_nis))) {
        ioprintf(stream, "%s" CRLF, cmd);
        if (ioflush(stream))
            return (stream);
    }

    if (!(stream = account_msshell_stream_new(account, use_nis))) {
        account_message(account,
                        "Failed to connect to account management server");
        return (NIL);
    }

    ioprintf(stream, "%s" CRLF, cmd);
    if (ioflush(stream))
        return (stream);

    account_message(account,
                    "Failed to send command to account management server");
    return (NIL);
}

static struct iostream *
account_msshell_send_cmd1(struct account *account,
                  BOOL use_nis, char *cmd, char *arg1)
{
    struct iostream *stream;

    if ((stream = account_msshell_stream_existing(account, use_nis))) {
        ioprintf(stream, "%s %s" CRLF, cmd, arg1);
        if (ioflush(stream))
            return (stream);
    }

    if (!(stream = account_msshell_stream_new(account, use_nis))) {
        account_message(account,
                        "Failed to connect to account management server");
        return (NIL);
    }

    ioprintf(stream, "%s %s" CRLF, cmd, arg1);
    if (ioflush(stream))
        return (stream);

    account_message(account,
                    "Failed to send command to account management server");
    return (NIL);
}

static struct iostream *
account_msshell_send_cmd2(struct account *account,
                  BOOL use_nis, char *cmd, char *arg1, char *arg2)
{
    struct iostream *stream;

    if ((stream = account_msshell_stream_existing(account, use_nis))) {
        ioprintf(stream, "%s %s %s" CRLF, cmd, arg1, arg2);
        if (ioflush(stream))
            return (stream);
    }

    if (!(stream = account_msshell_stream_new(account, use_nis))) {
        account_message(account,
                        "Failed to connect to account management server");
        return (NIL);
    }

    ioprintf(stream, "%s %s %s" CRLF, cmd, arg1, arg2);
    if (ioflush(stream))
        return (stream);

    account_message(account,
                    "Failed to send command to account management server");
    return (NIL);
}

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

/* account_msshell_send_text() *******************************************
 *
 * Send and flush text string to server.
 * account:
 *  stream: Stream  to use
 *       s: String.
 *
 * Returns: T on sucess. NIL => couldn't write to server
 ***********************************************************************/

static BOOL
account_msshell_send_text(struct account *account,
                          struct iostream *stream, char *s)
{
    int c;

    while ((c = *s++))
        ioputc(c, stream);
    ioputs(stream, "" CRLF);

    return (ioflush(stream));
}

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

/* account_msshell_parse_response() *************************************
 *
 * Parse "OK/NO/BAD" response line from server
 * account:
 *  stream: Stream  to use
 *    pool: Scratch pool nominated by client.
 *
 * Returns: Server message on "OK"
 *          NIL on error (reason to account_message)
 ***********************************************************************/

static char *account_msshell_parse_response(struct account *account,
                                    struct iostream *stream,
                                    struct pool *pool)
{
    char *line, *rcode, *text;

    if ((line = account_msshell_get_line(stream, pool)) == NIL) {
        account_message(account, "Account management server vanished");
        return (NIL);
    }

    rcode = string_get_token(&line);
    text = line;
    string_ucase(rcode);

    if (!strcmp(rcode, "NO")) {
        account_message(account, "%s", text);
        return (NIL);
    }

    if (!strcmp(rcode, "BAD")) {
        account_message(account, "Protocol failure: %s", text);
        return (NIL);
    }

    if (strcmp(rcode, "OK") != NIL) {
        account_message(account, ("Unknown communication failure with "
                                  "account management server"));
        return (NIL);
    }

    return (text);
}

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

/* account_msshell_parse_size() *****************************************
 *
 * Parse literal size e.g: "{76}"
 * account:
 *    text: Text to parse
 *
 * Returns: Positive size value
 *          (-1) on error. (Detail to account_message)
 ***********************************************************************/

static int
account_msshell_parse_size(struct account *account, char *text)
{
    char *size;
    unsigned long len;

    if (!((size = string_get_token(&text)) && (size[0]))) {
        account_message(account,
                        "Protocol error communicating with accountd server");
        return (-1);
    }

    if (((len = strlen(size)) < 2) ||
        (size[0] != '{') || (size[len - 1] != '}')) {
        account_message(account,
                        "Protocol error communicating with accountd server");
        return (-1);
    }
    /* Check that size[1] -> size[len-1] all digits? */

    size[len - 1] = '\0';
    return (atoi(size + 1));
}

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

/* account_msshell_fetch_bytes() ****************************************
 *
 * Fetch bytes from input stream
 * account:
 *  stream: iostream to use
 *    pool: Target pool (result pool_alloced here, then copied in)
 *
 * Returns: text string, NULL terminated.
 *          NIL on error, detail to account_message
 *         
 ***********************************************************************/

static char *
account_msshell_fetch_bytes(struct account *account,
                    struct iostream *stream,
                    struct pool *pool, unsigned long len)
{
    char *result = pool_alloc(pool, len + 1);
    char *s;
    int c;

    /* Read len bytes into buffer */

    s = result;
    while ((len > 0) && ((c = iogetc(stream)) != EOF)) {
        *s++ = c;
        len--;
    }

    if (len > 0) {
        account_message(account, ("Connection to account management server"
                                  "closed unexpectedly"));
        return (NIL);
    }
    *s = '\0';

    return (result);
}

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

/* account_msshell_fetch_literal() **************************************
 *
 * Fetch literal from stream using routines defined above.
 * account:
 *  stream: iostream to use
 *    pool: Target pool (result pool_alloced here, then copied in)
 *
 * Returns: text string, NULL terminated.
 *          NIL on error, detail to account_message
 *         
 ***********************************************************************/

static char *account_msshell_fetch_literal(struct account *account,
                                   struct iostream *stream,
                                   struct pool *pool)
{
    char *response;
    int len;

    if (!
        (response =
         account_msshell_parse_response(account, stream, pool)))
        return (NIL);

    if ((len = account_msshell_parse_size(account, response)) < 0)
        return (NIL);

    return (account_msshell_fetch_bytes(account, stream, pool, len));
}

/* account_msshell_fetch_literal_catch_no() ******************************
 *
 * Fetch literal from stream using routines defined above. Translates
 * NO response into empty string.
 * account:
 *  stream: iostream to use
 *    pool: Target pool (result pool_alloced here, then copied in)
 *
 * Returns: text string, NULL terminated.
 *          NIL on error, detail to account_message
 *         
 ***********************************************************************/

static char *
account_msshell_fetch_literal_catch_no(struct account *account,
                                       struct iostream *stream,
                                       struct pool *pool)
{
    char *response;
    int len;

    if (!(response = account_msshell_parse_response(account, stream, pool)))
        return ("");

    if ((len = account_msshell_parse_size(account, response)) < 0)
        return (NIL);

    return (account_msshell_fetch_bytes(account, stream, pool, len));
}

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

/* External interface */

/* account_msshell_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_msshell_change_password(struct account * account,
                                struct pool * pool, char *old, char *new)
{
    struct session *session = account->session;
    struct iostream *stream;
    char *response;

    if (!(stream = account_msshell_send_cmd2(account, T, "PASSWORD",
                                     string_canon_encode(pool, old),
                                     string_canon_encode(pool, new))))
        return (NIL);

    if (!
        (response =
         account_msshell_parse_response(account, stream, pool)))
        return (NIL);

    /* Record password for transparent changeover */
    session->newpassword = pool_strdup(session->pool, new);
    account_message(account, "%s", response);
    return (T);
}

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

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

char *
account_msshell_fullname(struct account *account, struct pool *pool)
{
    struct iostream *stream;
    char *response;

    if (account->fullname && account->fullname[0])
        return (account->fullname);

    if (!(stream = account_msshell_send_cmd(account, T, "CHECKFULLNAME")))
        return (NIL);

    if (!
        (response =
         account_msshell_parse_response(account, stream, pool)))
        return (NIL);

    account->fullname = strdup(response);
    return (account->fullname);
}

/* account_msshell_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_msshell_change_fullname(struct account * account,
                        struct pool * pool, char *new)
{
    struct session *session = account->session;
    struct iostream *stream;
    char *response;

    stream=account_msshell_send_cmd2(account, T, "FULLNAME",
                             string_canon_encode(pool, session->password),
                             string_canon_encode(pool, new));

    if (!stream)
        return (NIL);

    response = account_msshell_parse_response(account, stream, pool);

    if (!response)
        return(NIL);

    account_message(account, "%s", response);
    if (account->fullname)
        free(account->fullname);
    account->fullname = strdup(new);

    return (T);
}

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

/* account_msshell_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_msshell_check_quota(struct account * account, struct pool * pool)
{
    struct iostream *stream;
    char *response;
    char *key, *value;

    if (!(stream = account_msshell_send_cmd(account, NIL, "QUOTA")))
        return (NIL);

    if (!
        (response =
         account_msshell_parse_response(account, stream, pool)))
        return (NIL);

    while (response && response[0]) {
        if (!((key = string_get_token(&response)) &&
              (value = string_get_token(&response)))) {
            account_message(account,
                            "Unknown communication failure with server");
            return (NIL);
        }

        string_ucase(key);

        if (!strcmp(key, "BUSED:"))
            account->bused = atoi(value);
        else if (!strcmp(key, "BLIMIT:"))
            account->blimit = atoi(value);
        else if (!strcmp(key, "IUSED:"))
            account->iused = atoi(value);
        else if (!strcmp(key, "ILIMIT:"))
            account->ilimit = atoi(value);
    }
    return (T);
}

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

/* account_msshell_filter_check() ***************************************
 *
 * Check mail filtering and redirection status.
 * account:
 *    pool: Scratch stream
 *
 * Returns: Filter as NULL terminated string.
 *          NIL => error (reason sent to account_message).
 *         
 ***********************************************************************/

static BOOL
account_msshell_filter_check(struct account *account, struct pool *pool)
{
    struct iostream *stream;
    char *filter;

    if (!(stream = account_msshell_send_cmd(account, NIL, "MAILSTATUS")))
        return (NIL);

    if (!(filter = account_msshell_fetch_literal(account, stream, pool)))
        return (NIL);

    return ((account_support_process_filter(account, filter, pool)) ? T : NIL);
}

/* account_msshell_vacation_fetch() *************************************
 *
 * Fetch vacation message (catches noexistence case)
 * account:
 *    pool: Scratch stream
 *
 * Returns: Vacation message as NULL terminated string.
 *          NIL => error (reason sent to account_message).
 *         
 ***********************************************************************/

static BOOL
account_msshell_vacation_fetch(struct account *account, struct pool *pool)
{
    struct iostream *stream;
    char *message;

    stream = account_msshell_send_cmd1(account, NIL, "GET", "vacation.message");

    if (!stream)
        return (NIL);

    message = account_msshell_fetch_literal_catch_no(account, stream, pool);

    if (!message)
        return (NIL);

    /* Record vacation message */
    string_strdup(&account->vacation_msg, message);

    return (T);
}

/* account_msshell_vacalias_fetch() *************************************
 *
 * Fetch vacation alias list (catches noexistence case)
 * account:
 *    pool: Scratch stream
 *
 * Returns: Vacation aliases as NULL terminated string.
 *          NIL => error (reason sent to account_message).
 *         
 ***********************************************************************/

static BOOL
account_msshell_vacalias_fetch(struct account *account, struct pool *pool)
{
    struct iostream *stream;
    char *message, *s, c;
    struct buffer *alias = buffer_create(pool, 256);    /* Likely small */

    string_free((void *) &account->vacation_aliases);

    stream = account_msshell_send_cmd1(account, NIL, "GET", "vacation.aliases");

    if (!stream)
        return(NIL);

    message = account_msshell_fetch_literal_catch_no(account, stream, pool);

    if (!message)
        return(NIL);

    /* Translate CRLF -> ", " */

    for (s = message; (c = *s); s++) {
        if (c == '\n') {
            if (s[1] && s[1] != '\n')
                bputs(alias, ", ");
        } else
            bputc(alias, c);
    }

    /* Record vacation aliases */
    if (buffer_size(alias) > 0)
        string_strdup(&account->vacation_aliases,
                      buffer_fetch(alias, 0, buffer_size(alias), NIL));

    return (T);
}

/* account_msshell_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_msshell_mail_check(struct account * account, struct pool * pool)
{
    if (!account_msshell_filter_check(account, pool))
        return (NIL);

    if (!account_msshell_vacation_fetch(account, pool))
        return (NIL);

    if (!account_msshell_vacalias_fetch(account, pool))
        return (NIL);

    return (T);
}

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

/* account_msshell_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_msshell_mail_update(struct account * account, struct pool * pool)
{
    struct iostream *stream;
    char *text;
    char *s;

    text   = account_support_mail_text(account, pool, NIL);
    s      = pool_printf(pool, "{%lu}", strlen(text));
    stream = account_msshell_send_cmd1(account, NIL, "MAILCHANGE", s);

    if (!stream)
        return (NIL);

    account_msshell_send_text(account, stream, text);

    return ((account_msshell_parse_response(account, stream, pool)) ? T :
            NIL);
}

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

BOOL
account_msshell_vacation_update(struct account * account, struct pool * pool)
{
    struct iostream *stream;
    char *file = account->vacation_msg;

    if (!(file && file[0]))
        return (T);

    stream = account_msshell_send_cmd2(account, NIL,
                               "PUT", "vacation.message",
                               pool_printf(pool, "{%lu}", strlen(file)));

    if (!stream)
        return (NIL);

    account_msshell_send_text(account, stream, file);

    if (!account_msshell_parse_response(account, stream, pool))
        return (NIL);

    if (account->vacation_aliases && account->vacation_aliases[0]) {
        struct buffer *b = buffer_create(pool, 256);    /* Likely small */
        ADDRESS *addr = NIL;
        ADDRESS *a = NIL;

        if (!(addr=addr_parse(pool, account->vacation_aliases, ""))) {
            account_message(account,
                            "Vacation Alias list invalid: %s", ml_errmsg());
            return (NIL);
        }

        for (a = addr; a; a = a->next) {
            if (a->mailbox && a->host)
                bprintf(b, "%s@%s\n", a->mailbox, a->host);
        }
        mail_free_address(&addr);
        file = buffer_fetch(b, 0, buffer_size(b), NIL);
    } else
        file = "";

    stream = account_msshell_send_cmd2(account, NIL, "PUT", "vacation.aliases",
                               pool_printf(pool, "{%lu}", strlen(file)));
    if (!stream)
        return (NIL);

    account_msshell_send_text(account, stream, file);

    return((account_msshell_parse_response(account, stream, pool)) ? T : NIL);
}

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

/* account_msshell_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_msshell_vaclog_fetch(struct account *account, struct pool *pool)
{
    struct iostream *stream;

    stream = account_msshell_send_cmd1(account, NIL, "GET", "vacation.log");

    if (!stream)
        return (NIL);

    return(account_msshell_fetch_literal_catch_no(account, stream, pool));
}

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


BOOL
account_msshell_vaclog_clear(struct account * account, struct pool * pool)
{
    struct iostream *stream;

    stream = account_msshell_send_cmd(account, NIL, "VACATION_CLEAR");

    if (!stream)
        return(NIL);

    if (!account_msshell_parse_response(account, stream, pool))
        return (NIL);

    return (T);
}

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

/* account_msshell_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_msshell_abook_get(struct account *account, struct pool *pool)
{
    struct iostream *stream;

    stream = account_msshell_send_cmd1(account, NIL, "GET", ".addressbook");

    if (!stream)
        return (NIL);

    return (account_msshell_fetch_literal_catch_no(account, stream, pool));
}

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


BOOL
account_msshell_abook_put(struct account * account,
                          struct pool * pool, char *text)
{
    struct iostream *stream;

    stream = account_msshell_send_cmd2(account, NIL, "PUT", ".addressbook",
                               pool_printf(pool, "{%lu}", strlen(text)));

    if (!stream)
        return (NIL);

    account_msshell_send_text(account, stream, text);

    return((account_msshell_parse_response(account, stream, pool)) ? T : NIL);
}
