/* $Cambridge: hermes/src/prayer/session/prefs.c,v 1.4 2011/07/04 09:37:27 dpc22 Exp $ */
/************************************************
 *    Prayer - a Webmail Interface              *
 ************************************************/

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

#include "prayer_session.h"

/* Set of routines for writing out and parsing user preferences stored
 * on IMAP server */

/* Small static support routine */

static SORTMODE prefs_sort_mode(char *mode)
{
    if (mode == NIL)
        return (SORTARRIVAL);

    switch (Utoupper(mode[0])) {
    case 'A':
        if (!strcasecmp(mode, "ARRIVAL"))
            return (ARRIVAL);
        break;
    case 'C':
        if (!strcasecmp(mode, "CC"))
            return (CC);
        break;
    case 'D':
        if (!strcasecmp(mode, "DATE"))
            return (DATE);
        break;
    case 'F':
        if (!strcasecmp(mode, "FROM"))
            return (FROM);
        break;
    case 'S':
        if (!strcasecmp(mode, "SUBJECT"))
            return (SUBJECT);
        else if (!strcasecmp(mode, "SIZE"))
            return (SIZE);
        break;
    case 'T':
        if (!strcasecmp(mode, "TO"))
            return (TO);
        break;
    }

    return (ARRIVAL);
}


static abook_sort_mode prefs_abook_sort_mode(char *mode)
{
    if (mode == NIL)
        return (SORTARRIVAL);

    switch (Utoupper(mode[0])) {
    case 'A':
        if (!strcasecmp(mode, "EMAIL"))
            return (ABOOK_SORT_EMAIL);
        if (!strcasecmp(mode, "ALIAS"))
            return (ABOOK_SORT_ALIAS);
        break;
    case 'C':
        if (!strcasecmp(mode, "COMMENT"))
            return (ABOOK_SORT_COMMENT);
        break;
    case 'N':
        if (!strcasecmp(mode, "NAME"))
            return (ABOOK_SORT_NAME);
        break;
    case 'O':
        if (!strcasecmp(mode, "ORDER"))
            return (ABOOK_SORT_ORDER);
        break;
    }
    return (ABOOK_SORT_ORDER);
}


/* prefs_create() *******************************************************
 *
 * Create a new preferences structure with its own pool.
 *   config: Prayer configuration
 *
 * Returns: New prefs structure with system wide defaults filled in
 ************************************************************************/

struct prefs *prefs_create(struct config *config)
{
    struct pool *pool = pool_create(PREFS_POOL_SIZE);
    struct prefs *p = pool_alloc(pool, sizeof(struct prefs));

    p->pool = pool;
    p->allow_raven_login = config->allow_raven_login;
    p->confirm_expunge   = config->confirm_expunge;
    p->confirm_logout    = config->confirm_logout;
    p->confirm_rm        = config->confirm_rm;

    if (config->msgs_per_page > 0)
        p->msgs_per_page = config->msgs_per_page;
    else
        p->msgs_per_page = 12;

    if (config->abook_per_page > 0)
        p->abook_per_page = config->abook_per_page;
    else
        p->abook_per_page = 12;

    p->template_set = config->template_set;

    if (config->maildir)
        p->maildir = config->maildir;
    else
        p->maildir = "mail";

    p->postponed_folder = config->postponed_folder;
    p->sent_mail_folder = config->sent_mail_folder;

    p->suppress_dotfiles = config->suppress_dotfiles;
    p->from_personal = "";
    p->from_address = "";
    p->default_reply_to = "";
    p->signature = "";
    p->alt_addr = "";

    p->ispell_language = config->ispell_language;
    p->spell_skip_quoted = config->spell_skip_quoted;

    if (config->small_cols > 0)
        p->small_cols = config->small_cols;
    else
        p->small_cols = 80;

    if (config->small_rows > 0)
        p->small_rows = config->small_rows;
    else
        p->small_rows = 80;

    if (config->large_cols > 0)
        p->large_cols = config->large_cols;
    else
        p->large_cols = 80;

    if (config->large_rows > 0)
        p->large_rows = config->large_rows;
    else
        p->large_rows = 80;

    if (config->default_domain == NIL)  /* Should be impossible */
        fatal("[prefs_create()] default_domain not defined!");

    p->theme_main_name = config->theme_default_main;
    p->theme_help_name = config->theme_default_help;

    p->default_domain = pool_strdup(pool, config->default_domain);
    p->sort_mode = prefs_sort_mode(config->sort_mode);
    p->sort_reverse = config->sort_reverse;
    p->abook_sort_mode = prefs_abook_sort_mode(config->abook_sort_mode);
    p->abook_sort_reverse = config->abook_sort_reverse;

    p->line_wrap_len = config->line_wrap_len;
    p->line_wrap_advanced = config->line_wrap_advanced;
    p->line_wrap_on_reply = config->line_wrap_on_reply;
    p->line_wrap_on_spell = config->line_wrap_on_spell;
    p->line_wrap_on_send = config->line_wrap_on_send;


    p->use_sent_mail = config->use_sent_mail;
    p->use_search_zoom = config->use_search_zoom;
    p->use_agg_unmark = config->use_agg_unmark;

    p->use_icons = config->use_icons;
    p->use_welcome = config->use_welcome;
    p->use_unread = config->use_unread;
    p->use_tail_banner = config->use_tail_banner;
    p->use_mark_persist = config->use_mark_persist;
    p->use_cookie = config->use_cookie;
    p->use_substitution = config->use_substitution;

    p->use_http_1_1 = config->use_http_1_1;
    p->use_pipelining = config->use_pipelining;
    p->use_persist = config->use_persist;
    p->use_short = config->use_short;
    p->use_gzip = config->use_gzip;

    p->html_inline = config->html_inline;
    p->html_inline_auto = config->html_inline_auto;
    p->html_remote_images = config->html_remote_images;
    p->preserve_mimetype = config->preserve_mimetype;
    p->expunge_on_exit = config->expunge_on_exit;

    return (p);
}

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

/* prefs_copy() **********************************************************
 *
 * Clone an existing preferences structure into a fresh structure with
 * its own pool.
 *   src: Initial prefs structure
 *
 * Returns: New prefs structure which is independant clone of src
 ************************************************************************/

struct prefs *prefs_copy(struct prefs *src)
{
    struct pool *pool = pool_create(PREFS_POOL_SIZE);
    struct prefs *dest = pool_alloc(pool, sizeof(struct prefs));

    dest->pool = pool;
    dest->allow_raven_login = src->allow_raven_login;
    dest->confirm_expunge  = src->confirm_expunge;
    dest->confirm_logout   = src->confirm_logout;
    dest->confirm_rm       = src->confirm_rm;
    dest->msgs_per_page    = src->msgs_per_page;
    dest->abook_per_page   = src->abook_per_page;
    dest->template_set     = pool_strdup(pool, src->template_set);
    dest->maildir = pool_strdup(pool, src->maildir);
    dest->postponed_folder = pool_strdup(pool, src->postponed_folder);
    dest->sent_mail_folder = pool_strdup(pool, src->sent_mail_folder);

    dest->suppress_dotfiles = src->suppress_dotfiles;
    dest->from_personal = pool_strdup(pool, src->from_personal);
    dest->from_address = pool_strdup(pool, src->from_address);
    dest->default_reply_to = pool_strdup(pool, src->default_reply_to);
    dest->signature = pool_strdup(pool, src->signature);
    dest->alt_addr = pool_strdup(pool, src->alt_addr);
    dest->ispell_language = pool_strdup(pool, src->ispell_language);
    dest->spell_skip_quoted = src->spell_skip_quoted;
    dest->small_cols = src->small_cols;
    dest->small_rows = src->small_rows;
    dest->large_cols = src->large_cols;
    dest->large_rows = src->large_rows;
    dest->default_domain = pool_strdup(pool, src->default_domain);

    dest->theme_main_name = pool_strdup(pool, src->theme_main_name);
    dest->theme_help_name = pool_strdup(pool, src->theme_help_name);

    dest->sort_mode = src->sort_mode;
    dest->sort_reverse = src->sort_reverse;
    dest->abook_sort_mode = src->abook_sort_mode;
    dest->abook_sort_reverse = src->abook_sort_reverse;

    dest->line_wrap_len = src->line_wrap_len;
    dest->line_wrap_advanced = src->line_wrap_advanced;
    dest->line_wrap_on_reply = src->line_wrap_on_reply;
    dest->line_wrap_on_spell = src->line_wrap_on_spell;
    dest->line_wrap_on_send = src->line_wrap_on_send;

    dest->use_sent_mail = src->use_sent_mail;
    dest->use_search_zoom = src->use_search_zoom;
    dest->use_agg_unmark = src->use_agg_unmark;

    dest->use_icons = src->use_icons;
    dest->use_welcome = src->use_welcome;
    dest->use_unread = src->use_unread;
    dest->use_tail_banner = src->use_tail_banner;
    dest->use_mark_persist = src->use_mark_persist;
    dest->use_cookie = src->use_cookie;
    dest->use_substitution = src->use_substitution;
    dest->use_http_1_1 = src->use_http_1_1;
    dest->use_pipelining = src->use_pipelining;
    dest->use_persist = src->use_persist;
    dest->use_short = src->use_short;
    dest->use_gzip = src->use_gzip;

    dest->html_inline = src->html_inline;
    dest->html_inline_auto = src->html_inline_auto;
    dest->html_remote_images = src->html_remote_images;
    dest->preserve_mimetype = src->preserve_mimetype;
    dest->expunge_on_exit = src->expunge_on_exit;

    return (dest);
}

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

/* prefs_free() **********************************************************
 *
 * Free (underlying pool of) prefs structure
 *   prefs: Prefs to free
 ************************************************************************/

void prefs_free(struct prefs *prefs)
{
    pool_free(prefs->pool);
}

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

/* prefs_parse_option() **************************************************
 *
 * Parse a line from user preferences file: overwrite prefs structure
 *   prefs: Prefs structure
 *    line: Line from preferences file
 * session: For logging purposes only
 ************************************************************************/

void
prefs_parse_option(struct prefs *prefs, char *line,
                   struct session *session)
{
    struct config *config = session->config;
    unsigned long numvalue;
    char *key, *value;
    unsigned long len;

    if (!(key = string_get_token(&line)))
        return;

    value = line;

    if (((len = strlen(key)) > 0) && (key[len - 1] == ':'))
        key[--len] = '\0';

    /* Skip blank lines */
    if (!(key && key[0] && value))
        return;

    switch (key[0]) {
    case 'a':
        if (!strcmp(key, "alt_addr")) {
            prefs->alt_addr =
                pool_strdup(prefs->pool, options_decode(value));
        } else if (!strcmp(key, "abook_per_page")) {
            numvalue = atoi(value);
            if ((numvalue >= 5) && (numvalue <= 50))
                prefs->abook_per_page = numvalue;
        } else if (!strcmp(key, "abook_sort_mode")) {
            if (!strcmp(value, "alias"))
                prefs->abook_sort_mode = ABOOK_SORT_ALIAS;
            else if (!strcmp(value, "name"))
                prefs->abook_sort_mode = ABOOK_SORT_NAME;
            else if (!strcmp(value, "comment"))
                prefs->abook_sort_mode = ABOOK_SORT_COMMENT;
            else if (!strcmp(value, "email"))
                prefs->abook_sort_mode = ABOOK_SORT_EMAIL;
            else
                prefs->abook_sort_mode = ABOOK_SORT_ORDER;     /* Default */
        } else if (!strcmp(key, "abook_sort_reverse")) {
            prefs->abook_sort_reverse = options_parse_bool(value);
        } else if (!strcmp(key, "allow_raven_login")) {
            prefs->allow_raven_login = options_parse_bool(value);
        }
        break;
    case 'c':
        if (!strcmp(key, "confirm_expunge"))
            prefs->confirm_expunge = options_parse_bool(value);
        else if (!strcmp(key, "confirm_logout"))
            prefs->confirm_logout = options_parse_bool(value);
        else if (!strcmp(key, "confirm_rm"))
            prefs->confirm_rm = options_parse_bool(value);
        break;
    case 'd':
        if (!strcmp(key, "default_domain"))
            prefs->default_domain =
                pool_strdup(prefs->pool, options_decode(value));
        else if (!strcmp(key, "default_reply_to"))
            prefs->default_reply_to
                = pool_strdup(prefs->pool, options_decode(value));
        break;
    case 'e':
        if (!strcmp(key, "expunge_on_exit"))
            prefs->expunge_on_exit = options_parse_bool(value);
        break;
    case 'h':
        if (!strcmp(key, "html_inline"))
            prefs->html_inline = options_parse_bool(value);
        else if (!strcmp(key, "html_inline_auto"))
            prefs->html_inline_auto = options_parse_bool(value);
        else if (!strcmp(key, "html_remote_images"))
            prefs->html_remote_images = options_parse_bool(value);
        break;
    case 'i':
        if (!strcmp(key, "ispell_language"))
            prefs->ispell_language =
                pool_strdup(prefs->pool, options_decode(value));
        break;
    case 'f':
        if (!strcmp(key, "from_personal"))
            prefs->from_personal =
                pool_strdup(prefs->pool, options_decode(value));
        else if (!strcmp(key, "from_address"))
            prefs->from_address =
                pool_strdup(prefs->pool, options_decode(value));
        break;
    case 'l':
        if (!strcmp(key, "large_cols"))
            prefs->large_cols = atoi(value);
        else if (!strcmp(key, "large_rows"))
            prefs->large_rows = atoi(value);
        else if (!strcmp(key, "line_wrap_len"))
            prefs->line_wrap_len = atoi(value);
        else if (!strcmp(key, "line_wrap_advanced"))
            prefs->line_wrap_advanced = options_parse_bool(value);
        else if (!strcmp(key, "line_wrap_on_reply"))
            prefs->line_wrap_on_reply = options_parse_bool(value);
        else if (!strcmp(key, "line_wrap_on_spell"))
            prefs->line_wrap_on_spell = options_parse_bool(value);
        else if (!strcmp(key, "line_wrap_on_send"))
            prefs->line_wrap_on_send = options_parse_bool(value);
        break;
    case 'm':
        if (!strcmp(key, "msgs_per_page")) {
            numvalue = atoi(value);
            if ((numvalue >= config->msgs_per_page_min) &&
                (numvalue <= config->msgs_per_page_max))
                prefs->msgs_per_page = numvalue;
        } else if (!strcmp(key, "maildir")) {
            value = options_decode(value);

            if (string_filename_valid(value))
                prefs->maildir = pool_strdup(prefs->pool, value);
            else
                session_log(session,
                            "[prefs_parse_option] maildir invalid");
        }
        break;
    case 'p':
        if (!strcmp(key, "preserve_mimetype"))
            prefs->preserve_mimetype = options_parse_bool(value);
        else if (!strcmp(key, "postponed_folder")) {
            value = options_decode(value);
            if (string_filename_valid(value))
                prefs->postponed_folder = pool_strdup(prefs->pool, value);
            else
                session_log(session,
                            "[prefs_parse_option] postponed_folder invalid");
        }
        break;
    case 's':
        if (!strcmp(key, "suppress_dotfiles"))
            prefs->suppress_dotfiles = options_parse_bool(value);
        else if (!strcmp(key, "signature"))
            prefs->signature =
                pool_strdup(prefs->pool, options_decode(value));
        else if (!strcmp(key, "small_cols"))
            prefs->small_cols = atoi(value);
        else if (!strcmp(key, "small_rows"))
            prefs->small_rows = atoi(value);
        else if (!strcmp(key, "sort_mode")) {
            if (!strcmp(value, "date"))
                prefs->sort_mode = DATE;
            else if (!strcmp(value, "from"))
                prefs->sort_mode = FROM;
            else if (!strcmp(value, "to"))
                prefs->sort_mode = TO;
            else if (!strcmp(value, "cc"))
                prefs->sort_mode = CC;
            else if (!strcmp(value, "size"))
                prefs->sort_mode = SIZE;
            else if (!strcmp(value, "subject"))
                prefs->sort_mode = SUBJECT;
            else if (!strcmp(value, "references"))
                prefs->sort_mode = REFERENCES;
            else if (!strcmp(value, "orderedsubject"))
                prefs->sort_mode = ORDEREDSUBJECT;
            else
                prefs->sort_mode = ARRIVAL;     /* Default */
        } else if (!strcmp(key, "sort_reverse")) {
            prefs->sort_reverse = options_parse_bool(value);
        } else if (!strcmp(key, "sent_mail_folder")) {
            value = options_decode(value);
            if (string_filename_valid(value))
                prefs->sent_mail_folder = pool_strdup(prefs->pool, value);
            else
                session_log(session,
                            "[prefs_parse_option] sent_mail_folder invalid");
        } else if (!strcmp(key, "spell_skip_quoted")) {
            prefs->spell_skip_quoted = options_parse_bool(value);
        }
        break;
    case 't':
        if (!strcmp(key, "template_set")) {
            char *s = pool_strdup(prefs->pool, options_decode(value));

            if (config->template_list &&
                list_lookup_byname(config->template_list, s))
                prefs->template_set = s;
        } else if (!strcmp(key, "theme_main_name"))
            prefs->theme_main_name =
                pool_strdup(prefs->pool, options_decode(value));
        else if (!strcmp(key, "theme_help_name"))
            prefs->theme_help_name =
                pool_strdup(prefs->pool, options_decode(value));
    case 'u':
        if (!strcmp(key, "use_icons"))
            prefs->use_icons = options_parse_bool(value);
        else if (!strcmp(key, "use_welcome"))
            prefs->use_welcome = options_parse_bool(value);
        else if (!strcmp(key, "use_unread"))
            prefs->use_unread = options_parse_bool(value);
        else if (!strcmp(key, "use_tail_banner"))
            prefs->use_tail_banner = options_parse_bool(value);
        else if (!strcmp(key, "use_mark_persist"))
            prefs->use_mark_persist = options_parse_bool(value);
        else if (!strcmp(key, "use_cookie"))
            prefs->use_cookie = options_parse_bool(value);
        else if (!strcmp(key, "use_substitution"))
            prefs->use_substitution = options_parse_bool(value);
        else if (!strcmp(key, "use_http_1_1"))
            prefs->use_http_1_1 = options_parse_bool(value);
        else if (!strcmp(key, "use_pipelining"))
            prefs->use_pipelining = options_parse_bool(value);
        else if (!strcmp(key, "use_persist"))
            prefs->use_persist = options_parse_bool(value);
        else if (!strcmp(key, "use_short"))
            prefs->use_short = options_parse_bool(value);
        else if (!strcmp(key, "use_gzip"))
            prefs->use_gzip = options_parse_bool(value);

        else if (!strcmp(key, "use_sent_mail"))
            prefs->use_sent_mail = options_parse_bool(value);
        else if (!strcmp(key, "use_search_zoom"))
            prefs->use_search_zoom = options_parse_bool(value);
        else if (!strcmp(key, "use_agg_unmark"))
            prefs->use_agg_unmark = options_parse_bool(value);

        break;
    }
}

/* prefs_parse_check() ***************************************************
 *
 * Sanity check preferences
 ************************************************************************/

void prefs_parse_check(struct prefs *prefs)
{
    if (prefs->maildir && prefs->maildir[0]) {
        unsigned long len = strlen(prefs->maildir);

        /* Check postponed_folder */
        if (prefs->postponed_folder && prefs->postponed_folder[0] &&
            !strncmp(prefs->postponed_folder, prefs->maildir, len) &&
            (prefs->postponed_folder[len] == '/'))
            prefs->postponed_folder += len + 1;

        /* Check sent_mail_folder */
        if (prefs->sent_mail_folder && prefs->sent_mail_folder[0] &&
            !strncmp(prefs->sent_mail_folder, prefs->maildir, len) &&
            (prefs->sent_mail_folder[len] == '/'))
            prefs->sent_mail_folder += len + 1;
    }
}

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

/* Static utiliy routines */

static BOOL prefs_compare_strings(char *s1, char *s2)
{
    if (s1 && s2)
        return (!strcmp(s1, s2) ? T : NIL);     /* Simple string test */
    else if (s1 && !s2)
        return (NIL);           /* Only one NIL */
    else if (!s1 && s2)
        return (NIL);           /* Both values NIL */

    return (T);                 /* Both values NIL */
}

/* prefs_print_options() *************************************************
 *
 * Convert preferences to textual representation suitable for user
 * preferences file on IMAP server.
 *   prefs: Prefs to print
 *  config: Prayer configuration
 *       b: Output buffer
 ************************************************************************/

void
prefs_print_options(struct prefs *prefs,
                    struct config *config, struct buffer *b)
{
    if (prefs->allow_raven_login != config->allow_raven_login)
        options_print_bool(b, "allow_raven_login", prefs->allow_raven_login);
    if (prefs->confirm_expunge != config->confirm_expunge)
        options_print_bool(b, "confirm_expunge", prefs->confirm_expunge);
    if (prefs->confirm_logout != config->confirm_logout)
        options_print_bool(b, "confirm_logout", prefs->confirm_logout);
    if (prefs->confirm_rm != config->confirm_rm)
        options_print_bool(b, "confirm_rm", prefs->confirm_rm);
    if (prefs->msgs_per_page != config->msgs_per_page)
        options_print_number(b, "msgs_per_page", prefs->msgs_per_page);
    if (prefs->abook_per_page != config->abook_per_page)
        options_print_number(b, "abook_per_page", prefs->abook_per_page);

    if (!prefs_compare_strings(prefs->template_set, config->template_set))
        options_print(b, "template_set", prefs->template_set);
    if (!prefs_compare_strings(prefs->maildir, config->maildir))
        options_print(b, "maildir", prefs->maildir);
    if (!prefs_compare_strings
        (prefs->postponed_folder, config->postponed_folder))
        options_print(b, "postponed_folder", prefs->postponed_folder);
    if (!prefs_compare_strings
        (prefs->sent_mail_folder, config->sent_mail_folder))
        options_print(b, "sent_mail_folder", prefs->sent_mail_folder);

    if (prefs->suppress_dotfiles != config->suppress_dotfiles)
        options_print_bool(b, "suppress_dotfiles",
                           prefs->suppress_dotfiles);

    if (prefs->from_personal && prefs->from_personal[0])
        options_print(b, "from_personal", prefs->from_personal);
    if (prefs->from_address && prefs->from_address[0])
        options_print(b, "from_address", prefs->from_address);
    if (prefs->default_reply_to && prefs->default_reply_to[0])
        options_print(b, "default_reply_to", prefs->default_reply_to);

    if (!prefs_compare_strings
        (prefs->ispell_language, config->ispell_language))
        options_print(b, "ispell_language", prefs->ispell_language);

    if (prefs->spell_skip_quoted != config->spell_skip_quoted)
        options_print_bool(b, "spell_skip_quoted", prefs->spell_skip_quoted);

    if (prefs->signature && prefs->signature[0])
        options_print(b, "signature", prefs->signature);
    if (prefs->alt_addr && prefs->alt_addr[0])
        options_print(b, "alt_addr", prefs->alt_addr);

    if (prefs->small_cols != config->small_cols)
        options_print_number(b, "small_cols", prefs->small_cols);
    if (prefs->small_rows != config->small_rows)
        options_print_number(b, "small_rows", prefs->small_rows);
    if (prefs->large_cols != config->large_cols)
        options_print_number(b, "large_cols", prefs->large_cols);
    if (prefs->large_rows != config->large_rows)
        options_print_number(b, "large_rows", prefs->large_rows);

    if (!prefs_compare_strings
        (prefs->default_domain, config->default_domain))
        options_print(b, "default_domain", prefs->default_domain);

    if (!prefs_compare_strings(prefs->theme_main_name,
                               config->theme_default_main))
        options_print(b, "theme_main_name", prefs->theme_main_name);

    if (!prefs_compare_strings(prefs->theme_help_name,
                               config->theme_default_help))
        options_print(b, "theme_help_name", prefs->theme_help_name);

    if (!prefs_compare_strings
        (prefs->default_domain, config->default_domain))
        options_print(b, "default_domain", prefs->default_domain);

    if (prefs->use_icons != config->use_icons)
        options_print_bool(b, "use_icons", prefs->use_icons);
    if (prefs->use_welcome != config->use_welcome)
        options_print_bool(b, "use_welcome", prefs->use_welcome);
    if (prefs->use_unread != config->use_unread)
        options_print_bool(b, "use_unread", prefs->use_unread);

    if (prefs->use_tail_banner != config->use_tail_banner)
        options_print_bool(b, "use_tail_banner", prefs->use_tail_banner);
    if (prefs->use_mark_persist != config->use_mark_persist)
        options_print_bool(b, "use_mark_persist", prefs->use_mark_persist);

    if (prefs->use_cookie != config->use_cookie)
        options_print_bool(b, "use_cookie", prefs->use_cookie);
    if (prefs->use_substitution != config->use_substitution)
        options_print_bool(b, "use_substitution", prefs->use_substitution);

    if (prefs->use_http_1_1 != config->use_http_1_1)
        options_print_bool(b, "use_http_1_1", prefs->use_http_1_1);
    if (prefs->use_pipelining != config->use_pipelining)
        options_print_bool(b, "use_pipelining", prefs->use_pipelining);
    if (prefs->use_persist != config->use_persist)
        options_print_bool(b, "use_persist", prefs->use_persist);
    if (prefs->use_short != config->use_short)
        options_print_bool(b, "use_short", prefs->use_short);
    if (prefs->use_gzip != config->use_gzip)
        options_print_bool(b, "use_gzip", prefs->use_gzip);

    if (prefs->html_inline != config->html_inline)
        options_print_bool(b, "html_inline", prefs->html_inline);
    if (prefs->html_inline_auto != config->html_inline_auto)
        options_print_bool(b, "html_inline_auto", prefs->html_inline_auto);
    if (prefs->html_remote_images != config->html_remote_images)
        options_print_bool(b, "html_remote_images", prefs->html_remote_images);
    if (prefs->preserve_mimetype != config->preserve_mimetype)
        options_print_bool(b, "preserve_mimetype",
                           prefs->preserve_mimetype);
    if (prefs->expunge_on_exit != config->expunge_on_exit)
        options_print_bool(b, "expunge_on_exit",
                           prefs->expunge_on_exit);

    if (prefs->sort_mode != prefs_sort_mode(config->sort_mode)) {
        if (prefs->sort_mode == DATE)
            options_print(b, "sort_mode", "date");
        else if (prefs->sort_mode == FROM)
            options_print(b, "sort_mode", "from");
        else if (prefs->sort_mode == TO)
            options_print(b, "sort_mode", "to");
        else if (prefs->sort_mode == CC)
            options_print(b, "sort_mode", "cc");
        else if (prefs->sort_mode == SIZE)
            options_print(b, "sort_mode", "size");
        else if (prefs->sort_mode == SUBJECT)
            options_print(b, "sort_mode", "subject");
        else if (prefs->sort_mode == REFERENCES)
            options_print(b, "sort_mode", "references");
        else if (prefs->sort_mode == ORDEREDSUBJECT)
            options_print(b, "sort_mode", "orderedsubject");
        else
            options_print(b, "sort_mode", "arrival");   /* Default */
    }

    if (prefs->sort_reverse != config->sort_reverse)
        options_print_bool(b, "sort_reverse", prefs->sort_reverse);

    if (prefs->abook_sort_mode != prefs_abook_sort_mode(config->sort_mode)) {
        if (prefs->abook_sort_mode == ABOOK_SORT_ALIAS)
            options_print(b, "abook_sort_mode", "alias");
        else if (prefs->abook_sort_mode == ABOOK_SORT_NAME)
            options_print(b, "abook_sort_mode", "name");
        else if (prefs->abook_sort_mode == ABOOK_SORT_COMMENT)
            options_print(b, "abook_sort_mode", "comment");
        else if (prefs->abook_sort_mode == ABOOK_SORT_EMAIL)
            options_print(b, "abook_sort_mode", "email");
        else
            options_print(b, "abook_sort_mode", "order");
    }

    if (prefs->abook_sort_reverse != config->abook_sort_reverse)
        options_print_bool(b, "abook_sort_reverse", prefs->abook_sort_reverse);

    if (prefs->line_wrap_len != config->line_wrap_len)
        options_print_number(b, "line_wrap_len", prefs->line_wrap_len);

    if (prefs->line_wrap_advanced != config->line_wrap_advanced)
        options_print_bool(b, "line_wrap_advanced",
                           prefs->line_wrap_advanced);

    if (prefs->line_wrap_on_reply != config->line_wrap_on_reply)
        options_print_bool(b, "line_wrap_on_reply",
                           prefs->line_wrap_on_reply);

    if (prefs->line_wrap_on_spell != config->line_wrap_on_spell)
        options_print_bool(b, "line_wrap_on_spell",
                           prefs->line_wrap_on_spell);

    if (prefs->line_wrap_on_send != config->line_wrap_on_send)
        options_print_bool(b, "line_wrap_on_send",
                           prefs->line_wrap_on_send);

    if (prefs->use_sent_mail != config->use_sent_mail)
        options_print_bool(b, "use_sent_mail", prefs->use_sent_mail);

    if (prefs->use_search_zoom != config->use_search_zoom)
        options_print_bool(b, "use_search_zoom", prefs->use_search_zoom);

    if (prefs->use_agg_unmark != config->use_agg_unmark)
        options_print_bool(b, "use_agg_unmark", prefs->use_agg_unmark);
}
