/* 
   elmo - ELectronic Mail Operator

   Copyright (C) 2003, 2004 rzyjontko

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  

   ----------------------------------------------------------------------

   This file contains an implementation of an address book.

*/
/****************************************************************************
 *    IMPLEMENTATION HEADERS
 ****************************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>

#ifdef HAVE_HOME_ETC_H
# include <home_etc.h>
# define HOMEDIR_RC _HEdir
#else
# define HOMEDIR_RC getenv("HOME")
#endif

#include "address.h"
#include "raddress.h"
#include "error.h"
#include "file.h"
#include "xmalloc.h"
#include "ask.h"
#include "cmd.h"
#include "mail.h"
#include "select.h"
#include "folder.h"
#include "read.h"
#include "gettext.h"
#include "memblock.h"
#include "confread.h"
#include "abook.h"
#include "eprintf.h"
#include "str.h"
#include "sender.h"
#include "ecurses.h"
#include "color.h"
#include "label.h"
#include "interface.h"
#include "bitarray.h"

/****************************************************************************
 *    IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
 ****************************************************************************/

#define INITIAL_BLOCK_SIZE 2048

#define DFL_LOCATION() file_with_dir (HOMEDIR_RC, ".addressbook")
#define NONEMPTY do { if (abook->count == 0) return; } while (0)

/****************************************************************************
 *    IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
 ****************************************************************************/

/**
 * There is only one structure of this type.  It is used to collect data
 * about the address being read from the addressbook file.
 */
typedef struct new_item {
        address_t  *addr;
        char      **s_field;
        int         shift;
        unsigned    mask;
        int         group;
} new_item_t;

/****************************************************************************
 *    IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID)
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE DATA
 ****************************************************************************/

/**
 * This is to decide if the addressbook should be flushed back to the file.
 */
static int abook_changed = 0;

/**
 * This is to decide if the addressbook should be sorted before showing
 * it to the user.
 */
static int abook_sorted = 0;

/**
 * This is the address book itself.  It's just a set of addresses grouped
 * in a single array.
 */
static raddress_t *abook = NULL;


/* Address window contains all addresses defined in a message, so user can
   easily add new addresses to abook.  It consists of select_t object,
   optional label, and set of addresses. */
static elabel_t   *label_add    = NULL;
static select_t   *add_select   = NULL;
static raddress_t *add_raddress = NULL;


/* Addressbook window constis of select_t object and an optional label.
   We also have to store the information about which addresses have been
   selected. */
static elabel_t   *label        = NULL;
static select_t   *abook_select = NULL;
static bitarray_t *selected     = NULL;

/* Colors used in abook window. */
static chtype text_color;
static chtype picked_color;
static chtype picked_bar_color;
static chtype hilight_color;

/**
 * This is used when reading configuration.
 */
static new_item_t new_item = {NULL, NULL, 0, 0, 0};

/* Addresses are usually parsed by address.c module which has its own
   memory block to allocate all the strings used in addresses.  We have
   to store our data in some other location. */
static memblock_t *addr_block = NULL;

/* This string is used to eprintf the address, and display in the window. */
static str_t *str_line = NULL;

/* This is used as format in eprintf_addr. */
static char *abook_fmt = "%s %020n %e";

/****************************************************************************
 *    INTERFACE DATA
 ****************************************************************************/
/****************************************************************************
 *    IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
 ****************************************************************************/

/* This file is generated by interface.pl script from interface.desc,
   and inc.in. */
static WINDOW *interface_init (void);
#include "abook.inc"

static WINDOW *interface_init_2 (void);
#include "abook_add.inc"

/****************************************************************************
 *    IMPLEMENTATION PRIVATE FUNCTIONS
 ****************************************************************************/


static int
int_value (const char *s)
{
        if (strcmp (s, "M") == 0)
                return SEX_MALE;
        if (strcmp (s, "m") == 0)
                return SEX_MALE;
        if (strcmp (s, "male") == 0)
                return SEX_MALE;

        if (strcmp (s, "F") == 0)
                return SEX_FEMALE;
        if (strcmp (s, "f") == 0)
                return SEX_FEMALE;
        if (strcmp (s, "female") == 0)
                return SEX_FEMALE;

        if (strcmp (s, "Y") == 0)
                return YES;
        if (strcmp (s, "y") == 0)
                return YES;
        if (strcmp (s, "yes") == 0)
                return YES;
        if (strcmp (s, "YES") == 0)
                return YES;
        if (strcmp (s, "1") == 0)
                return YES;
        if (strcmp (s, "true") == 0)
                return YES;
        if (strcmp (s, "t") == 0)
                return YES;
        if (strcmp (s, "T") == 0)
                return YES;

        return NO;
}


static void
write_groups (rstring_t *groups, FILE *fp)
{
        int i;

        for (i = 0; i < groups->count; i++){
                fprintf (fp, " group:\t\t%s\n", groups->array[i]);
        }
}


static void
write_addr (address_t *addr, FILE *fp)
{
        fprintf (fp, "addr {\n");

        /**
         * it won't work if name has both kinds of quotes (single and double)
         */
        if (addr->name){
                if (addr->flags.bits.atomic_name)
                        fprintf (fp, " name:\t\t%s\n", addr->name);
                else if (! addr->flags.bits.quotes_in_name)
                        fprintf (fp, " name:\t\t\"%s\"\n", addr->name);
                else
                        fprintf (fp, " name:\t\t'%s'\n", addr->name);
        }
        if (addr->email)
                fprintf (fp, " email:\t\t%s\n", addr->email);
        if (addr->initials)
                fprintf (fp, " initials:\t%s\n", addr->initials);
        if (addr->flags.bits.sex == SEX_MALE)
                fprintf (fp, " sex:\t\tM\n");
        else if (addr->flags.bits.sex == SEX_FEMALE)
                fprintf (fp, " sex:\t\tF\n");
        if (addr->flags.bits.official)
                fprintf (fp, " official:\tY\n");
        if (addr->flags.bits.foreign)
                fprintf (fp, " foreign:\tY\n");
        if (addr->groups)
                write_groups (addr->groups, fp);

        fprintf (fp, "}\n");
}


static int
cmp_addr (const void *a, const void *b)
{
        const address_t **aa = (const address_t **) a;
        const address_t **bb = (const address_t **) b;

        return address_cmp (*aa, *bb);
}


static void
set_color (WINDOW *win, int index)
{
        if (win == abook_select->win){
                if (bitarray_is_set (selected, index))
                        wattrset (win, picked_color);
                else
                        wattrset (win, text_color);
        }
        else {
                if (bitarray_is_set (selected, index))
                        wattrset (win, picked_bar_color);
                else
                        wattrset (win, select_bar_color ());
        }
}


static void
set_hilight_color (WINDOW *win)
{
        if (win == abook_select->win)
                wattrset (win, hilight_color);
        else
                wattrset (win, select_hilight_color ());
}


static void
unset_hilight_color (WINDOW *win)
{
        if (win == abook_select->win)
                wattrset (win, text_color);
        else
                wattrset (win, select_bar_color ());
}


static int
add_string (WINDOW *win, char *str, int maxlen, search_t *search)
{
        int pos = -1;
        int len = 1;
  
        if (maxlen <= 0)
                return 0;

        if (search)
                pos = search_perform (search, str);

        if (pos != -1){
                len  = search->pattern->len;
                pos -= len - 1;
                if (pos < 0)
                        pos = 0;
                window_addnstr (win, str, pos);
                set_hilight_color (win);
                window_addnstr (win, str + pos, len);
                unset_hilight_color (win);
                maxlen -= pos + len;
        }

        return pos + len + window_addnstr (win, str + pos + len, maxlen - 1);
}


static void
abook_draw_line (WINDOW *win, int maxlen, int index, search_t *search)
{
        if (str_line == NULL)
                str_line = str_create ();

        if (index >= 0 && abook && index < abook->count){
                eprintf_addr_str (abook_fmt, abook->array[index], str_line);
                set_color (win, index);
                maxlen -= add_string (win, str_line->str, maxlen, search);
        }

        while (maxlen-- > 0)
                window_addch (win, ' ');
}


static int
abook_count (select_t *nothing)
{
        return (abook) ? abook->count : 0;
}


static int
match_groups (search_t *search, rstring_t *groups)
{
        int i;

        for (i = 0; i < groups->count; i++){
                if (search_perform (search, groups->array[i]) != -1)
                        return 1;
        }

        return 0;
}


static int
match_address (search_t *search, int index)
{
        address_t *addr;
        
        if (index < 0 || index >= abook->count)
                return 0;

        addr = abook->array[index];

        if (addr->name && search_perform (search, addr->name) != -1)
                return 1;

        if (addr->email && search_perform (search, addr->email) != -1)
                return 1;

        if (addr->groups && match_groups (search, addr->groups))
                return 1;

        return 0;
}


static void
add_draw_line (WINDOW *win, int maxlen, int index, search_t *search)
{
        if (str_line == NULL)
                str_line = str_create ();

        if (index >= 0 && add_raddress && index < add_raddress->count){
                eprintf_addr_str (abook_fmt, add_raddress->array[index],
                                  str_line);
                maxlen -= window_addnstr (win, str_line->str, maxlen);
        }

        while (maxlen-- > 0)
                window_addch (win, ' ');
}


static int
add_count (select_t *nothing)
{
        return (add_raddress) ? add_raddress->count : 0;
}


static void
redraw_label (void)
{
        if (label == NULL)
                return;

        if (str_line == NULL)
                str_line = str_create ();

        eprintf_addr_desc (abook_fmt, str_line);
        label_set_text (label, str_line->str);
        label_redraw (label);
}


static void
redraw_add_label (void)
{
        if (label_add == NULL)
                return;

        if (str_line == NULL)
                str_line = str_create ();

        eprintf_addr_desc (abook_fmt, str_line);
        label_set_text (label_add, str_line->str);
        label_redraw (label_add);
}



static void
destroy_groups (void)
{
        int        i;
        address_t *addr;

        for (i = 0; i < abook->count; i++){
                addr = abook->array[i];
                if (addr->groups)
                        rstring_delete (addr->groups);
        }
}


/****************************************************************************
 *    INTERFACE FUNCTIONS
 ****************************************************************************/


void
abook_init (void)
{
        WINDOW *window;

        window     = interface_init_2 ();
        add_select = select_open (window, 0, add_draw_line, add_count);
        window_set_functions (window, abook_add_refresh, abook_add_redraw,
                              abook_add_set_focus, abook_add_unset_focus);

        window       = interface_init ();
        abook_select = select_open (window, 0, abook_draw_line, abook_count);

        window_set_functions (window, abook_refresh, abook_redraw,
                              abook_set_focus, abook_unset_focus);

        abook_load ();
}



void
abook_free_resources (void)
{
        destroy_groups ();
        
        if (addr_block)
                memblock_destroy (addr_block);
        addr_block = NULL;
        
        if (abook)
                raddress_destroy (abook);
        abook = NULL;

        if (str_line)
                str_destroy (str_line);
        str_line = NULL;

        if (abook_select)
                select_close (abook_select);
        abook_select = NULL;

        if (add_select)
                select_close (add_select);
        add_select = NULL;

        if (label)
                label_destroy (label);
        label = NULL;

        if (label_add)
                label_destroy (label_add);
        label_add = NULL;

        if (selected)
                bitarray_destroy (selected);
        selected = NULL;

        if (add_raddress)
                raddress_destroy (add_raddress);
        add_raddress = NULL;
}



void
abook_refresh (void)
{
        select_show (abook_select);
        if (label)
                label_show (label);
}


void
abook_redraw (void)
{
        select_redraw (abook_select);
        redraw_label ();
}


void
abook_set_focus (void)
{
        if (label)
                label_set_focus (label);
        cmd_state_push (CMD_ABOOK);

        abook_redraw ();
}


void
abook_unset_focus (void)
{
        if (label){
                label_unset_focus (label);
                redraw_label ();
        }
        cmd_state_pop ();
}


void
abook_add_refresh (void)
{
        select_show (add_select);
        if (label_add)
                label_show (label_add);
}


void
abook_add_redraw (void)
{
        select_redraw (add_select);
        redraw_add_label ();
}


void
abook_add_set_focus (void)
{
        if (label_add)
                label_set_focus (label_add);
        cmd_state_push (CMD_ABOOK_ADD);

        abook_add_redraw ();
}


void
abook_add_unset_focus (void)
{
        if (label_add){
                label_unset_focus (label_add);
                redraw_add_label ();
        }
        cmd_state_pop ();
}


void
abook_show (void)
{
        window_show (abook_select->win);
        abook_sort ();
}


void
abook_hide (void)
{
        window_hide (abook_select->win);
}


void
abook_load (void)
{
        char *dfl_location = DFL_LOCATION ();
        char *fname        = ask_for_default ("addressbook", NULL);

        if (fname == NULL)
                fname = dfl_location;

        addr_block   = memblock_create (INITIAL_BLOCK_SIZE);
        abook        = raddress_create ();
        abook_sorted = 0;
        confread_read_file (fname, fname == dfl_location);
        selected     = bitarray_create (abook->count + 1);

        bitarray_zeros (selected);
  
        xfree (dfl_location);
}


void
abook_save (void)
{
        int     i;
        address_t *addr;
        char   *dfl_location;
        char   *fname;
        FILE   *fp;


        if (! abook_changed)
                return;

        dfl_location = DFL_LOCATION ();
        fname        = ask_for_default ("addressbook", NULL);

        if (fname == NULL)
                fname = dfl_location;

        fp = fopen (fname, "w");
        if (fp == NULL){
                error_ (errno, "%s", fname);
                xfree (dfl_location);
                return;
        }

        for (i = 0; i < abook->count; i++){
                addr = abook->array[i];
                write_addr (addr, fp);
        }

        fclose (fp);
        xfree (dfl_location);
}



void
abook_sort (void)
{
        if (abook == NULL)
                return;
  
        if (abook_sorted)
                return;

        qsort (abook->array, abook->count, sizeof (address_t *), cmp_addr);
        abook_sorted = 1;
        abook_redraw ();
}


rstring_t *
abook_strings (const char *prefix)
{
        int        i;
        char      *str;
        address_t *addr;
        rstring_t *result;

        if (abook == NULL)
                return NULL;
        
        result = rstring_create_size (abook->count + 1);

        if (*prefix == '"')
                prefix++;
  
        for (i = 0; i < abook->count; i++){
                addr = abook->array[i];
                if (*addr->full == '"')
                        str = addr->full + 1;
                else
                        str = addr->full;
                if (strstr (str, prefix) == str)
                        rstring_add (result, abook->array[i]->full);
        }
  
        return result;
}

/****************************************************************************
 *    ADDRESSBOOK WINDOW PRIVATE DATA
 ****************************************************************************/

/**
 * This string holds list of addresses that may be a value of To field.
 */
static str_t *to_str = NULL;

/****************************************************************************
 *    ADDRESSBOOK WINDOW PRIVATE FUNCTIONS
 ****************************************************************************/

static void
action_remove (int index)
{
        address_t *addr = abook->array[index];

        addr->flags.bits.abook = NO;
  
        abook_changed = 1;
        raddress_remove (abook, index);
}



static void
action_change_sex (int index)
{
        address_t *addr = abook->array[index];

        if (addr->flags.bits.sex == SEX_MALE)
                addr->flags.bits.sex = SEX_FEMALE;
        else if (addr->flags.bits.sex == SEX_FEMALE)
                addr->flags.bits.sex = SEX_MALE;

        if (addr->flags.bits.sex != SEX_UNKNOWN)
                abook_changed = 1;
}


static void
action_change_official (int index)
{
        address_t *addr = abook->array[index];

        addr->flags.bits.official = ! addr->flags.bits.official;
        abook_changed             = 1;
}


static void
action_change_foreign (int index)
{
        address_t *addr = abook->array[index];

        addr->flags.bits.foreign = ! addr->flags.bits.foreign;
        abook_changed            = 1;
}


static void
action_add_to_str (int index)
{
        address_t *addr = abook->array[index];
  
        if (to_str->len == 0)
                str_sprintf (to_str, "%s", addr->full);
        else
                str_sprintf (to_str, ", %s", addr->full);
}


static void
take_action (void (*fun)(int))
{
        int i;
        int took = 0;

        for (i = abook->count - 1; i >= 0; i--){
                if (bitarray_is_set (selected, i)){
                        fun (i);
                        took = 1;
                }
        }

        if (! took && abook->count > 0){
                fun (abook_select->bar_pos);
        }

        bitarray_zeros (selected);
}


/****************************************************************************
 *    ADDRESSBOOK WINDOW INTERFACE FUNCTIONS
 ****************************************************************************/


void
abook_next (void)
{
        select_next (abook_select);
}



void
abook_prev (void)
{
        select_prev (abook_select);
}



void
abook_next_page (void)
{
        select_next_page (abook_select);
}



void
abook_prev_page (void)
{
        select_prev_page (abook_select);
}



void
abook_first (void)
{
        select_first (abook_select);
}



void
abook_last (void)
{
        select_last (abook_select);
}


void
abook_hit (void)
{
        bitarray_change_bit (selected, abook_select->bar_pos);
        select_redraw (abook_select);
}



void
abook_hit_all (void)
{
        bitarray_neg (selected);
        select_redraw (abook_select);
}


void
abook_set (void)
{
        bitarray_set (selected, abook_select->bar_pos);
        select_redraw (abook_select);
}


void
abook_unset (void)
{
        bitarray_unset (selected, abook_select->bar_pos);
        select_redraw (abook_select);
}


void
abook_set_all (void)
{
        bitarray_ones (selected);
        select_redraw (abook_select);
}


void
abook_unset_all (void)
{
        bitarray_zeros (selected);
        select_redraw (abook_select);
}



void
abook_remove (void)
{
        take_action (action_remove);
        select_redraw (abook_select);
}


void
abook_change_official (void)
{
        take_action (action_change_official);
        select_redraw (abook_select);
}



void
abook_change_sex (void)
{
        take_action (action_change_sex);
        select_redraw (abook_select);
}


void
abook_change_foreign (void)
{
        take_action (action_change_foreign);
        select_redraw (abook_select);
}


void
abook_compose (void)
{
        to_str = str_create ();
        take_action (action_add_to_str);
        if (to_str){
                sender_open_new_to (to_str->str);
                str_destroy (to_str);
        }
        to_str = NULL;
}


void
abook_insert (void)
{
        address_t *addr;
        char      *name;
        char      *email;

        name = read_argument (_("Name: "), NULL, COMPLETE_NONE, HIDE_NO);
        if (name == NULL)
                return;
        if (*name == '\0')
                name = NULL;
        else
                name = memblock_strdup (& addr_block, name);

        email = read_argument (_("Email: "), NULL, COMPLETE_NONE, HIDE_NO);
        if (email == NULL)
                return;
        if (*email == '\0')
                email = NULL;
        else
                email = memblock_strdup (& addr_block, email);

        if (name == NULL && email == NULL)
                return;
        
        addr        = address_empty ();
        addr->name  = name;
        addr->email = email;

        addr = address_complete (addr);

        addr->flags.bits.abook = YES;

        raddress_add (abook, addr);
        abook_changed = 1;
        abook_sorted  = 0;

        bitarray_resize (selected, abook->count);

        select_redraw (abook_select);
}



void
abook_change_name (void)
{
        address_t *addr;
        address_t *new;
        char      *name;

        addr = abook->array[abook_select->bar_pos];
        name = read_argument (_("Name: "), addr->name, COMPLETE_NONE,
                              HIDE_NO);
        if (name == NULL)
                return;
        if (*name == '\0')
                name = NULL;
        else
                name = memblock_strdup (& addr_block, name);

        addr->name = name;
        addr->full = NULL;

        new = address_complete (addr);

        if (new != addr){
                new->flags.bits.abook = YES;
        }

        abook_changed = 1;

        select_redraw (abook_select);
}



void
abook_change_email (void)
{
        address_t *addr;
        address_t *new;
        char      *email;

        addr  = abook->array[abook_select->bar_pos];
        email = read_argument (_("Email: "), addr->email, COMPLETE_NONE,
                               HIDE_NO);
        if (email == NULL)
                return;
        if (*email == '\0')
                email = NULL;
        else
                email = memblock_strdup (& addr_block, email);

        addr->email = email;
        addr->full  = NULL;

        new = address_complete (addr);

        if (new != addr){
                new->flags.bits.abook = YES;
        }

        abook_changed = 1;

        select_redraw (abook_select);
}



void
abook_change_groups (void)
{
        address_t *addr;
        char      *groups_str;
        char      *oldgroups;
        rstring_t *groups;

        addr       = abook->array[abook_select->bar_pos];
        oldgroups  = (addr->groups) ? rstring_flatten (addr->groups, ", ")
                : NULL;
        groups_str = read_argument (_("Groups: "), oldgroups, COMPLETE_NONE,
                                    HIDE_NO);
        if (oldgroups)
                xfree (oldgroups);
        
        if (groups_str == NULL)
                return;

        if (addr->groups)
                rstring_delete (addr->groups);
        addr->groups = NULL;

        if (*groups_str == '\0')
                return;

        groups_str = xstrdup (groups_str);
        groups     = rstring_split_re (groups_str, "[ \t]*,[ \t]*");
        groups->allocated_first = 1;

        addr->groups  = groups;
        abook_changed = 1;

        select_redraw (abook_select);
}



void
abook_search_forward (void)
{
        select_search_setup_forward (abook_select, match_address);
}


void
abook_search_backward (void)
{
        select_search_setup_backward (abook_select, match_address);
}


/****************************************************************************
 *    ADDRESSBOOK ADDING WINDOW FUNCTIONS
 ****************************************************************************/


void
abook_add_show (void)
{
        mail_t *mail = folder_mail_selected ();
  
        if (mail == NULL)
                return;
  
        if (add_raddress)
                raddress_destroy (add_raddress);

        add_raddress = raddress_create ();

        if (mail->from && ! mail->from->flags.bits.abook)
                raddress_add (add_raddress, mail->from);
        if (mail->reply_to && mail->reply_to != mail->from
            && ! mail->from->flags.bits.abook)
                raddress_add (add_raddress, mail->reply_to);
        if (mail->to)
                raddress_add_array (add_raddress, mail->to);
        if (mail->cc)
                raddress_add_array (add_raddress, mail->cc);

        window_show (add_select->win);
}



void
abook_add_hide (void)
{
        if (add_raddress){
                raddress_destroy (add_raddress);
                add_raddress = NULL;
        }

        window_hide (add_select->win);
}



void
abook_add_next (void)
{
        select_next (add_select);
}



void
abook_add_prev (void)
{
        select_prev (add_select);
}



void
abook_add_next_page (void)
{
        select_next_page (add_select);
}



void
abook_add_prev_page (void)
{
        select_prev_page (add_select);
}



void
abook_add_first (void)
{
        select_first (add_select);
}



void
abook_add_last (void)
{
        select_last (add_select);
}



void
abook_add_hit (void)
{
        address_t *addr = add_raddress->array[add_select->bar_pos];
        
        if (addr == NULL || addr->flags.bits.abook)
                return;

        raddress_remove (add_raddress, add_select->bar_pos);
        
        addr->flags.bits.abook = YES;
        raddress_add (abook, addr);
        abook_changed = 1;
        abook_sorted  = 0;

        bitarray_resize (selected, abook->count);

        select_redraw (add_select);
}


/****************************************************************************
 *    CONFIG FUNCTIONS
 ****************************************************************************/


void
abook_new_prepare (void)
{
        if (new_item.addr == NULL)
                new_item.addr = address_empty ();
}



void
abook_new_drop (void)
{
        new_item.s_field = NULL;
        new_item.shift   = 0;
        new_item.mask    = 0;
        new_item.group   = 0;
}



void
abook_new_store (void)
{
        address_t *addr = NULL;
        
        if (new_item.addr == NULL)
                return;

        if (new_item.addr->name == NULL && new_item.addr->email == NULL){
                abook_new_drop ();
                return;
        }

        addr = address_complete (new_item.addr);
        addr->flags.bits.abook = YES;
        
        raddress_add (abook, addr);

        new_item.addr    = NULL;
        new_item.s_field = NULL;
        new_item.shift   = 0;
        new_item.mask    = 0;
        new_item.group   = 0;
}



int
abook_new_field (const char *field)
{
        new_item.s_field = NULL;
        new_item.shift   = 0;
        new_item.mask    = 0;
        new_item.group   = 0;

        if (strcmp (field, "name") == 0)
                new_item.s_field = & new_item.addr->name;
        else if (strcmp (field, "email") == 0)
                new_item.s_field = & new_item.addr->email;
        else if (strcmp (field, "initials") == 0)
                new_item.s_field = & new_item.addr->initials;
        else if (strcmp (field, "sex") == 0){
                new_item.shift = A_SHIFT_SEX;
                new_item.mask  = A_MASK_SEX;
        }
        else if (strcmp (field, "official") == 0){
                new_item.shift = A_SHIFT_OFFICIAL;
                new_item.mask  = A_MASK_OFFICIAL;
        }
        else if (strcmp (field, "foreign") == 0){
                new_item.shift = A_SHIFT_FOREIGN;
                new_item.mask  = A_MASK_FOREIGN;
        }
        else if (strcmp (field, "group") == 0){
                new_item.group = 1;
        }

        if (new_item.s_field == NULL && new_item.shift == 0
            && new_item.mask == 0    && new_item.group == 0)
                return 1;
        
        return 0;
}



void
abook_new_value (const char *value)
{
        if (new_item.group){
                if (new_item.addr->groups == NULL)
                        new_item.addr->groups = rstring_create ();
                rstring_add (new_item.addr->groups,
                             memblock_strdup (& addr_block, value));
        }
        else if (new_item.s_field){
                *new_item.s_field = memblock_strdup (& addr_block, value);
        }
        else if (new_item.mask){
                new_item.addr->flags.value |=
                        (int_value (value) << new_item.shift) & new_item.mask;
        }
}



/****************************************************************************
 *    INTERFACE CLASS BODIES
 ****************************************************************************/
/****************************************************************************
 *
 *    END MODULE abook.c
 *
 ****************************************************************************/


syntax highlighted by Code2HTML, v. 0.9.1