/* $Cambridge: hermes/src/prayer/cmd/cmd_abook_lookup.c,v 1.2 2008/05/19 15:55:54 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"

static BOOL
cmd_abook_lookup_addnav(struct template_vals *tvals,
                        unsigned long offset,
                        unsigned long count,
                        unsigned long per_page)
{
    unsigned long page;
    unsigned long pages;

    if (count > 0) {
        page = ((offset - 1) / per_page) + 1;
        pages = ((count - 1) / per_page) + 1;
    } else {
        page = 0;
        pages = 0;
    }

    template_vals_ulong(tvals, "entries", count);
    template_vals_ulong(tvals, "page_current", page);
    template_vals_ulong(tvals, "page_total", pages);

    if (page > 1) {
        template_vals_hash_ulong(tvals, "$nav", "first_page", 1);
        template_vals_hash_ulong(tvals, "$nav", "prev_page", offset-per_page);
    }
    if (page < pages) {
        template_vals_hash_ulong(tvals, "$nav", "next_page", offset+per_page);
        template_vals_hash_ulong(tvals, "$nav", "last_page", count);
    }
    return(T);
}

/* Is display_name sufficiently different from registered_name to
   warant showing both? Ignore case, spaces and punctuation */

static BOOL
compare_display_ignore_char(char c)
{
    return ((c == ' ') || (c == '\t') || (c == ',') || (c == '.'));
}

static BOOL
compare_display_name(char *display, char *registered)
{
    while (1) {
        while (*display && compare_display_ignore_char(*display))
            display++;

        while (*registered && compare_display_ignore_char(*registered))
            registered++;

        if ((*display == '\0') || (*registered == '\0'))
            break;

        if (Utolower(*display) != Utolower(*registered))
            break;

        display++;
        registered++;
    }

    return (((*display == '\0') && (*registered == '\0')) ? T : NIL);
}

static void
cmd_abook_lookup_single(struct template_vals *tvals,
                        struct lookup_item *entry, unsigned long offset,
                        BOOL have_draft, unsigned long count)
{
    template_vals_foreach_init(tvals, "@list", count);
    template_vals_foreach_ulong(tvals, "@list", count,
                                "offset", offset);

    if (count % 2 == 0)
        template_vals_foreach_ulong(tvals, "@list", count,
                                    "even_row", 1);

    template_vals_foreach_string(tvals, "@list", count,
                                 "userid", entry->userid);

    template_vals_foreach_string(tvals, "@list", count,
                                 "display_name", entry->display_name);
 
   if (!compare_display_name(entry->display_name, entry->registered_name)) {
        template_vals_foreach_string(tvals, "@list", count,
                                     "registered_name", entry->registered_name);
    }

    template_vals_foreach_string(tvals, "@list", count,
                                 "affiliation", entry->affiliation);

    if (entry->cancelled)
        template_vals_foreach_ulong(tvals, "@list", count,
                                    "cancelled", 1);

    template_vals_foreach_string(tvals, "@list", count,
                                 "phone", entry->phone);

    template_vals_foreach_string(tvals, "@list", count,
                                 "email", entry->email);
}

void
my_generate_page(struct session *session)
{
    struct template_vals *tvals = session->template_vals;
    struct prefs *prefs = session->options->prefs;
    struct lookup  *lookup = session->lookup;
    struct request *request = session->request;
    struct buffer  *b = request->write_buffer;
    BOOL have_draft = session->draft->have_draft;
    unsigned long i, offset, first, last;
    unsigned long count;

    /* Calculate first and last entry on page. */
    offset = lookup->current;

    if (offset >= prefs->abook_per_page)
        first = (offset - ((offset - 1) % prefs->abook_per_page));
    else
        first = 1;

    last = (((first + (prefs->abook_per_page - 1)) <= lookup->count)
            ? (first + (prefs->abook_per_page - 1)) : lookup->count);

    count = 0;
    for (i = first ; i <= last ; i++) {
        cmd_abook_lookup_single(tvals, lookup->entries[i-1], i,
                                have_draft, count);
        count++;
    }

    cmd_abook_lookup_addnav(tvals, first, lookup->count, prefs->abook_per_page);
    template_vals_string(tvals, "$query", lookup->query);
    template_vals_ulong(tvals, "$count", lookup->count);

    if (lookup->have_phone)
        template_vals_ulong(tvals, "$have_phone", 1);

    if (lookup->have_cancelled)
        template_vals_ulong(tvals, "$have_cancelled", 1);

    session_seed_template(session, tvals);
    template_expand("abook_lookup", tvals, b);
    response_html(request, 200);
}

static void
my_add_addresses(struct session *session)
{
    struct request *request = session->request;
    struct pool *pool = request->pool;
    struct draft *draft = session->draft;
    unsigned long offset;
    unsigned long count;
    struct lookup *lookup = session->lookup;
    struct lookup_item **entries = lookup->entries, *entry;
    unsigned long max = lookup->count;
    void (*fn)(struct draft *draft, char *text) = NIL; 
    char *key, *name;

    if (!entries)
        return;

    assoc_scan_reset(request->form);

    count = 0;
    while (assoc_scan_next(request->form, &key, NIL)) {
        if (!strncmp(key, "to_", strlen("to_"))) {
            key += strlen("to_");
            fn = draft_add_to;
        } else if (!strncmp(key, "cc_", strlen("cc_"))) {
            key += strlen("cc_");
            fn = draft_add_cc;
        } else if (!strncmp(key, "bcc_", strlen("bcc_"))) {
            key += strlen("bcc_");
            fn = draft_add_bcc;
        } else
            continue;

        if ((offset = atoi(key)) > max)
            continue;

        entry = entries[offset-1];
        if (!(entry->email && entry->email[0]))
            continue;

        if (entry->display_name && entry->display_name[0])
            name = entry->display_name;
        else if (entry->registered_name && entry->registered_name[0])
            name = entry->registered_name;
        else
            name = "";

        (*fn)(draft, abook_text_to_string(pool, name, entry->email));
        count++;
    }

    if (count != 1)
        session_message(session, "Added %lu addresses to draft", count);
    else
        session_message(session, "Added 1 address to draft");
}

static BOOL
validate_query(char *s)
{
    char c;

    if (!s)
        return(NIL);

    while ((c=*s++)) {
        if (strchr("()|&=", c) != NIL)
            return(NIL);
    }

    return(T);
}

void cmd_abook_lookup(struct session *session)
{
    struct lookup  *lookup = session->lookup;
    struct prefs   *prefs = session->options->prefs;
    struct request *request = session->request;
    struct assoc   *h = NIL;
    char *query;
    BOOL do_ldap = NIL;

    if (request->method != POST) {
        if (request->argc == 2)
            lookup->current = atoi(request->argv[1]);  /* Move to page */

        my_generate_page(session);
        return;
    }

    request_decode_form(request);
    h = request->form;

    if (assoc_lookup(h, "sub_cancel")) {
        lookup_clear(lookup);
        session_redirect(session, request, "abook_list");
        return;
    }

    /* Record last command for addressbook take */
    session->take_parent_cmd = "abook_lookup";

    /* Record last command for compose/cancel and friends */
    if (!session->draft->have_draft)
        session->compose_parent_cmd = "abook_lookup";

    if (assoc_lookup(h, "sub_page")) {
        char *pstr = assoc_lookup(request->form, "page");
        unsigned long page = pstr ? atoi(pstr) : 0;
        unsigned long pages = (lookup->count / prefs->abook_per_page) + 1;

        if ((page > 0) && (page <= pages))
            lookup->current = (page - 1) * prefs->abook_per_page + 1;

        if (lookup->current > lookup->count)
            lookup->current = lookup->count;
        
        my_generate_page(session);
        return;
    }

    if (assoc_lookup(h, "sub_add_address")) {
        my_add_addresses(session);
        my_generate_page(session);
        return;
    }

    /* If we get this far then there is a fresh query */
    if ((query=assoc_lookup(h, "query")))
        query = string_trim_whitespace(query);

    if (!(query && query[0])) {
        session_message(session, "No search term provided");
        session_redirect(session, request, "abook_list");
        return;
    }

    if (!validate_query(query)) {
        session_message(session, "Query contained illegal characters");
        session_redirect(session, request, "abook_list");
        return;
    }

    if (assoc_lookup(h, "sub_ldap")) {
        do_ldap = T;
    } else if (assoc_lookup(h, "sub_local")) {
        do_ldap = NIL;
    } else if (lookup_ldap_available(lookup)) {
        do_ldap = T;
    } else
        do_ldap = NIL;

    if (do_ldap) {
        session_log(session,
                    "[cmd_abook_lookup] LDAP lookup for \"%s\"", query);
        if (!lookup_ldap(lookup, query)) {
            session_redirect(session, request, "abook_list");
            return;
        }
    } else {
        session_log(session,
                    "[cmd_abook_lookup] Local lookup for \"%s\"", query);
        if (!lookup_local(lookup, query, prefs->default_domain)) {
            session_redirect(session, request, "abook_list");
            return;
        }
    }

    if (lookup->count == 0) {
        session_message(session,
                        ("0 matches for \"%s\" (may indicate too"
                         " many possible matches)"), query);
    } else if (lookup->count == 1) {
        session_message(session, "1 match for \"%s\"", query);
    } else {
        session_message(session, "%lu matches for \"%s\"",
                        lookup->count, query);
    }

    if (!lookup->entries) {
        session_redirect(session, request, "abook_list");
        return;
    }

    my_generate_page(session);
}
